blob: 52e056719b30462cdfc79e542b65e6ffb2d762a3 [file] [log] [blame]
Clarence Ipaac9f332016-08-31 15:46:35 -04001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002 *
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
Clarence Ip282dad62016-09-27 17:07:35 -040041/* dirty bits for update function */
42#define SDE_PLANE_DIRTY_RECTS 0x1
43#define SDE_PLANE_DIRTY_FORMAT 0x2
44#define SDE_PLANE_DIRTY_SHARPEN 0x4
45#define SDE_PLANE_DIRTY_ALL 0xFFFFFFFF
46
Alan Kwong1a00e4d2016-07-18 09:42:30 -040047/**
48 * enum sde_plane_qos - Different qos configurations for each pipe
49 *
50 * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
51 * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
52 * this configuration is mutually exclusive from VBLANK_CTRL.
53 * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
54 */
55enum sde_plane_qos {
56 SDE_PLANE_QOS_VBLANK_CTRL = BIT(0),
57 SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
58 SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
59};
60
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070061struct sde_plane {
62 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040063
64 int mmu_id;
65
Clarence Ip730e7192016-06-26 22:45:09 -040066 struct mutex lock;
67
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040068 enum sde_sspp pipe;
69 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070070 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -040071 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040072
73 struct sde_hw_pipe *pipe_hw;
74 struct sde_hw_pipe_cfg pipe_cfg;
75 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040076 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040077 struct sde_hw_scaler3_cfg scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040078 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -040079 uint32_t color_fill;
80 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040081 bool is_rt_pipe;
Clarence Ip4ce59322016-06-26 22:27:51 -040082
Clarence Ip373f8592016-05-26 00:58:42 -040083 struct sde_csc_cfg csc_cfg;
84 struct sde_csc_cfg *csc_ptr;
85
Clarence Ip4c1d9772016-06-26 09:35:38 -040086 const struct sde_sspp_sub_blks *pipe_sblk;
87
Clarence Ip5e2a9222016-06-26 22:38:24 -040088 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040089
Clarence Ipaa0faf42016-05-30 12:07:48 -040090 struct msm_property_info property_info;
91 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -070092 struct drm_property_blob *blob_info;
Clarence Ip730e7192016-06-26 22:45:09 -040093
Clarence Ip4ce59322016-06-26 22:27:51 -040094 /* debugfs related stuff */
95 struct dentry *debugfs_root;
96 struct sde_debugfs_regset32 debugfs_src;
97 struct sde_debugfs_regset32 debugfs_scaler;
98 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070099};
Dhaval Patel47302cf2016-08-18 15:04:28 -0700100
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700101#define to_sde_plane(x) container_of(x, struct sde_plane, base)
102
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400103static bool sde_plane_enabled(struct drm_plane_state *state)
104{
Clarence Ipdbde9832016-06-26 09:48:36 -0400105 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400106}
107
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400108/**
109 * _sde_plane_calc_fill_level - calculate fill level of the given source format
110 * @plane: Pointer to drm plane
111 * @fmt: Pointer to source buffer format
112 * @src_wdith: width of source buffer
113 * Return: fill level corresponding to the source buffer/format or 0 if error
114 */
115static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
116 const struct sde_format *fmt, u32 src_width)
117{
118 struct sde_plane *psde;
119 u32 fixed_buff_size;
120 u32 total_fl;
121
122 if (!plane || !fmt) {
123 SDE_ERROR("invalid arguments\n");
124 return 0;
125 }
126
127 psde = to_sde_plane(plane);
128 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
129
130 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
131 if (fmt->chroma_sample == SDE_CHROMA_420) {
132 /* NV12 */
133 total_fl = (fixed_buff_size / 2) /
134 ((src_width + 32) * fmt->bpp);
135 } else {
136 /* non NV12 */
137 total_fl = (fixed_buff_size) /
138 ((src_width + 32) * fmt->bpp);
139 }
140 } else {
141 total_fl = (fixed_buff_size * 2) /
142 ((src_width + 32) * fmt->bpp);
143 }
144
145 SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
146 plane->base.id, psde->pipe - SSPP_VIG0,
147 fmt->base.pixel_format, src_width, total_fl);
148
149 return total_fl;
150}
151
152/**
153 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
154 * @total_fl: fill level
155 * Return: LUT setting corresponding to the fill level
156 */
157static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
158{
159 u32 qos_lut;
160
161 if (total_fl <= 4)
162 qos_lut = 0x1B;
163 else if (total_fl <= 5)
164 qos_lut = 0x5B;
165 else if (total_fl <= 6)
166 qos_lut = 0x15B;
167 else if (total_fl <= 7)
168 qos_lut = 0x55B;
169 else if (total_fl <= 8)
170 qos_lut = 0x155B;
171 else if (total_fl <= 9)
172 qos_lut = 0x555B;
173 else if (total_fl <= 10)
174 qos_lut = 0x1555B;
175 else if (total_fl <= 11)
176 qos_lut = 0x5555B;
177 else if (total_fl <= 12)
178 qos_lut = 0x15555B;
179 else
180 qos_lut = 0x55555B;
181
182 return qos_lut;
183}
184
185/**
186 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
187 * @total_fl: fill level
188 * Return: LUT setting corresponding to the fill level
189 */
190static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
191{
192 u32 qos_lut;
193
194 if (total_fl <= 10)
195 qos_lut = 0x1AAff;
196 else if (total_fl <= 11)
197 qos_lut = 0x5AAFF;
198 else if (total_fl <= 12)
199 qos_lut = 0x15AAFF;
200 else
201 qos_lut = 0x55AAFF;
202
203 return qos_lut;
204}
205
206/**
207 * _sde_plane_is_rt_pipe - check if the given plane requires real-time QoS
208 * @plane: Pointer to drm plane
209 * @crtc: Pointer to drm crtc associated with the given plane
210 */
211static bool _sde_plane_is_rt_pipe(struct drm_plane *plane,
212 struct drm_crtc *crtc)
213{
214 struct sde_plane *psde = to_sde_plane(plane);
215 struct drm_connector *connector;
216 bool is_rt = false;
217
218 /* check if this plane has a physical connector interface */
219 drm_for_each_connector(connector, plane->dev)
220 if (connector->state &&
221 (connector->state->crtc == crtc) &&
222 (connector->connector_type
223 != DRM_MODE_CONNECTOR_VIRTUAL)) {
224 is_rt = true;
225 break;
226 }
227
228 SDE_DEBUG("plane%u: pnum:%d rt:%d\n",
229 plane->base.id, psde->pipe - SSPP_VIG0, is_rt);
230
231 return is_rt;
232}
233
234/**
235 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
236 * @plane: Pointer to drm plane
237 * @fb: Pointer to framebuffer associated with the given plane
238 */
239static void _sde_plane_set_qos_lut(struct drm_plane *plane,
240 struct drm_framebuffer *fb)
241{
242 struct sde_plane *psde;
243 const struct sde_format *fmt = NULL;
244 u32 qos_lut;
245 u32 total_fl = 0;
246
247 if (!plane || !fb) {
248 SDE_ERROR("invalid arguments plane %d fb %d\n",
249 plane != 0, fb != 0);
250 return;
251 }
252
253 psde = to_sde_plane(plane);
254
255 if (!psde->pipe_hw || !psde->pipe_sblk) {
256 SDE_ERROR("invalid arguments\n");
257 return;
258 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
259 return;
260 }
261
262 if (!psde->is_rt_pipe) {
263 qos_lut = psde->pipe_sblk->creq_lut_nrt;
264 } else {
265 fmt = sde_get_sde_format_ext(
266 fb->pixel_format,
267 fb->modifier,
268 drm_format_num_planes(fb->pixel_format));
269 total_fl = _sde_plane_calc_fill_level(plane, fmt,
270 psde->pipe_cfg.src_rect.w);
271
272 if (SDE_FORMAT_IS_LINEAR(fmt))
273 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
274 else
275 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
276 }
277
278 psde->pipe_qos_cfg.creq_lut = qos_lut;
279
280 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
281 (fmt) ? fmt->base.pixel_format : 0,
282 psde->is_rt_pipe, total_fl, qos_lut,
283 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
284
285 SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
286 plane->base.id,
287 psde->pipe - SSPP_VIG0,
288 (fmt) ? fmt->base.pixel_format : 0,
289 psde->is_rt_pipe, total_fl, qos_lut);
290
291 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
292}
293
294/**
295 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
296 * @plane: Pointer to drm plane
297 * @fb: Pointer to framebuffer associated with the given plane
298 */
299static void _sde_plane_set_danger_lut(struct drm_plane *plane,
300 struct drm_framebuffer *fb)
301{
302 struct sde_plane *psde;
303 const struct sde_format *fmt = NULL;
304 u32 danger_lut, safe_lut;
305
306 if (!plane || !fb) {
307 SDE_ERROR("invalid arguments\n");
308 return;
309 }
310
311 psde = to_sde_plane(plane);
312
313 if (!psde->pipe_hw || !psde->pipe_sblk) {
314 SDE_ERROR("invalid arguments\n");
315 return;
316 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
317 return;
318 }
319
320 if (!psde->is_rt_pipe) {
321 danger_lut = psde->pipe_sblk->danger_lut_nrt;
322 safe_lut = psde->pipe_sblk->safe_lut_nrt;
323 } else {
324 fmt = sde_get_sde_format_ext(
325 fb->pixel_format,
326 fb->modifier,
327 drm_format_num_planes(fb->pixel_format));
328
329 if (SDE_FORMAT_IS_LINEAR(fmt)) {
330 danger_lut = psde->pipe_sblk->danger_lut_linear;
331 safe_lut = psde->pipe_sblk->safe_lut_linear;
332 } else {
333 danger_lut = psde->pipe_sblk->danger_lut_tile;
334 safe_lut = psde->pipe_sblk->safe_lut_tile;
335 }
336 }
337
338 psde->pipe_qos_cfg.danger_lut = danger_lut;
339 psde->pipe_qos_cfg.safe_lut = safe_lut;
340
341 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
342 (fmt) ? fmt->base.pixel_format : 0,
343 (fmt) ? fmt->fetch_mode : 0,
344 psde->pipe_qos_cfg.danger_lut,
345 psde->pipe_qos_cfg.safe_lut);
346
347 SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
348 plane->base.id,
349 psde->pipe - SSPP_VIG0,
350 fmt ? fmt->base.pixel_format : 0,
351 fmt ? fmt->fetch_mode : -1,
352 psde->pipe_qos_cfg.danger_lut,
353 psde->pipe_qos_cfg.safe_lut);
354
355 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
356 &psde->pipe_qos_cfg);
357}
358
359/**
360 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
361 * @plane: Pointer to drm plane
362 * @enable: true to enable QoS control
363 * @flags: QoS control mode (enum sde_plane_qos)
364 */
365static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
366 bool enable, u32 flags)
367{
368 struct sde_plane *psde;
369
370 if (!plane) {
371 SDE_ERROR("invalid arguments\n");
372 return;
373 }
374
375 psde = to_sde_plane(plane);
376
377 if (!psde->pipe_hw || !psde->pipe_sblk) {
378 SDE_ERROR("invalid arguments\n");
379 return;
380 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
381 return;
382 }
383
384 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
385 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
386 psde->pipe_qos_cfg.danger_vblank =
387 psde->pipe_sblk->danger_vblank;
388 psde->pipe_qos_cfg.vblank_en = enable;
389 }
390
391 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
392 /* this feature overrules previous VBLANK_CTRL */
393 psde->pipe_qos_cfg.vblank_en = false;
394 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
395 }
396
397 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
398 psde->pipe_qos_cfg.danger_safe_en = enable;
399
400 if (!psde->is_rt_pipe) {
401 psde->pipe_qos_cfg.vblank_en = false;
402 psde->pipe_qos_cfg.danger_safe_en = false;
403 }
404
405 SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x]\n",
406 plane->base.id,
407 psde->pipe - SSPP_VIG0,
408 psde->pipe_qos_cfg.danger_safe_en,
409 psde->pipe_qos_cfg.vblank_en,
410 psde->pipe_qos_cfg.creq_vblank,
411 psde->pipe_qos_cfg.danger_vblank);
412
413 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
414 &psde->pipe_qos_cfg);
415}
416
Alan Kwong5d324e42016-07-28 22:56:18 -0400417/**
418 * _sde_plane_set_ot_limit - set OT limit for the given plane
419 * @plane: Pointer to drm plane
420 * @crtc: Pointer to drm crtc
421 */
422static void _sde_plane_set_ot_limit(struct drm_plane *plane,
423 struct drm_crtc *crtc)
424{
425 struct sde_plane *psde;
426 struct sde_vbif_set_ot_params ot_params;
427 struct msm_drm_private *priv;
428 struct sde_kms *sde_kms;
429
430 if (!plane || !plane->dev || !crtc) {
431 SDE_ERROR("invalid arguments plane %d crtc %d\n",
432 plane != 0, crtc != 0);
433 return;
434 }
435
436 priv = plane->dev->dev_private;
437 if (!priv || !priv->kms) {
438 SDE_ERROR("invalid KMS reference\n");
439 return;
440 }
441
442 sde_kms = to_sde_kms(priv->kms);
443 psde = to_sde_plane(plane);
444 if (!psde->pipe_hw) {
445 SDE_ERROR("invalid pipe reference\n");
446 return;
447 }
448
449 memset(&ot_params, 0, sizeof(ot_params));
450 ot_params.xin_id = psde->pipe_hw->cap->xin_id;
451 ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
452 ot_params.width = psde->pipe_cfg.src_rect.w;
453 ot_params.height = psde->pipe_cfg.src_rect.h;
454 ot_params.is_wfd = !psde->is_rt_pipe;
455 ot_params.frame_rate = crtc->mode.vrefresh;
456 ot_params.vbif_idx = VBIF_RT;
457 ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
458 ot_params.rd = true;
459
460 sde_vbif_set_ot_limit(sde_kms, &ot_params);
461}
462
Clarence Ipcae1bb62016-07-07 12:07:13 -0400463/* helper to update a state's input fence pointer from the property */
464static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400465 struct sde_plane_state *pstate, uint64_t fd)
466{
467 if (!plane || !pstate)
468 return;
469
470 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400471 if (pstate->input_fence)
472 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400473
474 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400475 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400476
Dhaval Patel47302cf2016-08-18 15:04:28 -0700477 SDE_DEBUG("0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400478}
479
Clarence Ipcae1bb62016-07-07 12:07:13 -0400480int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400481{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400482 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400483 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400484 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400485 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400486
487 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700488 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400489 } else if (!plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700490 SDE_ERROR("invalid plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400491 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400492 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400493 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400494 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400495
Clarence Ipcae1bb62016-07-07 12:07:13 -0400496 if (input_fence) {
497 ret = sde_sync_wait(input_fence, wait_ms);
498 switch (ret) {
499 case 0:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700500 SDE_DEBUG("%s signaled\n", psde->pipe_name);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400501 break;
502 case -ETIME:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700503 SDE_ERROR("timeout on %s, %ums\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400504 psde->pipe_name, wait_ms);
505 psde->is_error = true;
506 break;
507 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700508 SDE_ERROR("error on %s, %d\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400509 psde->pipe_name, ret);
510 psde->is_error = true;
511 break;
512 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400513 } else {
514 ret = 0;
515 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400516 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400517 return ret;
518}
519
Clarence Ip282dad62016-09-27 17:07:35 -0400520static inline void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400521 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400522 struct sde_hw_pipe_cfg *pipe_cfg,
523 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400524{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400525 struct sde_plane *psde;
Clarence Ip282dad62016-09-27 17:07:35 -0400526 int ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400527
Clarence Ipae4e60c2016-06-26 22:44:04 -0400528 if (!plane || !pstate || !pipe_cfg || !fb)
529 return;
530
531 psde = to_sde_plane(plane);
532
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400533 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
534 if (ret) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700535 SDE_ERROR("failed to get format layout, error: %d\n", ret);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400536 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400537 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400538
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400539 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
540 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400541}
542
Clarence Ipcb410d42016-06-26 22:52:33 -0400543static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400544 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
545 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400546 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400547 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
548{
549}
550
Clarence Ipcb410d42016-06-26 22:52:33 -0400551/**
552 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
553 * @psde: Pointer to SDE plane object
554 * @src: Source size
555 * @dst: Destination size
556 * @phase_steps: Pointer to output array for phase steps
557 * @filter: Pointer to output array for filter type
558 * @fmt: Pointer to format definition
559 * @chroma_subsampling: Subsampling amount for chroma channel
560 *
561 * Returns: 0 on success
562 */
563static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400564 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400565 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400566 uint32_t chroma_subsampling)
567{
Clarence Ipcb410d42016-06-26 22:52:33 -0400568 if (!psde || !phase_steps || !filter || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700569 SDE_ERROR("invalid arguments\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400570 return -EINVAL;
571 }
572
Clarence Ip4c1d9772016-06-26 09:35:38 -0400573 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400574 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400575 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400576 phase_steps[SDE_SSPP_COMP_1_2] =
577 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
578 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
579 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400580
581 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400582 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400583 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400584 (src <= dst) ? SDE_SCALE_FILTER_BIL :
585 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400586
Clarence Ipdbde9832016-06-26 09:48:36 -0400587 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400588 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400589 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
590 } else {
591 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
592 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400593 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400594 }
595 } else {
596 /* disable scaler */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700597 SDE_DEBUG("disable scaler\n");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400598 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
599 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
600 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400601 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400602 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400603}
604
Clarence Ipcb410d42016-06-26 22:52:33 -0400605/**
606 * _sde_plane_setup_pixel_ext - determine default pixel extension values
607 * @psde: Pointer to SDE plane object
608 * @src: Source size
609 * @dst: Destination size
610 * @decimated_src: Source size after decimation, if any
611 * @phase_steps: Pointer to output array for phase steps
612 * @out_src: Output array for pixel extension values
613 * @out_edge1: Output array for pixel extension first edge
614 * @out_edge2: Output array for pixel extension second edge
615 * @filter: Pointer to array for filter type
616 * @fmt: Pointer to format definition
617 * @chroma_subsampling: Subsampling amount for chroma channel
618 * @post_compare: Whether to chroma subsampled source size for comparisions
619 */
620static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400621 uint32_t src, uint32_t dst, uint32_t decimated_src,
622 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400623 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400624 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400625 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400626{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400627 int64_t edge1, edge2, caf;
628 uint32_t src_work;
629 int i, tmp;
630
Clarence Ipcb410d42016-06-26 22:52:33 -0400631 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400632 out_edge2 && filter && fmt) {
633 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400634 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400635 caf = PHASE_STEP_UNIT_SCALE;
636 else
637 caf = 0;
638
639 for (i = 0; i < SDE_MAX_PLANES; i++) {
640 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400641 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400642 src_work /= chroma_subsampling;
643 if (post_compare)
644 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400645 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400646 /* unity */
647 edge1 = 0;
648 edge2 = 0;
649 } else if (dst >= src) {
650 /* upscale */
651 edge1 = (1 << PHASE_RESIDUAL);
652 edge1 -= caf;
653 edge2 = (1 << PHASE_RESIDUAL);
654 edge2 += (dst - 1) * *(phase_steps + i);
655 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
656 edge2 += caf;
657 edge2 = -(edge2);
658 } else {
659 /* downscale */
660 edge1 = 0;
661 edge2 = (dst - 1) * *(phase_steps + i);
662 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
663 edge2 += *(phase_steps + i);
664 edge2 = -(edge2);
665 }
666
667 /* only enable CAF for luma plane */
668 caf = 0;
669
670 /* populate output arrays */
671 *(out_src + i) = src_work;
672
673 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400674 if (edge1 >= 0) {
675 tmp = (uint32_t)edge1;
676 tmp >>= PHASE_STEP_SHIFT;
677 *(out_edge1 + i) = -tmp;
678 } else {
679 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400680 *(out_edge1 + i) =
681 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
682 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400683 }
684 if (edge2 >= 0) {
685 tmp = (uint32_t)edge2;
686 tmp >>= PHASE_STEP_SHIFT;
687 *(out_edge2 + i) = -tmp;
688 } else {
689 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400690 *(out_edge2 + i) =
691 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
692 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400693 }
694 }
695 }
696}
697
Clarence Ip5e2a9222016-06-26 22:38:24 -0400698/**
699 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
700 * sub-structure
701 * @blob_ptr: Pointer to start of incoming blob data
702 * @blob_size: Size of incoming blob data, in bytes
703 * @sub_ptr: Pointer to start of desired sub-structure
704 * @sub_size: Required size of sub-structure, in bytes
705 */
706static int _sde_plane_verify_blob(void *blob_ptr,
707 size_t blob_size,
708 void *sub_ptr,
709 size_t sub_size)
710{
711 /*
712 * Use the blob size provided by drm to check if there are enough
713 * bytes from the start of versioned sub-structures to the end of
714 * blob data:
715 *
716 * e.g.,
717 * blob_ptr --> struct blob_data {
718 * uint32_t version;
719 * sub_ptr --> struct blob_data_v1 v1;
720 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
721 * blob_ptr + blob_size --> };
722 *
723 * It's important to check the actual number of bytes from the start
724 * of the sub-structure to the end of the blob data, and not just rely
725 * on something like,
726 *
727 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
728 *
729 * This is because the start of the sub-structure can vary based on
730 * how the compiler pads the overall structure.
731 */
732 if (blob_ptr && sub_ptr)
733 /* return zero if end of blob >= end of sub-struct */
734 return ((unsigned char *)blob_ptr + blob_size) <
735 ((unsigned char *)sub_ptr + sub_size);
736 return -EINVAL;
737}
738
Clarence Ipe78efb72016-06-24 18:35:21 -0400739static void _sde_plane_setup_csc(struct sde_plane *psde,
740 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400741 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400742{
743 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
744 {
Clarence Ip373f8592016-05-26 00:58:42 -0400745 /* S15.16 format */
746 0x00012A00, 0x00000000, 0x00019880,
747 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
748 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400749 },
Clarence Ip373f8592016-05-26 00:58:42 -0400750 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400751 { 0xfff0, 0xff80, 0xff80,},
752 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400753 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400754 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400755 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400756 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400757 static const struct sde_csc_cfg sde_csc_NOP = {
758 {
Clarence Ip373f8592016-05-26 00:58:42 -0400759 /* identity matrix, S15.16 format */
760 0x10000, 0x00000, 0x00000,
761 0x00000, 0x10000, 0x00000,
762 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400763 },
Clarence Ip373f8592016-05-26 00:58:42 -0400764 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400765 { 0x0, 0x0, 0x0,},
766 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400767 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400768 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
769 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
770 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400771 struct sde_drm_csc *csc = NULL;
772 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400773 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400774
Clarence Ipaa0faf42016-05-30 12:07:48 -0400775 if (!psde || !pstate || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700776 SDE_ERROR("invalid arguments\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400777 return;
778 }
779 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400780 return;
781
Clarence Ip5e2a9222016-06-26 22:38:24 -0400782 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400783 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400784 csc = msm_property_get_blob(&psde->property_info,
785 pstate->property_blobs,
786 &csc_size,
787 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400788 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400789 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400790 memcpy(&psde->csc_cfg,
791 &sde_csc_NOP,
792 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400793 switch (csc->version) {
794 case SDE_DRM_CSC_V1:
795 if (!_sde_plane_verify_blob(csc,
796 csc_size,
797 &csc->v1,
798 sizeof(struct sde_drm_csc_v1))) {
799 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400800 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400801 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400802 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400803 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400804 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400805 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400806 csc->v1.post_bias[i];
807 }
808 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400809 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400810 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400811 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400812 csc->v1.post_clamp[i];
813 }
Clarence Ipb493d762016-07-19 18:49:10 -0400814 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400815 }
816 break;
817 default:
818 break;
819 }
Clarence Ipb493d762016-07-19 18:49:10 -0400820 if (!psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700821 SDE_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400822 }
823
Clarence Ipcae1bb62016-07-07 12:07:13 -0400824 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400825 if (psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700826 SDE_DEBUG("user blob override for csc\n");
Clarence Ipb493d762016-07-19 18:49:10 -0400827 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400828 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400829}
830
Clarence Ipcb410d42016-06-26 22:52:33 -0400831static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400832 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400833 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700834{
Clarence Ipcb410d42016-06-26 22:52:33 -0400835 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400836 struct sde_drm_scaler *sc_u = NULL;
837 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400838 size_t sc_u_size = 0;
839 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
840 uint32_t tmp;
841 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400842
Clarence Ipcb410d42016-06-26 22:52:33 -0400843 if (!psde || !fmt)
844 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400845
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400846 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400847 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400848
Clarence Ip5e2a9222016-06-26 22:38:24 -0400849 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400850 if (pstate)
851 sc_u = msm_property_get_blob(&psde->property_info,
852 pstate->property_blobs,
853 &sc_u_size,
854 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400855 if (sc_u) {
856 switch (sc_u->version) {
857 case SDE_DRM_SCALER_V1:
858 if (!_sde_plane_verify_blob(sc_u,
859 sc_u_size,
860 &sc_u->v1,
861 sizeof(*sc_u1)))
862 sc_u1 = &sc_u->v1;
863 break;
864 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700865 SDE_DEBUG("unrecognized scaler blob v%lld\n",
866 sc_u->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400867 break;
868 }
869 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400870
Clarence Ip04ec67d2016-05-26 01:16:15 -0400871 /* decimation */
872 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
873 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
874 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400875 } else {
876 psde->pipe_cfg.horz_decimation = 0;
877 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400878 }
879
880 /* don't chroma subsample if decimating */
881 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400882 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400883 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400884 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400885
Clarence Ip5e2a9222016-06-26 22:38:24 -0400886 /* update scaler */
887 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
888 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Dhaval Patel47302cf2016-08-18 15:04:28 -0700889 SDE_DEBUG("SCALER3 blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400890 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400891 _sde_plane_setup_scaler3(psde,
892 psde->pipe_cfg.src_rect.w,
893 psde->pipe_cfg.src_rect.h,
894 psde->pipe_cfg.dst_rect.w,
895 psde->pipe_cfg.dst_rect.h,
896 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400897 chroma_subsmpl_h, chroma_subsmpl_v);
898 } else {
899 /* always calculate basic scaler config */
900 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
901 /* populate from user space */
902 for (i = 0; i < SDE_MAX_PLANES; i++) {
903 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
904 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
905 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
906 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400907
Clarence Ip5e2a9222016-06-26 22:38:24 -0400908 pe->horz_filter[i] = sc_u1->horz_filter[i];
909 pe->vert_filter[i] = sc_u1->vert_filter[i];
910 }
911 } else {
912 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400913 _sde_plane_setup_scaler2(psde,
914 psde->pipe_cfg.src_rect.w,
915 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400916 pe->phase_step_x,
917 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400918 _sde_plane_setup_scaler2(psde,
919 psde->pipe_cfg.src_rect.h,
920 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400921 pe->phase_step_y,
922 pe->vert_filter, fmt, chroma_subsmpl_v);
923 }
924 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400925
Clarence Ip5e2a9222016-06-26 22:38:24 -0400926 /* update pixel extensions */
927 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
928 /* populate from user space */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700929 SDE_DEBUG("pixel ext blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400930 for (i = 0; i < SDE_MAX_PLANES; i++) {
931 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
932 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
933 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
934 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
935 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
936 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
937 pe->roi_w[i] = sc_u1->lr.roi[i];
938
939 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
940 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
941 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
942 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
943 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
944 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
945 pe->roi_h[i] = sc_u1->tb.roi[i];
946 }
947 } else {
948 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400949 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400950 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400951 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400952 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400953 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
954 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400955 pe->phase_step_x,
956 pe->roi_w,
957 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400958 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400959 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400960
Clarence Ipcb410d42016-06-26 22:52:33 -0400961 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400962 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400963 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
964 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400965 pe->phase_step_y,
966 pe->roi_h,
967 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400968 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400969 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400970
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400971 for (i = 0; i < SDE_MAX_PLANES; i++) {
972 if (pe->num_ext_pxls_left[i] >= 0)
973 pe->left_rpt[i] =
974 pe->num_ext_pxls_left[i];
975 else
976 pe->left_ftch[i] =
977 pe->num_ext_pxls_left[i];
978
979 if (pe->num_ext_pxls_right[i] >= 0)
980 pe->right_rpt[i] =
981 pe->num_ext_pxls_right[i];
982 else
983 pe->right_ftch[i] =
984 pe->num_ext_pxls_right[i];
985
986 if (pe->num_ext_pxls_top[i] >= 0)
987 pe->top_rpt[i] =
988 pe->num_ext_pxls_top[i];
989 else
990 pe->top_ftch[i] =
991 pe->num_ext_pxls_top[i];
992
993 if (pe->num_ext_pxls_btm[i] >= 0)
994 pe->btm_rpt[i] =
995 pe->num_ext_pxls_btm[i];
996 else
997 pe->btm_ftch[i] =
998 pe->num_ext_pxls_btm[i];
999 }
1000 }
Clarence Ipcb410d42016-06-26 22:52:33 -04001001}
1002
Clarence Ipcae1bb62016-07-07 12:07:13 -04001003/**
1004 * _sde_plane_color_fill - enables color fill on plane
1005 * @plane: Pointer to DRM plane object
1006 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
1007 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
1008 * Returns: 0 on success
1009 */
1010static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -04001011 uint32_t color, uint32_t alpha)
1012{
1013 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001014 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -04001015
1016 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001017 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001018 return -EINVAL;
1019 }
1020
1021 psde = to_sde_plane(plane);
1022 if (!psde->pipe_hw) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001023 SDE_ERROR("invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001024 return -EINVAL;
1025 }
1026
Clarence Ipcae1bb62016-07-07 12:07:13 -04001027 DBG("");
1028
Clarence Ipcb410d42016-06-26 22:52:33 -04001029 /*
1030 * select fill format to match user property expectation,
1031 * h/w only supports RGB variants
1032 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001033 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -04001034
1035 /* update sspp */
1036 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
1037 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
1038 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
1039
1040 /* override scaler/decimation if solid fill */
1041 psde->pipe_cfg.src_rect.x = 0;
1042 psde->pipe_cfg.src_rect.y = 0;
1043 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
1044 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
1045
1046 _sde_plane_setup_scaler(psde, fmt, 0);
1047
1048 if (psde->pipe_hw->ops.setup_format)
1049 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
1050 fmt, SDE_SSPP_SOLID_FILL);
1051
1052 if (psde->pipe_hw->ops.setup_rects)
1053 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1054 &psde->pipe_cfg, &psde->pixel_ext);
1055 }
1056
1057 return 0;
1058}
1059
1060static int _sde_plane_mode_set(struct drm_plane *plane,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001061 struct drm_plane_state *state)
Clarence Ipcb410d42016-06-26 22:52:33 -04001062{
Clarence Ip282dad62016-09-27 17:07:35 -04001063 uint32_t nplanes, src_flags, zpos, split_w;
Clarence Ipcb410d42016-06-26 22:52:33 -04001064 struct sde_plane *psde;
1065 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001066 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001067 struct drm_crtc *crtc;
1068 struct drm_framebuffer *fb;
1069 struct sde_rect src, dst;
1070 bool q16_data = true;
Clarence Ip282dad62016-09-27 17:07:35 -04001071 int idx;
Clarence Ipcb410d42016-06-26 22:52:33 -04001072
1073 if (!plane || !plane->state) {
Clarence Ip282dad62016-09-27 17:07:35 -04001074 SDE_ERROR("invalid plane\n");
1075 return -EINVAL;
1076 } else if (!plane->state) {
1077 SDE_ERROR("invalid plane state\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001078 return -EINVAL;
1079 }
1080
1081 psde = to_sde_plane(plane);
1082 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -04001083
Dhaval Patel47302cf2016-08-18 15:04:28 -07001084 crtc = state->crtc;
1085 fb = state->fb;
1086 if (!crtc || !fb) {
1087 SDE_ERROR("invalid crtc/fb\n");
1088 return -EINVAL;
1089 }
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001090 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001091 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -04001092
Clarence Ip282dad62016-09-27 17:07:35 -04001093 /* determine what needs to be refreshed */
1094 while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
1095 switch (idx) {
1096 case PLANE_PROP_SCALER:
1097 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
1098 break;
1099 case PLANE_PROP_CSC:
1100 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
1101 break;
1102 case PLANE_PROP_COLOR_FILL:
1103 /* potentially need to refresh everything */
1104 pstate->dirty = SDE_PLANE_DIRTY_ALL;
1105 break;
1106 case PLANE_PROP_ROTATION:
1107 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
1108 break;
1109 case PLANE_PROP_SRC_CONFIG:
1110 case PLANE_PROP_ZPOS:
1111 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
1112 break;
1113 case PLANE_PROP_INFO:
1114 case PLANE_PROP_ALPHA:
1115 case PLANE_PROP_INPUT_FENCE:
1116 case PLANE_PROP_BLEND_OP:
1117 /* no special action required */
1118 break;
1119 default:
1120 /* unknown property, refresh everything */
1121 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
1122 SDE_ERROR("executing full mode set, prp_idx %d\n", idx);
1123 break;
1124 }
Clarence Ipcb410d42016-06-26 22:52:33 -04001125 }
1126
Clarence Ip282dad62016-09-27 17:07:35 -04001127 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
1128 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ipcb410d42016-06-26 22:52:33 -04001129
1130 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
1131
Clarence Ip282dad62016-09-27 17:07:35 -04001132 /* early out if nothing dirty */
1133 if (!pstate->dirty)
1134 return 0;
1135 pstate->pending = true;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001136
Clarence Ip282dad62016-09-27 17:07:35 -04001137 psde->is_rt_pipe = _sde_plane_is_rt_pipe(plane, crtc);
1138 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1139
1140 /* update roi config */
1141 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) {
1142 POPULATE_RECT(&src, state->src_x, state->src_y,
1143 state->src_w, state->src_h, q16_data);
1144 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
1145 state->crtc_w, state->crtc_h, !q16_data);
1146
1147 SDE_DEBUG(
1148 "%s:FB[%u] %u,%u,%u,%u -> crtc%u %d,%d,%u,%u, %s ubwc %d\n",
1149 psde->pipe_name,
1150 fb->base.id, src.x, src.y, src.w, src.h,
1151 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
1152 drm_get_format_name(fmt->base.pixel_format),
1153 SDE_FORMAT_IS_UBWC(fmt));
1154
1155 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
1156 BIT(SDE_DRM_DEINTERLACE)) {
1157 SDE_DEBUG("deinterlace\n");
1158 for (idx = 0; idx < SDE_MAX_PLANES; ++idx)
1159 psde->pipe_cfg.layout.plane_pitch[idx] <<= 1;
1160 src.h /= 2;
1161 src.y = DIV_ROUND_UP(src.y, 2);
1162 src.y &= ~0x1;
1163 }
1164
1165 psde->pipe_cfg.src_rect = src;
1166 psde->pipe_cfg.dst_rect = dst;
1167
1168 /* check for color fill */
1169 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
1170 PLANE_PROP_COLOR_FILL);
1171 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) {
1172 /* skip remaining processing on color fill */
1173 pstate->dirty = 0x0;
1174 } else if (psde->pipe_hw->ops.setup_rects) {
1175 _sde_plane_setup_scaler(psde, fmt, pstate);
1176
1177 /* base layer source split needs update */
1178 zpos = sde_plane_get_property(pstate, PLANE_PROP_ZPOS);
1179 if (zpos == SDE_STAGE_BASE) {
1180 split_w = get_crtc_split_width(crtc);
1181 if (psde->pipe_cfg.dst_rect.x >= split_w)
1182 psde->pipe_cfg.dst_rect.x -= split_w;
1183 }
1184 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1185 &psde->pipe_cfg, &psde->pixel_ext);
1186 }
Dhaval Patel48c76022016-09-01 17:51:23 -07001187 }
1188
Clarence Ip282dad62016-09-27 17:07:35 -04001189 if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
1190 psde->pipe_hw->ops.setup_format) {
1191 src_flags = 0x0;
1192 SDE_DEBUG("rotation 0x%llX\n",
1193 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
1194 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1195 BIT(DRM_REFLECT_X))
1196 src_flags |= SDE_SSPP_FLIP_LR;
1197 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1198 BIT(DRM_REFLECT_Y))
1199 src_flags |= SDE_SSPP_FLIP_UD;
1200
1201 /* update format */
1202 psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, src_flags);
1203
1204 /* update csc */
1205 if (SDE_FORMAT_IS_YUV(fmt))
1206 _sde_plane_setup_csc(psde, pstate, fmt);
1207 else
1208 psde->csc_ptr = 0;
1209 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001210
Clarence Ipe78efb72016-06-24 18:35:21 -04001211 /* update sharpening */
Clarence Ip282dad62016-09-27 17:07:35 -04001212 if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) &&
1213 psde->pipe_hw->ops.setup_sharpening) {
1214 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
1215 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
1216 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
1217 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
Clarence Ipe78efb72016-06-24 18:35:21 -04001218
Clarence Ipe78efb72016-06-24 18:35:21 -04001219 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
Clarence Ip282dad62016-09-27 17:07:35 -04001220 &psde->sharp_cfg);
1221 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001222
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001223 _sde_plane_set_qos_lut(plane, fb);
1224 _sde_plane_set_danger_lut(plane, fb);
1225
Alan Kwong5d324e42016-07-28 22:56:18 -04001226 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001227 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
Alan Kwong5d324e42016-07-28 22:56:18 -04001228 _sde_plane_set_ot_limit(plane, crtc);
1229 }
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001230
Clarence Ip282dad62016-09-27 17:07:35 -04001231 /* clear dirty */
1232 pstate->dirty = 0x0;
1233
Clarence Ip5e2a9222016-06-26 22:38:24 -04001234 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001235}
1236
1237static int sde_plane_prepare_fb(struct drm_plane *plane,
1238 const struct drm_plane_state *new_state)
1239{
1240 struct drm_framebuffer *fb = new_state->fb;
1241 struct sde_plane *psde = to_sde_plane(plane);
1242
1243 if (!new_state->fb)
1244 return 0;
1245
Dhaval Patel47302cf2016-08-18 15:04:28 -07001246 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001247 return msm_framebuffer_prepare(fb, psde->mmu_id);
1248}
1249
1250static void sde_plane_cleanup_fb(struct drm_plane *plane,
1251 const struct drm_plane_state *old_state)
1252{
1253 struct drm_framebuffer *fb = old_state->fb;
1254 struct sde_plane *psde = to_sde_plane(plane);
1255
1256 if (!fb)
1257 return;
1258
Dhaval Patel47302cf2016-08-18 15:04:28 -07001259 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001260 msm_framebuffer_cleanup(fb, psde->mmu_id);
1261}
1262
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001263static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
1264 struct drm_plane_state *state,
1265 struct drm_plane_state *old_state)
1266{
1267 struct sde_plane_state *pstate = to_sde_plane_state(state);
1268
Dhaval Patel47302cf2016-08-18 15:04:28 -07001269 /* no need to check it again */
Clarence Ip282dad62016-09-27 17:07:35 -04001270 if (pstate->dirty == SDE_PLANE_DIRTY_ALL)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001271 return;
1272
Clarence Ip282dad62016-09-27 17:07:35 -04001273 if (!sde_plane_enabled(state) || !sde_plane_enabled(old_state)
1274 || psde->is_error) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001275 SDE_DEBUG("%s: pipe enabling/disabling full modeset required\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001276 psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001277 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001278 } else if (to_sde_plane_state(old_state)->pending) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001279 SDE_DEBUG("%s: still pending\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001280 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001281 } else if (state->src_w != old_state->src_w ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07001282 state->src_h != old_state->src_h ||
1283 state->src_x != old_state->src_x ||
1284 state->src_y != old_state->src_y) {
1285 SDE_DEBUG("%s: src rect updated\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001286 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001287 } else if (state->crtc_w != old_state->crtc_w ||
1288 state->crtc_h != old_state->crtc_h ||
1289 state->crtc_x != old_state->crtc_x ||
1290 state->crtc_y != old_state->crtc_y) {
1291 SDE_DEBUG("%s: crtc rect updated\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001292 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
1293 }
1294
1295 if (!state->fb || !old_state->fb) {
1296 SDE_DEBUG("%s: can't compare fb handles\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001297 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001298 SDE_DEBUG("%s: format change!\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001299 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001300 } else {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001301 uint64_t *new_mods = state->fb->modifier;
1302 uint64_t *old_mods = old_state->fb->modifier;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001303 uint32_t *new_pitches = state->fb->pitches;
1304 uint32_t *old_pitches = old_state->fb->pitches;
1305 uint32_t *new_offset = state->fb->offsets;
1306 uint32_t *old_offset = old_state->fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001307 int i;
1308
1309 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
1310 if (new_mods[i] != old_mods[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001311 SDE_DEBUG("%s: format modifiers change\"\
1312 plane:%d new_mode:%llu old_mode:%llu\n",
1313 psde->pipe_name, i, new_mods[i],
1314 old_mods[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04001315 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
1316 SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001317 break;
1318 }
1319 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001320 for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
1321 if (new_pitches[i] != old_pitches[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001322 SDE_DEBUG("%s: pitches change plane:%d\"\
1323 old_pitches:%u new_pitches:%u\n",
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001324 psde->pipe_name, i, old_pitches[i],
1325 new_pitches[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04001326 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001327 break;
1328 }
1329 }
Dhaval Patel47302cf2016-08-18 15:04:28 -07001330 for (i = 0; i < ARRAY_SIZE(state->fb->offsets); i++) {
1331 if (new_offset[i] != old_offset[i]) {
1332 SDE_DEBUG("%s: offset change plane:%d\"\
1333 old_offset:%u new_offset:%u\n",
1334 psde->pipe_name, i, old_offset[i],
1335 new_offset[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04001336 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
1337 SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001338 break;
1339 }
1340 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001341 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001342}
1343
Dhaval Patel47302cf2016-08-18 15:04:28 -07001344static bool __get_scale_data(struct sde_plane *psde,
1345 struct sde_plane_state *pstate, struct sde_drm_scaler *sc_u,
1346 size_t *sc_u_size)
1347{
1348 bool valid_flag = false;
1349
1350 sc_u = msm_property_get_blob(&psde->property_info,
1351 pstate->property_blobs,
1352 sc_u_size,
1353 PLANE_PROP_SCALER);
1354 if (sc_u) {
1355 switch (sc_u->version) {
1356 case SDE_DRM_SCALER_V1:
1357 if (!_sde_plane_verify_blob(sc_u, *sc_u_size,
1358 &sc_u->v1, sizeof(struct sde_drm_scaler_v1)))
1359 valid_flag = true;
1360 break;
1361 default:
1362 SDE_DEBUG("unrecognized scaler blob v%lld\n",
1363 sc_u->version);
1364 break;
1365 }
1366 }
1367
1368 return valid_flag;
1369}
1370
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001371static int sde_plane_atomic_check(struct drm_plane *plane,
1372 struct drm_plane_state *state)
1373{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001374 int ret = 0, valid_scale_data;
Clarence Ipdbde9832016-06-26 09:48:36 -04001375 struct sde_plane *psde;
1376 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001377 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -04001378 size_t sc_u_size = 0;
1379 struct sde_drm_scaler *sc_u = NULL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001380 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04001381 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001382 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
1383 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04001384
1385 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001386 SDE_ERROR("invalid plane/state\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001387 ret = -EINVAL;
1388 goto exit;
1389 }
1390
1391 psde = to_sde_plane(plane);
1392 pstate = to_sde_plane_state(state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001393
1394 if (!psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001395 SDE_ERROR("invalid plane catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001396 ret = -EINVAL;
1397 goto exit;
1398 }
1399
Dhaval Patel47302cf2016-08-18 15:04:28 -07001400 valid_scale_data = __get_scale_data(psde, pstate, sc_u, &sc_u_size);
1401 deci_w = valid_scale_data && sc_u ? sc_u->v1.horz_decimate : 0;
1402 deci_h = valid_scale_data && sc_u ? sc_u->v1.vert_decimate : 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04001403
1404 /* src values are in Q16 fixed point, convert to integer */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001405 POPULATE_RECT(&src, state->src_x, state->src_y, state->src_w,
1406 state->src_h, q16_data);
1407 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
1408 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04001409
Dhaval Patel47302cf2016-08-18 15:04:28 -07001410 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
1411 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04001412
Dhaval Patel47302cf2016-08-18 15:04:28 -07001413 max_upscale = psde->pipe_sblk->maxupscale;
1414 max_downscale = psde->pipe_sblk->maxdwnscale;
1415 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04001416
Dhaval Patel47302cf2016-08-18 15:04:28 -07001417 SDE_DEBUG("%s: check (%d -> %d)\n", psde->pipe_name,
1418 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001419
Dhaval Patel47302cf2016-08-18 15:04:28 -07001420 if (!sde_plane_enabled(state))
1421 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04001422
Dhaval Patel47302cf2016-08-18 15:04:28 -07001423 fmt = to_sde_format(msm_framebuffer_format(state->fb));
1424
1425 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
1426
1427 if (SDE_FORMAT_IS_YUV(fmt) &&
1428 (!(psde->features & SDE_SSPP_SCALER) ||
1429 !(psde->features & BIT(SDE_SSPP_CSC)))) {
1430 SDE_ERROR("plane doesn't have scaler/csc capability for yuv\n");
1431 ret = -EINVAL;
1432
1433 /* check src bounds */
1434 } else if (state->fb->width > MAX_IMG_WIDTH ||
1435 state->fb->height > MAX_IMG_HEIGHT ||
1436 src.w < min_src_size || src.h < min_src_size ||
1437 CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
1438 CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
1439 SDE_ERROR("invalid source (%u, %u) -> (%u, %u)\n",
1440 src.x, src.y, src.w, src.h);
1441 ret = -E2BIG;
1442
1443 /* valid yuv image */
1444 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
1445 (src.w & 0x1) || (src.h & 0x1))) {
1446 SDE_ERROR("invalid yuv source (%u, %u) -> (%u, %u)\n",
1447 src.x, src.y, src.w, src.h);
1448 ret = -EINVAL;
1449
1450 /* min dst support */
1451 } else if (dst.w < 0x1 || dst.h < 0x1) {
1452 SDE_ERROR("invalid dest rect (%u, %u) -> (%u, %u)\n",
1453 dst.x, dst.y, dst.w, dst.h);
1454 ret = -EINVAL;
1455
1456 /* decimation validation */
1457 } else if (deci_w || deci_h) {
1458 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1459 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1460 SDE_ERROR("too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001461 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001462 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
1463 SDE_ERROR("decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001464 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001465 }
1466
Dhaval Patel47302cf2016-08-18 15:04:28 -07001467 } else if (!(psde->features & SDE_SSPP_SCALER) &&
1468 ((src.w != dst.w) || (src.h != dst.h))) {
1469 SDE_ERROR("pipe doesn't support scaling %ux%u->%ux%u\n",
1470 src.w, src.h, dst.w, dst.h);
1471 ret = -EINVAL;
1472
1473 /* check decimated source width */
1474 } else if (src_deci_w > max_linewidth) {
1475 SDE_ERROR("invalid source width:%u, deci wid:%u, line wid:%u\n",
1476 src.w, src_deci_w, max_linewidth);
1477 ret = -E2BIG;
1478
1479 /* check max scaler capability */
1480 } else if (((src_deci_w * max_upscale) < dst.w) ||
1481 ((src_deci_h * max_upscale) < dst.h) ||
1482 ((dst.w * max_downscale) < src_deci_w) ||
1483 ((dst.h * max_downscale) < src_deci_h)) {
1484 SDE_ERROR("too much scaling requested %ux%u -> %ux%u\n",
1485 src_deci_w, src_deci_h, dst.w, dst.h);
1486 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001487 }
1488
Dhaval Patel47302cf2016-08-18 15:04:28 -07001489modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001490 if (!ret)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001491 _sde_plane_atomic_check_mode_changed(psde, state, plane->state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001492exit:
1493 return ret;
1494}
1495
Clarence Ipcae1bb62016-07-07 12:07:13 -04001496/**
1497 * sde_plane_flush - final plane operations before commit flush
1498 * @plane: Pointer to drm plane structure
1499 */
1500void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001501{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001502 struct sde_plane *psde;
1503
1504 if (!plane)
1505 return;
1506
1507 psde = to_sde_plane(plane);
1508
1509 /*
1510 * These updates have to be done immediately before the plane flush
1511 * timing, and may not be moved to the atomic_update/mode_set functions.
1512 */
1513 if (psde->is_error)
1514 /* force white frame with 0% alpha pipe output on error */
1515 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1516 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1517 /* force 100% alpha */
1518 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1519 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1520 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1521
1522 /* flag h/w flush complete */
1523 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001524 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001525}
1526
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001527static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001528 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001529{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001530 struct sde_plane *sde_plane;
1531 struct drm_plane_state *state;
1532 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001533
Clarence Ip5e2a9222016-06-26 22:38:24 -04001534 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001535 SDE_ERROR("invalid plane/state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001536 return;
1537 }
1538
1539 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001540 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001541 state = plane->state;
1542 pstate = to_sde_plane_state(state);
1543
Dhaval Patel47302cf2016-08-18 15:04:28 -07001544 SDE_DEBUG("%s: update\n", sde_plane->pipe_name);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001545
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001546 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001547 pstate->pending = true;
Clarence Ip282dad62016-09-27 17:07:35 -04001548 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001549 int ret;
1550
Dhaval Patel47302cf2016-08-18 15:04:28 -07001551 ret = _sde_plane_mode_set(plane, state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001552 /* atomic_check should have ensured that this doesn't fail */
1553 WARN_ON(ret < 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001554 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001555}
1556
Dhaval Patel47302cf2016-08-18 15:04:28 -07001557
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001558/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001559static void _sde_plane_install_properties(struct drm_plane *plane,
1560 u32 max_blendstages)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001561{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001562 static const struct drm_prop_enum_list e_blend_op[] = {
1563 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1564 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1565 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1566 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1567 };
1568 static const struct drm_prop_enum_list e_src_config[] = {
1569 {SDE_DRM_DEINTERLACE, "deinterlace"}
1570 };
Clarence Ipea3d6262016-07-15 16:20:11 -04001571 const struct sde_format_extended *format_list;
Dhaval Patel4e574842016-08-23 15:11:37 -07001572 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001573 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001574
Clarence Ipaa0faf42016-05-30 12:07:48 -04001575 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001576 SDE_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001577 return;
1578 }
1579
Dhaval Patel47302cf2016-08-18 15:04:28 -07001580 msm_property_install_range(&psde->property_info, "zpos", 0x0, 0,
Dhaval Patel48c76022016-09-01 17:51:23 -07001581 max_blendstages, SDE_STAGE_BASE, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001582
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001583 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07001584 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001585
Dhaval Patel47302cf2016-08-18 15:04:28 -07001586 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001587 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07001588 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001589
1590 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001591 msm_property_install_rotation(&psde->property_info,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001592 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y), PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001593
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001594 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001595 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001596
Dhaval Patel47302cf2016-08-18 15:04:28 -07001597 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
1598 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
1599
1600 if (psde->pipe_hw->ops.setup_solidfill)
1601 msm_property_install_range(&psde->property_info, "color_fill",
1602 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
1603
Clarence Ip4c1d9772016-06-26 09:35:38 -04001604 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001605 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001606 PLANE_PROP_SCALER);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001607
1608 if (psde->features & BIT(SDE_SSPP_CSC))
Clarence Ipaa0faf42016-05-30 12:07:48 -04001609 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001610 PLANE_PROP_CSC);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001611
Dhaval Patel4e574842016-08-23 15:11:37 -07001612 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
1613 if (!info)
1614 return;
1615
1616 msm_property_install_blob(&psde->property_info, "capabilities",
1617 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
1618 sde_kms_info_reset(info);
1619
Clarence Ipea3d6262016-07-15 16:20:11 -04001620 format_list = psde->pipe_sblk->format_list;
1621 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04001622 sde_kms_info_start(info, "pixel_formats");
1623 while (format_list->fourcc_format) {
1624 sde_kms_info_append_format(info,
1625 format_list->fourcc_format,
1626 format_list->modifier);
1627 ++format_list;
1628 }
1629 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04001630 }
Dhaval Patel4e574842016-08-23 15:11:37 -07001631
1632 sde_kms_info_add_keyint(info, "max_linewidth",
1633 psde->pipe_sblk->maxlinewidth);
1634 sde_kms_info_add_keyint(info, "max_upscale",
1635 psde->pipe_sblk->maxupscale);
1636 sde_kms_info_add_keyint(info, "max_downscale",
1637 psde->pipe_sblk->maxdwnscale);
1638 sde_kms_info_add_keyint(info, "max_horizontal_deci",
1639 psde->pipe_sblk->maxhdeciexp);
1640 sde_kms_info_add_keyint(info, "max_vertical_deci",
1641 psde->pipe_sblk->maxvdeciexp);
1642 msm_property_set_blob(&psde->property_info, &psde->blob_info,
1643 info->data, info->len, PLANE_PROP_INFO);
1644
1645 kfree(info);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001646}
1647
1648static int sde_plane_atomic_set_property(struct drm_plane *plane,
1649 struct drm_plane_state *state, struct drm_property *property,
1650 uint64_t val)
1651{
Clarence Ip730e7192016-06-26 22:45:09 -04001652 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001653 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001654 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001655
Clarence Ipaa0faf42016-05-30 12:07:48 -04001656 DBG("");
1657
1658 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001659 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001660 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001661 SDE_ERROR("invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001662 } else {
1663 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001664 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001665 ret = msm_property_atomic_set(&psde->property_info,
1666 pstate->property_values, pstate->property_blobs,
1667 property, val);
1668 if (!ret) {
1669 idx = msm_property_index(&psde->property_info,
1670 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001671 if (idx == PLANE_PROP_INPUT_FENCE)
1672 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001673 }
1674 }
1675
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001676 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001677}
1678
1679static int sde_plane_set_property(struct drm_plane *plane,
1680 struct drm_property *property, uint64_t val)
1681{
Clarence Ip4ce59322016-06-26 22:27:51 -04001682 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001683
Clarence Ipae4e60c2016-06-26 22:44:04 -04001684 return sde_plane_atomic_set_property(plane,
1685 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001686}
1687
1688static int sde_plane_atomic_get_property(struct drm_plane *plane,
1689 const struct drm_plane_state *state,
1690 struct drm_property *property, uint64_t *val)
1691{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001692 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001693 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001694 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001695
Clarence Ipaa0faf42016-05-30 12:07:48 -04001696 DBG("");
1697
1698 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001699 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001700 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001701 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001702 } else {
1703 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001704 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001705 ret = msm_property_atomic_get(&psde->property_info,
1706 pstate->property_values, pstate->property_blobs,
1707 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001708 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001709
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001710 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001711}
1712
1713static void sde_plane_destroy(struct drm_plane *plane)
1714{
Clarence Ip4ce59322016-06-26 22:27:51 -04001715 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001716
Clarence Ip4ce59322016-06-26 22:27:51 -04001717 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001718
Clarence Ip4ce59322016-06-26 22:27:51 -04001719 if (plane) {
1720 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001721
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001722 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1723
Clarence Ip4ce59322016-06-26 22:27:51 -04001724 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001725
Dhaval Patel4e574842016-08-23 15:11:37 -07001726 if (psde->blob_info)
1727 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001728 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001729 mutex_destroy(&psde->lock);
1730
Clarence Ip4ce59322016-06-26 22:27:51 -04001731 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001732
Clarence Ip4ce59322016-06-26 22:27:51 -04001733 /* this will destroy the states as well */
1734 drm_plane_cleanup(plane);
1735
Clarence Ip4c1d9772016-06-26 09:35:38 -04001736 if (psde->pipe_hw)
1737 sde_hw_sspp_destroy(psde->pipe_hw);
1738
Clarence Ip4ce59322016-06-26 22:27:51 -04001739 kfree(psde);
1740 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001741}
1742
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001743static void sde_plane_destroy_state(struct drm_plane *plane,
1744 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001745{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001746 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001747 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001748
Clarence Ipae4e60c2016-06-26 22:44:04 -04001749 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001750 SDE_ERROR("invalid plane/state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001751 return;
1752 }
1753
Clarence Ipaa0faf42016-05-30 12:07:48 -04001754 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001755 pstate = to_sde_plane_state(state);
1756
1757 DBG("");
1758
Clarence Ipe78efb72016-06-24 18:35:21 -04001759 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001760 if (state->fb)
1761 drm_framebuffer_unreference(state->fb);
1762
Clarence Ipae4e60c2016-06-26 22:44:04 -04001763 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001764 if (pstate->input_fence)
1765 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001766
Clarence Ipaa0faf42016-05-30 12:07:48 -04001767 /* destroy value helper */
1768 msm_property_destroy_state(&psde->property_info, pstate,
1769 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001770}
1771
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001772static struct drm_plane_state *
1773sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001774{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001775 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001776 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001777 struct sde_plane_state *old_state;
Clarence Ip17e908b2016-09-29 15:58:00 -04001778 uint64_t input_fence_default;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001779
Clarence Ip730e7192016-06-26 22:45:09 -04001780 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001781 return NULL;
1782
Clarence Ip730e7192016-06-26 22:45:09 -04001783 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001784 psde = to_sde_plane(plane);
1785 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001786 if (!pstate)
1787 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001788
Clarence Ipaa0faf42016-05-30 12:07:48 -04001789 DBG("");
1790
1791 /* duplicate value helper */
1792 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1793 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001794
Clarence Ip730e7192016-06-26 22:45:09 -04001795 /* add ref count for frame buffer */
1796 if (pstate->base.fb)
1797 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001798
Clarence Ip17e908b2016-09-29 15:58:00 -04001799 /* clear out any input fence */
1800 pstate->input_fence = 0;
1801 input_fence_default = msm_property_get_default(
1802 &psde->property_info, PLANE_PROP_INPUT_FENCE);
1803 msm_property_set_property(&psde->property_info, pstate->property_values,
1804 PLANE_PROP_INPUT_FENCE, input_fence_default);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001805
Clarence Ip282dad62016-09-27 17:07:35 -04001806 pstate->dirty = 0x0;
Clarence Ip730e7192016-06-26 22:45:09 -04001807 pstate->pending = false;
1808
1809 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001810}
1811
1812static void sde_plane_reset(struct drm_plane *plane)
1813{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001814 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001815 struct sde_plane_state *pstate;
1816
Clarence Ipae4e60c2016-06-26 22:44:04 -04001817 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001818 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001819 return;
1820 }
1821
Clarence Ip730e7192016-06-26 22:45:09 -04001822 psde = to_sde_plane(plane);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001823 SDE_DEBUG("%s\n", psde->pipe_name);
Clarence Ip730e7192016-06-26 22:45:09 -04001824
Clarence Ipae4e60c2016-06-26 22:44:04 -04001825 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001826 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001827 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001828 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001829 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001830
Clarence Ipaa0faf42016-05-30 12:07:48 -04001831 pstate = msm_property_alloc_state(&psde->property_info);
1832 if (!pstate)
1833 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001834
Clarence Ipaa0faf42016-05-30 12:07:48 -04001835 /* reset value helper */
1836 msm_property_reset_state(&psde->property_info, pstate,
1837 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001838
1839 pstate->base.plane = plane;
1840
1841 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001842}
1843
1844static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001845 .update_plane = drm_atomic_helper_update_plane,
1846 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001847 .destroy = sde_plane_destroy,
1848 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001849 .atomic_set_property = sde_plane_atomic_set_property,
1850 .atomic_get_property = sde_plane_atomic_get_property,
1851 .reset = sde_plane_reset,
1852 .atomic_duplicate_state = sde_plane_duplicate_state,
1853 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001854};
1855
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001856static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1857 .prepare_fb = sde_plane_prepare_fb,
1858 .cleanup_fb = sde_plane_cleanup_fb,
1859 .atomic_check = sde_plane_atomic_check,
1860 .atomic_update = sde_plane_atomic_update,
1861};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001862
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001863enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001864{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001865 struct sde_plane *sde_plane = to_sde_plane(plane);
1866
1867 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001868}
1869
Clarence Ip4ce59322016-06-26 22:27:51 -04001870static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1871{
1872 const struct sde_sspp_sub_blks *sblk = 0;
1873 const struct sde_sspp_cfg *cfg = 0;
1874
1875 if (psde && psde->pipe_hw)
1876 cfg = psde->pipe_hw->cap;
1877 if (cfg)
1878 sblk = cfg->sblk;
1879
1880 if (kms && sblk) {
1881 /* create overall sub-directory for the pipe */
1882 psde->debugfs_root =
1883 debugfs_create_dir(psde->pipe_name,
1884 sde_debugfs_get_root(kms));
1885 if (psde->debugfs_root) {
1886 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001887 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001888 psde->debugfs_root, &psde->features);
1889
1890 /* add register dump support */
1891 sde_debugfs_setup_regset32(&psde->debugfs_src,
1892 sblk->src_blk.base + cfg->base,
1893 sblk->src_blk.len,
Clarence Ipaac9f332016-08-31 15:46:35 -04001894 kms);
Clarence Ip4ce59322016-06-26 22:27:51 -04001895 sde_debugfs_create_regset32("src_blk", 0444,
1896 psde->debugfs_root, &psde->debugfs_src);
1897
1898 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1899 sblk->scaler_blk.base + cfg->base,
1900 sblk->scaler_blk.len,
Clarence Ipaac9f332016-08-31 15:46:35 -04001901 kms);
Clarence Ip4ce59322016-06-26 22:27:51 -04001902 sde_debugfs_create_regset32("scaler_blk", 0444,
1903 psde->debugfs_root,
1904 &psde->debugfs_scaler);
1905
1906 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1907 sblk->csc_blk.base + cfg->base,
1908 sblk->csc_blk.len,
Clarence Ipaac9f332016-08-31 15:46:35 -04001909 kms);
Clarence Ip4ce59322016-06-26 22:27:51 -04001910 sde_debugfs_create_regset32("csc_blk", 0444,
1911 psde->debugfs_root, &psde->debugfs_csc);
1912 }
1913 }
1914}
1915
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001916/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001917struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001918 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001919{
1920 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001921 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001922 struct msm_drm_private *priv;
1923 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001924 enum drm_plane_type type;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001925 int ret = -EINVAL, max_blendstages = 255;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001926
1927 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001928 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001929 goto exit;
1930 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001931
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001932 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001933 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001934 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001935 goto exit;
1936 }
1937
1938 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001939 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001940 goto exit;
1941 }
1942 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001943
Clarence Ip4c1d9772016-06-26 09:35:38 -04001944 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001945 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001946 goto exit;
1947 }
1948
Clarence Ip4ce59322016-06-26 22:27:51 -04001949 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001950 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1951 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001952 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001953 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001954 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001955 }
1956
Clarence Ip4c1d9772016-06-26 09:35:38 -04001957 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001958 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001959 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04001960 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001961
Clarence Ip4c1d9772016-06-26 09:35:38 -04001962 /* initialize underlying h/w driver */
1963 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1964 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001965 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001966 ret = PTR_ERR(psde->pipe_hw);
1967 goto clean_plane;
1968 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001969 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001970 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001971 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001972
1973 /* cache features mask for later */
1974 psde->features = psde->pipe_hw->cap->features;
1975 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04001976 if (!psde->pipe_sblk) {
1977 SDE_ERROR("invalid sblk on pipe %d\n", pipe);
1978 goto clean_sspp;
1979 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001980
Dhaval Patel47302cf2016-08-18 15:04:28 -07001981 if (kms->catalog && kms->catalog->mixer_count && kms->catalog->mixer)
1982 max_blendstages = kms->catalog->mixer[0].sblk->maxblendstages;
1983
Clarence Ip4c1d9772016-06-26 09:35:38 -04001984 /* add plane to DRM framework */
Clarence Ipea3d6262016-07-15 16:20:11 -04001985 psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
1986 psde->formats,
1987 0,
1988 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001989
Clarence Ip4c1d9772016-06-26 09:35:38 -04001990 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001991 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001992 goto clean_sspp;
1993 }
1994
1995 if (psde->features & BIT(SDE_SSPP_CURSOR))
1996 type = DRM_PLANE_TYPE_CURSOR;
1997 else if (primary_plane)
1998 type = DRM_PLANE_TYPE_PRIMARY;
1999 else
2000 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002001 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
2002 psde->formats, psde->nformats,
2003 type);
2004 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04002005 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002006
Clarence Ip4c1d9772016-06-26 09:35:38 -04002007 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002008 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002009
Clarence Ipaa0faf42016-05-30 12:07:48 -04002010 msm_property_init(&psde->property_info, &plane->base, dev,
2011 priv->plane_property, psde->property_data,
2012 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
2013 sizeof(struct sde_plane_state));
2014
Dhaval Patel47302cf2016-08-18 15:04:28 -07002015 _sde_plane_install_properties(plane, max_blendstages);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002016
Clarence Ip4ce59322016-06-26 22:27:51 -04002017 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04002018 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04002019
Clarence Ip730e7192016-06-26 22:45:09 -04002020 mutex_init(&psde->lock);
2021
Clarence Ip4ce59322016-06-26 22:27:51 -04002022 _sde_plane_init_debugfs(psde, kms);
2023
Dhaval Patel47302cf2016-08-18 15:04:28 -07002024 DRM_INFO("[%u]successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002025 return plane;
2026
Clarence Ip4c1d9772016-06-26 09:35:38 -04002027clean_sspp:
2028 if (psde && psde->pipe_hw)
2029 sde_hw_sspp_destroy(psde->pipe_hw);
2030clean_plane:
2031 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04002032exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002033 return ERR_PTR(ret);
2034}