blob: 906428d50f636fd6ff71637e695d9fbca704fe3e [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,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400169 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400170 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,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400188 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400189 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] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400207 (src <= dst) ? SDE_SCALE_FILTER_BIL :
208 SDE_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)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400211 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400212 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] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400216 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400217 }
218 } else {
219 /* disable scaler */
Clarence Ipcb410d42016-06-26 22:52:33 -0400220 DBG("Disable scaler");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400221 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
222 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
223 filter[SDE_SSPP_COMP_3] = SDE_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,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400247 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400248 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 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400257 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400258 caf = PHASE_STEP_UNIT_SCALE;
259 else
260 caf = 0;
261
262 for (i = 0; i < SDE_MAX_PLANES; i++) {
263 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400264 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400265 src_work /= chroma_subsampling;
266 if (post_compare)
267 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400268 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400269 /* unity */
270 edge1 = 0;
271 edge2 = 0;
272 } else if (dst >= src) {
273 /* upscale */
274 edge1 = (1 << PHASE_RESIDUAL);
275 edge1 -= caf;
276 edge2 = (1 << PHASE_RESIDUAL);
277 edge2 += (dst - 1) * *(phase_steps + i);
278 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
279 edge2 += caf;
280 edge2 = -(edge2);
281 } else {
282 /* downscale */
283 edge1 = 0;
284 edge2 = (dst - 1) * *(phase_steps + i);
285 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
286 edge2 += *(phase_steps + i);
287 edge2 = -(edge2);
288 }
289
290 /* only enable CAF for luma plane */
291 caf = 0;
292
293 /* populate output arrays */
294 *(out_src + i) = src_work;
295
296 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400297 if (edge1 >= 0) {
298 tmp = (uint32_t)edge1;
299 tmp >>= PHASE_STEP_SHIFT;
300 *(out_edge1 + i) = -tmp;
301 } else {
302 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400303 *(out_edge1 + i) =
304 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
305 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400306 }
307 if (edge2 >= 0) {
308 tmp = (uint32_t)edge2;
309 tmp >>= PHASE_STEP_SHIFT;
310 *(out_edge2 + i) = -tmp;
311 } else {
312 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400313 *(out_edge2 + i) =
314 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
315 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400316 }
317 }
318 }
319}
320
Clarence Ip5e2a9222016-06-26 22:38:24 -0400321static void *_sde_plane_get_blob(struct sde_plane_state *pstate,
322 enum msm_mdp_plane_property property, size_t *byte_len)
323{
324 struct drm_property_blob *blob;
325 size_t len = 0;
326 void *ret = 0;
327
Clarence Ip4c1d9772016-06-26 09:35:38 -0400328 if (!pstate || (property >= PLANE_PROP_BLOBCOUNT)) {
329 DRM_ERROR("Invalid argument(s)\n");
330 } else {
331 blob = pstate->property_blobs[property];
Clarence Ip5e2a9222016-06-26 22:38:24 -0400332 if (blob) {
333 len = blob->length;
334 ret = &blob->data;
335 }
336 }
337
338 if (byte_len)
339 *byte_len = len;
340
341 return ret;
342}
343
344/**
345 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
346 * sub-structure
347 * @blob_ptr: Pointer to start of incoming blob data
348 * @blob_size: Size of incoming blob data, in bytes
349 * @sub_ptr: Pointer to start of desired sub-structure
350 * @sub_size: Required size of sub-structure, in bytes
351 */
352static int _sde_plane_verify_blob(void *blob_ptr,
353 size_t blob_size,
354 void *sub_ptr,
355 size_t sub_size)
356{
357 /*
358 * Use the blob size provided by drm to check if there are enough
359 * bytes from the start of versioned sub-structures to the end of
360 * blob data:
361 *
362 * e.g.,
363 * blob_ptr --> struct blob_data {
364 * uint32_t version;
365 * sub_ptr --> struct blob_data_v1 v1;
366 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
367 * blob_ptr + blob_size --> };
368 *
369 * It's important to check the actual number of bytes from the start
370 * of the sub-structure to the end of the blob data, and not just rely
371 * on something like,
372 *
373 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
374 *
375 * This is because the start of the sub-structure can vary based on
376 * how the compiler pads the overall structure.
377 */
378 if (blob_ptr && sub_ptr)
379 /* return zero if end of blob >= end of sub-struct */
380 return ((unsigned char *)blob_ptr + blob_size) <
381 ((unsigned char *)sub_ptr + sub_size);
382 return -EINVAL;
383}
384
Clarence Ipe78efb72016-06-24 18:35:21 -0400385static void _sde_plane_setup_csc(struct sde_plane *psde,
386 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400387 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400388{
389 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
390 {
Clarence Ip373f8592016-05-26 00:58:42 -0400391 /* S15.16 format */
392 0x00012A00, 0x00000000, 0x00019880,
393 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
394 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400395 },
Clarence Ip373f8592016-05-26 00:58:42 -0400396 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400397 { 0xfff0, 0xff80, 0xff80,},
398 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400399 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400400 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400401 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400402 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400403 static const struct sde_csc_cfg sde_csc_NOP = {
404 {
Clarence Ip373f8592016-05-26 00:58:42 -0400405 /* identity matrix, S15.16 format */
406 0x10000, 0x00000, 0x00000,
407 0x00000, 0x10000, 0x00000,
408 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400409 },
Clarence Ip373f8592016-05-26 00:58:42 -0400410 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400411 { 0x0, 0x0, 0x0,},
412 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400413 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400414 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
415 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
416 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400417 struct sde_drm_csc *csc = NULL;
418 size_t csc_size = 0;
419 bool user_blob = false;
Clarence Ipe78efb72016-06-24 18:35:21 -0400420
421 if (!psde->pipe_hw->ops.setup_csc)
422 return;
423
Clarence Ip5e2a9222016-06-26 22:38:24 -0400424 /* check for user space override */
425 csc = _sde_plane_get_blob(pstate, PLANE_PROP_CSC, &csc_size);
426 if (csc) {
427 struct sde_csc_cfg cfg;
428 int i;
429
430 /* user space override */
431 memcpy(&cfg, &sde_csc_NOP, sizeof(struct sde_csc_cfg));
432 switch (csc->version) {
433 case SDE_DRM_CSC_V1:
434 if (!_sde_plane_verify_blob(csc,
435 csc_size,
436 &csc->v1,
437 sizeof(struct sde_drm_csc_v1))) {
438 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
439 cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400440 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400441 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
442 cfg.csc_pre_bv[i] =
443 csc->v1.pre_bias[i];
444 cfg.csc_post_bv[i] =
445 csc->v1.post_bias[i];
446 }
447 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
448 cfg.csc_pre_lv[i] =
449 csc->v1.pre_clamp[i];
450 cfg.csc_post_lv[i] =
451 csc->v1.post_clamp[i];
452 }
453 user_blob = true;
454 }
455 break;
456 default:
457 break;
458 }
459
460 if (!user_blob)
461 DRM_ERROR("Invalid csc blob, v%lld\n", csc->version);
462 else
463 psde->pipe_hw->ops.setup_csc(psde->pipe_hw,
464 (struct sde_csc_cfg *)&cfg);
465 }
466
467 if (user_blob) {
468 DBG("User blobs override for CSC");
Clarence Ip373f8592016-05-26 00:58:42 -0400469 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400470 /* revert to kernel default */
Clarence Ipdbde9832016-06-26 09:48:36 -0400471 } else if (SDE_FORMAT_IS_YUV(fmt)) {
Clarence Ip373f8592016-05-26 00:58:42 -0400472 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400473 } else {
Clarence Ip373f8592016-05-26 00:58:42 -0400474 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_NOP;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400475 }
Clarence Ip373f8592016-05-26 00:58:42 -0400476
477 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
Clarence Ipe78efb72016-06-24 18:35:21 -0400478}
479
Clarence Ipcb410d42016-06-26 22:52:33 -0400480static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400481 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400482 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700483{
Clarence Ipcb410d42016-06-26 22:52:33 -0400484 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400485 struct sde_drm_scaler *sc_u = NULL;
486 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400487 size_t sc_u_size = 0;
488 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
489 uint32_t tmp;
490 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400491
Clarence Ipcb410d42016-06-26 22:52:33 -0400492 if (!psde || !fmt)
493 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400494
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400495 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400496 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400497
Clarence Ip5e2a9222016-06-26 22:38:24 -0400498 /* get scaler config from user space */
499 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
500 if (sc_u) {
501 switch (sc_u->version) {
502 case SDE_DRM_SCALER_V1:
503 if (!_sde_plane_verify_blob(sc_u,
504 sc_u_size,
505 &sc_u->v1,
506 sizeof(*sc_u1)))
507 sc_u1 = &sc_u->v1;
508 break;
509 default:
510 DBG("Unrecognized scaler blob v%lld", sc_u->version);
511 break;
512 }
513 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400514
Clarence Ip04ec67d2016-05-26 01:16:15 -0400515 /* decimation */
516 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
517 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
518 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400519 } else {
520 psde->pipe_cfg.horz_decimation = 0;
521 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400522 }
523
524 /* don't chroma subsample if decimating */
525 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400526 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400527 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400528 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400529
Clarence Ip5e2a9222016-06-26 22:38:24 -0400530 /* update scaler */
531 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
532 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Clarence Ipcb410d42016-06-26 22:52:33 -0400533 DBG("SCALER3 blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400534 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400535 _sde_plane_setup_scaler3(psde,
536 psde->pipe_cfg.src_rect.w,
537 psde->pipe_cfg.src_rect.h,
538 psde->pipe_cfg.dst_rect.w,
539 psde->pipe_cfg.dst_rect.h,
540 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400541 chroma_subsmpl_h, chroma_subsmpl_v);
542 } else {
543 /* always calculate basic scaler config */
544 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
545 /* populate from user space */
546 for (i = 0; i < SDE_MAX_PLANES; i++) {
547 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
548 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
549 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
550 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400551
Clarence Ip5e2a9222016-06-26 22:38:24 -0400552 pe->horz_filter[i] = sc_u1->horz_filter[i];
553 pe->vert_filter[i] = sc_u1->vert_filter[i];
554 }
555 } else {
556 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400557 _sde_plane_setup_scaler2(psde,
558 psde->pipe_cfg.src_rect.w,
559 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400560 pe->phase_step_x,
561 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400562 _sde_plane_setup_scaler2(psde,
563 psde->pipe_cfg.src_rect.h,
564 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400565 pe->phase_step_y,
566 pe->vert_filter, fmt, chroma_subsmpl_v);
567 }
568 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400569
Clarence Ip5e2a9222016-06-26 22:38:24 -0400570 /* update pixel extensions */
571 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
572 /* populate from user space */
Clarence Ipcb410d42016-06-26 22:52:33 -0400573 DBG("PIXEXT blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400574 for (i = 0; i < SDE_MAX_PLANES; i++) {
575 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
576 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
577 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
578 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
579 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
580 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
581 pe->roi_w[i] = sc_u1->lr.roi[i];
582
583 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
584 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
585 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
586 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
587 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
588 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
589 pe->roi_h[i] = sc_u1->tb.roi[i];
590 }
591 } else {
592 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400593 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400594 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400595 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400596 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400597 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
598 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400599 pe->phase_step_x,
600 pe->roi_w,
601 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400602 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400603 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400604
Clarence Ipcb410d42016-06-26 22:52:33 -0400605 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400606 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400607 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
608 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400609 pe->phase_step_y,
610 pe->roi_h,
611 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400612 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400613 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400614
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400615 for (i = 0; i < SDE_MAX_PLANES; i++) {
616 if (pe->num_ext_pxls_left[i] >= 0)
617 pe->left_rpt[i] =
618 pe->num_ext_pxls_left[i];
619 else
620 pe->left_ftch[i] =
621 pe->num_ext_pxls_left[i];
622
623 if (pe->num_ext_pxls_right[i] >= 0)
624 pe->right_rpt[i] =
625 pe->num_ext_pxls_right[i];
626 else
627 pe->right_ftch[i] =
628 pe->num_ext_pxls_right[i];
629
630 if (pe->num_ext_pxls_top[i] >= 0)
631 pe->top_rpt[i] =
632 pe->num_ext_pxls_top[i];
633 else
634 pe->top_ftch[i] =
635 pe->num_ext_pxls_top[i];
636
637 if (pe->num_ext_pxls_btm[i] >= 0)
638 pe->btm_rpt[i] =
639 pe->num_ext_pxls_btm[i];
640 else
641 pe->btm_ftch[i] =
642 pe->num_ext_pxls_btm[i];
643 }
644 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400645}
646
647int sde_plane_color_fill(struct drm_plane *plane,
648 uint32_t color, uint32_t alpha)
649{
650 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400651 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400652
653 if (!plane) {
654 DRM_ERROR("Invalid plane\n");
655 return -EINVAL;
656 }
657
658 psde = to_sde_plane(plane);
659 if (!psde->pipe_hw) {
660 DRM_ERROR("Invalid plane h/w pointer\n");
661 return -EINVAL;
662 }
663
664 /*
665 * select fill format to match user property expectation,
666 * h/w only supports RGB variants
667 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400668 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -0400669
670 /* update sspp */
671 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
672 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
673 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
674
675 /* override scaler/decimation if solid fill */
676 psde->pipe_cfg.src_rect.x = 0;
677 psde->pipe_cfg.src_rect.y = 0;
678 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
679 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
680
681 _sde_plane_setup_scaler(psde, fmt, 0);
682
683 if (psde->pipe_hw->ops.setup_format)
684 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
685 fmt, SDE_SSPP_SOLID_FILL);
686
687 if (psde->pipe_hw->ops.setup_rects)
688 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
689 &psde->pipe_cfg, &psde->pixel_ext);
690 }
691
692 return 0;
693}
694
695static int _sde_plane_mode_set(struct drm_plane *plane,
696 struct drm_crtc *crtc, struct drm_framebuffer *fb,
697 int crtc_x, int crtc_y,
698 unsigned int crtc_w, unsigned int crtc_h,
699 uint32_t src_x, uint32_t src_y,
700 uint32_t src_w, uint32_t src_h)
701{
702 struct sde_plane *psde;
703 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400704 uint32_t nplanes, color_fill;
Clarence Ipcb410d42016-06-26 22:52:33 -0400705 uint32_t src_flags;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400706 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400707
708 DBG("");
709
710 if (!plane || !plane->state) {
711 DRM_ERROR("Invalid plane/state\n");
712 return -EINVAL;
713 }
714 if (!crtc || !fb) {
715 DRM_ERROR("Invalid crtc/fb\n");
716 return -EINVAL;
717 }
718
719 psde = to_sde_plane(plane);
720 pstate = to_sde_plane_state(plane->state);
721 nplanes = drm_format_num_planes(fb->pixel_format);
722
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400723 fmt = to_sde_format(msm_framebuffer_format(fb));
Clarence Ipcb410d42016-06-26 22:52:33 -0400724
725 /* src values are in Q16 fixed point, convert to integer */
726 src_x = src_x >> 16;
727 src_y = src_y >> 16;
728 src_w = src_w >> 16;
729 src_h = src_h >> 16;
730
731 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
732 fb->base.id, src_x, src_y, src_w, src_h,
733 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
734
735 /* update format configuration */
736 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
737 src_flags = 0;
738
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400739 psde->pipe_cfg.src.format = fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400740 psde->pipe_cfg.src.width = fb->width;
741 psde->pipe_cfg.src.height = fb->height;
742 psde->pipe_cfg.src.num_planes = nplanes;
743
744 /* flags */
745 DBG("Flags 0x%llX, rotation 0x%llX",
746 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
747 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
748 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
749 BIT(DRM_REFLECT_X))
750 src_flags |= SDE_SSPP_FLIP_LR;
751 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
752 BIT(DRM_REFLECT_Y))
753 src_flags |= SDE_SSPP_FLIP_UD;
754 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
755 BIT(SDE_DRM_DEINTERLACE)) {
756 src_h /= 2;
757 src_y = DIV_ROUND_UP(src_y, 2);
758 src_y &= ~0x1;
759 }
760
761 psde->pipe_cfg.src_rect.x = src_x;
762 psde->pipe_cfg.src_rect.y = src_y;
763 psde->pipe_cfg.src_rect.w = src_w;
764 psde->pipe_cfg.src_rect.h = src_h;
765
766 psde->pipe_cfg.dst_rect.x = crtc_x;
767 psde->pipe_cfg.dst_rect.y = crtc_y;
768 psde->pipe_cfg.dst_rect.w = crtc_w;
769 psde->pipe_cfg.dst_rect.h = crtc_h;
770
771 /* get sde pixel format definition */
772 fmt = psde->pipe_cfg.src.format;
773
774 /* check for color fill */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400775 color_fill = (uint32_t)sde_plane_get_property(pstate,
776 PLANE_PROP_COLOR_FILL);
777 if (color_fill & BIT(31)) {
Clarence Ipcb410d42016-06-26 22:52:33 -0400778 /* force 100% alpha, stop other processing */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400779 return sde_plane_color_fill(plane, color_fill, 0xFF);
Clarence Ipcb410d42016-06-26 22:52:33 -0400780 }
781
782 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
783
784 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400785
Clarence Ip4c1d9772016-06-26 09:35:38 -0400786 if (psde->pipe_hw->ops.setup_format)
787 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -0400788 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400789 if (psde->pipe_hw->ops.setup_rects)
790 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
791 &psde->pipe_cfg, &psde->pixel_ext);
792
Clarence Ipe78efb72016-06-24 18:35:21 -0400793 /* update sharpening */
794 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
795 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
796 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
797 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
798
799 if (psde->pipe_hw->ops.setup_sharpening)
800 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
801 &psde->sharp_cfg);
802
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400803 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -0400804 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -0400805 _sde_plane_setup_csc(psde, pstate, fmt);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400806
Clarence Ip5e2a9222016-06-26 22:38:24 -0400807 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400808}
809
810static int sde_plane_prepare_fb(struct drm_plane *plane,
811 const struct drm_plane_state *new_state)
812{
813 struct drm_framebuffer *fb = new_state->fb;
814 struct sde_plane *psde = to_sde_plane(plane);
815
816 if (!new_state->fb)
817 return 0;
818
Clarence Ipae4e60c2016-06-26 22:44:04 -0400819 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400820 return msm_framebuffer_prepare(fb, psde->mmu_id);
821}
822
823static void sde_plane_cleanup_fb(struct drm_plane *plane,
824 const struct drm_plane_state *old_state)
825{
826 struct drm_framebuffer *fb = old_state->fb;
827 struct sde_plane *psde = to_sde_plane(plane);
828
829 if (!fb)
830 return;
831
Clarence Ipae4e60c2016-06-26 22:44:04 -0400832 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400833 msm_framebuffer_cleanup(fb, psde->mmu_id);
834}
835
Clarence Ipdbde9832016-06-26 09:48:36 -0400836static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
837 struct sde_plane_state *pstate,
838 struct drm_framebuffer *fb)
839{
840 return 0;
841}
842
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400843static int sde_plane_atomic_check(struct drm_plane *plane,
844 struct drm_plane_state *state)
845{
Clarence Ipdbde9832016-06-26 09:48:36 -0400846 struct sde_plane *psde;
847 struct sde_plane_state *pstate;
848 struct drm_plane_state *old_state;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400849 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -0400850 size_t sc_u_size = 0;
851 struct sde_drm_scaler *sc_u = NULL;
852 int ret = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400853
Clarence Ipdbde9832016-06-26 09:48:36 -0400854 uint32_t src_x, src_y;
855 uint32_t src_w, src_h;
856 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
857 uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
858 uint32_t upscale_max, downscale_max;
859
860 DBG();
861
862 if (!plane || !state) {
863 DRM_ERROR("Invalid plane/state\n");
864 ret = -EINVAL;
865 goto exit;
866 }
867
868 psde = to_sde_plane(plane);
869 pstate = to_sde_plane_state(state);
870 old_state = plane->state;
871
872 if (!psde->pipe_sblk) {
873 DRM_ERROR("Invalid plane catalog\n");
874 ret = -EINVAL;
875 goto exit;
876 }
877
878 /* get decimation config from user space */
879 deci_w = 0;
880 deci_h = 0;
881 sc_u = _sde_plane_get_blob(pstate, PLANE_PROP_SCALER, &sc_u_size);
882 if (sc_u) {
883 switch (sc_u->version) {
884 case SDE_DRM_SCALER_V1:
885 if (!_sde_plane_verify_blob(sc_u,
886 sc_u_size,
887 &sc_u->v1,
888 sizeof(struct sde_drm_scaler_v1))) {
889 deci_w = sc_u->v1.horz_decimate;
890 deci_h = sc_u->v1.vert_decimate;
891 }
892 break;
893 default:
894 DBG("Unrecognized scaler blob v%lld", sc_u->version);
895 break;
896 }
897 }
898
899 /* src values are in Q16 fixed point, convert to integer */
900 src_x = state->src_x >> 16;
901 src_y = state->src_y >> 16;
902 src_w = state->src_w >> 16;
903 src_h = state->src_h >> 16;
904
905 src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
906 src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
907
908 src_max_x = 0xFFFF;
909 src_max_y = 0xFFFF;
910 src_max_w = 0x3FFF;
911 src_max_h = 0x3FFF;
912 upscale_max = psde->pipe_sblk->maxupscale;
913 downscale_max = psde->pipe_sblk->maxdwnscale;
914
915 /*
916 * Including checks from mdss
917 * - mdss_mdp_overlay_req_check()
918 */
Clarence Ip4ce59322016-06-26 22:27:51 -0400919 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400920 sde_plane_enabled(old_state), sde_plane_enabled(state));
921
922 if (sde_plane_enabled(state)) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400923 /* determine SDE format definition. State's fb is valid here. */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400924 fmt = to_sde_format(msm_framebuffer_format(state->fb));
Clarence Ipdbde9832016-06-26 09:48:36 -0400925
926 /* don't check for other errors after first failure */
927 if (SDE_FORMAT_IS_YUV(fmt) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400928 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400929 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400930 DRM_ERROR("Pipe doesn't support YUV\n");
Clarence Ipdbde9832016-06-26 09:48:36 -0400931 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400932
Clarence Ipdbde9832016-06-26 09:48:36 -0400933 /* verify source size/region */
934 } else if (!src_w || !src_h ||
935 (src_w > src_max_w) || (src_h > src_max_h) ||
936 (src_x > src_max_x) || (src_y > src_max_y) ||
937 (src_x + src_w > src_max_x) ||
938 (src_y + src_h > src_max_y)) {
939 DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
940 src_x, src_y, src_x + src_w,
941 src_y + src_h);
942 ret = -EINVAL;
943
944 /* require even source for YUV */
945 } else if (SDE_FORMAT_IS_YUV(fmt) &&
946 ((src_x & 0x1) || (src_y & 0x1) ||
947 (src_w & 0x1) || (src_h & 0x1))) {
948 DRM_ERROR("Invalid odd src res/pos for YUV\n");
949 ret = -EINVAL;
950
951 /* verify scaler requirements */
952 } else if (!(psde->features & SDE_SSPP_SCALER) &&
953 ((src_w != state->crtc_w) ||
954 (src_h != state->crtc_h))) {
955 DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
956 src_w, src_h, state->crtc_w,
957 state->crtc_h);
958 ret = -EINVAL;
959
960 /* check decimated source width */
961 } else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
962 DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
963 src_w, src_deci_w,
964 psde->pipe_sblk->maxlinewidth);
965 ret = -EINVAL;
966
967 /* check max scaler capability */
968 } else if (((src_deci_w * upscale_max) < state->crtc_w) ||
969 ((src_deci_h * upscale_max) < state->crtc_h) ||
970 ((state->crtc_w * downscale_max) < src_deci_w) ||
971 ((state->crtc_h * downscale_max) < src_deci_h)) {
972 DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
973 src_deci_w, src_deci_h,
974 state->crtc_w, state->crtc_h);
975 ret = -EINVAL;
976
977 /* check frame buffer */
978 } else if (_sde_plane_atomic_check_fb(
979 psde, pstate, state->fb)) {
980 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400981 }
982
Clarence Ipdbde9832016-06-26 09:48:36 -0400983 /* check decimation (and bwc/fetch mode) */
984 if (!ret && (deci_w || deci_h)) {
985 if (SDE_FORMAT_IS_UBWC(fmt)) {
986 DRM_ERROR("No decimation with BWC\n");
987 ret = -EINVAL;
988 } else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
989 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
990 DRM_ERROR("Too much decimation requested\n");
991 ret = -EINVAL;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400992 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400993 DRM_ERROR("Decimation requires linear fetch\n");
994 ret = -EINVAL;
995 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400996 }
997 }
998
Clarence Ipdbde9832016-06-26 09:48:36 -0400999 if (!ret) {
1000 if (sde_plane_enabled(state) &&
1001 sde_plane_enabled(old_state)) {
1002 bool full_modeset = false;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001003
Clarence Ipdbde9832016-06-26 09:48:36 -04001004 if (state->fb->pixel_format !=
1005 old_state->fb->pixel_format) {
1006 DBG("%s: format change!", psde->pipe_name);
1007 full_modeset = true;
1008 }
1009 if (state->src_w != old_state->src_w ||
1010 state->src_h != old_state->src_h) {
1011 DBG("%s: src_w change!", psde->pipe_name);
1012 full_modeset = true;
1013 }
1014 if (to_sde_plane_state(old_state)->pending) {
1015 DBG("%s: still pending!", psde->pipe_name);
1016 full_modeset = true;
1017 }
Lloyd Atkinson66358902016-03-23 11:58:23 -04001018 if (full_modeset)
Clarence Ipdbde9832016-06-26 09:48:36 -04001019 to_sde_plane_state(state)->mode_changed = true;
Lloyd Atkinson66358902016-03-23 11:58:23 -04001020
Clarence Ipdbde9832016-06-26 09:48:36 -04001021 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001022 to_sde_plane_state(state)->mode_changed = true;
1023 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001024 }
1025
Clarence Ipdbde9832016-06-26 09:48:36 -04001026exit:
1027 return ret;
1028}
1029
1030void sde_plane_complete_flip(struct drm_plane *plane)
1031{
1032 if (plane && plane->state)
1033 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001034}
1035
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001036static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001037 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001038{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001039 struct sde_plane *sde_plane;
1040 struct drm_plane_state *state;
1041 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001042
Clarence Ip5e2a9222016-06-26 22:38:24 -04001043 if (!plane || !plane->state) {
1044 DRM_ERROR("Invalid plane/state\n");
1045 return;
1046 }
1047
1048 sde_plane = to_sde_plane(plane);
1049 state = plane->state;
1050 pstate = to_sde_plane_state(state);
1051
Clarence Ipae4e60c2016-06-26 22:44:04 -04001052 DBG("%s: update", sde_plane->pipe_name);
1053
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001054 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001055 pstate->pending = true;
1056 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001057 int ret;
1058
Clarence Ip5e2a9222016-06-26 22:38:24 -04001059 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -04001060 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001061 state->crtc, state->fb,
1062 state->crtc_x, state->crtc_y,
1063 state->crtc_w, state->crtc_h,
1064 state->src_x, state->src_y,
1065 state->src_w, state->src_h);
1066 /* atomic_check should have ensured that this doesn't fail */
1067 WARN_ON(ret < 0);
1068 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001069 _sde_plane_set_scanout(plane, pstate,
1070 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001071 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001072}
1073
Clarence Ipae4e60c2016-06-26 22:44:04 -04001074static inline struct drm_property **_sde_plane_get_property_entry(
1075 struct drm_device *dev, enum msm_mdp_plane_property property)
1076{
1077 struct msm_drm_private *priv;
1078
1079 if (!dev || !dev->dev_private || (property >= PLANE_PROP_COUNT))
1080 return NULL;
1081
1082 priv = dev->dev_private;
1083
1084 return &(priv->plane_property[property]);
1085}
1086
Clarence Ipe78efb72016-06-24 18:35:21 -04001087static void _sde_plane_install_range_property(struct drm_plane *plane,
1088 struct drm_device *dev, const char *name,
1089 uint64_t min, uint64_t max, uint64_t init,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001090 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001091{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001092 struct drm_property **prop;
1093
1094 prop = _sde_plane_get_property_entry(dev, property);
1095 if (plane && name && prop) {
Clarence Ipe78efb72016-06-24 18:35:21 -04001096 /* only create the property once */
1097 if (*prop == 0) {
1098 *prop = drm_property_create_range(dev,
1099 0 /* flags */, name, min, max);
1100 if (*prop == 0)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001101 DRM_ERROR("Create %s property failed\n", name);
Clarence Ipe78efb72016-06-24 18:35:21 -04001102 }
1103
Clarence Ipae4e60c2016-06-26 22:44:04 -04001104 /* save init value for later */
1105 to_sde_plane(plane)->property_defaults[property] = init;
1106
Clarence Ipe78efb72016-06-24 18:35:21 -04001107 /* always attach property, if created */
1108 if (*prop)
1109 drm_object_attach_property(&plane->base, *prop, init);
1110 }
1111}
1112
Clarence Ip5e2a9222016-06-26 22:38:24 -04001113static void _sde_plane_install_rotation_property(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001114 struct drm_device *dev, enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001115{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001116 struct sde_plane *psde;
1117 struct drm_property **prop;
1118
1119 prop = _sde_plane_get_property_entry(dev, property);
1120 if (plane && prop) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001121 /* only create the property once */
1122 if (*prop == 0) {
1123 *prop = drm_mode_create_rotation_property(dev,
1124 BIT(DRM_REFLECT_X) |
1125 BIT(DRM_REFLECT_Y));
1126 if (*prop == 0)
1127 DRM_ERROR("Create rotation property failed\n");
1128 }
1129
Clarence Ipae4e60c2016-06-26 22:44:04 -04001130 /* save init value for later */
1131 psde = to_sde_plane(plane);
1132 psde->property_defaults[property] = 0;
1133
Clarence Ip5e2a9222016-06-26 22:38:24 -04001134 /* always attach property, if created */
1135 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001136 drm_object_attach_property(&plane->base, *prop,
1137 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001138 }
1139}
1140
1141static void _sde_plane_install_enum_property(struct drm_plane *plane,
1142 struct drm_device *dev, const char *name, int is_bitmask,
1143 const struct drm_prop_enum_list *values, int num_values,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001144 enum msm_mdp_plane_property property)
Clarence Ip5e2a9222016-06-26 22:38:24 -04001145{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001146 struct sde_plane *psde;
1147 struct drm_property **prop;
1148
1149 prop = _sde_plane_get_property_entry(dev, property);
1150 if (plane && name && prop && values && num_values) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001151 /* only create the property once */
1152 if (*prop == 0) {
1153 /* 'bitmask' is a special type of 'enum' */
1154 if (is_bitmask)
1155 *prop = drm_property_create_bitmask(dev,
1156 DRM_MODE_PROP_BITMASK, name,
1157 values, num_values, -1);
1158 else
1159 *prop = drm_property_create_enum(dev,
1160 DRM_MODE_PROP_ENUM, name,
1161 values, num_values);
1162 if (*prop == 0)
1163 DRM_ERROR("Create %s property failed\n", name);
1164 }
1165
Clarence Ipae4e60c2016-06-26 22:44:04 -04001166 /* save init value for later */
1167 psde = to_sde_plane(plane);
1168 psde->property_defaults[property] = 0;
1169
Clarence Ip5e2a9222016-06-26 22:38:24 -04001170 /* always attach property, if created */
1171 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001172 drm_object_attach_property(&plane->base, *prop,
1173 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001174 }
1175}
1176
Clarence Ipe78efb72016-06-24 18:35:21 -04001177static void _sde_plane_install_blob_property(struct drm_plane *plane,
1178 struct drm_device *dev, const char *name,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001179 enum msm_mdp_plane_property property)
Clarence Ipe78efb72016-06-24 18:35:21 -04001180{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001181 struct sde_plane *psde;
1182 struct drm_property **prop;
1183
1184 prop = _sde_plane_get_property_entry(dev, property);
1185 if (plane && name && prop && (property < PLANE_PROP_BLOBCOUNT)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001186 /* only create the property once */
1187 if (*prop == 0) {
1188 /* use 'create' for blob property place holder */
1189 *prop = drm_property_create(dev,
1190 DRM_MODE_PROP_BLOB, name, 0);
1191 if (*prop == 0)
1192 DRM_ERROR("Create %s property failed\n", name);
1193 }
1194
Clarence Ipae4e60c2016-06-26 22:44:04 -04001195 /* save init value for later */
1196 psde = to_sde_plane(plane);
1197 psde->property_defaults[property] = 0;
1198
Clarence Ip5e2a9222016-06-26 22:38:24 -04001199 /* always attach property, if created */
1200 if (*prop)
Clarence Ipae4e60c2016-06-26 22:44:04 -04001201 drm_object_attach_property(&plane->base, *prop,
1202 psde->property_defaults[property]);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001203 }
Clarence Ipe78efb72016-06-24 18:35:21 -04001204}
1205
Clarence Ip4c1d9772016-06-26 09:35:38 -04001206static int _sde_plane_get_property_index(struct drm_plane *plane,
1207 struct drm_property *property)
1208{
1209 struct drm_property **prop_array;
1210 int idx = PLANE_PROP_COUNT;
1211
1212 if (!plane) {
1213 DRM_ERROR("Invalid plane\n");
1214 } else if (!plane->dev || !plane->dev->dev_private) {
1215 /* don't access dev_private if !dev */
1216 DRM_ERROR("Invalid device\n");
1217 } else if (!property) {
1218 DRM_ERROR("Incoming property is NULL\n");
1219 } else {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001220 prop_array = _sde_plane_get_property_entry(plane->dev, 0);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001221 if (!prop_array)
1222 /* should never hit this */
1223 DRM_ERROR("Invalid property array\n");
1224
1225 /* linear search is okay */
1226 for (idx = 0; idx < PLANE_PROP_COUNT; ++idx) {
1227 if (prop_array[idx] == property)
1228 break;
1229 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001230
1231 if (idx == PLANE_PROP_COUNT)
1232 DRM_ERROR("Invalid property pointer\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001233 }
1234
1235 return idx;
1236}
1237
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001238/* helper to install properties which are common to planes and crtcs */
Clarence Ipe78efb72016-06-24 18:35:21 -04001239static void _sde_plane_install_properties(struct drm_plane *plane,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001240 struct drm_mode_object *obj,
1241 struct sde_mdss_cfg *catalog)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001242{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001243 static const struct drm_prop_enum_list e_blend_op[] = {
1244 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1245 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1246 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1247 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1248 };
1249 static const struct drm_prop_enum_list e_src_config[] = {
1250 {SDE_DRM_DEINTERLACE, "deinterlace"}
1251 };
1252 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001253 struct drm_device *dev = plane->dev;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001254
Clarence Ip4ce59322016-06-26 22:27:51 -04001255 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001256
Clarence Ipcb410d42016-06-26 22:52:33 -04001257 if (!psde || !psde->pipe_hw || !psde->pipe_sblk || !catalog) {
1258 DRM_ERROR("Catalog or h/w driver definition error\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001259 return;
1260 }
1261
1262 /* range properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001263 _sde_plane_install_range_property(plane, dev, "zpos", 0, 255,
1264 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1265 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1266 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001267
Clarence Ip5e2a9222016-06-26 22:38:24 -04001268 _sde_plane_install_range_property(plane, dev, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001269 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001270
Clarence Ipcb410d42016-06-26 22:52:33 -04001271 if (psde->pipe_hw->ops.setup_solidfill)
1272 _sde_plane_install_range_property(plane, dev, "color_fill",
1273 0, 0xFFFFFFFF, 0,
1274 PLANE_PROP_COLOR_FILL);
1275
Clarence Ipae4e60c2016-06-26 22:44:04 -04001276 _sde_plane_install_range_property(plane, dev, "sync_fence", 0, ~0, ~0,
1277 PLANE_PROP_SYNC_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001278
Clarence Ipcb410d42016-06-26 22:52:33 -04001279 _sde_plane_install_range_property(plane, dev, "sync_fence_timeout",
1280 0, ~0, 10000,
1281 PLANE_PROP_SYNC_FENCE_TIMEOUT);
1282
Clarence Ip5e2a9222016-06-26 22:38:24 -04001283 /* standard properties */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001284 _sde_plane_install_rotation_property(plane, dev, PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001285
Clarence Ip04ec67d2016-05-26 01:16:15 -04001286 /* enum/bitmask properties */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001287 _sde_plane_install_enum_property(plane, dev, "blend_op", 0,
1288 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001289 PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001290 _sde_plane_install_enum_property(plane, dev, "src_config", 1,
1291 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001292 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001293
Clarence Ipe78efb72016-06-24 18:35:21 -04001294 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001295 if (psde->features & SDE_SSPP_SCALER)
1296 _sde_plane_install_blob_property(plane, dev, "scaler",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001297 PLANE_PROP_SCALER);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001298 if (psde->features & BIT(SDE_SSPP_CSC))
1299 _sde_plane_install_blob_property(plane, dev, "csc",
Clarence Ipae4e60c2016-06-26 22:44:04 -04001300 PLANE_PROP_CSC);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001301}
1302
1303static int sde_plane_atomic_set_property(struct drm_plane *plane,
1304 struct drm_plane_state *state, struct drm_property *property,
1305 uint64_t val)
1306{
Clarence Ip730e7192016-06-26 22:45:09 -04001307 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001308 struct sde_plane_state *pstate;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001309 struct drm_property_blob *blob, **pr_blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001310 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001311
Clarence Ip4c1d9772016-06-26 09:35:38 -04001312 idx = _sde_plane_get_property_index(plane, property);
1313 if (!state) {
1314 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001315 } else if (idx >= PLANE_PROP_COUNT) {
1316 DRM_ERROR("Invalid property\n");
1317 } else {
1318 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001319 pstate = to_sde_plane_state(state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001320
Lloyd Atkinson0fda6c52016-02-04 15:09:43 -05001321 DBG("%s: pipe %d, prop %s, val %d", psde->pipe_name,
1322 sde_plane_pipe(plane),
1323 property->name, (int)val);
Clarence Ip730e7192016-06-26 22:45:09 -04001324
Clarence Ipae4e60c2016-06-26 22:44:04 -04001325 /* extra handling for incoming properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001326 if ((property->flags & DRM_MODE_PROP_BLOB) &&
1327 (idx < PLANE_PROP_BLOBCOUNT)) {
1328 /* DRM lookup also takes a reference */
1329 blob = drm_property_lookup_blob(plane->dev,
1330 (uint32_t)val);
1331 if (!blob) {
1332 DRM_ERROR("Blob not found\n");
1333 val = 0;
1334 } else {
1335 DBG("Blob %u saved", blob->base.id);
1336 val = blob->base.id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001337
Clarence Ip4c1d9772016-06-26 09:35:38 -04001338 /* save blobs for later */
1339 pr_blob = &pstate->property_blobs[idx];
1340 /* need to clear previous reference */
1341 if (*pr_blob)
1342 drm_property_unreference_blob(*pr_blob);
1343 *pr_blob = blob;
Clarence Ipe78efb72016-06-24 18:35:21 -04001344 }
Clarence Ipae4e60c2016-06-26 22:44:04 -04001345 } else if (idx == PLANE_PROP_SYNC_FENCE) {
1346 _sde_plane_update_sync_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001347 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001348 pstate->property_values[idx] = val;
1349 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001350 }
1351
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001352 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001353}
1354
1355static int sde_plane_set_property(struct drm_plane *plane,
1356 struct drm_property *property, uint64_t val)
1357{
Clarence Ip4ce59322016-06-26 22:27:51 -04001358 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001359
1360 if (!plane)
1361 return -EINVAL;
1362
Clarence Ipae4e60c2016-06-26 22:44:04 -04001363 return sde_plane_atomic_set_property(plane,
1364 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001365}
1366
1367static int sde_plane_atomic_get_property(struct drm_plane *plane,
1368 const struct drm_plane_state *state,
1369 struct drm_property *property, uint64_t *val)
1370{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001371 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001372 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001373
Clarence Ip4c1d9772016-06-26 09:35:38 -04001374 idx = _sde_plane_get_property_index(plane, property);
1375 if (!state) {
1376 DRM_ERROR("Invalid state\n");
1377 } else if (!val) {
1378 DRM_ERROR("Value pointer is NULL\n");
1379 } else if (idx < PLANE_PROP_COUNT) {
1380 pstate = to_sde_plane_state(state);
1381
1382 *val = pstate->property_values[idx];
Clarence Ipae4e60c2016-06-26 22:44:04 -04001383 DBG("%d 0x%llX", idx, *val);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001384 ret = 0;
Clarence Ipe78efb72016-06-24 18:35:21 -04001385 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001386
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001387 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001388}
1389
Clarence Ip730e7192016-06-26 22:45:09 -04001390static struct sde_plane_state *sde_plane_alloc_state(struct drm_plane *plane)
1391{
1392 struct sde_plane *psde;
1393 struct sde_plane_state *pstate;
1394
1395 if (!plane)
1396 return NULL;
1397
1398 psde = to_sde_plane(plane);
1399 pstate = NULL;
1400
1401 mutex_lock(&psde->lock);
1402 if (psde->state_cache_size)
1403 pstate = psde->state_cache[--(psde->state_cache_size)];
1404 mutex_unlock(&psde->lock);
1405
1406 if (!pstate)
1407 pstate = kmalloc(sizeof(struct sde_plane_state), GFP_KERNEL);
1408
1409 return pstate;
1410}
1411
1412static void sde_plane_free_state(struct drm_plane *plane,
1413 struct sde_plane_state *pstate)
1414{
1415 struct sde_plane *psde;
1416
1417 if (!plane || !pstate)
1418 return;
1419
1420 psde = to_sde_plane(plane);
1421
1422 mutex_lock(&psde->lock);
1423 if (psde->state_cache_size < SDE_STATE_CACHE_SIZE) {
1424 psde->state_cache[(psde->state_cache_size)++] = pstate;
1425 mutex_unlock(&psde->lock);
1426 } else {
1427 mutex_unlock(&psde->lock);
1428 kfree(pstate);
1429 }
1430}
1431
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001432static void sde_plane_destroy(struct drm_plane *plane)
1433{
Clarence Ip4ce59322016-06-26 22:27:51 -04001434 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001435
Clarence Ip4ce59322016-06-26 22:27:51 -04001436 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001437
Clarence Ip4ce59322016-06-26 22:27:51 -04001438 if (plane) {
1439 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001440
Clarence Ip4ce59322016-06-26 22:27:51 -04001441 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001442
Clarence Ip730e7192016-06-26 22:45:09 -04001443 mutex_destroy(&psde->lock);
1444
Clarence Ip4ce59322016-06-26 22:27:51 -04001445 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001446
Clarence Ip4ce59322016-06-26 22:27:51 -04001447 /* this will destroy the states as well */
1448 drm_plane_cleanup(plane);
1449
Clarence Ip4c1d9772016-06-26 09:35:38 -04001450 if (psde->pipe_hw)
1451 sde_hw_sspp_destroy(psde->pipe_hw);
1452
Clarence Ip730e7192016-06-26 22:45:09 -04001453 /* free state cache */
1454 while (psde->state_cache_size > 0)
1455 kfree(psde->state_cache[--(psde->state_cache_size)]);
1456
Clarence Ip4ce59322016-06-26 22:27:51 -04001457 kfree(psde);
1458 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001459}
1460
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001461static void sde_plane_destroy_state(struct drm_plane *plane,
1462 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001463{
Clarence Ipe78efb72016-06-24 18:35:21 -04001464 struct sde_plane_state *pstate;
1465 int i;
1466
Clarence Ipae4e60c2016-06-26 22:44:04 -04001467 if (!plane || !state) {
1468 DRM_ERROR("Invalid plane/state\n");
1469 return;
1470 }
1471
Clarence Ip730e7192016-06-26 22:45:09 -04001472 pstate = to_sde_plane_state(state);
1473
1474 DBG("");
1475
Clarence Ipe78efb72016-06-24 18:35:21 -04001476 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001477 if (state->fb)
1478 drm_framebuffer_unreference(state->fb);
1479
Clarence Ipae4e60c2016-06-26 22:44:04 -04001480 /* remove ref count for fence */
1481 if (pstate->sync_fence)
1482 sde_sync_put(pstate->sync_fence);
1483
Clarence Ipe78efb72016-06-24 18:35:21 -04001484 /* remove ref count for blobs */
1485 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1486 if (pstate->property_blobs[i])
1487 drm_property_unreference_blob(
1488 pstate->property_blobs[i]);
Clarence Ip730e7192016-06-26 22:45:09 -04001489 sde_plane_free_state(plane, pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001490}
1491
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001492static struct drm_plane_state *
1493sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001494{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001495 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001496 struct sde_plane_state *old_state;
Clarence Ipe78efb72016-06-24 18:35:21 -04001497 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001498
Clarence Ip730e7192016-06-26 22:45:09 -04001499 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001500 return NULL;
1501
Clarence Ip730e7192016-06-26 22:45:09 -04001502 old_state = to_sde_plane_state(plane->state);
1503 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001504
1505 DBG("");
1506
Clarence Ip730e7192016-06-26 22:45:09 -04001507 if (!pstate)
1508 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001509
Clarence Ip730e7192016-06-26 22:45:09 -04001510 memcpy(pstate, old_state, sizeof(*pstate));
Clarence Ipae4e60c2016-06-26 22:44:04 -04001511
Clarence Ip730e7192016-06-26 22:45:09 -04001512 /* add ref count for frame buffer */
1513 if (pstate->base.fb)
1514 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001515
Clarence Ip730e7192016-06-26 22:45:09 -04001516 /* add ref count for fence */
1517 if (pstate->sync_fence) {
1518 pstate->sync_fence = 0;
1519 _sde_plane_update_sync_fence(plane, pstate, pstate->
1520 property_values[PLANE_PROP_SYNC_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001521 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001522
Clarence Ip730e7192016-06-26 22:45:09 -04001523 /* add ref count for blobs */
1524 for (i = 0; i < PLANE_PROP_BLOBCOUNT; ++i)
1525 if (pstate->property_blobs[i])
1526 drm_property_reference_blob(
1527 pstate->property_blobs[i]);
1528
1529 pstate->mode_changed = false;
1530 pstate->pending = false;
1531
1532 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001533}
1534
1535static void sde_plane_reset(struct drm_plane *plane)
1536{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001537 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001538 struct sde_plane_state *pstate;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001539 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001540
Clarence Ipae4e60c2016-06-26 22:44:04 -04001541 if (!plane) {
1542 DRM_ERROR("Invalid plane\n");
1543 return;
1544 }
1545
Clarence Ip730e7192016-06-26 22:45:09 -04001546 psde = to_sde_plane(plane);
1547 DBG("%s", psde->pipe_name);
1548
Clarence Ipae4e60c2016-06-26 22:44:04 -04001549 /* remove previous state, if present */
1550 if (plane->state)
1551 sde_plane_destroy_state(plane, plane->state);
1552 plane->state = 0;
1553
Clarence Ip730e7192016-06-26 22:45:09 -04001554 pstate = sde_plane_alloc_state(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001555 if (!pstate) {
Clarence Ip730e7192016-06-26 22:45:09 -04001556 DRM_ERROR("Failed to (re)allocate plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001557 return;
1558 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001559
Clarence Ip730e7192016-06-26 22:45:09 -04001560 memset(pstate, 0, sizeof(*pstate));
1561
Clarence Ipae4e60c2016-06-26 22:44:04 -04001562 /* assign default property values */
Clarence Ipae4e60c2016-06-26 22:44:04 -04001563 for (i = 0; i < PLANE_PROP_COUNT; ++i)
1564 pstate->property_values[i] = psde->property_defaults[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001565
1566 pstate->base.plane = plane;
1567
1568 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001569}
1570
1571static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001572 .update_plane = drm_atomic_helper_update_plane,
1573 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001574 .destroy = sde_plane_destroy,
1575 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001576 .atomic_set_property = sde_plane_atomic_set_property,
1577 .atomic_get_property = sde_plane_atomic_get_property,
1578 .reset = sde_plane_reset,
1579 .atomic_duplicate_state = sde_plane_duplicate_state,
1580 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001581};
1582
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001583static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1584 .prepare_fb = sde_plane_prepare_fb,
1585 .cleanup_fb = sde_plane_cleanup_fb,
1586 .atomic_check = sde_plane_atomic_check,
1587 .atomic_update = sde_plane_atomic_update,
1588};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001589
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001590enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001591{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001592 struct sde_plane *sde_plane = to_sde_plane(plane);
1593
1594 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001595}
1596
Clarence Ip4ce59322016-06-26 22:27:51 -04001597static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1598{
1599 const struct sde_sspp_sub_blks *sblk = 0;
1600 const struct sde_sspp_cfg *cfg = 0;
1601
1602 if (psde && psde->pipe_hw)
1603 cfg = psde->pipe_hw->cap;
1604 if (cfg)
1605 sblk = cfg->sblk;
1606
1607 if (kms && sblk) {
1608 /* create overall sub-directory for the pipe */
1609 psde->debugfs_root =
1610 debugfs_create_dir(psde->pipe_name,
1611 sde_debugfs_get_root(kms));
1612 if (psde->debugfs_root) {
1613 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001614 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001615 psde->debugfs_root, &psde->features);
1616
1617 /* add register dump support */
1618 sde_debugfs_setup_regset32(&psde->debugfs_src,
1619 sblk->src_blk.base + cfg->base,
1620 sblk->src_blk.len,
1621 kms->mmio);
1622 sde_debugfs_create_regset32("src_blk", 0444,
1623 psde->debugfs_root, &psde->debugfs_src);
1624
1625 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1626 sblk->scaler_blk.base + cfg->base,
1627 sblk->scaler_blk.len,
1628 kms->mmio);
1629 sde_debugfs_create_regset32("scaler_blk", 0444,
1630 psde->debugfs_root,
1631 &psde->debugfs_scaler);
1632
1633 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1634 sblk->csc_blk.base + cfg->base,
1635 sblk->csc_blk.len,
1636 kms->mmio);
1637 sde_debugfs_create_regset32("csc_blk", 0444,
1638 psde->debugfs_root, &psde->debugfs_csc);
1639 }
1640 }
1641}
1642
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001643/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001644struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001645 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001646{
1647 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001648 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001649 struct msm_drm_private *priv;
1650 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001651 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001652 int ret = -EINVAL;
1653
1654 if (!dev) {
1655 DRM_ERROR("[%u]Device is NULL\n", pipe);
1656 goto exit;
1657 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001658
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001659 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001660 if (!priv) {
1661 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1662 goto exit;
1663 }
1664
1665 if (!priv->kms) {
1666 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1667 goto exit;
1668 }
1669 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001670
Clarence Ip4c1d9772016-06-26 09:35:38 -04001671 if (!kms->catalog) {
1672 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1673 goto exit;
1674 }
1675
Clarence Ip4ce59322016-06-26 22:27:51 -04001676 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001677 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1678 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001679 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001680 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001681 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001682 }
1683
Clarence Ip4c1d9772016-06-26 09:35:38 -04001684 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001685 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001686 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001687 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001688
Clarence Ip4c1d9772016-06-26 09:35:38 -04001689 /* initialize underlying h/w driver */
1690 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1691 if (IS_ERR(psde->pipe_hw)) {
1692 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1693 ret = PTR_ERR(psde->pipe_hw);
1694 goto clean_plane;
1695 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1696 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1697 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001698 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001699
1700 /* cache features mask for later */
1701 psde->features = psde->pipe_hw->cap->features;
1702 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1703
1704 /* add plane to DRM framework */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001705 psde->nformats = sde_populate_formats(psde->formats,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001706 ARRAY_SIZE(psde->formats),
1707 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001708 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001709
Clarence Ip4c1d9772016-06-26 09:35:38 -04001710 if (!psde->nformats) {
1711 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1712 goto clean_sspp;
1713 }
1714
1715 if (psde->features & BIT(SDE_SSPP_CURSOR))
1716 type = DRM_PLANE_TYPE_CURSOR;
1717 else if (primary_plane)
1718 type = DRM_PLANE_TYPE_PRIMARY;
1719 else
1720 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001721 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1722 psde->formats, psde->nformats,
1723 type);
1724 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001725 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001726
Clarence Ip4c1d9772016-06-26 09:35:38 -04001727 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001728 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001729
Clarence Ip4c1d9772016-06-26 09:35:38 -04001730 _sde_plane_install_properties(plane, &plane->base, kms->catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001731
Clarence Ip4ce59322016-06-26 22:27:51 -04001732 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001733 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001734
Clarence Ip730e7192016-06-26 22:45:09 -04001735 mutex_init(&psde->lock);
1736
Clarence Ip4ce59322016-06-26 22:27:51 -04001737 _sde_plane_init_debugfs(psde, kms);
1738
Clarence Ip4c1d9772016-06-26 09:35:38 -04001739 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001740 return plane;
1741
Clarence Ip4c1d9772016-06-26 09:35:38 -04001742clean_sspp:
1743 if (psde && psde->pipe_hw)
1744 sde_hw_sspp_destroy(psde->pipe_hw);
1745clean_plane:
1746 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001747exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001748 return ERR_PTR(ret);
1749}