blob: c09fe5d5688a14142a0873378f9e9f5f78090c32 [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
Clarence Ip5fc00c52016-09-23 15:03:34 -040061/*
62 * struct sde_plane - local sde plane structure
63 * @csc_cfg: Decoded user configuration for csc
64 * @csc_usr_ptr: Points to csc_cfg if valid user config available
65 * @csc_ptr: Points to sde_csc_cfg structure to use for current
66 */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070067struct sde_plane {
68 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040069
70 int mmu_id;
71
Clarence Ip730e7192016-06-26 22:45:09 -040072 struct mutex lock;
73
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040074 enum sde_sspp pipe;
75 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070076 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -040077 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040078
79 struct sde_hw_pipe *pipe_hw;
80 struct sde_hw_pipe_cfg pipe_cfg;
81 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040082 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040083 struct sde_hw_scaler3_cfg scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040084 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -040085 uint32_t color_fill;
86 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040087 bool is_rt_pipe;
Clarence Ip4ce59322016-06-26 22:27:51 -040088
Clarence Ip373f8592016-05-26 00:58:42 -040089 struct sde_csc_cfg csc_cfg;
Clarence Ip5fc00c52016-09-23 15:03:34 -040090 struct sde_csc_cfg *csc_usr_ptr;
Clarence Ip373f8592016-05-26 00:58:42 -040091 struct sde_csc_cfg *csc_ptr;
92
Clarence Ip4c1d9772016-06-26 09:35:38 -040093 const struct sde_sspp_sub_blks *pipe_sblk;
94
Clarence Ip5e2a9222016-06-26 22:38:24 -040095 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040096
Clarence Ipaa0faf42016-05-30 12:07:48 -040097 struct msm_property_info property_info;
98 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -070099 struct drm_property_blob *blob_info;
Clarence Ip730e7192016-06-26 22:45:09 -0400100
Clarence Ip4ce59322016-06-26 22:27:51 -0400101 /* debugfs related stuff */
102 struct dentry *debugfs_root;
103 struct sde_debugfs_regset32 debugfs_src;
104 struct sde_debugfs_regset32 debugfs_scaler;
105 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700106};
Dhaval Patel47302cf2016-08-18 15:04:28 -0700107
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700108#define to_sde_plane(x) container_of(x, struct sde_plane, base)
109
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400110static bool sde_plane_enabled(struct drm_plane_state *state)
111{
Clarence Ipdbde9832016-06-26 09:48:36 -0400112 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400113}
114
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400115/**
116 * _sde_plane_calc_fill_level - calculate fill level of the given source format
117 * @plane: Pointer to drm plane
118 * @fmt: Pointer to source buffer format
119 * @src_wdith: width of source buffer
120 * Return: fill level corresponding to the source buffer/format or 0 if error
121 */
122static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
123 const struct sde_format *fmt, u32 src_width)
124{
125 struct sde_plane *psde;
126 u32 fixed_buff_size;
127 u32 total_fl;
128
129 if (!plane || !fmt) {
130 SDE_ERROR("invalid arguments\n");
131 return 0;
132 }
133
134 psde = to_sde_plane(plane);
135 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
136
137 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
138 if (fmt->chroma_sample == SDE_CHROMA_420) {
139 /* NV12 */
140 total_fl = (fixed_buff_size / 2) /
141 ((src_width + 32) * fmt->bpp);
142 } else {
143 /* non NV12 */
144 total_fl = (fixed_buff_size) /
145 ((src_width + 32) * fmt->bpp);
146 }
147 } else {
148 total_fl = (fixed_buff_size * 2) /
149 ((src_width + 32) * fmt->bpp);
150 }
151
152 SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
153 plane->base.id, psde->pipe - SSPP_VIG0,
154 fmt->base.pixel_format, src_width, total_fl);
155
156 return total_fl;
157}
158
159/**
160 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
161 * @total_fl: fill level
162 * Return: LUT setting corresponding to the fill level
163 */
164static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
165{
166 u32 qos_lut;
167
168 if (total_fl <= 4)
169 qos_lut = 0x1B;
170 else if (total_fl <= 5)
171 qos_lut = 0x5B;
172 else if (total_fl <= 6)
173 qos_lut = 0x15B;
174 else if (total_fl <= 7)
175 qos_lut = 0x55B;
176 else if (total_fl <= 8)
177 qos_lut = 0x155B;
178 else if (total_fl <= 9)
179 qos_lut = 0x555B;
180 else if (total_fl <= 10)
181 qos_lut = 0x1555B;
182 else if (total_fl <= 11)
183 qos_lut = 0x5555B;
184 else if (total_fl <= 12)
185 qos_lut = 0x15555B;
186 else
187 qos_lut = 0x55555B;
188
189 return qos_lut;
190}
191
192/**
193 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
194 * @total_fl: fill level
195 * Return: LUT setting corresponding to the fill level
196 */
197static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
198{
199 u32 qos_lut;
200
201 if (total_fl <= 10)
202 qos_lut = 0x1AAff;
203 else if (total_fl <= 11)
204 qos_lut = 0x5AAFF;
205 else if (total_fl <= 12)
206 qos_lut = 0x15AAFF;
207 else
208 qos_lut = 0x55AAFF;
209
210 return qos_lut;
211}
212
213/**
214 * _sde_plane_is_rt_pipe - check if the given plane requires real-time QoS
215 * @plane: Pointer to drm plane
216 * @crtc: Pointer to drm crtc associated with the given plane
217 */
218static bool _sde_plane_is_rt_pipe(struct drm_plane *plane,
219 struct drm_crtc *crtc)
220{
221 struct sde_plane *psde = to_sde_plane(plane);
222 struct drm_connector *connector;
223 bool is_rt = false;
224
225 /* check if this plane has a physical connector interface */
226 drm_for_each_connector(connector, plane->dev)
227 if (connector->state &&
228 (connector->state->crtc == crtc) &&
229 (connector->connector_type
230 != DRM_MODE_CONNECTOR_VIRTUAL)) {
231 is_rt = true;
232 break;
233 }
234
235 SDE_DEBUG("plane%u: pnum:%d rt:%d\n",
236 plane->base.id, psde->pipe - SSPP_VIG0, is_rt);
237
238 return is_rt;
239}
240
241/**
242 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
243 * @plane: Pointer to drm plane
244 * @fb: Pointer to framebuffer associated with the given plane
245 */
246static void _sde_plane_set_qos_lut(struct drm_plane *plane,
247 struct drm_framebuffer *fb)
248{
249 struct sde_plane *psde;
250 const struct sde_format *fmt = NULL;
251 u32 qos_lut;
252 u32 total_fl = 0;
253
254 if (!plane || !fb) {
255 SDE_ERROR("invalid arguments plane %d fb %d\n",
256 plane != 0, fb != 0);
257 return;
258 }
259
260 psde = to_sde_plane(plane);
261
262 if (!psde->pipe_hw || !psde->pipe_sblk) {
263 SDE_ERROR("invalid arguments\n");
264 return;
265 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
266 return;
267 }
268
269 if (!psde->is_rt_pipe) {
270 qos_lut = psde->pipe_sblk->creq_lut_nrt;
271 } else {
272 fmt = sde_get_sde_format_ext(
273 fb->pixel_format,
274 fb->modifier,
275 drm_format_num_planes(fb->pixel_format));
276 total_fl = _sde_plane_calc_fill_level(plane, fmt,
277 psde->pipe_cfg.src_rect.w);
278
279 if (SDE_FORMAT_IS_LINEAR(fmt))
280 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
281 else
282 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
283 }
284
285 psde->pipe_qos_cfg.creq_lut = qos_lut;
286
287 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
288 (fmt) ? fmt->base.pixel_format : 0,
289 psde->is_rt_pipe, total_fl, qos_lut,
290 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
291
292 SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
293 plane->base.id,
294 psde->pipe - SSPP_VIG0,
295 (fmt) ? fmt->base.pixel_format : 0,
296 psde->is_rt_pipe, total_fl, qos_lut);
297
298 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
299}
300
301/**
302 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
303 * @plane: Pointer to drm plane
304 * @fb: Pointer to framebuffer associated with the given plane
305 */
306static void _sde_plane_set_danger_lut(struct drm_plane *plane,
307 struct drm_framebuffer *fb)
308{
309 struct sde_plane *psde;
310 const struct sde_format *fmt = NULL;
311 u32 danger_lut, safe_lut;
312
313 if (!plane || !fb) {
314 SDE_ERROR("invalid arguments\n");
315 return;
316 }
317
318 psde = to_sde_plane(plane);
319
320 if (!psde->pipe_hw || !psde->pipe_sblk) {
321 SDE_ERROR("invalid arguments\n");
322 return;
323 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
324 return;
325 }
326
327 if (!psde->is_rt_pipe) {
328 danger_lut = psde->pipe_sblk->danger_lut_nrt;
329 safe_lut = psde->pipe_sblk->safe_lut_nrt;
330 } else {
331 fmt = sde_get_sde_format_ext(
332 fb->pixel_format,
333 fb->modifier,
334 drm_format_num_planes(fb->pixel_format));
335
336 if (SDE_FORMAT_IS_LINEAR(fmt)) {
337 danger_lut = psde->pipe_sblk->danger_lut_linear;
338 safe_lut = psde->pipe_sblk->safe_lut_linear;
339 } else {
340 danger_lut = psde->pipe_sblk->danger_lut_tile;
341 safe_lut = psde->pipe_sblk->safe_lut_tile;
342 }
343 }
344
345 psde->pipe_qos_cfg.danger_lut = danger_lut;
346 psde->pipe_qos_cfg.safe_lut = safe_lut;
347
348 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
349 (fmt) ? fmt->base.pixel_format : 0,
350 (fmt) ? fmt->fetch_mode : 0,
351 psde->pipe_qos_cfg.danger_lut,
352 psde->pipe_qos_cfg.safe_lut);
353
354 SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
355 plane->base.id,
356 psde->pipe - SSPP_VIG0,
357 fmt ? fmt->base.pixel_format : 0,
358 fmt ? fmt->fetch_mode : -1,
359 psde->pipe_qos_cfg.danger_lut,
360 psde->pipe_qos_cfg.safe_lut);
361
362 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
363 &psde->pipe_qos_cfg);
364}
365
366/**
367 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
368 * @plane: Pointer to drm plane
369 * @enable: true to enable QoS control
370 * @flags: QoS control mode (enum sde_plane_qos)
371 */
372static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
373 bool enable, u32 flags)
374{
375 struct sde_plane *psde;
376
377 if (!plane) {
378 SDE_ERROR("invalid arguments\n");
379 return;
380 }
381
382 psde = to_sde_plane(plane);
383
384 if (!psde->pipe_hw || !psde->pipe_sblk) {
385 SDE_ERROR("invalid arguments\n");
386 return;
387 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
388 return;
389 }
390
391 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
392 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
393 psde->pipe_qos_cfg.danger_vblank =
394 psde->pipe_sblk->danger_vblank;
395 psde->pipe_qos_cfg.vblank_en = enable;
396 }
397
398 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
399 /* this feature overrules previous VBLANK_CTRL */
400 psde->pipe_qos_cfg.vblank_en = false;
401 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
402 }
403
404 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
405 psde->pipe_qos_cfg.danger_safe_en = enable;
406
407 if (!psde->is_rt_pipe) {
408 psde->pipe_qos_cfg.vblank_en = false;
409 psde->pipe_qos_cfg.danger_safe_en = false;
410 }
411
412 SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x]\n",
413 plane->base.id,
414 psde->pipe - SSPP_VIG0,
415 psde->pipe_qos_cfg.danger_safe_en,
416 psde->pipe_qos_cfg.vblank_en,
417 psde->pipe_qos_cfg.creq_vblank,
418 psde->pipe_qos_cfg.danger_vblank);
419
420 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
421 &psde->pipe_qos_cfg);
422}
423
Alan Kwong5d324e42016-07-28 22:56:18 -0400424/**
425 * _sde_plane_set_ot_limit - set OT limit for the given plane
426 * @plane: Pointer to drm plane
427 * @crtc: Pointer to drm crtc
428 */
429static void _sde_plane_set_ot_limit(struct drm_plane *plane,
430 struct drm_crtc *crtc)
431{
432 struct sde_plane *psde;
433 struct sde_vbif_set_ot_params ot_params;
434 struct msm_drm_private *priv;
435 struct sde_kms *sde_kms;
436
437 if (!plane || !plane->dev || !crtc) {
438 SDE_ERROR("invalid arguments plane %d crtc %d\n",
439 plane != 0, crtc != 0);
440 return;
441 }
442
443 priv = plane->dev->dev_private;
444 if (!priv || !priv->kms) {
445 SDE_ERROR("invalid KMS reference\n");
446 return;
447 }
448
449 sde_kms = to_sde_kms(priv->kms);
450 psde = to_sde_plane(plane);
451 if (!psde->pipe_hw) {
452 SDE_ERROR("invalid pipe reference\n");
453 return;
454 }
455
456 memset(&ot_params, 0, sizeof(ot_params));
457 ot_params.xin_id = psde->pipe_hw->cap->xin_id;
458 ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
459 ot_params.width = psde->pipe_cfg.src_rect.w;
460 ot_params.height = psde->pipe_cfg.src_rect.h;
461 ot_params.is_wfd = !psde->is_rt_pipe;
462 ot_params.frame_rate = crtc->mode.vrefresh;
463 ot_params.vbif_idx = VBIF_RT;
464 ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
465 ot_params.rd = true;
466
467 sde_vbif_set_ot_limit(sde_kms, &ot_params);
468}
469
Clarence Ipcae1bb62016-07-07 12:07:13 -0400470/* helper to update a state's input fence pointer from the property */
471static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400472 struct sde_plane_state *pstate, uint64_t fd)
473{
474 if (!plane || !pstate)
475 return;
476
477 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400478 if (pstate->input_fence)
479 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400480
481 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400482 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400483
Dhaval Patel47302cf2016-08-18 15:04:28 -0700484 SDE_DEBUG("0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400485}
486
Clarence Ipcae1bb62016-07-07 12:07:13 -0400487int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400488{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400489 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400490 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400491 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400492 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400493
494 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700495 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400496 } else if (!plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700497 SDE_ERROR("invalid plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400498 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400499 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400500 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400501 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400502
Clarence Ipcae1bb62016-07-07 12:07:13 -0400503 if (input_fence) {
504 ret = sde_sync_wait(input_fence, wait_ms);
505 switch (ret) {
506 case 0:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700507 SDE_DEBUG("%s signaled\n", psde->pipe_name);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400508 break;
509 case -ETIME:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700510 SDE_ERROR("timeout on %s, %ums\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400511 psde->pipe_name, wait_ms);
512 psde->is_error = true;
513 break;
514 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700515 SDE_ERROR("error on %s, %d\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400516 psde->pipe_name, ret);
517 psde->is_error = true;
518 break;
519 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400520 } else {
521 ret = 0;
522 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400523 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400524 return ret;
525}
526
Clarence Ip282dad62016-09-27 17:07:35 -0400527static inline void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400528 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400529 struct sde_hw_pipe_cfg *pipe_cfg,
530 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400531{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400532 struct sde_plane *psde;
Clarence Ip282dad62016-09-27 17:07:35 -0400533 int ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400534
Clarence Ipae4e60c2016-06-26 22:44:04 -0400535 if (!plane || !pstate || !pipe_cfg || !fb)
536 return;
537
538 psde = to_sde_plane(plane);
539
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400540 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
541 if (ret) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700542 SDE_ERROR("failed to get format layout, error: %d\n", ret);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400543 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400544 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400545
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400546 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
547 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400548}
549
Clarence Ipcb410d42016-06-26 22:52:33 -0400550static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400551 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
552 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400553 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400554 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
555{
556}
557
Clarence Ipcb410d42016-06-26 22:52:33 -0400558/**
559 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
560 * @psde: Pointer to SDE plane object
561 * @src: Source size
562 * @dst: Destination size
563 * @phase_steps: Pointer to output array for phase steps
564 * @filter: Pointer to output array for filter type
565 * @fmt: Pointer to format definition
566 * @chroma_subsampling: Subsampling amount for chroma channel
567 *
568 * Returns: 0 on success
569 */
570static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400571 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400572 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573 uint32_t chroma_subsampling)
574{
Clarence Ipcb410d42016-06-26 22:52:33 -0400575 if (!psde || !phase_steps || !filter || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700576 SDE_ERROR("invalid arguments\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400577 return -EINVAL;
578 }
579
Clarence Ip4c1d9772016-06-26 09:35:38 -0400580 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400581 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400582 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400583 phase_steps[SDE_SSPP_COMP_1_2] =
584 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
585 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
586 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400587
588 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400589 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400590 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400591 (src <= dst) ? SDE_SCALE_FILTER_BIL :
592 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400593
Clarence Ipdbde9832016-06-26 09:48:36 -0400594 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400595 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400596 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
597 } else {
598 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
599 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400600 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400601 }
602 } else {
603 /* disable scaler */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700604 SDE_DEBUG("disable scaler\n");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400605 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
606 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
607 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400608 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400609 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400610}
611
Clarence Ipcb410d42016-06-26 22:52:33 -0400612/**
613 * _sde_plane_setup_pixel_ext - determine default pixel extension values
614 * @psde: Pointer to SDE plane object
615 * @src: Source size
616 * @dst: Destination size
617 * @decimated_src: Source size after decimation, if any
618 * @phase_steps: Pointer to output array for phase steps
619 * @out_src: Output array for pixel extension values
620 * @out_edge1: Output array for pixel extension first edge
621 * @out_edge2: Output array for pixel extension second edge
622 * @filter: Pointer to array for filter type
623 * @fmt: Pointer to format definition
624 * @chroma_subsampling: Subsampling amount for chroma channel
625 * @post_compare: Whether to chroma subsampled source size for comparisions
626 */
627static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400628 uint32_t src, uint32_t dst, uint32_t decimated_src,
629 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400630 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400631 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400632 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400633{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400634 int64_t edge1, edge2, caf;
635 uint32_t src_work;
636 int i, tmp;
637
Clarence Ipcb410d42016-06-26 22:52:33 -0400638 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400639 out_edge2 && filter && fmt) {
640 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400641 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400642 caf = PHASE_STEP_UNIT_SCALE;
643 else
644 caf = 0;
645
646 for (i = 0; i < SDE_MAX_PLANES; i++) {
647 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400648 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400649 src_work /= chroma_subsampling;
650 if (post_compare)
651 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400652 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400653 /* unity */
654 edge1 = 0;
655 edge2 = 0;
656 } else if (dst >= src) {
657 /* upscale */
658 edge1 = (1 << PHASE_RESIDUAL);
659 edge1 -= caf;
660 edge2 = (1 << PHASE_RESIDUAL);
661 edge2 += (dst - 1) * *(phase_steps + i);
662 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
663 edge2 += caf;
664 edge2 = -(edge2);
665 } else {
666 /* downscale */
667 edge1 = 0;
668 edge2 = (dst - 1) * *(phase_steps + i);
669 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
670 edge2 += *(phase_steps + i);
671 edge2 = -(edge2);
672 }
673
674 /* only enable CAF for luma plane */
675 caf = 0;
676
677 /* populate output arrays */
678 *(out_src + i) = src_work;
679
680 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400681 if (edge1 >= 0) {
682 tmp = (uint32_t)edge1;
683 tmp >>= PHASE_STEP_SHIFT;
684 *(out_edge1 + i) = -tmp;
685 } else {
686 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400687 *(out_edge1 + i) =
688 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
689 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400690 }
691 if (edge2 >= 0) {
692 tmp = (uint32_t)edge2;
693 tmp >>= PHASE_STEP_SHIFT;
694 *(out_edge2 + i) = -tmp;
695 } else {
696 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400697 *(out_edge2 + i) =
698 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
699 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400700 }
701 }
702 }
703}
704
Clarence Ip5e2a9222016-06-26 22:38:24 -0400705/**
706 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
707 * sub-structure
708 * @blob_ptr: Pointer to start of incoming blob data
709 * @blob_size: Size of incoming blob data, in bytes
710 * @sub_ptr: Pointer to start of desired sub-structure
711 * @sub_size: Required size of sub-structure, in bytes
712 */
713static int _sde_plane_verify_blob(void *blob_ptr,
714 size_t blob_size,
715 void *sub_ptr,
716 size_t sub_size)
717{
718 /*
719 * Use the blob size provided by drm to check if there are enough
720 * bytes from the start of versioned sub-structures to the end of
721 * blob data:
722 *
723 * e.g.,
724 * blob_ptr --> struct blob_data {
725 * uint32_t version;
726 * sub_ptr --> struct blob_data_v1 v1;
727 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
728 * blob_ptr + blob_size --> };
729 *
730 * It's important to check the actual number of bytes from the start
731 * of the sub-structure to the end of the blob data, and not just rely
732 * on something like,
733 *
734 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
735 *
736 * This is because the start of the sub-structure can vary based on
737 * how the compiler pads the overall structure.
738 */
739 if (blob_ptr && sub_ptr)
740 /* return zero if end of blob >= end of sub-struct */
741 return ((unsigned char *)blob_ptr + blob_size) <
742 ((unsigned char *)sub_ptr + sub_size);
743 return -EINVAL;
744}
745
Clarence Ip5fc00c52016-09-23 15:03:34 -0400746static inline void _sde_plane_setup_csc(struct sde_plane *psde)
Clarence Ipe78efb72016-06-24 18:35:21 -0400747{
748 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
749 {
Clarence Ip373f8592016-05-26 00:58:42 -0400750 /* S15.16 format */
751 0x00012A00, 0x00000000, 0x00019880,
752 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
753 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400754 },
Clarence Ip373f8592016-05-26 00:58:42 -0400755 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400756 { 0xfff0, 0xff80, 0xff80,},
757 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400758 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400759 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400760 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400761 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400762
Clarence Ip5fc00c52016-09-23 15:03:34 -0400763 if (!psde) {
764 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400765 return;
766 }
Clarence Ip5e2a9222016-06-26 22:38:24 -0400767
Clarence Ipcae1bb62016-07-07 12:07:13 -0400768 /* revert to kernel default if override not available */
Clarence Ip5fc00c52016-09-23 15:03:34 -0400769 if (psde->csc_usr_ptr)
770 psde->csc_ptr = psde->csc_usr_ptr;
771 else
Clarence Ip373f8592016-05-26 00:58:42 -0400772 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400773
774 SDE_DEBUG("using 0x%X 0x%X 0x%X...\n",
775 psde->csc_ptr->csc_mv[0],
776 psde->csc_ptr->csc_mv[1],
777 psde->csc_ptr->csc_mv[2]);
Clarence Ipe78efb72016-06-24 18:35:21 -0400778}
779
Clarence Ipcb410d42016-06-26 22:52:33 -0400780static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400781 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400782 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700783{
Clarence Ipcb410d42016-06-26 22:52:33 -0400784 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400785 struct sde_drm_scaler *sc_u = NULL;
786 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400787 size_t sc_u_size = 0;
788 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
789 uint32_t tmp;
790 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400791
Clarence Ipcb410d42016-06-26 22:52:33 -0400792 if (!psde || !fmt)
793 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400794
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400795 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400796 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400797
Clarence Ip5e2a9222016-06-26 22:38:24 -0400798 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400799 if (pstate)
800 sc_u = msm_property_get_blob(&psde->property_info,
801 pstate->property_blobs,
802 &sc_u_size,
803 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400804 if (sc_u) {
805 switch (sc_u->version) {
806 case SDE_DRM_SCALER_V1:
807 if (!_sde_plane_verify_blob(sc_u,
808 sc_u_size,
809 &sc_u->v1,
810 sizeof(*sc_u1)))
811 sc_u1 = &sc_u->v1;
812 break;
813 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700814 SDE_DEBUG("unrecognized scaler blob v%lld\n",
815 sc_u->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400816 break;
817 }
818 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400819
Clarence Ip04ec67d2016-05-26 01:16:15 -0400820 /* decimation */
821 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
822 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
823 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400824 } else {
825 psde->pipe_cfg.horz_decimation = 0;
826 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400827 }
828
829 /* don't chroma subsample if decimating */
830 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400831 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400832 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400833 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400834
Clarence Ip5e2a9222016-06-26 22:38:24 -0400835 /* update scaler */
836 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
837 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Dhaval Patel47302cf2016-08-18 15:04:28 -0700838 SDE_DEBUG("SCALER3 blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400839 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400840 _sde_plane_setup_scaler3(psde,
841 psde->pipe_cfg.src_rect.w,
842 psde->pipe_cfg.src_rect.h,
843 psde->pipe_cfg.dst_rect.w,
844 psde->pipe_cfg.dst_rect.h,
845 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400846 chroma_subsmpl_h, chroma_subsmpl_v);
847 } else {
848 /* always calculate basic scaler config */
849 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
850 /* populate from user space */
851 for (i = 0; i < SDE_MAX_PLANES; i++) {
852 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
853 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
854 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
855 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400856
Clarence Ip5e2a9222016-06-26 22:38:24 -0400857 pe->horz_filter[i] = sc_u1->horz_filter[i];
858 pe->vert_filter[i] = sc_u1->vert_filter[i];
859 }
860 } else {
861 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400862 _sde_plane_setup_scaler2(psde,
863 psde->pipe_cfg.src_rect.w,
864 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400865 pe->phase_step_x,
866 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400867 _sde_plane_setup_scaler2(psde,
868 psde->pipe_cfg.src_rect.h,
869 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400870 pe->phase_step_y,
871 pe->vert_filter, fmt, chroma_subsmpl_v);
872 }
873 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400874
Clarence Ip5e2a9222016-06-26 22:38:24 -0400875 /* update pixel extensions */
876 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
877 /* populate from user space */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700878 SDE_DEBUG("pixel ext blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400879 for (i = 0; i < SDE_MAX_PLANES; i++) {
880 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
881 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
882 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
883 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
884 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
885 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
886 pe->roi_w[i] = sc_u1->lr.roi[i];
887
888 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
889 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
890 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
891 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
892 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
893 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
894 pe->roi_h[i] = sc_u1->tb.roi[i];
895 }
896 } else {
897 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400898 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400899 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400900 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400901 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400902 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
903 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400904 pe->phase_step_x,
905 pe->roi_w,
906 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400907 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400908 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400909
Clarence Ipcb410d42016-06-26 22:52:33 -0400910 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400911 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400912 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
913 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400914 pe->phase_step_y,
915 pe->roi_h,
916 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400917 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400918 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400919
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400920 for (i = 0; i < SDE_MAX_PLANES; i++) {
921 if (pe->num_ext_pxls_left[i] >= 0)
922 pe->left_rpt[i] =
923 pe->num_ext_pxls_left[i];
924 else
925 pe->left_ftch[i] =
926 pe->num_ext_pxls_left[i];
927
928 if (pe->num_ext_pxls_right[i] >= 0)
929 pe->right_rpt[i] =
930 pe->num_ext_pxls_right[i];
931 else
932 pe->right_ftch[i] =
933 pe->num_ext_pxls_right[i];
934
935 if (pe->num_ext_pxls_top[i] >= 0)
936 pe->top_rpt[i] =
937 pe->num_ext_pxls_top[i];
938 else
939 pe->top_ftch[i] =
940 pe->num_ext_pxls_top[i];
941
942 if (pe->num_ext_pxls_btm[i] >= 0)
943 pe->btm_rpt[i] =
944 pe->num_ext_pxls_btm[i];
945 else
946 pe->btm_ftch[i] =
947 pe->num_ext_pxls_btm[i];
948 }
949 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400950}
951
Clarence Ipcae1bb62016-07-07 12:07:13 -0400952/**
953 * _sde_plane_color_fill - enables color fill on plane
954 * @plane: Pointer to DRM plane object
955 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
956 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
957 * Returns: 0 on success
958 */
959static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -0400960 uint32_t color, uint32_t alpha)
961{
962 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400963 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400964
965 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700966 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400967 return -EINVAL;
968 }
969
970 psde = to_sde_plane(plane);
971 if (!psde->pipe_hw) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700972 SDE_ERROR("invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400973 return -EINVAL;
974 }
975
Clarence Ipcae1bb62016-07-07 12:07:13 -0400976 DBG("");
977
Clarence Ipcb410d42016-06-26 22:52:33 -0400978 /*
979 * select fill format to match user property expectation,
980 * h/w only supports RGB variants
981 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400982 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -0400983
984 /* update sspp */
985 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
986 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
987 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
988
989 /* override scaler/decimation if solid fill */
990 psde->pipe_cfg.src_rect.x = 0;
991 psde->pipe_cfg.src_rect.y = 0;
992 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
993 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
994
995 _sde_plane_setup_scaler(psde, fmt, 0);
996
997 if (psde->pipe_hw->ops.setup_format)
998 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
999 fmt, SDE_SSPP_SOLID_FILL);
1000
1001 if (psde->pipe_hw->ops.setup_rects)
1002 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1003 &psde->pipe_cfg, &psde->pixel_ext);
1004 }
1005
1006 return 0;
1007}
1008
1009static int _sde_plane_mode_set(struct drm_plane *plane,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001010 struct drm_plane_state *state)
Clarence Ipcb410d42016-06-26 22:52:33 -04001011{
Clarence Ip282dad62016-09-27 17:07:35 -04001012 uint32_t nplanes, src_flags, zpos, split_w;
Clarence Ipcb410d42016-06-26 22:52:33 -04001013 struct sde_plane *psde;
1014 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001015 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001016 struct drm_crtc *crtc;
1017 struct drm_framebuffer *fb;
1018 struct sde_rect src, dst;
1019 bool q16_data = true;
Clarence Ip282dad62016-09-27 17:07:35 -04001020 int idx;
Clarence Ipcb410d42016-06-26 22:52:33 -04001021
1022 if (!plane || !plane->state) {
Clarence Ip282dad62016-09-27 17:07:35 -04001023 SDE_ERROR("invalid plane\n");
1024 return -EINVAL;
1025 } else if (!plane->state) {
1026 SDE_ERROR("invalid plane state\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001027 return -EINVAL;
1028 }
1029
1030 psde = to_sde_plane(plane);
1031 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -04001032
Dhaval Patel47302cf2016-08-18 15:04:28 -07001033 crtc = state->crtc;
1034 fb = state->fb;
1035 if (!crtc || !fb) {
1036 SDE_ERROR("invalid crtc/fb\n");
1037 return -EINVAL;
1038 }
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001039 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001040 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -04001041
Clarence Ip282dad62016-09-27 17:07:35 -04001042 /* determine what needs to be refreshed */
1043 while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
1044 switch (idx) {
1045 case PLANE_PROP_SCALER:
1046 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
1047 break;
Clarence Ip5fc00c52016-09-23 15:03:34 -04001048 case PLANE_PROP_CSC_V1:
Clarence Ip282dad62016-09-27 17:07:35 -04001049 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
1050 break;
1051 case PLANE_PROP_COLOR_FILL:
1052 /* potentially need to refresh everything */
1053 pstate->dirty = SDE_PLANE_DIRTY_ALL;
1054 break;
1055 case PLANE_PROP_ROTATION:
1056 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
1057 break;
1058 case PLANE_PROP_SRC_CONFIG:
1059 case PLANE_PROP_ZPOS:
1060 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
1061 break;
1062 case PLANE_PROP_INFO:
1063 case PLANE_PROP_ALPHA:
1064 case PLANE_PROP_INPUT_FENCE:
1065 case PLANE_PROP_BLEND_OP:
1066 /* no special action required */
1067 break;
1068 default:
1069 /* unknown property, refresh everything */
1070 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
1071 SDE_ERROR("executing full mode set, prp_idx %d\n", idx);
1072 break;
1073 }
Clarence Ipcb410d42016-06-26 22:52:33 -04001074 }
1075
Clarence Ip282dad62016-09-27 17:07:35 -04001076 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
1077 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ipcb410d42016-06-26 22:52:33 -04001078
1079 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
1080
Clarence Ip282dad62016-09-27 17:07:35 -04001081 /* early out if nothing dirty */
1082 if (!pstate->dirty)
1083 return 0;
1084 pstate->pending = true;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001085
Clarence Ip282dad62016-09-27 17:07:35 -04001086 psde->is_rt_pipe = _sde_plane_is_rt_pipe(plane, crtc);
1087 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1088
1089 /* update roi config */
1090 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) {
1091 POPULATE_RECT(&src, state->src_x, state->src_y,
1092 state->src_w, state->src_h, q16_data);
1093 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
1094 state->crtc_w, state->crtc_h, !q16_data);
1095
1096 SDE_DEBUG(
1097 "%s:FB[%u] %u,%u,%u,%u -> crtc%u %d,%d,%u,%u, %s ubwc %d\n",
1098 psde->pipe_name,
1099 fb->base.id, src.x, src.y, src.w, src.h,
1100 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
1101 drm_get_format_name(fmt->base.pixel_format),
1102 SDE_FORMAT_IS_UBWC(fmt));
1103
1104 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
1105 BIT(SDE_DRM_DEINTERLACE)) {
1106 SDE_DEBUG("deinterlace\n");
1107 for (idx = 0; idx < SDE_MAX_PLANES; ++idx)
1108 psde->pipe_cfg.layout.plane_pitch[idx] <<= 1;
1109 src.h /= 2;
1110 src.y = DIV_ROUND_UP(src.y, 2);
1111 src.y &= ~0x1;
1112 }
1113
1114 psde->pipe_cfg.src_rect = src;
1115 psde->pipe_cfg.dst_rect = dst;
1116
1117 /* check for color fill */
1118 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
1119 PLANE_PROP_COLOR_FILL);
1120 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) {
1121 /* skip remaining processing on color fill */
1122 pstate->dirty = 0x0;
1123 } else if (psde->pipe_hw->ops.setup_rects) {
1124 _sde_plane_setup_scaler(psde, fmt, pstate);
1125
1126 /* base layer source split needs update */
1127 zpos = sde_plane_get_property(pstate, PLANE_PROP_ZPOS);
1128 if (zpos == SDE_STAGE_BASE) {
1129 split_w = get_crtc_split_width(crtc);
1130 if (psde->pipe_cfg.dst_rect.x >= split_w)
1131 psde->pipe_cfg.dst_rect.x -= split_w;
1132 }
1133 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1134 &psde->pipe_cfg, &psde->pixel_ext);
1135 }
Dhaval Patel48c76022016-09-01 17:51:23 -07001136 }
1137
Clarence Ip282dad62016-09-27 17:07:35 -04001138 if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
1139 psde->pipe_hw->ops.setup_format) {
1140 src_flags = 0x0;
1141 SDE_DEBUG("rotation 0x%llX\n",
1142 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
1143 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1144 BIT(DRM_REFLECT_X))
1145 src_flags |= SDE_SSPP_FLIP_LR;
1146 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1147 BIT(DRM_REFLECT_Y))
1148 src_flags |= SDE_SSPP_FLIP_UD;
1149
1150 /* update format */
1151 psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, src_flags);
1152
1153 /* update csc */
1154 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip5fc00c52016-09-23 15:03:34 -04001155 _sde_plane_setup_csc(psde);
Clarence Ip282dad62016-09-27 17:07:35 -04001156 else
1157 psde->csc_ptr = 0;
1158 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001159
Clarence Ipe78efb72016-06-24 18:35:21 -04001160 /* update sharpening */
Clarence Ip282dad62016-09-27 17:07:35 -04001161 if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) &&
1162 psde->pipe_hw->ops.setup_sharpening) {
1163 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
1164 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
1165 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
1166 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
Clarence Ipe78efb72016-06-24 18:35:21 -04001167
Clarence Ipe78efb72016-06-24 18:35:21 -04001168 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
Clarence Ip282dad62016-09-27 17:07:35 -04001169 &psde->sharp_cfg);
1170 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001171
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001172 _sde_plane_set_qos_lut(plane, fb);
1173 _sde_plane_set_danger_lut(plane, fb);
1174
Alan Kwong5d324e42016-07-28 22:56:18 -04001175 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001176 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
Alan Kwong5d324e42016-07-28 22:56:18 -04001177 _sde_plane_set_ot_limit(plane, crtc);
1178 }
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001179
Clarence Ip282dad62016-09-27 17:07:35 -04001180 /* clear dirty */
1181 pstate->dirty = 0x0;
1182
Clarence Ip5e2a9222016-06-26 22:38:24 -04001183 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001184}
1185
1186static int sde_plane_prepare_fb(struct drm_plane *plane,
1187 const struct drm_plane_state *new_state)
1188{
1189 struct drm_framebuffer *fb = new_state->fb;
1190 struct sde_plane *psde = to_sde_plane(plane);
1191
1192 if (!new_state->fb)
1193 return 0;
1194
Dhaval Patel47302cf2016-08-18 15:04:28 -07001195 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001196 return msm_framebuffer_prepare(fb, psde->mmu_id);
1197}
1198
1199static void sde_plane_cleanup_fb(struct drm_plane *plane,
1200 const struct drm_plane_state *old_state)
1201{
1202 struct drm_framebuffer *fb = old_state->fb;
1203 struct sde_plane *psde = to_sde_plane(plane);
1204
1205 if (!fb)
1206 return;
1207
Dhaval Patel47302cf2016-08-18 15:04:28 -07001208 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001209 msm_framebuffer_cleanup(fb, psde->mmu_id);
1210}
1211
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001212static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
1213 struct drm_plane_state *state,
1214 struct drm_plane_state *old_state)
1215{
1216 struct sde_plane_state *pstate = to_sde_plane_state(state);
1217
Dhaval Patel47302cf2016-08-18 15:04:28 -07001218 /* no need to check it again */
Clarence Ip282dad62016-09-27 17:07:35 -04001219 if (pstate->dirty == SDE_PLANE_DIRTY_ALL)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001220 return;
1221
Clarence Ip282dad62016-09-27 17:07:35 -04001222 if (!sde_plane_enabled(state) || !sde_plane_enabled(old_state)
1223 || psde->is_error) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001224 SDE_DEBUG("%s: pipe enabling/disabling full modeset required\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001225 psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001226 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001227 } else if (to_sde_plane_state(old_state)->pending) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001228 SDE_DEBUG("%s: still pending\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001229 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001230 } else if (state->src_w != old_state->src_w ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07001231 state->src_h != old_state->src_h ||
1232 state->src_x != old_state->src_x ||
1233 state->src_y != old_state->src_y) {
1234 SDE_DEBUG("%s: src rect updated\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001235 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001236 } else if (state->crtc_w != old_state->crtc_w ||
1237 state->crtc_h != old_state->crtc_h ||
1238 state->crtc_x != old_state->crtc_x ||
1239 state->crtc_y != old_state->crtc_y) {
1240 SDE_DEBUG("%s: crtc rect updated\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001241 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
1242 }
1243
1244 if (!state->fb || !old_state->fb) {
1245 SDE_DEBUG("%s: can't compare fb handles\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001246 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001247 SDE_DEBUG("%s: format change!\n", psde->pipe_name);
Clarence Ip282dad62016-09-27 17:07:35 -04001248 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001249 } else {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001250 uint64_t *new_mods = state->fb->modifier;
1251 uint64_t *old_mods = old_state->fb->modifier;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001252 uint32_t *new_pitches = state->fb->pitches;
1253 uint32_t *old_pitches = old_state->fb->pitches;
1254 uint32_t *new_offset = state->fb->offsets;
1255 uint32_t *old_offset = old_state->fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001256 int i;
1257
1258 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
1259 if (new_mods[i] != old_mods[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001260 SDE_DEBUG("%s: format modifiers change\"\
1261 plane:%d new_mode:%llu old_mode:%llu\n",
1262 psde->pipe_name, i, new_mods[i],
1263 old_mods[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04001264 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
1265 SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001266 break;
1267 }
1268 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001269 for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
1270 if (new_pitches[i] != old_pitches[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001271 SDE_DEBUG("%s: pitches change plane:%d\"\
1272 old_pitches:%u new_pitches:%u\n",
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001273 psde->pipe_name, i, old_pitches[i],
1274 new_pitches[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04001275 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001276 break;
1277 }
1278 }
Dhaval Patel47302cf2016-08-18 15:04:28 -07001279 for (i = 0; i < ARRAY_SIZE(state->fb->offsets); i++) {
1280 if (new_offset[i] != old_offset[i]) {
1281 SDE_DEBUG("%s: offset change plane:%d\"\
1282 old_offset:%u new_offset:%u\n",
1283 psde->pipe_name, i, old_offset[i],
1284 new_offset[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04001285 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
1286 SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001287 break;
1288 }
1289 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001290 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001291}
1292
Dhaval Patel47302cf2016-08-18 15:04:28 -07001293static bool __get_scale_data(struct sde_plane *psde,
1294 struct sde_plane_state *pstate, struct sde_drm_scaler *sc_u,
1295 size_t *sc_u_size)
1296{
1297 bool valid_flag = false;
1298
1299 sc_u = msm_property_get_blob(&psde->property_info,
1300 pstate->property_blobs,
1301 sc_u_size,
1302 PLANE_PROP_SCALER);
1303 if (sc_u) {
1304 switch (sc_u->version) {
1305 case SDE_DRM_SCALER_V1:
1306 if (!_sde_plane_verify_blob(sc_u, *sc_u_size,
1307 &sc_u->v1, sizeof(struct sde_drm_scaler_v1)))
1308 valid_flag = true;
1309 break;
1310 default:
1311 SDE_DEBUG("unrecognized scaler blob v%lld\n",
1312 sc_u->version);
1313 break;
1314 }
1315 }
1316
1317 return valid_flag;
1318}
1319
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001320static int sde_plane_atomic_check(struct drm_plane *plane,
1321 struct drm_plane_state *state)
1322{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001323 int ret = 0, valid_scale_data;
Clarence Ipdbde9832016-06-26 09:48:36 -04001324 struct sde_plane *psde;
1325 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001326 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -04001327 size_t sc_u_size = 0;
1328 struct sde_drm_scaler *sc_u = NULL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001329 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04001330 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001331 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
1332 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04001333
1334 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001335 SDE_ERROR("invalid plane/state\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001336 ret = -EINVAL;
1337 goto exit;
1338 }
1339
1340 psde = to_sde_plane(plane);
1341 pstate = to_sde_plane_state(state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001342
1343 if (!psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001344 SDE_ERROR("invalid plane catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001345 ret = -EINVAL;
1346 goto exit;
1347 }
1348
Dhaval Patel47302cf2016-08-18 15:04:28 -07001349 valid_scale_data = __get_scale_data(psde, pstate, sc_u, &sc_u_size);
1350 deci_w = valid_scale_data && sc_u ? sc_u->v1.horz_decimate : 0;
1351 deci_h = valid_scale_data && sc_u ? sc_u->v1.vert_decimate : 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04001352
1353 /* src values are in Q16 fixed point, convert to integer */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001354 POPULATE_RECT(&src, state->src_x, state->src_y, state->src_w,
1355 state->src_h, q16_data);
1356 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
1357 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04001358
Dhaval Patel47302cf2016-08-18 15:04:28 -07001359 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
1360 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04001361
Dhaval Patel47302cf2016-08-18 15:04:28 -07001362 max_upscale = psde->pipe_sblk->maxupscale;
1363 max_downscale = psde->pipe_sblk->maxdwnscale;
1364 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04001365
Dhaval Patel47302cf2016-08-18 15:04:28 -07001366 SDE_DEBUG("%s: check (%d -> %d)\n", psde->pipe_name,
1367 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001368
Dhaval Patel47302cf2016-08-18 15:04:28 -07001369 if (!sde_plane_enabled(state))
1370 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04001371
Dhaval Patel47302cf2016-08-18 15:04:28 -07001372 fmt = to_sde_format(msm_framebuffer_format(state->fb));
1373
1374 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
1375
1376 if (SDE_FORMAT_IS_YUV(fmt) &&
1377 (!(psde->features & SDE_SSPP_SCALER) ||
1378 !(psde->features & BIT(SDE_SSPP_CSC)))) {
1379 SDE_ERROR("plane doesn't have scaler/csc capability for yuv\n");
1380 ret = -EINVAL;
1381
1382 /* check src bounds */
1383 } else if (state->fb->width > MAX_IMG_WIDTH ||
1384 state->fb->height > MAX_IMG_HEIGHT ||
1385 src.w < min_src_size || src.h < min_src_size ||
1386 CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
1387 CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
1388 SDE_ERROR("invalid source (%u, %u) -> (%u, %u)\n",
1389 src.x, src.y, src.w, src.h);
1390 ret = -E2BIG;
1391
1392 /* valid yuv image */
1393 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
1394 (src.w & 0x1) || (src.h & 0x1))) {
1395 SDE_ERROR("invalid yuv source (%u, %u) -> (%u, %u)\n",
1396 src.x, src.y, src.w, src.h);
1397 ret = -EINVAL;
1398
1399 /* min dst support */
1400 } else if (dst.w < 0x1 || dst.h < 0x1) {
1401 SDE_ERROR("invalid dest rect (%u, %u) -> (%u, %u)\n",
1402 dst.x, dst.y, dst.w, dst.h);
1403 ret = -EINVAL;
1404
1405 /* decimation validation */
1406 } else if (deci_w || deci_h) {
1407 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1408 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1409 SDE_ERROR("too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001410 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001411 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
1412 SDE_ERROR("decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001413 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001414 }
1415
Dhaval Patel47302cf2016-08-18 15:04:28 -07001416 } else if (!(psde->features & SDE_SSPP_SCALER) &&
1417 ((src.w != dst.w) || (src.h != dst.h))) {
1418 SDE_ERROR("pipe doesn't support scaling %ux%u->%ux%u\n",
1419 src.w, src.h, dst.w, dst.h);
1420 ret = -EINVAL;
1421
1422 /* check decimated source width */
1423 } else if (src_deci_w > max_linewidth) {
1424 SDE_ERROR("invalid source width:%u, deci wid:%u, line wid:%u\n",
1425 src.w, src_deci_w, max_linewidth);
1426 ret = -E2BIG;
1427
1428 /* check max scaler capability */
1429 } else if (((src_deci_w * max_upscale) < dst.w) ||
1430 ((src_deci_h * max_upscale) < dst.h) ||
1431 ((dst.w * max_downscale) < src_deci_w) ||
1432 ((dst.h * max_downscale) < src_deci_h)) {
1433 SDE_ERROR("too much scaling requested %ux%u -> %ux%u\n",
1434 src_deci_w, src_deci_h, dst.w, dst.h);
1435 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001436 }
1437
Dhaval Patel47302cf2016-08-18 15:04:28 -07001438modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001439 if (!ret)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001440 _sde_plane_atomic_check_mode_changed(psde, state, plane->state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001441exit:
1442 return ret;
1443}
1444
Clarence Ipcae1bb62016-07-07 12:07:13 -04001445/**
1446 * sde_plane_flush - final plane operations before commit flush
1447 * @plane: Pointer to drm plane structure
1448 */
1449void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001450{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001451 struct sde_plane *psde;
1452
1453 if (!plane)
1454 return;
1455
1456 psde = to_sde_plane(plane);
1457
1458 /*
1459 * These updates have to be done immediately before the plane flush
1460 * timing, and may not be moved to the atomic_update/mode_set functions.
1461 */
1462 if (psde->is_error)
1463 /* force white frame with 0% alpha pipe output on error */
1464 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1465 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1466 /* force 100% alpha */
1467 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1468 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1469 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1470
1471 /* flag h/w flush complete */
1472 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001473 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001474}
1475
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001476static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001477 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001478{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001479 struct sde_plane *sde_plane;
1480 struct drm_plane_state *state;
1481 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001482
Clarence Ip5e2a9222016-06-26 22:38:24 -04001483 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001484 SDE_ERROR("invalid plane/state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001485 return;
1486 }
1487
1488 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001489 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001490 state = plane->state;
1491 pstate = to_sde_plane_state(state);
1492
Dhaval Patel47302cf2016-08-18 15:04:28 -07001493 SDE_DEBUG("%s: update\n", sde_plane->pipe_name);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001494
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001495 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001496 pstate->pending = true;
Clarence Ip282dad62016-09-27 17:07:35 -04001497 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001498 int ret;
1499
Dhaval Patel47302cf2016-08-18 15:04:28 -07001500 ret = _sde_plane_mode_set(plane, state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001501 /* atomic_check should have ensured that this doesn't fail */
1502 WARN_ON(ret < 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001503 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001504}
1505
Dhaval Patel47302cf2016-08-18 15:04:28 -07001506
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001507/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001508static void _sde_plane_install_properties(struct drm_plane *plane,
1509 u32 max_blendstages)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001510{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001511 static const struct drm_prop_enum_list e_blend_op[] = {
1512 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1513 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1514 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1515 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1516 };
1517 static const struct drm_prop_enum_list e_src_config[] = {
1518 {SDE_DRM_DEINTERLACE, "deinterlace"}
1519 };
Clarence Ipea3d6262016-07-15 16:20:11 -04001520 const struct sde_format_extended *format_list;
Dhaval Patel4e574842016-08-23 15:11:37 -07001521 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001522 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001523
Clarence Ipaa0faf42016-05-30 12:07:48 -04001524 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001525 SDE_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001526 return;
1527 }
1528
Dhaval Patel47302cf2016-08-18 15:04:28 -07001529 msm_property_install_range(&psde->property_info, "zpos", 0x0, 0,
Dhaval Patel48c76022016-09-01 17:51:23 -07001530 max_blendstages, SDE_STAGE_BASE, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001531
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001532 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07001533 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001534
Dhaval Patel47302cf2016-08-18 15:04:28 -07001535 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001536 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07001537 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001538
Clarence Ip5fc00c52016-09-23 15:03:34 -04001539 if (psde->features & BIT(SDE_SSPP_CSC)) {
1540 msm_property_install_volatile_range(&psde->property_info,
1541 "csc_v1", 0x0, 0, ~0, 0, PLANE_PROP_CSC_V1);
1542 }
1543
Clarence Ip5e2a9222016-06-26 22:38:24 -04001544 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001545 msm_property_install_rotation(&psde->property_info,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001546 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y), PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001547
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001548 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001549 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001550
Dhaval Patel47302cf2016-08-18 15:04:28 -07001551 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
1552 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
1553
1554 if (psde->pipe_hw->ops.setup_solidfill)
1555 msm_property_install_range(&psde->property_info, "color_fill",
1556 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
1557
Clarence Ip4c1d9772016-06-26 09:35:38 -04001558 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001559 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001560 PLANE_PROP_SCALER);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001561
Dhaval Patel4e574842016-08-23 15:11:37 -07001562 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
1563 if (!info)
1564 return;
1565
1566 msm_property_install_blob(&psde->property_info, "capabilities",
1567 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
1568 sde_kms_info_reset(info);
1569
Clarence Ipea3d6262016-07-15 16:20:11 -04001570 format_list = psde->pipe_sblk->format_list;
1571 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04001572 sde_kms_info_start(info, "pixel_formats");
1573 while (format_list->fourcc_format) {
1574 sde_kms_info_append_format(info,
1575 format_list->fourcc_format,
1576 format_list->modifier);
1577 ++format_list;
1578 }
1579 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04001580 }
Dhaval Patel4e574842016-08-23 15:11:37 -07001581
1582 sde_kms_info_add_keyint(info, "max_linewidth",
1583 psde->pipe_sblk->maxlinewidth);
1584 sde_kms_info_add_keyint(info, "max_upscale",
1585 psde->pipe_sblk->maxupscale);
1586 sde_kms_info_add_keyint(info, "max_downscale",
1587 psde->pipe_sblk->maxdwnscale);
1588 sde_kms_info_add_keyint(info, "max_horizontal_deci",
1589 psde->pipe_sblk->maxhdeciexp);
1590 sde_kms_info_add_keyint(info, "max_vertical_deci",
1591 psde->pipe_sblk->maxvdeciexp);
1592 msm_property_set_blob(&psde->property_info, &psde->blob_info,
1593 info->data, info->len, PLANE_PROP_INFO);
1594
1595 kfree(info);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001596}
1597
Clarence Ip5fc00c52016-09-23 15:03:34 -04001598static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr)
1599{
1600 struct sde_drm_csc_v1 csc_v1;
1601 int i;
1602
1603 if (!psde) {
1604 SDE_ERROR("invalid plane\n");
1605 return;
1606 }
1607
1608 psde->csc_usr_ptr = NULL;
1609 if (!usr_ptr) {
1610 SDE_DEBUG("csc data removed\n");
1611 return;
1612 }
1613
1614 if (copy_from_user(&csc_v1, usr_ptr, sizeof(csc_v1))) {
1615 SDE_ERROR("failed to copy csc data\n");
1616 return;
1617 }
1618
1619 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
1620 psde->csc_cfg.csc_mv[i] = csc_v1.ctm_coeff[i] >> 16;
1621 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
1622 psde->csc_cfg.csc_pre_bv[i] = csc_v1.pre_bias[i];
1623 psde->csc_cfg.csc_post_bv[i] = csc_v1.post_bias[i];
1624 }
1625 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
1626 psde->csc_cfg.csc_pre_lv[i] = csc_v1.pre_clamp[i];
1627 psde->csc_cfg.csc_post_lv[i] = csc_v1.post_clamp[i];
1628 }
1629 psde->csc_usr_ptr = &psde->csc_cfg;
1630}
1631
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001632static int sde_plane_atomic_set_property(struct drm_plane *plane,
1633 struct drm_plane_state *state, struct drm_property *property,
1634 uint64_t val)
1635{
Clarence Ip730e7192016-06-26 22:45:09 -04001636 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001637 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001638 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001639
Clarence Ipaa0faf42016-05-30 12:07:48 -04001640 DBG("");
1641
1642 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001643 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001644 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001645 SDE_ERROR("invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001646 } else {
1647 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001648 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001649 ret = msm_property_atomic_set(&psde->property_info,
1650 pstate->property_values, pstate->property_blobs,
1651 property, val);
1652 if (!ret) {
1653 idx = msm_property_index(&psde->property_info,
1654 property);
Clarence Ip5fc00c52016-09-23 15:03:34 -04001655 switch (idx) {
1656 case PLANE_PROP_INPUT_FENCE:
Clarence Ipcae1bb62016-07-07 12:07:13 -04001657 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ip5fc00c52016-09-23 15:03:34 -04001658 break;
1659 case PLANE_PROP_CSC_V1:
1660 _sde_plane_set_csc_v1(psde, (void *)val);
1661 break;
1662 default:
1663 /* nothing to do */
1664 break;
1665 }
Clarence Ipe78efb72016-06-24 18:35:21 -04001666 }
1667 }
1668
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001669 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001670}
1671
1672static int sde_plane_set_property(struct drm_plane *plane,
1673 struct drm_property *property, uint64_t val)
1674{
Clarence Ip4ce59322016-06-26 22:27:51 -04001675 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001676
Clarence Ipae4e60c2016-06-26 22:44:04 -04001677 return sde_plane_atomic_set_property(plane,
1678 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001679}
1680
1681static int sde_plane_atomic_get_property(struct drm_plane *plane,
1682 const struct drm_plane_state *state,
1683 struct drm_property *property, uint64_t *val)
1684{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001685 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001686 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001687 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001688
Clarence Ipaa0faf42016-05-30 12:07:48 -04001689 DBG("");
1690
1691 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001692 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001693 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001694 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001695 } else {
1696 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001697 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001698 ret = msm_property_atomic_get(&psde->property_info,
1699 pstate->property_values, pstate->property_blobs,
1700 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001701 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001702
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001703 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001704}
1705
1706static void sde_plane_destroy(struct drm_plane *plane)
1707{
Clarence Ip4ce59322016-06-26 22:27:51 -04001708 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001709
Clarence Ip4ce59322016-06-26 22:27:51 -04001710 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001711
Clarence Ip4ce59322016-06-26 22:27:51 -04001712 if (plane) {
1713 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001714
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001715 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1716
Clarence Ip4ce59322016-06-26 22:27:51 -04001717 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001718
Dhaval Patel4e574842016-08-23 15:11:37 -07001719 if (psde->blob_info)
1720 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001721 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001722 mutex_destroy(&psde->lock);
1723
Clarence Ip4ce59322016-06-26 22:27:51 -04001724 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001725
Clarence Ip4ce59322016-06-26 22:27:51 -04001726 /* this will destroy the states as well */
1727 drm_plane_cleanup(plane);
1728
Clarence Ip4c1d9772016-06-26 09:35:38 -04001729 if (psde->pipe_hw)
1730 sde_hw_sspp_destroy(psde->pipe_hw);
1731
Clarence Ip4ce59322016-06-26 22:27:51 -04001732 kfree(psde);
1733 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001734}
1735
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001736static void sde_plane_destroy_state(struct drm_plane *plane,
1737 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001738{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001739 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001740 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001741
Clarence Ipae4e60c2016-06-26 22:44:04 -04001742 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001743 SDE_ERROR("invalid plane/state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001744 return;
1745 }
1746
Clarence Ipaa0faf42016-05-30 12:07:48 -04001747 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001748 pstate = to_sde_plane_state(state);
1749
1750 DBG("");
1751
Clarence Ipe78efb72016-06-24 18:35:21 -04001752 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001753 if (state->fb)
1754 drm_framebuffer_unreference(state->fb);
1755
Clarence Ipae4e60c2016-06-26 22:44:04 -04001756 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001757 if (pstate->input_fence)
1758 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001759
Clarence Ipaa0faf42016-05-30 12:07:48 -04001760 /* destroy value helper */
1761 msm_property_destroy_state(&psde->property_info, pstate,
1762 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001763}
1764
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001765static struct drm_plane_state *
1766sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001767{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001768 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001769 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001770 struct sde_plane_state *old_state;
Clarence Ip17e908b2016-09-29 15:58:00 -04001771 uint64_t input_fence_default;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001772
Clarence Ip730e7192016-06-26 22:45:09 -04001773 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001774 return NULL;
1775
Clarence Ip730e7192016-06-26 22:45:09 -04001776 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001777 psde = to_sde_plane(plane);
1778 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001779 if (!pstate)
1780 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001781
Clarence Ipaa0faf42016-05-30 12:07:48 -04001782 DBG("");
1783
1784 /* duplicate value helper */
1785 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1786 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001787
Clarence Ip730e7192016-06-26 22:45:09 -04001788 /* add ref count for frame buffer */
1789 if (pstate->base.fb)
1790 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001791
Clarence Ip17e908b2016-09-29 15:58:00 -04001792 /* clear out any input fence */
1793 pstate->input_fence = 0;
1794 input_fence_default = msm_property_get_default(
1795 &psde->property_info, PLANE_PROP_INPUT_FENCE);
1796 msm_property_set_property(&psde->property_info, pstate->property_values,
1797 PLANE_PROP_INPUT_FENCE, input_fence_default);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001798
Clarence Ip282dad62016-09-27 17:07:35 -04001799 pstate->dirty = 0x0;
Clarence Ip730e7192016-06-26 22:45:09 -04001800 pstate->pending = false;
1801
1802 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001803}
1804
1805static void sde_plane_reset(struct drm_plane *plane)
1806{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001807 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001808 struct sde_plane_state *pstate;
1809
Clarence Ipae4e60c2016-06-26 22:44:04 -04001810 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001811 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001812 return;
1813 }
1814
Clarence Ip730e7192016-06-26 22:45:09 -04001815 psde = to_sde_plane(plane);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001816 SDE_DEBUG("%s\n", psde->pipe_name);
Clarence Ip730e7192016-06-26 22:45:09 -04001817
Clarence Ipae4e60c2016-06-26 22:44:04 -04001818 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001819 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001820 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001821 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001822 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001823
Clarence Ipaa0faf42016-05-30 12:07:48 -04001824 pstate = msm_property_alloc_state(&psde->property_info);
1825 if (!pstate)
1826 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001827
Clarence Ipaa0faf42016-05-30 12:07:48 -04001828 /* reset value helper */
1829 msm_property_reset_state(&psde->property_info, pstate,
1830 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001831
1832 pstate->base.plane = plane;
1833
1834 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001835}
1836
1837static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001838 .update_plane = drm_atomic_helper_update_plane,
1839 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001840 .destroy = sde_plane_destroy,
1841 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001842 .atomic_set_property = sde_plane_atomic_set_property,
1843 .atomic_get_property = sde_plane_atomic_get_property,
1844 .reset = sde_plane_reset,
1845 .atomic_duplicate_state = sde_plane_duplicate_state,
1846 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001847};
1848
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001849static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1850 .prepare_fb = sde_plane_prepare_fb,
1851 .cleanup_fb = sde_plane_cleanup_fb,
1852 .atomic_check = sde_plane_atomic_check,
1853 .atomic_update = sde_plane_atomic_update,
1854};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001855
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001856enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001857{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001858 struct sde_plane *sde_plane = to_sde_plane(plane);
1859
1860 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001861}
1862
Clarence Ip4ce59322016-06-26 22:27:51 -04001863static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1864{
1865 const struct sde_sspp_sub_blks *sblk = 0;
1866 const struct sde_sspp_cfg *cfg = 0;
1867
1868 if (psde && psde->pipe_hw)
1869 cfg = psde->pipe_hw->cap;
1870 if (cfg)
1871 sblk = cfg->sblk;
1872
1873 if (kms && sblk) {
1874 /* create overall sub-directory for the pipe */
1875 psde->debugfs_root =
1876 debugfs_create_dir(psde->pipe_name,
1877 sde_debugfs_get_root(kms));
1878 if (psde->debugfs_root) {
1879 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001880 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001881 psde->debugfs_root, &psde->features);
1882
1883 /* add register dump support */
1884 sde_debugfs_setup_regset32(&psde->debugfs_src,
1885 sblk->src_blk.base + cfg->base,
1886 sblk->src_blk.len,
Clarence Ipaac9f332016-08-31 15:46:35 -04001887 kms);
Clarence Ip4ce59322016-06-26 22:27:51 -04001888 sde_debugfs_create_regset32("src_blk", 0444,
1889 psde->debugfs_root, &psde->debugfs_src);
1890
1891 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1892 sblk->scaler_blk.base + cfg->base,
1893 sblk->scaler_blk.len,
Clarence Ipaac9f332016-08-31 15:46:35 -04001894 kms);
Clarence Ip4ce59322016-06-26 22:27:51 -04001895 sde_debugfs_create_regset32("scaler_blk", 0444,
1896 psde->debugfs_root,
1897 &psde->debugfs_scaler);
1898
1899 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1900 sblk->csc_blk.base + cfg->base,
1901 sblk->csc_blk.len,
Clarence Ipaac9f332016-08-31 15:46:35 -04001902 kms);
Clarence Ip4ce59322016-06-26 22:27:51 -04001903 sde_debugfs_create_regset32("csc_blk", 0444,
1904 psde->debugfs_root, &psde->debugfs_csc);
1905 }
1906 }
1907}
1908
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001909/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001910struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001911 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001912{
1913 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001914 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001915 struct msm_drm_private *priv;
1916 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001917 enum drm_plane_type type;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001918 int ret = -EINVAL, max_blendstages = 255;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001919
1920 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001921 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001922 goto exit;
1923 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001924
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001925 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001926 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001927 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001928 goto exit;
1929 }
1930
1931 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001932 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001933 goto exit;
1934 }
1935 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001936
Clarence Ip4c1d9772016-06-26 09:35:38 -04001937 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001938 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001939 goto exit;
1940 }
1941
Clarence Ip4ce59322016-06-26 22:27:51 -04001942 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001943 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1944 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001945 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001946 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001947 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001948 }
1949
Clarence Ip4c1d9772016-06-26 09:35:38 -04001950 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001951 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001952 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04001953 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001954
Clarence Ip4c1d9772016-06-26 09:35:38 -04001955 /* initialize underlying h/w driver */
1956 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1957 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001958 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001959 ret = PTR_ERR(psde->pipe_hw);
1960 goto clean_plane;
1961 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001962 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001963 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001964 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001965
1966 /* cache features mask for later */
1967 psde->features = psde->pipe_hw->cap->features;
1968 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04001969 if (!psde->pipe_sblk) {
1970 SDE_ERROR("invalid sblk on pipe %d\n", pipe);
1971 goto clean_sspp;
1972 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001973
Dhaval Patel47302cf2016-08-18 15:04:28 -07001974 if (kms->catalog && kms->catalog->mixer_count && kms->catalog->mixer)
1975 max_blendstages = kms->catalog->mixer[0].sblk->maxblendstages;
1976
Clarence Ip4c1d9772016-06-26 09:35:38 -04001977 /* add plane to DRM framework */
Clarence Ipea3d6262016-07-15 16:20:11 -04001978 psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
1979 psde->formats,
1980 0,
1981 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001982
Clarence Ip4c1d9772016-06-26 09:35:38 -04001983 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001984 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001985 goto clean_sspp;
1986 }
1987
1988 if (psde->features & BIT(SDE_SSPP_CURSOR))
1989 type = DRM_PLANE_TYPE_CURSOR;
1990 else if (primary_plane)
1991 type = DRM_PLANE_TYPE_PRIMARY;
1992 else
1993 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001994 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1995 psde->formats, psde->nformats,
1996 type);
1997 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001998 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001999
Clarence Ip4c1d9772016-06-26 09:35:38 -04002000 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002001 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002002
Clarence Ipaa0faf42016-05-30 12:07:48 -04002003 msm_property_init(&psde->property_info, &plane->base, dev,
2004 priv->plane_property, psde->property_data,
2005 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
2006 sizeof(struct sde_plane_state));
2007
Dhaval Patel47302cf2016-08-18 15:04:28 -07002008 _sde_plane_install_properties(plane, max_blendstages);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002009
Clarence Ip4ce59322016-06-26 22:27:51 -04002010 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04002011 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04002012
Clarence Ip730e7192016-06-26 22:45:09 -04002013 mutex_init(&psde->lock);
2014
Clarence Ip4ce59322016-06-26 22:27:51 -04002015 _sde_plane_init_debugfs(psde, kms);
2016
Dhaval Patel47302cf2016-08-18 15:04:28 -07002017 DRM_INFO("[%u]successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002018 return plane;
2019
Clarence Ip4c1d9772016-06-26 09:35:38 -04002020clean_sspp:
2021 if (psde && psde->pipe_hw)
2022 sde_hw_sspp_destroy(psde->pipe_hw);
2023clean_plane:
2024 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04002025exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002026 return ERR_PTR(ret);
2027}