blob: a15985ec40ed74d75c013f2d9aa2242958f66542 [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 */
Alan Kwong1a00e4d2016-07-18 09:42:30 -040012
13#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
14
Clarence Ip4ce59322016-06-26 22:27:51 -040015#include <linux/debugfs.h>
Clarence Ip5e2a9222016-06-26 22:38:24 -040016#include <uapi/drm/sde_drm.h>
Clarence Ipaa0faf42016-05-30 12:07:48 -040017
18#include "msm_prop.h"
19
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070020#include "sde_kms.h"
Clarence Ipae4e60c2016-06-26 22:44:04 -040021#include "sde_fence.h"
Clarence Ipc475b082016-06-26 09:27:23 -040022#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040023#include "sde_hw_sspp.h"
Alan Kwong1a00e4d2016-07-18 09:42:30 -040024#include "sde_trace.h"
Dhaval Patel48c76022016-09-01 17:51:23 -070025#include "sde_crtc.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040026
27#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
28#define PHASE_STEP_SHIFT 21
29#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
30#define PHASE_RESIDUAL 15
31
Clarence Ipe78efb72016-06-24 18:35:21 -040032#define SHARP_STRENGTH_DEFAULT 32
33#define SHARP_EDGE_THR_DEFAULT 112
34#define SHARP_SMOOTH_THR_DEFAULT 8
35#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040036
Clarence Ip5e2a9222016-06-26 22:38:24 -040037#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070038
Clarence Ipcae1bb62016-07-07 12:07:13 -040039#define SDE_PLANE_COLOR_FILL_FLAG BIT(31)
40
Alan Kwong1a00e4d2016-07-18 09:42:30 -040041/**
42 * enum sde_plane_qos - Different qos configurations for each pipe
43 *
44 * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
45 * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
46 * this configuration is mutually exclusive from VBLANK_CTRL.
47 * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
48 */
49enum sde_plane_qos {
50 SDE_PLANE_QOS_VBLANK_CTRL = BIT(0),
51 SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
52 SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
53};
54
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070055struct sde_plane {
56 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040057
58 int mmu_id;
59
Clarence Ip730e7192016-06-26 22:45:09 -040060 struct mutex lock;
61
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040062 enum sde_sspp pipe;
63 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070064 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -040065 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040066
67 struct sde_hw_pipe *pipe_hw;
68 struct sde_hw_pipe_cfg pipe_cfg;
69 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040070 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040071 struct sde_hw_scaler3_cfg scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040072 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -040073 uint32_t color_fill;
74 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040075 bool is_rt_pipe;
Clarence Ip4ce59322016-06-26 22:27:51 -040076
Clarence Ip373f8592016-05-26 00:58:42 -040077 struct sde_csc_cfg csc_cfg;
78 struct sde_csc_cfg *csc_ptr;
79
Clarence Ip4c1d9772016-06-26 09:35:38 -040080 const struct sde_sspp_sub_blks *pipe_sblk;
81
Clarence Ip5e2a9222016-06-26 22:38:24 -040082 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040083
Clarence Ipaa0faf42016-05-30 12:07:48 -040084 struct msm_property_info property_info;
85 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -070086 struct drm_property_blob *blob_info;
Clarence Ip730e7192016-06-26 22:45:09 -040087
Clarence Ip4ce59322016-06-26 22:27:51 -040088 /* debugfs related stuff */
89 struct dentry *debugfs_root;
90 struct sde_debugfs_regset32 debugfs_src;
91 struct sde_debugfs_regset32 debugfs_scaler;
92 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070093};
Dhaval Patel47302cf2016-08-18 15:04:28 -070094
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070095#define to_sde_plane(x) container_of(x, struct sde_plane, base)
96
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040097static bool sde_plane_enabled(struct drm_plane_state *state)
98{
Clarence Ipdbde9832016-06-26 09:48:36 -040099 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400100}
101
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400102/**
103 * _sde_plane_calc_fill_level - calculate fill level of the given source format
104 * @plane: Pointer to drm plane
105 * @fmt: Pointer to source buffer format
106 * @src_wdith: width of source buffer
107 * Return: fill level corresponding to the source buffer/format or 0 if error
108 */
109static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
110 const struct sde_format *fmt, u32 src_width)
111{
112 struct sde_plane *psde;
113 u32 fixed_buff_size;
114 u32 total_fl;
115
116 if (!plane || !fmt) {
117 SDE_ERROR("invalid arguments\n");
118 return 0;
119 }
120
121 psde = to_sde_plane(plane);
122 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
123
124 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
125 if (fmt->chroma_sample == SDE_CHROMA_420) {
126 /* NV12 */
127 total_fl = (fixed_buff_size / 2) /
128 ((src_width + 32) * fmt->bpp);
129 } else {
130 /* non NV12 */
131 total_fl = (fixed_buff_size) /
132 ((src_width + 32) * fmt->bpp);
133 }
134 } else {
135 total_fl = (fixed_buff_size * 2) /
136 ((src_width + 32) * fmt->bpp);
137 }
138
139 SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
140 plane->base.id, psde->pipe - SSPP_VIG0,
141 fmt->base.pixel_format, src_width, total_fl);
142
143 return total_fl;
144}
145
146/**
147 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
148 * @total_fl: fill level
149 * Return: LUT setting corresponding to the fill level
150 */
151static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
152{
153 u32 qos_lut;
154
155 if (total_fl <= 4)
156 qos_lut = 0x1B;
157 else if (total_fl <= 5)
158 qos_lut = 0x5B;
159 else if (total_fl <= 6)
160 qos_lut = 0x15B;
161 else if (total_fl <= 7)
162 qos_lut = 0x55B;
163 else if (total_fl <= 8)
164 qos_lut = 0x155B;
165 else if (total_fl <= 9)
166 qos_lut = 0x555B;
167 else if (total_fl <= 10)
168 qos_lut = 0x1555B;
169 else if (total_fl <= 11)
170 qos_lut = 0x5555B;
171 else if (total_fl <= 12)
172 qos_lut = 0x15555B;
173 else
174 qos_lut = 0x55555B;
175
176 return qos_lut;
177}
178
179/**
180 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
181 * @total_fl: fill level
182 * Return: LUT setting corresponding to the fill level
183 */
184static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
185{
186 u32 qos_lut;
187
188 if (total_fl <= 10)
189 qos_lut = 0x1AAff;
190 else if (total_fl <= 11)
191 qos_lut = 0x5AAFF;
192 else if (total_fl <= 12)
193 qos_lut = 0x15AAFF;
194 else
195 qos_lut = 0x55AAFF;
196
197 return qos_lut;
198}
199
200/**
201 * _sde_plane_is_rt_pipe - check if the given plane requires real-time QoS
202 * @plane: Pointer to drm plane
203 * @crtc: Pointer to drm crtc associated with the given plane
204 */
205static bool _sde_plane_is_rt_pipe(struct drm_plane *plane,
206 struct drm_crtc *crtc)
207{
208 struct sde_plane *psde = to_sde_plane(plane);
209 struct drm_connector *connector;
210 bool is_rt = false;
211
212 /* check if this plane has a physical connector interface */
213 drm_for_each_connector(connector, plane->dev)
214 if (connector->state &&
215 (connector->state->crtc == crtc) &&
216 (connector->connector_type
217 != DRM_MODE_CONNECTOR_VIRTUAL)) {
218 is_rt = true;
219 break;
220 }
221
222 SDE_DEBUG("plane%u: pnum:%d rt:%d\n",
223 plane->base.id, psde->pipe - SSPP_VIG0, is_rt);
224
225 return is_rt;
226}
227
228/**
229 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
230 * @plane: Pointer to drm plane
231 * @fb: Pointer to framebuffer associated with the given plane
232 */
233static void _sde_plane_set_qos_lut(struct drm_plane *plane,
234 struct drm_framebuffer *fb)
235{
236 struct sde_plane *psde;
237 const struct sde_format *fmt = NULL;
238 u32 qos_lut;
239 u32 total_fl = 0;
240
241 if (!plane || !fb) {
242 SDE_ERROR("invalid arguments plane %d fb %d\n",
243 plane != 0, fb != 0);
244 return;
245 }
246
247 psde = to_sde_plane(plane);
248
249 if (!psde->pipe_hw || !psde->pipe_sblk) {
250 SDE_ERROR("invalid arguments\n");
251 return;
252 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
253 return;
254 }
255
256 if (!psde->is_rt_pipe) {
257 qos_lut = psde->pipe_sblk->creq_lut_nrt;
258 } else {
259 fmt = sde_get_sde_format_ext(
260 fb->pixel_format,
261 fb->modifier,
262 drm_format_num_planes(fb->pixel_format));
263 total_fl = _sde_plane_calc_fill_level(plane, fmt,
264 psde->pipe_cfg.src_rect.w);
265
266 if (SDE_FORMAT_IS_LINEAR(fmt))
267 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
268 else
269 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
270 }
271
272 psde->pipe_qos_cfg.creq_lut = qos_lut;
273
274 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
275 (fmt) ? fmt->base.pixel_format : 0,
276 psde->is_rt_pipe, total_fl, qos_lut,
277 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
278
279 SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
280 plane->base.id,
281 psde->pipe - SSPP_VIG0,
282 (fmt) ? fmt->base.pixel_format : 0,
283 psde->is_rt_pipe, total_fl, qos_lut);
284
285 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
286}
287
288/**
289 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
290 * @plane: Pointer to drm plane
291 * @fb: Pointer to framebuffer associated with the given plane
292 */
293static void _sde_plane_set_danger_lut(struct drm_plane *plane,
294 struct drm_framebuffer *fb)
295{
296 struct sde_plane *psde;
297 const struct sde_format *fmt = NULL;
298 u32 danger_lut, safe_lut;
299
300 if (!plane || !fb) {
301 SDE_ERROR("invalid arguments\n");
302 return;
303 }
304
305 psde = to_sde_plane(plane);
306
307 if (!psde->pipe_hw || !psde->pipe_sblk) {
308 SDE_ERROR("invalid arguments\n");
309 return;
310 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
311 return;
312 }
313
314 if (!psde->is_rt_pipe) {
315 danger_lut = psde->pipe_sblk->danger_lut_nrt;
316 safe_lut = psde->pipe_sblk->safe_lut_nrt;
317 } else {
318 fmt = sde_get_sde_format_ext(
319 fb->pixel_format,
320 fb->modifier,
321 drm_format_num_planes(fb->pixel_format));
322
323 if (SDE_FORMAT_IS_LINEAR(fmt)) {
324 danger_lut = psde->pipe_sblk->danger_lut_linear;
325 safe_lut = psde->pipe_sblk->safe_lut_linear;
326 } else {
327 danger_lut = psde->pipe_sblk->danger_lut_tile;
328 safe_lut = psde->pipe_sblk->safe_lut_tile;
329 }
330 }
331
332 psde->pipe_qos_cfg.danger_lut = danger_lut;
333 psde->pipe_qos_cfg.safe_lut = safe_lut;
334
335 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
336 (fmt) ? fmt->base.pixel_format : 0,
337 (fmt) ? fmt->fetch_mode : 0,
338 psde->pipe_qos_cfg.danger_lut,
339 psde->pipe_qos_cfg.safe_lut);
340
341 SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
342 plane->base.id,
343 psde->pipe - SSPP_VIG0,
344 fmt ? fmt->base.pixel_format : 0,
345 fmt ? fmt->fetch_mode : -1,
346 psde->pipe_qos_cfg.danger_lut,
347 psde->pipe_qos_cfg.safe_lut);
348
349 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
350 &psde->pipe_qos_cfg);
351}
352
353/**
354 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
355 * @plane: Pointer to drm plane
356 * @enable: true to enable QoS control
357 * @flags: QoS control mode (enum sde_plane_qos)
358 */
359static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
360 bool enable, u32 flags)
361{
362 struct sde_plane *psde;
363
364 if (!plane) {
365 SDE_ERROR("invalid arguments\n");
366 return;
367 }
368
369 psde = to_sde_plane(plane);
370
371 if (!psde->pipe_hw || !psde->pipe_sblk) {
372 SDE_ERROR("invalid arguments\n");
373 return;
374 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
375 return;
376 }
377
378 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
379 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
380 psde->pipe_qos_cfg.danger_vblank =
381 psde->pipe_sblk->danger_vblank;
382 psde->pipe_qos_cfg.vblank_en = enable;
383 }
384
385 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
386 /* this feature overrules previous VBLANK_CTRL */
387 psde->pipe_qos_cfg.vblank_en = false;
388 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
389 }
390
391 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
392 psde->pipe_qos_cfg.danger_safe_en = enable;
393
394 if (!psde->is_rt_pipe) {
395 psde->pipe_qos_cfg.vblank_en = false;
396 psde->pipe_qos_cfg.danger_safe_en = false;
397 }
398
399 SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x]\n",
400 plane->base.id,
401 psde->pipe - SSPP_VIG0,
402 psde->pipe_qos_cfg.danger_safe_en,
403 psde->pipe_qos_cfg.vblank_en,
404 psde->pipe_qos_cfg.creq_vblank,
405 psde->pipe_qos_cfg.danger_vblank);
406
407 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
408 &psde->pipe_qos_cfg);
409}
410
Alan Kwong5d324e42016-07-28 22:56:18 -0400411/**
412 * _sde_plane_set_ot_limit - set OT limit for the given plane
413 * @plane: Pointer to drm plane
414 * @crtc: Pointer to drm crtc
415 */
416static void _sde_plane_set_ot_limit(struct drm_plane *plane,
417 struct drm_crtc *crtc)
418{
419 struct sde_plane *psde;
420 struct sde_vbif_set_ot_params ot_params;
421 struct msm_drm_private *priv;
422 struct sde_kms *sde_kms;
423
424 if (!plane || !plane->dev || !crtc) {
425 SDE_ERROR("invalid arguments plane %d crtc %d\n",
426 plane != 0, crtc != 0);
427 return;
428 }
429
430 priv = plane->dev->dev_private;
431 if (!priv || !priv->kms) {
432 SDE_ERROR("invalid KMS reference\n");
433 return;
434 }
435
436 sde_kms = to_sde_kms(priv->kms);
437 psde = to_sde_plane(plane);
438 if (!psde->pipe_hw) {
439 SDE_ERROR("invalid pipe reference\n");
440 return;
441 }
442
443 memset(&ot_params, 0, sizeof(ot_params));
444 ot_params.xin_id = psde->pipe_hw->cap->xin_id;
445 ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
446 ot_params.width = psde->pipe_cfg.src_rect.w;
447 ot_params.height = psde->pipe_cfg.src_rect.h;
448 ot_params.is_wfd = !psde->is_rt_pipe;
449 ot_params.frame_rate = crtc->mode.vrefresh;
450 ot_params.vbif_idx = VBIF_RT;
451 ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
452 ot_params.rd = true;
453
454 sde_vbif_set_ot_limit(sde_kms, &ot_params);
455}
456
Clarence Ipcae1bb62016-07-07 12:07:13 -0400457/* helper to update a state's input fence pointer from the property */
458static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400459 struct sde_plane_state *pstate, uint64_t fd)
460{
461 if (!plane || !pstate)
462 return;
463
464 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400465 if (pstate->input_fence)
466 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400467
468 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400469 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400470
Dhaval Patel47302cf2016-08-18 15:04:28 -0700471 SDE_DEBUG("0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400472}
473
Clarence Ipcae1bb62016-07-07 12:07:13 -0400474int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400475{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400476 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400477 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400478 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400479 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400480
481 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700482 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400483 } else if (!plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700484 SDE_ERROR("invalid plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400485 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400486 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400487 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400488 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400489
Clarence Ipcae1bb62016-07-07 12:07:13 -0400490 if (input_fence) {
491 ret = sde_sync_wait(input_fence, wait_ms);
492 switch (ret) {
493 case 0:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700494 SDE_DEBUG("%s signaled\n", psde->pipe_name);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400495 break;
496 case -ETIME:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700497 SDE_ERROR("timeout on %s, %ums\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400498 psde->pipe_name, wait_ms);
499 psde->is_error = true;
500 break;
501 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700502 SDE_ERROR("error on %s, %d\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400503 psde->pipe_name, ret);
504 psde->is_error = true;
505 break;
506 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400507 } else {
508 ret = 0;
509 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400510 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400511 return ret;
512}
513
Clarence Ipe78efb72016-06-24 18:35:21 -0400514static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400515 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400516 struct sde_hw_pipe_cfg *pipe_cfg,
517 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400518{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400519 struct sde_plane *psde;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400520 int ret, i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400521
Clarence Ipae4e60c2016-06-26 22:44:04 -0400522 if (!plane || !pstate || !pipe_cfg || !fb)
523 return;
524
525 psde = to_sde_plane(plane);
526
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400527 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
528 if (ret) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700529 SDE_ERROR("failed to get format layout, error: %d\n", ret);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400530 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400531 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400532
533 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
534 BIT(SDE_DRM_DEINTERLACE))
535 for (i = 0; i < SDE_MAX_PLANES; ++i)
536 pipe_cfg->layout.plane_pitch[i] <<= 1;
537
538 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
539 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400540}
541
Clarence Ipcb410d42016-06-26 22:52:33 -0400542static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400543 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
544 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400545 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400546 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
547{
548}
549
Clarence Ipcb410d42016-06-26 22:52:33 -0400550/**
551 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
552 * @psde: Pointer to SDE plane object
553 * @src: Source size
554 * @dst: Destination size
555 * @phase_steps: Pointer to output array for phase steps
556 * @filter: Pointer to output array for filter type
557 * @fmt: Pointer to format definition
558 * @chroma_subsampling: Subsampling amount for chroma channel
559 *
560 * Returns: 0 on success
561 */
562static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400563 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400564 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400565 uint32_t chroma_subsampling)
566{
Clarence Ipcb410d42016-06-26 22:52:33 -0400567 if (!psde || !phase_steps || !filter || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700568 SDE_ERROR("invalid arguments\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400569 return -EINVAL;
570 }
571
Clarence Ip4c1d9772016-06-26 09:35:38 -0400572 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400573 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400574 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400575 phase_steps[SDE_SSPP_COMP_1_2] =
576 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
577 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
578 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400579
580 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400581 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400582 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400583 (src <= dst) ? SDE_SCALE_FILTER_BIL :
584 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400585
Clarence Ipdbde9832016-06-26 09:48:36 -0400586 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400587 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400588 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
589 } else {
590 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
591 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400592 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400593 }
594 } else {
595 /* disable scaler */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700596 SDE_DEBUG("disable scaler\n");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400597 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
598 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
599 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400600 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400601 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400602}
603
Clarence Ipcb410d42016-06-26 22:52:33 -0400604/**
605 * _sde_plane_setup_pixel_ext - determine default pixel extension values
606 * @psde: Pointer to SDE plane object
607 * @src: Source size
608 * @dst: Destination size
609 * @decimated_src: Source size after decimation, if any
610 * @phase_steps: Pointer to output array for phase steps
611 * @out_src: Output array for pixel extension values
612 * @out_edge1: Output array for pixel extension first edge
613 * @out_edge2: Output array for pixel extension second edge
614 * @filter: Pointer to array for filter type
615 * @fmt: Pointer to format definition
616 * @chroma_subsampling: Subsampling amount for chroma channel
617 * @post_compare: Whether to chroma subsampled source size for comparisions
618 */
619static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400620 uint32_t src, uint32_t dst, uint32_t decimated_src,
621 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400622 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400623 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400624 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400625{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400626 int64_t edge1, edge2, caf;
627 uint32_t src_work;
628 int i, tmp;
629
Clarence Ipcb410d42016-06-26 22:52:33 -0400630 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400631 out_edge2 && filter && fmt) {
632 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400633 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400634 caf = PHASE_STEP_UNIT_SCALE;
635 else
636 caf = 0;
637
638 for (i = 0; i < SDE_MAX_PLANES; i++) {
639 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400640 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400641 src_work /= chroma_subsampling;
642 if (post_compare)
643 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400644 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400645 /* unity */
646 edge1 = 0;
647 edge2 = 0;
648 } else if (dst >= src) {
649 /* upscale */
650 edge1 = (1 << PHASE_RESIDUAL);
651 edge1 -= caf;
652 edge2 = (1 << PHASE_RESIDUAL);
653 edge2 += (dst - 1) * *(phase_steps + i);
654 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
655 edge2 += caf;
656 edge2 = -(edge2);
657 } else {
658 /* downscale */
659 edge1 = 0;
660 edge2 = (dst - 1) * *(phase_steps + i);
661 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
662 edge2 += *(phase_steps + i);
663 edge2 = -(edge2);
664 }
665
666 /* only enable CAF for luma plane */
667 caf = 0;
668
669 /* populate output arrays */
670 *(out_src + i) = src_work;
671
672 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400673 if (edge1 >= 0) {
674 tmp = (uint32_t)edge1;
675 tmp >>= PHASE_STEP_SHIFT;
676 *(out_edge1 + i) = -tmp;
677 } else {
678 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400679 *(out_edge1 + i) =
680 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
681 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400682 }
683 if (edge2 >= 0) {
684 tmp = (uint32_t)edge2;
685 tmp >>= PHASE_STEP_SHIFT;
686 *(out_edge2 + i) = -tmp;
687 } else {
688 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400689 *(out_edge2 + i) =
690 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
691 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400692 }
693 }
694 }
695}
696
Clarence Ip5e2a9222016-06-26 22:38:24 -0400697/**
698 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
699 * sub-structure
700 * @blob_ptr: Pointer to start of incoming blob data
701 * @blob_size: Size of incoming blob data, in bytes
702 * @sub_ptr: Pointer to start of desired sub-structure
703 * @sub_size: Required size of sub-structure, in bytes
704 */
705static int _sde_plane_verify_blob(void *blob_ptr,
706 size_t blob_size,
707 void *sub_ptr,
708 size_t sub_size)
709{
710 /*
711 * Use the blob size provided by drm to check if there are enough
712 * bytes from the start of versioned sub-structures to the end of
713 * blob data:
714 *
715 * e.g.,
716 * blob_ptr --> struct blob_data {
717 * uint32_t version;
718 * sub_ptr --> struct blob_data_v1 v1;
719 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
720 * blob_ptr + blob_size --> };
721 *
722 * It's important to check the actual number of bytes from the start
723 * of the sub-structure to the end of the blob data, and not just rely
724 * on something like,
725 *
726 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
727 *
728 * This is because the start of the sub-structure can vary based on
729 * how the compiler pads the overall structure.
730 */
731 if (blob_ptr && sub_ptr)
732 /* return zero if end of blob >= end of sub-struct */
733 return ((unsigned char *)blob_ptr + blob_size) <
734 ((unsigned char *)sub_ptr + sub_size);
735 return -EINVAL;
736}
737
Clarence Ipe78efb72016-06-24 18:35:21 -0400738static void _sde_plane_setup_csc(struct sde_plane *psde,
739 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400740 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400741{
742 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
743 {
Clarence Ip373f8592016-05-26 00:58:42 -0400744 /* S15.16 format */
745 0x00012A00, 0x00000000, 0x00019880,
746 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
747 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400748 },
Clarence Ip373f8592016-05-26 00:58:42 -0400749 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400750 { 0xfff0, 0xff80, 0xff80,},
751 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400752 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400753 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400754 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400755 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400756 static const struct sde_csc_cfg sde_csc_NOP = {
757 {
Clarence Ip373f8592016-05-26 00:58:42 -0400758 /* identity matrix, S15.16 format */
759 0x10000, 0x00000, 0x00000,
760 0x00000, 0x10000, 0x00000,
761 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400762 },
Clarence Ip373f8592016-05-26 00:58:42 -0400763 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400764 { 0x0, 0x0, 0x0,},
765 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400766 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400767 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
768 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
769 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400770 struct sde_drm_csc *csc = NULL;
771 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400772 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400773
Clarence Ipaa0faf42016-05-30 12:07:48 -0400774 if (!psde || !pstate || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700775 SDE_ERROR("invalid arguments\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400776 return;
777 }
778 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400779 return;
780
Clarence Ip5e2a9222016-06-26 22:38:24 -0400781 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400782 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400783 csc = msm_property_get_blob(&psde->property_info,
784 pstate->property_blobs,
785 &csc_size,
786 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400787 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400788 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400789 memcpy(&psde->csc_cfg,
790 &sde_csc_NOP,
791 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400792 switch (csc->version) {
793 case SDE_DRM_CSC_V1:
794 if (!_sde_plane_verify_blob(csc,
795 csc_size,
796 &csc->v1,
797 sizeof(struct sde_drm_csc_v1))) {
798 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400799 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400800 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400801 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400802 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400803 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400804 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400805 csc->v1.post_bias[i];
806 }
807 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400808 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400809 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400810 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400811 csc->v1.post_clamp[i];
812 }
Clarence Ipb493d762016-07-19 18:49:10 -0400813 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400814 }
815 break;
816 default:
817 break;
818 }
Clarence Ipb493d762016-07-19 18:49:10 -0400819 if (!psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700820 SDE_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400821 }
822
Clarence Ipcae1bb62016-07-07 12:07:13 -0400823 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400824 if (psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700825 SDE_DEBUG("user blob override for csc\n");
Clarence Ipb493d762016-07-19 18:49:10 -0400826 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400827 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400828}
829
Clarence Ipcb410d42016-06-26 22:52:33 -0400830static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400831 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400832 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700833{
Clarence Ipcb410d42016-06-26 22:52:33 -0400834 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400835 struct sde_drm_scaler *sc_u = NULL;
836 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400837 size_t sc_u_size = 0;
838 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
839 uint32_t tmp;
840 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400841
Clarence Ipcb410d42016-06-26 22:52:33 -0400842 if (!psde || !fmt)
843 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400844
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400845 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400846 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400847
Clarence Ip5e2a9222016-06-26 22:38:24 -0400848 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400849 if (pstate)
850 sc_u = msm_property_get_blob(&psde->property_info,
851 pstate->property_blobs,
852 &sc_u_size,
853 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400854 if (sc_u) {
855 switch (sc_u->version) {
856 case SDE_DRM_SCALER_V1:
857 if (!_sde_plane_verify_blob(sc_u,
858 sc_u_size,
859 &sc_u->v1,
860 sizeof(*sc_u1)))
861 sc_u1 = &sc_u->v1;
862 break;
863 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700864 SDE_DEBUG("unrecognized scaler blob v%lld\n",
865 sc_u->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400866 break;
867 }
868 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400869
Clarence Ip04ec67d2016-05-26 01:16:15 -0400870 /* decimation */
871 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
872 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
873 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400874 } else {
875 psde->pipe_cfg.horz_decimation = 0;
876 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400877 }
878
879 /* don't chroma subsample if decimating */
880 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400881 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400882 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400883 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400884
Clarence Ip5e2a9222016-06-26 22:38:24 -0400885 /* update scaler */
886 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
887 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Dhaval Patel47302cf2016-08-18 15:04:28 -0700888 SDE_DEBUG("SCALER3 blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400889 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400890 _sde_plane_setup_scaler3(psde,
891 psde->pipe_cfg.src_rect.w,
892 psde->pipe_cfg.src_rect.h,
893 psde->pipe_cfg.dst_rect.w,
894 psde->pipe_cfg.dst_rect.h,
895 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400896 chroma_subsmpl_h, chroma_subsmpl_v);
897 } else {
898 /* always calculate basic scaler config */
899 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
900 /* populate from user space */
901 for (i = 0; i < SDE_MAX_PLANES; i++) {
902 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
903 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
904 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
905 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400906
Clarence Ip5e2a9222016-06-26 22:38:24 -0400907 pe->horz_filter[i] = sc_u1->horz_filter[i];
908 pe->vert_filter[i] = sc_u1->vert_filter[i];
909 }
910 } else {
911 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400912 _sde_plane_setup_scaler2(psde,
913 psde->pipe_cfg.src_rect.w,
914 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400915 pe->phase_step_x,
916 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400917 _sde_plane_setup_scaler2(psde,
918 psde->pipe_cfg.src_rect.h,
919 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400920 pe->phase_step_y,
921 pe->vert_filter, fmt, chroma_subsmpl_v);
922 }
923 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400924
Clarence Ip5e2a9222016-06-26 22:38:24 -0400925 /* update pixel extensions */
926 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
927 /* populate from user space */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700928 SDE_DEBUG("pixel ext blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400929 for (i = 0; i < SDE_MAX_PLANES; i++) {
930 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
931 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
932 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
933 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
934 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
935 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
936 pe->roi_w[i] = sc_u1->lr.roi[i];
937
938 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
939 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
940 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
941 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
942 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
943 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
944 pe->roi_h[i] = sc_u1->tb.roi[i];
945 }
946 } else {
947 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400948 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400949 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400950 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400951 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400952 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
953 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400954 pe->phase_step_x,
955 pe->roi_w,
956 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400957 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400958 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400959
Clarence Ipcb410d42016-06-26 22:52:33 -0400960 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400961 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400962 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
963 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400964 pe->phase_step_y,
965 pe->roi_h,
966 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400967 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400968 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400969
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400970 for (i = 0; i < SDE_MAX_PLANES; i++) {
971 if (pe->num_ext_pxls_left[i] >= 0)
972 pe->left_rpt[i] =
973 pe->num_ext_pxls_left[i];
974 else
975 pe->left_ftch[i] =
976 pe->num_ext_pxls_left[i];
977
978 if (pe->num_ext_pxls_right[i] >= 0)
979 pe->right_rpt[i] =
980 pe->num_ext_pxls_right[i];
981 else
982 pe->right_ftch[i] =
983 pe->num_ext_pxls_right[i];
984
985 if (pe->num_ext_pxls_top[i] >= 0)
986 pe->top_rpt[i] =
987 pe->num_ext_pxls_top[i];
988 else
989 pe->top_ftch[i] =
990 pe->num_ext_pxls_top[i];
991
992 if (pe->num_ext_pxls_btm[i] >= 0)
993 pe->btm_rpt[i] =
994 pe->num_ext_pxls_btm[i];
995 else
996 pe->btm_ftch[i] =
997 pe->num_ext_pxls_btm[i];
998 }
999 }
Clarence Ipcb410d42016-06-26 22:52:33 -04001000}
1001
Clarence Ipcae1bb62016-07-07 12:07:13 -04001002/**
1003 * _sde_plane_color_fill - enables color fill on plane
1004 * @plane: Pointer to DRM plane object
1005 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
1006 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
1007 * Returns: 0 on success
1008 */
1009static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -04001010 uint32_t color, uint32_t alpha)
1011{
1012 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001013 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -04001014
1015 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001016 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001017 return -EINVAL;
1018 }
1019
1020 psde = to_sde_plane(plane);
1021 if (!psde->pipe_hw) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001022 SDE_ERROR("invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001023 return -EINVAL;
1024 }
1025
Clarence Ipcae1bb62016-07-07 12:07:13 -04001026 DBG("");
1027
Clarence Ipcb410d42016-06-26 22:52:33 -04001028 /*
1029 * select fill format to match user property expectation,
1030 * h/w only supports RGB variants
1031 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001032 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -04001033
1034 /* update sspp */
1035 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
1036 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
1037 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
1038
1039 /* override scaler/decimation if solid fill */
1040 psde->pipe_cfg.src_rect.x = 0;
1041 psde->pipe_cfg.src_rect.y = 0;
1042 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
1043 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
1044
1045 _sde_plane_setup_scaler(psde, fmt, 0);
1046
1047 if (psde->pipe_hw->ops.setup_format)
1048 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
1049 fmt, SDE_SSPP_SOLID_FILL);
1050
1051 if (psde->pipe_hw->ops.setup_rects)
1052 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1053 &psde->pipe_cfg, &psde->pixel_ext);
1054 }
1055
1056 return 0;
1057}
1058
1059static int _sde_plane_mode_set(struct drm_plane *plane,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001060 struct drm_plane_state *state)
Clarence Ipcb410d42016-06-26 22:52:33 -04001061{
Dhaval Patel48c76022016-09-01 17:51:23 -07001062 uint32_t nplanes, src_flags, zpos, split_width;
Clarence Ipcb410d42016-06-26 22:52:33 -04001063 struct sde_plane *psde;
1064 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001065 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001066 struct drm_crtc *crtc;
1067 struct drm_framebuffer *fb;
1068 struct sde_rect src, dst;
1069 bool q16_data = true;
Clarence Ipcb410d42016-06-26 22:52:33 -04001070
1071 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001072 SDE_ERROR("invalid plane/state\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001073 return -EINVAL;
1074 }
1075
1076 psde = to_sde_plane(plane);
1077 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -04001078
Dhaval Patel47302cf2016-08-18 15:04:28 -07001079 crtc = state->crtc;
1080 fb = state->fb;
1081 if (!crtc || !fb) {
1082 SDE_ERROR("invalid crtc/fb\n");
1083 return -EINVAL;
1084 }
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001085 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001086 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -04001087
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001088 psde->is_rt_pipe = _sde_plane_is_rt_pipe(plane, crtc);
1089
1090 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1091
Dhaval Patel47302cf2016-08-18 15:04:28 -07001092 POPULATE_RECT(&src, state->src_x, state->src_y,
1093 state->src_w, state->src_h, q16_data);
1094 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
1095 state->crtc_w, state->crtc_h, !q16_data);
Clarence Ipcb410d42016-06-26 22:52:33 -04001096
Dhaval Patel47302cf2016-08-18 15:04:28 -07001097 SDE_DEBUG("%s:FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001098 psde->pipe_name,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001099 fb->base.id, src.x, src.y, src.w, src.h,
1100 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001101 drm_get_format_name(fmt->base.pixel_format),
1102 SDE_FORMAT_IS_UBWC(fmt));
Clarence Ipcb410d42016-06-26 22:52:33 -04001103
1104 /* update format configuration */
1105 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
1106 src_flags = 0;
1107
Clarence Ipcb410d42016-06-26 22:52:33 -04001108 /* flags */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001109 SDE_DEBUG("flags 0x%llX, rotation 0x%llX\n",
Clarence Ipcb410d42016-06-26 22:52:33 -04001110 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
1111 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
1112 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1113 BIT(DRM_REFLECT_X))
1114 src_flags |= SDE_SSPP_FLIP_LR;
1115 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1116 BIT(DRM_REFLECT_Y))
1117 src_flags |= SDE_SSPP_FLIP_UD;
1118 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
1119 BIT(SDE_DRM_DEINTERLACE)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001120 src.h /= 2;
1121 src.y = DIV_ROUND_UP(src.y, 2);
1122 src.y &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -04001123 }
1124
Dhaval Patel47302cf2016-08-18 15:04:28 -07001125 psde->pipe_cfg.src_rect = src;
1126 psde->pipe_cfg.dst_rect = dst;
Clarence Ipcb410d42016-06-26 22:52:33 -04001127
Clarence Ipcb410d42016-06-26 22:52:33 -04001128 /* check for color fill */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001129 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001130 PLANE_PROP_COLOR_FILL);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001131 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1132 /* skip remaining processing on color fill */
1133 return 0;
Clarence Ipcb410d42016-06-26 22:52:33 -04001134
1135 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
1136
1137 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001138
Dhaval Patel48c76022016-09-01 17:51:23 -07001139 /* base layer source split needs update */
1140 zpos = sde_plane_get_property(pstate, PLANE_PROP_ZPOS);
1141 if (zpos == SDE_STAGE_BASE) {
1142 split_width = get_crtc_split_width(crtc);
1143 if (psde->pipe_cfg.dst_rect.x >= split_width)
1144 psde->pipe_cfg.dst_rect.x -= split_width;
1145 }
1146
Clarence Ip4c1d9772016-06-26 09:35:38 -04001147 if (psde->pipe_hw->ops.setup_format)
1148 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -04001149 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001150 if (psde->pipe_hw->ops.setup_rects)
1151 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1152 &psde->pipe_cfg, &psde->pixel_ext);
1153
Clarence Ipe78efb72016-06-24 18:35:21 -04001154 /* update sharpening */
1155 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
1156 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
1157 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
1158 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
1159
1160 if (psde->pipe_hw->ops.setup_sharpening)
1161 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
1162 &psde->sharp_cfg);
1163
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001164 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -04001165 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -04001166 _sde_plane_setup_csc(psde, pstate, fmt);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001167 else
1168 psde->csc_ptr = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001169
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001170 _sde_plane_set_qos_lut(plane, fb);
1171 _sde_plane_set_danger_lut(plane, fb);
1172
Alan Kwong5d324e42016-07-28 22:56:18 -04001173 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001174 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
Alan Kwong5d324e42016-07-28 22:56:18 -04001175 _sde_plane_set_ot_limit(plane, crtc);
1176 }
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001177
Clarence Ip5e2a9222016-06-26 22:38:24 -04001178 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001179}
1180
1181static int sde_plane_prepare_fb(struct drm_plane *plane,
1182 const struct drm_plane_state *new_state)
1183{
1184 struct drm_framebuffer *fb = new_state->fb;
1185 struct sde_plane *psde = to_sde_plane(plane);
1186
1187 if (!new_state->fb)
1188 return 0;
1189
Dhaval Patel47302cf2016-08-18 15:04:28 -07001190 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001191 return msm_framebuffer_prepare(fb, psde->mmu_id);
1192}
1193
1194static void sde_plane_cleanup_fb(struct drm_plane *plane,
1195 const struct drm_plane_state *old_state)
1196{
1197 struct drm_framebuffer *fb = old_state->fb;
1198 struct sde_plane *psde = to_sde_plane(plane);
1199
1200 if (!fb)
1201 return;
1202
Dhaval Patel47302cf2016-08-18 15:04:28 -07001203 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001204 msm_framebuffer_cleanup(fb, psde->mmu_id);
1205}
1206
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001207static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
1208 struct drm_plane_state *state,
1209 struct drm_plane_state *old_state)
1210{
1211 struct sde_plane_state *pstate = to_sde_plane_state(state);
1212
Dhaval Patel47302cf2016-08-18 15:04:28 -07001213 /* no need to check it again */
1214 if (pstate->mode_changed)
1215 return;
1216
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001217 if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001218 SDE_DEBUG("%s: pipe enabling/disabling full modeset required\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001219 psde->pipe_name);
1220 pstate->mode_changed = true;
1221 } else if (to_sde_plane_state(old_state)->pending) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001222 SDE_DEBUG("%s: still pending\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001223 pstate->mode_changed = true;
1224 } else if (state->src_w != old_state->src_w ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07001225 state->src_h != old_state->src_h ||
1226 state->src_x != old_state->src_x ||
1227 state->src_y != old_state->src_y) {
1228 SDE_DEBUG("%s: src rect updated\n", psde->pipe_name);
1229 pstate->mode_changed = true;
1230 } else if (state->crtc_w != old_state->crtc_w ||
1231 state->crtc_h != old_state->crtc_h ||
1232 state->crtc_x != old_state->crtc_x ||
1233 state->crtc_y != old_state->crtc_y) {
1234 SDE_DEBUG("%s: crtc rect updated\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001235 pstate->mode_changed = true;
1236 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001237 SDE_DEBUG("%s: format change!\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001238 pstate->mode_changed = true;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001239 } else {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001240 uint64_t *new_mods = state->fb->modifier;
1241 uint64_t *old_mods = old_state->fb->modifier;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001242 uint32_t *new_pitches = state->fb->pitches;
1243 uint32_t *old_pitches = old_state->fb->pitches;
1244 uint32_t *new_offset = state->fb->offsets;
1245 uint32_t *old_offset = old_state->fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001246 int i;
1247
1248 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
1249 if (new_mods[i] != old_mods[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001250 SDE_DEBUG("%s: format modifiers change\"\
1251 plane:%d new_mode:%llu old_mode:%llu\n",
1252 psde->pipe_name, i, new_mods[i],
1253 old_mods[i]);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001254 pstate->mode_changed = true;
1255 break;
1256 }
1257 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001258 for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
1259 if (new_pitches[i] != old_pitches[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001260 SDE_DEBUG("%s: pitches change plane:%d\"\
1261 old_pitches:%u new_pitches:%u\n",
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001262 psde->pipe_name, i, old_pitches[i],
1263 new_pitches[i]);
1264 pstate->mode_changed = true;
1265 break;
1266 }
1267 }
Dhaval Patel47302cf2016-08-18 15:04:28 -07001268 for (i = 0; i < ARRAY_SIZE(state->fb->offsets); i++) {
1269 if (new_offset[i] != old_offset[i]) {
1270 SDE_DEBUG("%s: offset change plane:%d\"\
1271 old_offset:%u new_offset:%u\n",
1272 psde->pipe_name, i, old_offset[i],
1273 new_offset[i]);
1274 pstate->mode_changed = true;
1275 break;
1276 }
1277 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001278 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001279}
1280
Dhaval Patel47302cf2016-08-18 15:04:28 -07001281static bool __get_scale_data(struct sde_plane *psde,
1282 struct sde_plane_state *pstate, struct sde_drm_scaler *sc_u,
1283 size_t *sc_u_size)
1284{
1285 bool valid_flag = false;
1286
1287 sc_u = msm_property_get_blob(&psde->property_info,
1288 pstate->property_blobs,
1289 sc_u_size,
1290 PLANE_PROP_SCALER);
1291 if (sc_u) {
1292 switch (sc_u->version) {
1293 case SDE_DRM_SCALER_V1:
1294 if (!_sde_plane_verify_blob(sc_u, *sc_u_size,
1295 &sc_u->v1, sizeof(struct sde_drm_scaler_v1)))
1296 valid_flag = true;
1297 break;
1298 default:
1299 SDE_DEBUG("unrecognized scaler blob v%lld\n",
1300 sc_u->version);
1301 break;
1302 }
1303 }
1304
1305 return valid_flag;
1306}
1307
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001308static int sde_plane_atomic_check(struct drm_plane *plane,
1309 struct drm_plane_state *state)
1310{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001311 int ret = 0, valid_scale_data;
Clarence Ipdbde9832016-06-26 09:48:36 -04001312 struct sde_plane *psde;
1313 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001314 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -04001315 size_t sc_u_size = 0;
1316 struct sde_drm_scaler *sc_u = NULL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001317 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04001318 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001319 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
1320 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04001321
1322 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001323 SDE_ERROR("invalid plane/state\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001324 ret = -EINVAL;
1325 goto exit;
1326 }
1327
1328 psde = to_sde_plane(plane);
1329 pstate = to_sde_plane_state(state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001330
1331 if (!psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001332 SDE_ERROR("invalid plane catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001333 ret = -EINVAL;
1334 goto exit;
1335 }
1336
Dhaval Patel47302cf2016-08-18 15:04:28 -07001337 valid_scale_data = __get_scale_data(psde, pstate, sc_u, &sc_u_size);
1338 deci_w = valid_scale_data && sc_u ? sc_u->v1.horz_decimate : 0;
1339 deci_h = valid_scale_data && sc_u ? sc_u->v1.vert_decimate : 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04001340
1341 /* src values are in Q16 fixed point, convert to integer */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001342 POPULATE_RECT(&src, state->src_x, state->src_y, state->src_w,
1343 state->src_h, q16_data);
1344 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
1345 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04001346
Dhaval Patel47302cf2016-08-18 15:04:28 -07001347 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
1348 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04001349
Dhaval Patel47302cf2016-08-18 15:04:28 -07001350 max_upscale = psde->pipe_sblk->maxupscale;
1351 max_downscale = psde->pipe_sblk->maxdwnscale;
1352 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04001353
Dhaval Patel47302cf2016-08-18 15:04:28 -07001354 SDE_DEBUG("%s: check (%d -> %d)\n", psde->pipe_name,
1355 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001356
Dhaval Patel47302cf2016-08-18 15:04:28 -07001357 if (!sde_plane_enabled(state))
1358 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04001359
Dhaval Patel47302cf2016-08-18 15:04:28 -07001360 fmt = to_sde_format(msm_framebuffer_format(state->fb));
1361
1362 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
1363
1364 if (SDE_FORMAT_IS_YUV(fmt) &&
1365 (!(psde->features & SDE_SSPP_SCALER) ||
1366 !(psde->features & BIT(SDE_SSPP_CSC)))) {
1367 SDE_ERROR("plane doesn't have scaler/csc capability for yuv\n");
1368 ret = -EINVAL;
1369
1370 /* check src bounds */
1371 } else if (state->fb->width > MAX_IMG_WIDTH ||
1372 state->fb->height > MAX_IMG_HEIGHT ||
1373 src.w < min_src_size || src.h < min_src_size ||
1374 CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
1375 CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
1376 SDE_ERROR("invalid source (%u, %u) -> (%u, %u)\n",
1377 src.x, src.y, src.w, src.h);
1378 ret = -E2BIG;
1379
1380 /* valid yuv image */
1381 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
1382 (src.w & 0x1) || (src.h & 0x1))) {
1383 SDE_ERROR("invalid yuv source (%u, %u) -> (%u, %u)\n",
1384 src.x, src.y, src.w, src.h);
1385 ret = -EINVAL;
1386
1387 /* min dst support */
1388 } else if (dst.w < 0x1 || dst.h < 0x1) {
1389 SDE_ERROR("invalid dest rect (%u, %u) -> (%u, %u)\n",
1390 dst.x, dst.y, dst.w, dst.h);
1391 ret = -EINVAL;
1392
1393 /* decimation validation */
1394 } else if (deci_w || deci_h) {
1395 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1396 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1397 SDE_ERROR("too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001398 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001399 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
1400 SDE_ERROR("decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001401 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001402 }
1403
Dhaval Patel47302cf2016-08-18 15:04:28 -07001404 } else if (!(psde->features & SDE_SSPP_SCALER) &&
1405 ((src.w != dst.w) || (src.h != dst.h))) {
1406 SDE_ERROR("pipe doesn't support scaling %ux%u->%ux%u\n",
1407 src.w, src.h, dst.w, dst.h);
1408 ret = -EINVAL;
1409
1410 /* check decimated source width */
1411 } else if (src_deci_w > max_linewidth) {
1412 SDE_ERROR("invalid source width:%u, deci wid:%u, line wid:%u\n",
1413 src.w, src_deci_w, max_linewidth);
1414 ret = -E2BIG;
1415
1416 /* check max scaler capability */
1417 } else if (((src_deci_w * max_upscale) < dst.w) ||
1418 ((src_deci_h * max_upscale) < dst.h) ||
1419 ((dst.w * max_downscale) < src_deci_w) ||
1420 ((dst.h * max_downscale) < src_deci_h)) {
1421 SDE_ERROR("too much scaling requested %ux%u -> %ux%u\n",
1422 src_deci_w, src_deci_h, dst.w, dst.h);
1423 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001424 }
1425
Dhaval Patel47302cf2016-08-18 15:04:28 -07001426modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001427 if (!ret)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001428 _sde_plane_atomic_check_mode_changed(psde, state, plane->state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001429exit:
1430 return ret;
1431}
1432
Clarence Ipcae1bb62016-07-07 12:07:13 -04001433/**
1434 * sde_plane_flush - final plane operations before commit flush
1435 * @plane: Pointer to drm plane structure
1436 */
1437void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001438{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001439 struct sde_plane *psde;
1440
1441 if (!plane)
1442 return;
1443
1444 psde = to_sde_plane(plane);
1445
1446 /*
1447 * These updates have to be done immediately before the plane flush
1448 * timing, and may not be moved to the atomic_update/mode_set functions.
1449 */
1450 if (psde->is_error)
1451 /* force white frame with 0% alpha pipe output on error */
1452 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1453 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1454 /* force 100% alpha */
1455 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1456 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1457 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1458
1459 /* flag h/w flush complete */
1460 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001461 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001462}
1463
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001464static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001465 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001466{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001467 struct sde_plane *sde_plane;
1468 struct drm_plane_state *state;
1469 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001470
Clarence Ip5e2a9222016-06-26 22:38:24 -04001471 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001472 SDE_ERROR("invalid plane/state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001473 return;
1474 }
1475
1476 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001477 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001478 state = plane->state;
1479 pstate = to_sde_plane_state(state);
1480
Dhaval Patel47302cf2016-08-18 15:04:28 -07001481 SDE_DEBUG("%s: update\n", sde_plane->pipe_name);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001482
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001483 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001484 pstate->pending = true;
1485 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001486 int ret;
1487
Clarence Ip5e2a9222016-06-26 22:38:24 -04001488 pstate->pending = true;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001489 ret = _sde_plane_mode_set(plane, state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001490 /* atomic_check should have ensured that this doesn't fail */
1491 WARN_ON(ret < 0);
1492 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001493 _sde_plane_set_scanout(plane, pstate,
1494 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001495 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001496}
1497
Dhaval Patel47302cf2016-08-18 15:04:28 -07001498
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001499/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001500static void _sde_plane_install_properties(struct drm_plane *plane,
1501 u32 max_blendstages)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001502{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001503 static const struct drm_prop_enum_list e_blend_op[] = {
1504 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1505 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1506 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1507 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1508 };
1509 static const struct drm_prop_enum_list e_src_config[] = {
1510 {SDE_DRM_DEINTERLACE, "deinterlace"}
1511 };
Clarence Ipea3d6262016-07-15 16:20:11 -04001512 const struct sde_format_extended *format_list;
Dhaval Patel4e574842016-08-23 15:11:37 -07001513 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001514 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001515
Clarence Ipaa0faf42016-05-30 12:07:48 -04001516 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001517 SDE_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001518 return;
1519 }
1520
Dhaval Patel47302cf2016-08-18 15:04:28 -07001521 msm_property_install_range(&psde->property_info, "zpos", 0x0, 0,
Dhaval Patel48c76022016-09-01 17:51:23 -07001522 max_blendstages, SDE_STAGE_BASE, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001523
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001524 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07001525 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001526
Dhaval Patel47302cf2016-08-18 15:04:28 -07001527 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001528 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07001529 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001530
1531 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001532 msm_property_install_rotation(&psde->property_info,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001533 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y), PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001534
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001535 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001536 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001537
Dhaval Patel47302cf2016-08-18 15:04:28 -07001538 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
1539 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
1540
1541 if (psde->pipe_hw->ops.setup_solidfill)
1542 msm_property_install_range(&psde->property_info, "color_fill",
1543 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
1544
Clarence Ip4c1d9772016-06-26 09:35:38 -04001545 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001546 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001547 PLANE_PROP_SCALER);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001548
1549 if (psde->features & BIT(SDE_SSPP_CSC))
Clarence Ipaa0faf42016-05-30 12:07:48 -04001550 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001551 PLANE_PROP_CSC);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001552
Dhaval Patel4e574842016-08-23 15:11:37 -07001553 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
1554 if (!info)
1555 return;
1556
1557 msm_property_install_blob(&psde->property_info, "capabilities",
1558 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
1559 sde_kms_info_reset(info);
1560
Clarence Ipea3d6262016-07-15 16:20:11 -04001561 format_list = psde->pipe_sblk->format_list;
1562 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04001563 sde_kms_info_start(info, "pixel_formats");
1564 while (format_list->fourcc_format) {
1565 sde_kms_info_append_format(info,
1566 format_list->fourcc_format,
1567 format_list->modifier);
1568 ++format_list;
1569 }
1570 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04001571 }
Dhaval Patel4e574842016-08-23 15:11:37 -07001572
1573 sde_kms_info_add_keyint(info, "max_linewidth",
1574 psde->pipe_sblk->maxlinewidth);
1575 sde_kms_info_add_keyint(info, "max_upscale",
1576 psde->pipe_sblk->maxupscale);
1577 sde_kms_info_add_keyint(info, "max_downscale",
1578 psde->pipe_sblk->maxdwnscale);
1579 sde_kms_info_add_keyint(info, "max_horizontal_deci",
1580 psde->pipe_sblk->maxhdeciexp);
1581 sde_kms_info_add_keyint(info, "max_vertical_deci",
1582 psde->pipe_sblk->maxvdeciexp);
1583 msm_property_set_blob(&psde->property_info, &psde->blob_info,
1584 info->data, info->len, PLANE_PROP_INFO);
1585
1586 kfree(info);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001587}
1588
1589static int sde_plane_atomic_set_property(struct drm_plane *plane,
1590 struct drm_plane_state *state, struct drm_property *property,
1591 uint64_t val)
1592{
Clarence Ip730e7192016-06-26 22:45:09 -04001593 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001594 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001595 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001596
Clarence Ipaa0faf42016-05-30 12:07:48 -04001597 DBG("");
1598
1599 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001600 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001601 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001602 SDE_ERROR("invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001603 } else {
1604 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001605 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001606 ret = msm_property_atomic_set(&psde->property_info,
1607 pstate->property_values, pstate->property_blobs,
1608 property, val);
1609 if (!ret) {
1610 idx = msm_property_index(&psde->property_info,
1611 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001612 if (idx == PLANE_PROP_INPUT_FENCE)
1613 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001614 }
1615 }
1616
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001617 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001618}
1619
1620static int sde_plane_set_property(struct drm_plane *plane,
1621 struct drm_property *property, uint64_t val)
1622{
Clarence Ip4ce59322016-06-26 22:27:51 -04001623 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001624
Clarence Ipae4e60c2016-06-26 22:44:04 -04001625 return sde_plane_atomic_set_property(plane,
1626 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001627}
1628
1629static int sde_plane_atomic_get_property(struct drm_plane *plane,
1630 const struct drm_plane_state *state,
1631 struct drm_property *property, uint64_t *val)
1632{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001633 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001634 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001635 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001636
Clarence Ipaa0faf42016-05-30 12:07:48 -04001637 DBG("");
1638
1639 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001640 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001641 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001642 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001643 } else {
1644 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001645 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001646 ret = msm_property_atomic_get(&psde->property_info,
1647 pstate->property_values, pstate->property_blobs,
1648 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001649 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001650
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001651 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001652}
1653
1654static void sde_plane_destroy(struct drm_plane *plane)
1655{
Clarence Ip4ce59322016-06-26 22:27:51 -04001656 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001657
Clarence Ip4ce59322016-06-26 22:27:51 -04001658 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001659
Clarence Ip4ce59322016-06-26 22:27:51 -04001660 if (plane) {
1661 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001662
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001663 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1664
Clarence Ip4ce59322016-06-26 22:27:51 -04001665 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001666
Dhaval Patel4e574842016-08-23 15:11:37 -07001667 if (psde->blob_info)
1668 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001669 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001670 mutex_destroy(&psde->lock);
1671
Clarence Ip4ce59322016-06-26 22:27:51 -04001672 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001673
Clarence Ip4ce59322016-06-26 22:27:51 -04001674 /* this will destroy the states as well */
1675 drm_plane_cleanup(plane);
1676
Clarence Ip4c1d9772016-06-26 09:35:38 -04001677 if (psde->pipe_hw)
1678 sde_hw_sspp_destroy(psde->pipe_hw);
1679
Clarence Ip4ce59322016-06-26 22:27:51 -04001680 kfree(psde);
1681 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001682}
1683
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001684static void sde_plane_destroy_state(struct drm_plane *plane,
1685 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001686{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001687 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001688 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001689
Clarence Ipae4e60c2016-06-26 22:44:04 -04001690 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001691 SDE_ERROR("invalid plane/state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001692 return;
1693 }
1694
Clarence Ipaa0faf42016-05-30 12:07:48 -04001695 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001696 pstate = to_sde_plane_state(state);
1697
1698 DBG("");
1699
Clarence Ipe78efb72016-06-24 18:35:21 -04001700 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001701 if (state->fb)
1702 drm_framebuffer_unreference(state->fb);
1703
Clarence Ipae4e60c2016-06-26 22:44:04 -04001704 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001705 if (pstate->input_fence)
1706 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001707
Clarence Ipaa0faf42016-05-30 12:07:48 -04001708 /* destroy value helper */
1709 msm_property_destroy_state(&psde->property_info, pstate,
1710 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001711}
1712
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001713static struct drm_plane_state *
1714sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001715{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001716 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001717 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001718 struct sde_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001719
Clarence Ip730e7192016-06-26 22:45:09 -04001720 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001721 return NULL;
1722
Clarence Ip730e7192016-06-26 22:45:09 -04001723 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001724 psde = to_sde_plane(plane);
1725 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001726 if (!pstate)
1727 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001728
Clarence Ipaa0faf42016-05-30 12:07:48 -04001729 DBG("");
1730
1731 /* duplicate value helper */
1732 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1733 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001734
Clarence Ip730e7192016-06-26 22:45:09 -04001735 /* add ref count for frame buffer */
1736 if (pstate->base.fb)
1737 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001738
Clarence Ip730e7192016-06-26 22:45:09 -04001739 /* add ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001740 if (pstate->input_fence) {
1741 pstate->input_fence = 0;
1742 _sde_plane_set_input_fence(plane, pstate, pstate->
1743 property_values[PLANE_PROP_INPUT_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001744 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001745
Clarence Ip730e7192016-06-26 22:45:09 -04001746 pstate->mode_changed = false;
1747 pstate->pending = false;
1748
1749 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001750}
1751
1752static void sde_plane_reset(struct drm_plane *plane)
1753{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001754 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001755 struct sde_plane_state *pstate;
1756
Clarence Ipae4e60c2016-06-26 22:44:04 -04001757 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001758 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001759 return;
1760 }
1761
Clarence Ip730e7192016-06-26 22:45:09 -04001762 psde = to_sde_plane(plane);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001763 SDE_DEBUG("%s\n", psde->pipe_name);
Clarence Ip730e7192016-06-26 22:45:09 -04001764
Clarence Ipae4e60c2016-06-26 22:44:04 -04001765 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001766 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001767 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001768 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001769 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001770
Clarence Ipaa0faf42016-05-30 12:07:48 -04001771 pstate = msm_property_alloc_state(&psde->property_info);
1772 if (!pstate)
1773 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001774
Clarence Ipaa0faf42016-05-30 12:07:48 -04001775 /* reset value helper */
1776 msm_property_reset_state(&psde->property_info, pstate,
1777 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001778
1779 pstate->base.plane = plane;
1780
1781 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001782}
1783
1784static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001785 .update_plane = drm_atomic_helper_update_plane,
1786 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001787 .destroy = sde_plane_destroy,
1788 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001789 .atomic_set_property = sde_plane_atomic_set_property,
1790 .atomic_get_property = sde_plane_atomic_get_property,
1791 .reset = sde_plane_reset,
1792 .atomic_duplicate_state = sde_plane_duplicate_state,
1793 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001794};
1795
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001796static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1797 .prepare_fb = sde_plane_prepare_fb,
1798 .cleanup_fb = sde_plane_cleanup_fb,
1799 .atomic_check = sde_plane_atomic_check,
1800 .atomic_update = sde_plane_atomic_update,
1801};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001802
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001803enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001804{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001805 struct sde_plane *sde_plane = to_sde_plane(plane);
1806
1807 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001808}
1809
Clarence Ip4ce59322016-06-26 22:27:51 -04001810static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1811{
1812 const struct sde_sspp_sub_blks *sblk = 0;
1813 const struct sde_sspp_cfg *cfg = 0;
1814
1815 if (psde && psde->pipe_hw)
1816 cfg = psde->pipe_hw->cap;
1817 if (cfg)
1818 sblk = cfg->sblk;
1819
1820 if (kms && sblk) {
1821 /* create overall sub-directory for the pipe */
1822 psde->debugfs_root =
1823 debugfs_create_dir(psde->pipe_name,
1824 sde_debugfs_get_root(kms));
1825 if (psde->debugfs_root) {
1826 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001827 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001828 psde->debugfs_root, &psde->features);
1829
1830 /* add register dump support */
1831 sde_debugfs_setup_regset32(&psde->debugfs_src,
1832 sblk->src_blk.base + cfg->base,
1833 sblk->src_blk.len,
1834 kms->mmio);
1835 sde_debugfs_create_regset32("src_blk", 0444,
1836 psde->debugfs_root, &psde->debugfs_src);
1837
1838 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1839 sblk->scaler_blk.base + cfg->base,
1840 sblk->scaler_blk.len,
1841 kms->mmio);
1842 sde_debugfs_create_regset32("scaler_blk", 0444,
1843 psde->debugfs_root,
1844 &psde->debugfs_scaler);
1845
1846 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1847 sblk->csc_blk.base + cfg->base,
1848 sblk->csc_blk.len,
1849 kms->mmio);
1850 sde_debugfs_create_regset32("csc_blk", 0444,
1851 psde->debugfs_root, &psde->debugfs_csc);
1852 }
1853 }
1854}
1855
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001856/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001857struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001858 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001859{
1860 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001861 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001862 struct msm_drm_private *priv;
1863 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001864 enum drm_plane_type type;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001865 int ret = -EINVAL, max_blendstages = 255;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001866
1867 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001868 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001869 goto exit;
1870 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001871
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001872 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001873 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001874 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001875 goto exit;
1876 }
1877
1878 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001879 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001880 goto exit;
1881 }
1882 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001883
Clarence Ip4c1d9772016-06-26 09:35:38 -04001884 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001885 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001886 goto exit;
1887 }
1888
Clarence Ip4ce59322016-06-26 22:27:51 -04001889 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001890 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1891 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001892 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001893 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001894 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001895 }
1896
Clarence Ip4c1d9772016-06-26 09:35:38 -04001897 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001898 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001899 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04001900 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001901
Clarence Ip4c1d9772016-06-26 09:35:38 -04001902 /* initialize underlying h/w driver */
1903 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1904 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001905 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001906 ret = PTR_ERR(psde->pipe_hw);
1907 goto clean_plane;
1908 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001909 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001910 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001911 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001912
1913 /* cache features mask for later */
1914 psde->features = psde->pipe_hw->cap->features;
1915 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04001916 if (!psde->pipe_sblk) {
1917 SDE_ERROR("invalid sblk on pipe %d\n", pipe);
1918 goto clean_sspp;
1919 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001920
Dhaval Patel47302cf2016-08-18 15:04:28 -07001921 if (kms->catalog && kms->catalog->mixer_count && kms->catalog->mixer)
1922 max_blendstages = kms->catalog->mixer[0].sblk->maxblendstages;
1923
Clarence Ip4c1d9772016-06-26 09:35:38 -04001924 /* add plane to DRM framework */
Clarence Ipea3d6262016-07-15 16:20:11 -04001925 psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
1926 psde->formats,
1927 0,
1928 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001929
Clarence Ip4c1d9772016-06-26 09:35:38 -04001930 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001931 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001932 goto clean_sspp;
1933 }
1934
1935 if (psde->features & BIT(SDE_SSPP_CURSOR))
1936 type = DRM_PLANE_TYPE_CURSOR;
1937 else if (primary_plane)
1938 type = DRM_PLANE_TYPE_PRIMARY;
1939 else
1940 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001941 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1942 psde->formats, psde->nformats,
1943 type);
1944 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001945 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001946
Clarence Ip4c1d9772016-06-26 09:35:38 -04001947 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001948 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001949
Clarence Ipaa0faf42016-05-30 12:07:48 -04001950 msm_property_init(&psde->property_info, &plane->base, dev,
1951 priv->plane_property, psde->property_data,
1952 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
1953 sizeof(struct sde_plane_state));
1954
Dhaval Patel47302cf2016-08-18 15:04:28 -07001955 _sde_plane_install_properties(plane, max_blendstages);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001956
Clarence Ip4ce59322016-06-26 22:27:51 -04001957 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001958 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001959
Clarence Ip730e7192016-06-26 22:45:09 -04001960 mutex_init(&psde->lock);
1961
Clarence Ip4ce59322016-06-26 22:27:51 -04001962 _sde_plane_init_debugfs(psde, kms);
1963
Dhaval Patel47302cf2016-08-18 15:04:28 -07001964 DRM_INFO("[%u]successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001965 return plane;
1966
Clarence Ip4c1d9772016-06-26 09:35:38 -04001967clean_sspp:
1968 if (psde && psde->pipe_hw)
1969 sde_hw_sspp_destroy(psde->pipe_hw);
1970clean_plane:
1971 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001972exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001973 return ERR_PTR(ret);
1974}