blob: 39ae756200d696e639e3f59ba8f18860c78ff5d7 [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 }
1024 if (full_modeset) {
1025 struct drm_crtc_state *crtc_state =
1026 drm_atomic_get_crtc_state(state->state,
1027 state->crtc);
1028 crtc_state->mode_changed = true;
1029 to_sde_plane_state(state)->mode_changed = true;
1030 }
1031 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001032 to_sde_plane_state(state)->mode_changed = true;
1033 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001034 }
1035
Clarence Ipdbde9832016-06-26 09:48:36 -04001036exit:
1037 return ret;
1038}
1039
1040void sde_plane_complete_flip(struct drm_plane *plane)
1041{
1042 if (plane && plane->state)
1043 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001044}
1045
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001046static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001047 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001048{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001049 struct sde_plane *sde_plane;
1050 struct drm_plane_state *state;
1051 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001052
Clarence Ip5e2a9222016-06-26 22:38:24 -04001053 if (!plane || !plane->state) {
1054 DRM_ERROR("Invalid plane/state\n");
1055 return;
1056 }
1057
1058 sde_plane = to_sde_plane(plane);
1059 state = plane->state;
1060 pstate = to_sde_plane_state(state);
1061
Clarence Ipae4e60c2016-06-26 22:44:04 -04001062 DBG("%s: update", sde_plane->pipe_name);
1063
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001064 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001065 pstate->pending = true;
1066 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001067 int ret;
1068
Clarence Ip5e2a9222016-06-26 22:38:24 -04001069 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -04001070 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001071 state->crtc, state->fb,
1072 state->crtc_x, state->crtc_y,
1073 state->crtc_w, state->crtc_h,
1074 state->src_x, state->src_y,
1075 state->src_w, state->src_h);
1076 /* atomic_check should have ensured that this doesn't fail */
1077 WARN_ON(ret < 0);
1078 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001079 _sde_plane_set_scanout(plane, pstate,
1080 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001081 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001082}
1083
Clarence Ipae4e60c2016-06-26 22:44:04 -04001084static inline struct drm_property **_sde_plane_get_property_entry(
1085 struct drm_device *dev, enum msm_mdp_plane_property property)
1086{
1087 struct msm_drm_private *priv;
1088
1089 if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
1090 return NULL;
1091
1092 priv = dev->dev_private;
1093
1094 return &(priv->plane_property[property]);
1095}
1096
Clarence Ipe78efb72016-06-24 18:35:21 -04001097static void _sde_plane_install_range_property(struct drm_plane *plane,
1098 struct drm_device *dev, const char *name,
1099 uint64_t min, uint64_t max, uint64_t init,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001100 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001101{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001102 struct drm_property **prop;
1103
1104 prop = _sde_plane_get_property_entry(dev, property);
1105 if (plane && name && prop) {
Clarence Ipe78efb72016-06-24 18:35:21 -04001106 /* only create the property once */
1107 if (*prop == 0) {
1108 *prop = drm_property_create_range(dev,
1109 0 /* flags */, name, min, max);
1110 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001111 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -04001112 }
1113
Clarence Ipae4e60c2016-06-26 22:44:04 -04001114 /* save init value for later */
1115 to_sde_plane(plane)->property_defaults[property] = init;
1116
Clarence Ipe78efb72016-06-24 18:35:21 -04001117 /* always attach property, if created */
1118 if (*prop)
1119 drm_object_attach_property(&plane->base, *prop, init);
1120 }
1121}
1122
Clarence Ip5e2a9222016-06-26 22:38:24 -04001123static void _sde_plane_install_rotation_property(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001124 struct drm_device *dev, enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001125{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001126 struct sde_plane *psde;
1127 struct drm_property **prop;
1128
1129 prop = _sde_plane_get_property_entry(dev, property);
1130 if (plane && prop) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001131 /* only create the property once */
1132 if (*prop == 0) {
1133 *prop = drm_mode_create_rotation_property(dev,
1134 BIT(DRM_REFLECT_X) |
1135 BIT(DRM_REFLECT_Y));
1136 if (*prop == 0)
1137 DRM_ERROR("Create rotation property failed\n");
1138 }
1139
Clarence Ipae4e60c2016-06-26 22:44:04 -04001140 /* save init value for later */
1141 psde = to_sde_plane(plane);
1142 psde->property_defaults[property] = 0;
1143
Clarence Ip5e2a9222016-06-26 22:38:24 -04001144 /* always attach property, if created */
1145 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001146 drm_object_attach_property(&plane->base, *prop,
1147 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001148 }
1149}
1150
1151static void _sde_plane_install_enum_property(struct drm_plane *plane,
1152 struct drm_device *dev, const char *name, int is_bitmask,
1153 const struct drm_prop_enum_list *values, int num_values,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001154 enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001155{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001156 struct sde_plane *psde;
1157 struct drm_property **prop;
1158
1159 prop = _sde_plane_get_property_entry(dev, property);
1160 if (plane && name && prop && values && num_values) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001161 /* only create the property once */
1162 if (*prop == 0) {
1163 /* 'bitmask' is a special type of 'enum' */
1164 if (is_bitmask)
1165 *prop = drm_property_create_bitmask(dev,
1166 DRM_MODE_PROP_BITMASK, name,
1167 values, num_values, -1);
1168 else
1169 *prop = drm_property_create_enum(dev,
1170 DRM_MODE_PROP_ENUM, name,
1171 values, num_values);
1172 if (*prop == 0)
1173 DRM_ERROR("Create %s property failed\n", name);
1174 }
1175
Clarence Ipae4e60c2016-06-26 22:44:04 -04001176 /* save init value for later */
1177 psde = to_sde_plane(plane);
1178 psde->property_defaults[property] = 0;
1179
Clarence Ip5e2a9222016-06-26 22:38:24 -04001180 /* always attach property, if created */
1181 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001182 drm_object_attach_property(&plane->base, *prop,
1183 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001184 }
1185}
1186
Clarence Ipe78efb72016-06-24 18:35:21 -04001187static void _sde_plane_install_blob_property(struct drm_plane *plane,
1188 struct drm_device *dev, const char *name,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001189 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001190{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001191 struct sde_plane *psde;
1192 struct drm_property **prop;
1193
1194 prop = _sde_plane_get_property_entry(dev, property);
1195 if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001196 /* only create the property once */
1197 if (*prop == 0) {
1198 /* use 'create' for blob property place holder */
1199 *prop = drm_property_create(dev,
1200 DRM_MODE_PROP_BLOB, name, 0);
1201 if (*prop == 0)
1202 DRM_ERROR("Create %s property failed\n", name);
1203 }
1204
Clarence Ipae4e60c2016-06-26 22:44:04 -04001205 /* save init value for later */
1206 psde = to_sde_plane(plane);
1207 psde->property_defaults[property] = 0;
1208
Clarence Ip5e2a9222016-06-26 22:38:24 -04001209 /* always attach property, if created */
1210 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001211 drm_object_attach_property(&plane->base, *prop,
1212 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001213 }
Clarence Ipe78efb72016-06-24 18:35:21 -04001214}
1215
Clarence Ip4c1d9772016-06-26 09:35:38 -04001216static int _sde_plane_get_property_index(struct drm_plane *plane,
1217 struct drm_property *property)
1218{
1219 struct drm_property **prop_array;
1220 int idx = PLANE_PROP_COUNT;
1221
1222 if (!plane) {
1223 DRM_ERROR("Invalid plane\n");
1224 } else if (!plane->dev || !plane->dev->dev_private) {
1225 /* don't access dev_private if !dev */
1226 DRM_ERROR("Invalid device\n");
1227 } else if (!property) {
1228 DRM_ERROR("Incoming property is NULL\n");
1229 } else {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001230 prop_array = _sde_plane_get_property_entry(plane->dev, 0);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001231 if (!prop_array)
1232 /* should never hit this */
1233 DRM_ERROR("Invalid property array\n");
1234
1235 /* linear search is okay */
1236 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
1237 if (prop_array[idx] == property)
1238 break;
1239 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001240
1241 if (idx == PLANE_PROP_COUNT)
1242 DRM_ERROR("Invalid property pointer\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001243 }
1244
1245 return idx;
1246}
1247
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001248/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -04001249static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001250 struct drm_mode_object *obj,
1251 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001252{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001253 static const struct drm_prop_enum_list e_blend_op[] = {
1254 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1255 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1256 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1257 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1258 };
1259 static const struct drm_prop_enum_list e_src_config[] = {
1260 {SDE_DRM_DEINTERLACE, "deinterlace"}
1261 };
1262 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001263 struct drm_device *dev = plane->dev;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001264
Clarence Ip4ce59322016-06-26 22:27:51 -04001265 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001266
Clarence Ipcb410d42016-06-26 22:52:33 -04001267 if (!psde || !psde->pipe_hw || !psde->pipe_sblk || !catalog) {
1268 DRM_ERROR("Catalog or h/w driver definition error\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001269 return;
1270 }
1271
1272 /* range properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001273 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
1274 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1275 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1276 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001277
Clarence Ip5e2a9222016-06-26 22:38:24 -04001278 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001279 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001280
Clarence Ipcb410d42016-06-26 22:52:33 -04001281 if (psde->pipe_hw->ops.setup_solidfill)
1282 _sde_plane_install_range_property(plane, dev, "color_fill",
1283 0, 0xFFFFFFFF, 0,
1284 PLANE_PROP_COLOR_FILL);
1285
Clarence Ipae4e60c2016-06-26 22:44:04 -04001286 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
1287 PLANE_PROP_SYNC_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001288
Clarence Ipcb410d42016-06-26 22:52:33 -04001289 _sde_plane_install_range_property(plane, dev, "sync_fence_timeout",
1290 0, ~0, 10000,
1291 PLANE_PROP_SYNC_FENCE_TIMEOUT);
1292
Clarence Ip5e2a9222016-06-26 22:38:24 -04001293 /* standard properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001294 _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001295
Clarence Ip04ec67d2016-05-26 01:16:15 -04001296 /* enum/bitmask properties */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001297 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
1298 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001299 PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001300 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
1301 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001302 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001303
Clarence Ipe78efb72016-06-24 18:35:21 -04001304 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001305 if (psde->features & SDE_SSPP_SCALER)
1306 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001307 PLANE_PROP_SCALER);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001308 if (psde->features & BIT(SDE_SSPP_CSC))
1309 _sde_plane_install_blob_property(plane, dev, "csc",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001310 PLANE_PROP_CSC);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001311}
1312
1313static int sde_plane_atomic_set_property(struct drm_plane *plane,
1314 struct drm_plane_state *state, struct drm_property *property,
1315 uint64_t val)
1316{
Clarence Ip730e7192016-06-26 22:45:09 -04001317 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001318 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001319 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001320 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001321
Clarence Ip4c1d9772016-06-26 09:35:38 -04001322 idx = _sde_plane_get_property_index(plane, property);
1323 if (!state) {
1324 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001325 } else if (idx >= PLANE_PROP_COUNT) {
1326 DRM_ERROR("Invalid property\n");
1327 } else {
1328 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001329 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001330
Lloyd Atkinson0fda6c52016-02-04 15:09:43 -05001331 DBG("%s: pipe %d, prop %s, val %d", psde->pipe_name,
1332 sde_plane_pipe(plane),
1333 property->name, (int)val);
Clarence Ip730e7192016-06-26 22:45:09 -04001334
Clarence Ipae4e60c2016-06-26 22:44:04 -04001335 /* extra handling for incoming properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001336 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1337 (idx < PLANE_PROP_BLOBCOUNT)) {
1338 /* DRM lookup also takes a reference */
1339 blob = drm_property_lookup_blob(plane->dev,
1340 (uint32_t)val);
1341 if (!blob) {
1342 DRM_ERROR("Blob not found\n");
1343 val = 0;
1344 } else {
1345 DBG("Blob %u saved", blob->base.id);
1346 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001347
Clarence Ip4c1d9772016-06-26 09:35:38 -04001348 /* save blobs for later */
1349 pr_blob = &pstate->property_blobs[idx];
1350 /* need to clear previous reference */
1351 if (*pr_blob)
1352 drm_property_unreference_blob(*pr_blob);
1353 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001354 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001355 } else if (idx == PLANE_PROP_SYNC_FENCE) {
1356 _sde_plane_update_sync_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001357 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001358 pstate->property_values[idx] = val;
1359 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001360 }
1361
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001362 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001363}
1364
1365static int sde_plane_set_property(struct drm_plane *plane,
1366 struct drm_property *property, uint64_t val)
1367{
Clarence Ip4ce59322016-06-26 22:27:51 -04001368 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001369
1370 if (!plane)
1371 return -EINVAL;
1372
Clarence Ipae4e60c2016-06-26 22:44:04 -04001373 return sde_plane_atomic_set_property(plane,
1374 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001375}
1376
1377static int sde_plane_atomic_get_property(struct drm_plane *plane,
1378 const struct drm_plane_state *state,
1379 struct drm_property *property, uint64_t *val)
1380{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001381 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001382 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001383
Clarence Ip4c1d9772016-06-26 09:35:38 -04001384 idx = _sde_plane_get_property_index(plane, property);
1385 if (!state) {
1386 DRM_ERROR("Invalid state\n");
1387 } else if (!val) {
1388 DRM_ERROR("Value pointer is NULL\n");
1389 } else if (idx < PLANE_PROP_COUNT) {
1390 pstate = to_sde_plane_state(state);
1391
1392 *val = pstate->property_values[idx];
Clarence Ipae4e60c2016-06-26 22:44:04 -04001393 DBG("%d 0x%llX", idx, *val);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001394 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001395 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001396
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001397 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001398}
1399
Clarence Ip730e7192016-06-26 22:45:09 -04001400static struct sde_plane_state *sde_plane_alloc_state(struct drm_plane *plane)
1401{
1402 struct sde_plane *psde;
1403 struct sde_plane_state *pstate;
1404
1405 if (!plane)
1406 return NULL;
1407
1408 psde = to_sde_plane(plane);
1409 pstate = NULL;
1410
1411 mutex_lock(&psde->lock);
1412 if (psde->state_cache_size)
1413 pstate = psde->state_cache[--(psde->state_cache_size)];
1414 mutex_unlock(&psde->lock);
1415
1416 if (!pstate)
1417 pstate = kmalloc(sizeof(struct sde_plane_state), GFP_KERNEL);
1418
1419 return pstate;
1420}
1421
1422static void sde_plane_free_state(struct drm_plane *plane,
1423 struct sde_plane_state *pstate)
1424{
1425 struct sde_plane *psde;
1426
1427 if (!plane || !pstate)
1428 return;
1429
1430 psde = to_sde_plane(plane);
1431
1432 mutex_lock(&psde->lock);
1433 if (psde->state_cache_size < SDE_STATE_CACHE_SIZE) {
1434 psde->state_cache[(psde->state_cache_size)++] = pstate;
1435 mutex_unlock(&psde->lock);
1436 } else {
1437 mutex_unlock(&psde->lock);
1438 kfree(pstate);
1439 }
1440}
1441
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001442static void sde_plane_destroy(struct drm_plane *plane)
1443{
Clarence Ip4ce59322016-06-26 22:27:51 -04001444 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001445
Clarence Ip4ce59322016-06-26 22:27:51 -04001446 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001447
Clarence Ip4ce59322016-06-26 22:27:51 -04001448 if (plane) {
1449 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001450
Clarence Ip4ce59322016-06-26 22:27:51 -04001451 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001452
Clarence Ip730e7192016-06-26 22:45:09 -04001453 mutex_destroy(&psde->lock);
1454
Clarence Ip4ce59322016-06-26 22:27:51 -04001455 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001456
Clarence Ip4ce59322016-06-26 22:27:51 -04001457 /* this will destroy the states as well */
1458 drm_plane_cleanup(plane);
1459
Clarence Ip4c1d9772016-06-26 09:35:38 -04001460 if (psde->pipe_hw)
1461 sde_hw_sspp_destroy(psde->pipe_hw);
1462
Clarence Ip730e7192016-06-26 22:45:09 -04001463 /* free state cache */
1464 while (psde->state_cache_size > 0)
1465 kfree(psde->state_cache[--(psde->state_cache_size)]);
1466
Clarence Ip4ce59322016-06-26 22:27:51 -04001467 kfree(psde);
1468 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001469}
1470
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001471static void sde_plane_destroy_state(struct drm_plane *plane,
1472 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001473{
Clarence Ipe78efb72016-06-24 18:35:21 -04001474 struct sde_plane_state *pstate;
1475 int i;
1476
Clarence Ipae4e60c2016-06-26 22:44:04 -04001477 if (!plane || !state) {
1478 DRM_ERROR("Invalid plane/state\n");
1479 return;
1480 }
1481
Clarence Ip730e7192016-06-26 22:45:09 -04001482 pstate = to_sde_plane_state(state);
1483
1484 DBG("");
1485
Clarence Ipe78efb72016-06-24 18:35:21 -04001486 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001487 if (state->fb)
1488 drm_framebuffer_unreference(state->fb);
1489
Clarence Ipae4e60c2016-06-26 22:44:04 -04001490 /* remove ref count for fence */
1491 if (pstate->sync_fence)
1492 sde_sync_put(pstate->sync_fence);
1493
Clarence Ipe78efb72016-06-24 18:35:21 -04001494 /* remove ref count for blobs */
1495 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1496 if (pstate->property_blobs[i])
1497 drm_property_unreference_blob(
1498 pstate->property_blobs[i]);
Clarence Ip730e7192016-06-26 22:45:09 -04001499 sde_plane_free_state(plane, pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001500}
1501
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001502static struct drm_plane_state *
1503sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001504{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001505 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001506 struct sde_plane_state *old_state;
Clarence Ipe78efb72016-06-24 18:35:21 -04001507 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001508
Clarence Ip730e7192016-06-26 22:45:09 -04001509 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001510 return NULL;
1511
Clarence Ip730e7192016-06-26 22:45:09 -04001512 old_state = to_sde_plane_state(plane->state);
1513 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001514
1515 DBG("");
1516
Clarence Ip730e7192016-06-26 22:45:09 -04001517 if (!pstate)
1518 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001519
Clarence Ip730e7192016-06-26 22:45:09 -04001520 memcpy(pstate, old_state, sizeof(*pstate));
Clarence Ipae4e60c2016-06-26 22:44:04 -04001521
Clarence Ip730e7192016-06-26 22:45:09 -04001522 /* add ref count for frame buffer */
1523 if (pstate->base.fb)
1524 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001525
Clarence Ip730e7192016-06-26 22:45:09 -04001526 /* add ref count for fence */
1527 if (pstate->sync_fence) {
1528 pstate->sync_fence = 0;
1529 _sde_plane_update_sync_fence(plane, pstate, pstate->
1530 property_values[PLANE_PROP_SYNC_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001531 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001532
Clarence Ip730e7192016-06-26 22:45:09 -04001533 /* add ref count for blobs */
1534 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1535 if (pstate->property_blobs[i])
1536 drm_property_reference_blob(
1537 pstate->property_blobs[i]);
1538
1539 pstate->mode_changed = false;
1540 pstate->pending = false;
1541
1542 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001543}
1544
1545static void sde_plane_reset(struct drm_plane *plane)
1546{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001547 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001548 struct sde_plane_state *pstate;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001549 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001550
Clarence Ipae4e60c2016-06-26 22:44:04 -04001551 if (!plane) {
1552 DRM_ERROR("Invalid plane\n");
1553 return;
1554 }
1555
Clarence Ip730e7192016-06-26 22:45:09 -04001556 psde = to_sde_plane(plane);
1557 DBG("%s", psde->pipe_name);
1558
Clarence Ipae4e60c2016-06-26 22:44:04 -04001559 /* remove previous state, if present */
1560 if (plane->state)
1561 sde_plane_destroy_state(plane, plane->state);
1562 plane->state = 0;
1563
Clarence Ip730e7192016-06-26 22:45:09 -04001564 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001565 if (!pstate) {
Clarence Ip730e7192016-06-26 22:45:09 -04001566 DRM_ERROR("Failed to (re)allocate plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001567 return;
1568 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001569
Clarence Ip730e7192016-06-26 22:45:09 -04001570 memset(pstate, 0, sizeof(*pstate));
1571
Clarence Ipae4e60c2016-06-26 22:44:04 -04001572 /* assign default property values */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001573 for (i = 0; i < PLANE_PROP_COUNT; ++i)
1574 pstate->property_values[i] = psde->property_defaults[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001575
1576 pstate->base.plane = plane;
1577
1578 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001579}
1580
1581static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001582 .update_plane = drm_atomic_helper_update_plane,
1583 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001584 .destroy = sde_plane_destroy,
1585 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001586 .atomic_set_property = sde_plane_atomic_set_property,
1587 .atomic_get_property = sde_plane_atomic_get_property,
1588 .reset = sde_plane_reset,
1589 .atomic_duplicate_state = sde_plane_duplicate_state,
1590 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001591};
1592
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001593static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1594 .prepare_fb = sde_plane_prepare_fb,
1595 .cleanup_fb = sde_plane_cleanup_fb,
1596 .atomic_check = sde_plane_atomic_check,
1597 .atomic_update = sde_plane_atomic_update,
1598};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001599
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001600enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001601{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001602 struct sde_plane *sde_plane = to_sde_plane(plane);
1603
1604 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001605}
1606
Clarence Ip4ce59322016-06-26 22:27:51 -04001607static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1608{
1609 const struct sde_sspp_sub_blks *sblk = 0;
1610 const struct sde_sspp_cfg *cfg = 0;
1611
1612 if (psde && psde->pipe_hw)
1613 cfg = psde->pipe_hw->cap;
1614 if (cfg)
1615 sblk = cfg->sblk;
1616
1617 if (kms && sblk) {
1618 /* create overall sub-directory for the pipe */
1619 psde->debugfs_root =
1620 debugfs_create_dir(psde->pipe_name,
1621 sde_debugfs_get_root(kms));
1622 if (psde->debugfs_root) {
1623 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001624 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001625 psde->debugfs_root, &psde->features);
1626
1627 /* add register dump support */
1628 sde_debugfs_setup_regset32(&psde->debugfs_src,
1629 sblk->src_blk.base + cfg->base,
1630 sblk->src_blk.len,
1631 kms->mmio);
1632 sde_debugfs_create_regset32("src_blk", 0444,
1633 psde->debugfs_root, &psde->debugfs_src);
1634
1635 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1636 sblk->scaler_blk.base + cfg->base,
1637 sblk->scaler_blk.len,
1638 kms->mmio);
1639 sde_debugfs_create_regset32("scaler_blk", 0444,
1640 psde->debugfs_root,
1641 &psde->debugfs_scaler);
1642
1643 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1644 sblk->csc_blk.base + cfg->base,
1645 sblk->csc_blk.len,
1646 kms->mmio);
1647 sde_debugfs_create_regset32("csc_blk", 0444,
1648 psde->debugfs_root, &psde->debugfs_csc);
1649 }
1650 }
1651}
1652
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001653/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001654struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001655 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001656{
1657 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001658 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001659 struct msm_drm_private *priv;
1660 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001661 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001662 int ret = -EINVAL;
1663
1664 if (!dev) {
1665 DRM_ERROR("[%u]Device is NULL\n", pipe);
1666 goto exit;
1667 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001668
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001669 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001670 if (!priv) {
1671 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1672 goto exit;
1673 }
1674
1675 if (!priv->kms) {
1676 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1677 goto exit;
1678 }
1679 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001680
Clarence Ip4c1d9772016-06-26 09:35:38 -04001681 if (!kms->catalog) {
1682 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1683 goto exit;
1684 }
1685
Clarence Ip4ce59322016-06-26 22:27:51 -04001686 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001687 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1688 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001689 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001690 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001691 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001692 }
1693
Clarence Ip4c1d9772016-06-26 09:35:38 -04001694 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001695 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001696 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001697 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001698
Clarence Ip4c1d9772016-06-26 09:35:38 -04001699 /* initialize underlying h/w driver */
1700 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1701 if (IS_ERR(psde->pipe_hw)) {
1702 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1703 ret = PTR_ERR(psde->pipe_hw);
1704 goto clean_plane;
1705 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1706 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1707 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001708 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001709
1710 /* cache features mask for later */
1711 psde->features = psde->pipe_hw->cap->features;
1712 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1713
1714 /* add plane to DRM framework */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001715 psde->nformats = mdp_get_formats(psde->formats,
1716 ARRAY_SIZE(psde->formats),
1717 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001718 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001719
Clarence Ip4c1d9772016-06-26 09:35:38 -04001720 if (!psde->nformats) {
1721 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1722 goto clean_sspp;
1723 }
1724
1725 if (psde->features & BIT(SDE_SSPP_CURSOR))
1726 type = DRM_PLANE_TYPE_CURSOR;
1727 else if (primary_plane)
1728 type = DRM_PLANE_TYPE_PRIMARY;
1729 else
1730 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001731 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1732 psde->formats, psde->nformats,
1733 type);
1734 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001735 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001736
Clarence Ip4c1d9772016-06-26 09:35:38 -04001737 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001738 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001739
Clarence Ip4c1d9772016-06-26 09:35:38 -04001740 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001741
Clarence Ip4ce59322016-06-26 22:27:51 -04001742 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001743 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001744
Clarence Ip730e7192016-06-26 22:45:09 -04001745 mutex_init(&psde->lock);
1746
Clarence Ip4ce59322016-06-26 22:27:51 -04001747 _sde_plane_init_debugfs(psde, kms);
1748
Clarence Ip4c1d9772016-06-26 09:35:38 -04001749 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001750 return plane;
1751
Clarence Ip4c1d9772016-06-26 09:35:38 -04001752clean_sspp:
1753 if (psde && psde->pipe_hw)
1754 sde_hw_sspp_destroy(psde->pipe_hw);
1755clean_plane:
1756 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001757exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001758 return ERR_PTR(ret);
1759}