blob: 421d031c923cb6e021acb8d34849ecb3be4f13af [file] [log] [blame]
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Alan Kwong1a00e4d2016-07-18 09:42:30 -040012
13#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
14
Clarence Ip4ce59322016-06-26 22:27:51 -040015#include <linux/debugfs.h>
Clarence Ip5e2a9222016-06-26 22:38:24 -040016#include <uapi/drm/sde_drm.h>
Clarence Ipaa0faf42016-05-30 12:07:48 -040017
18#include "msm_prop.h"
19
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070020#include "sde_kms.h"
Clarence Ipae4e60c2016-06-26 22:44:04 -040021#include "sde_fence.h"
Clarence Ipc475b082016-06-26 09:27:23 -040022#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040023#include "sde_hw_sspp.h"
Alan Kwong1a00e4d2016-07-18 09:42:30 -040024#include "sde_trace.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040025
26#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
27#define PHASE_STEP_SHIFT 21
28#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
29#define PHASE_RESIDUAL 15
30
Clarence Ipe78efb72016-06-24 18:35:21 -040031#define SHARP_STRENGTH_DEFAULT 32
32#define SHARP_EDGE_THR_DEFAULT 112
33#define SHARP_SMOOTH_THR_DEFAULT 8
34#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040035
Clarence Ip5e2a9222016-06-26 22:38:24 -040036#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070037
Clarence Ipcae1bb62016-07-07 12:07:13 -040038#define SDE_PLANE_COLOR_FILL_FLAG BIT(31)
39
Alan Kwong1a00e4d2016-07-18 09:42:30 -040040/**
41 * enum sde_plane_qos - Different qos configurations for each pipe
42 *
43 * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
44 * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
45 * this configuration is mutually exclusive from VBLANK_CTRL.
46 * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
47 */
48enum sde_plane_qos {
49 SDE_PLANE_QOS_VBLANK_CTRL = BIT(0),
50 SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
51 SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
52};
53
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070054struct sde_plane {
55 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040056
57 int mmu_id;
58
Clarence Ip730e7192016-06-26 22:45:09 -040059 struct mutex lock;
60
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040061 enum sde_sspp pipe;
62 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070063 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -040064 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040065
66 struct sde_hw_pipe *pipe_hw;
67 struct sde_hw_pipe_cfg pipe_cfg;
68 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040069 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040070 struct sde_hw_scaler3_cfg scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040071 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -040072 uint32_t color_fill;
73 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040074 bool is_rt_pipe;
Clarence Ip4ce59322016-06-26 22:27:51 -040075
Clarence Ip373f8592016-05-26 00:58:42 -040076 struct sde_csc_cfg csc_cfg;
77 struct sde_csc_cfg *csc_ptr;
78
Clarence Ip4c1d9772016-06-26 09:35:38 -040079 const struct sde_sspp_sub_blks *pipe_sblk;
80
Clarence Ip5e2a9222016-06-26 22:38:24 -040081 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040082
Clarence Ipaa0faf42016-05-30 12:07:48 -040083 struct msm_property_info property_info;
84 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -070085 struct drm_property_blob *blob_info;
Clarence Ip730e7192016-06-26 22:45:09 -040086
Clarence Ip4ce59322016-06-26 22:27:51 -040087 /* debugfs related stuff */
88 struct dentry *debugfs_root;
89 struct sde_debugfs_regset32 debugfs_src;
90 struct sde_debugfs_regset32 debugfs_scaler;
91 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070092};
Dhaval Patel47302cf2016-08-18 15:04:28 -070093
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070094#define to_sde_plane(x) container_of(x, struct sde_plane, base)
95
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040096static bool sde_plane_enabled(struct drm_plane_state *state)
97{
Clarence Ipdbde9832016-06-26 09:48:36 -040098 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040099}
100
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400101/**
102 * _sde_plane_calc_fill_level - calculate fill level of the given source format
103 * @plane: Pointer to drm plane
104 * @fmt: Pointer to source buffer format
105 * @src_wdith: width of source buffer
106 * Return: fill level corresponding to the source buffer/format or 0 if error
107 */
108static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
109 const struct sde_format *fmt, u32 src_width)
110{
111 struct sde_plane *psde;
112 u32 fixed_buff_size;
113 u32 total_fl;
114
115 if (!plane || !fmt) {
116 SDE_ERROR("invalid arguments\n");
117 return 0;
118 }
119
120 psde = to_sde_plane(plane);
121 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
122
123 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
124 if (fmt->chroma_sample == SDE_CHROMA_420) {
125 /* NV12 */
126 total_fl = (fixed_buff_size / 2) /
127 ((src_width + 32) * fmt->bpp);
128 } else {
129 /* non NV12 */
130 total_fl = (fixed_buff_size) /
131 ((src_width + 32) * fmt->bpp);
132 }
133 } else {
134 total_fl = (fixed_buff_size * 2) /
135 ((src_width + 32) * fmt->bpp);
136 }
137
138 SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
139 plane->base.id, psde->pipe - SSPP_VIG0,
140 fmt->base.pixel_format, src_width, total_fl);
141
142 return total_fl;
143}
144
145/**
146 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
147 * @total_fl: fill level
148 * Return: LUT setting corresponding to the fill level
149 */
150static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
151{
152 u32 qos_lut;
153
154 if (total_fl <= 4)
155 qos_lut = 0x1B;
156 else if (total_fl <= 5)
157 qos_lut = 0x5B;
158 else if (total_fl <= 6)
159 qos_lut = 0x15B;
160 else if (total_fl <= 7)
161 qos_lut = 0x55B;
162 else if (total_fl <= 8)
163 qos_lut = 0x155B;
164 else if (total_fl <= 9)
165 qos_lut = 0x555B;
166 else if (total_fl <= 10)
167 qos_lut = 0x1555B;
168 else if (total_fl <= 11)
169 qos_lut = 0x5555B;
170 else if (total_fl <= 12)
171 qos_lut = 0x15555B;
172 else
173 qos_lut = 0x55555B;
174
175 return qos_lut;
176}
177
178/**
179 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
180 * @total_fl: fill level
181 * Return: LUT setting corresponding to the fill level
182 */
183static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
184{
185 u32 qos_lut;
186
187 if (total_fl <= 10)
188 qos_lut = 0x1AAff;
189 else if (total_fl <= 11)
190 qos_lut = 0x5AAFF;
191 else if (total_fl <= 12)
192 qos_lut = 0x15AAFF;
193 else
194 qos_lut = 0x55AAFF;
195
196 return qos_lut;
197}
198
199/**
200 * _sde_plane_is_rt_pipe - check if the given plane requires real-time QoS
201 * @plane: Pointer to drm plane
202 * @crtc: Pointer to drm crtc associated with the given plane
203 */
204static bool _sde_plane_is_rt_pipe(struct drm_plane *plane,
205 struct drm_crtc *crtc)
206{
207 struct sde_plane *psde = to_sde_plane(plane);
208 struct drm_connector *connector;
209 bool is_rt = false;
210
211 /* check if this plane has a physical connector interface */
212 drm_for_each_connector(connector, plane->dev)
213 if (connector->state &&
214 (connector->state->crtc == crtc) &&
215 (connector->connector_type
216 != DRM_MODE_CONNECTOR_VIRTUAL)) {
217 is_rt = true;
218 break;
219 }
220
221 SDE_DEBUG("plane%u: pnum:%d rt:%d\n",
222 plane->base.id, psde->pipe - SSPP_VIG0, is_rt);
223
224 return is_rt;
225}
226
227/**
228 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
229 * @plane: Pointer to drm plane
230 * @fb: Pointer to framebuffer associated with the given plane
231 */
232static void _sde_plane_set_qos_lut(struct drm_plane *plane,
233 struct drm_framebuffer *fb)
234{
235 struct sde_plane *psde;
236 const struct sde_format *fmt = NULL;
237 u32 qos_lut;
238 u32 total_fl = 0;
239
240 if (!plane || !fb) {
241 SDE_ERROR("invalid arguments plane %d fb %d\n",
242 plane != 0, fb != 0);
243 return;
244 }
245
246 psde = to_sde_plane(plane);
247
248 if (!psde->pipe_hw || !psde->pipe_sblk) {
249 SDE_ERROR("invalid arguments\n");
250 return;
251 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
252 return;
253 }
254
255 if (!psde->is_rt_pipe) {
256 qos_lut = psde->pipe_sblk->creq_lut_nrt;
257 } else {
258 fmt = sde_get_sde_format_ext(
259 fb->pixel_format,
260 fb->modifier,
261 drm_format_num_planes(fb->pixel_format));
262 total_fl = _sde_plane_calc_fill_level(plane, fmt,
263 psde->pipe_cfg.src_rect.w);
264
265 if (SDE_FORMAT_IS_LINEAR(fmt))
266 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
267 else
268 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
269 }
270
271 psde->pipe_qos_cfg.creq_lut = qos_lut;
272
273 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
274 (fmt) ? fmt->base.pixel_format : 0,
275 psde->is_rt_pipe, total_fl, qos_lut,
276 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
277
278 SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
279 plane->base.id,
280 psde->pipe - SSPP_VIG0,
281 (fmt) ? fmt->base.pixel_format : 0,
282 psde->is_rt_pipe, total_fl, qos_lut);
283
284 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
285}
286
287/**
288 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
289 * @plane: Pointer to drm plane
290 * @fb: Pointer to framebuffer associated with the given plane
291 */
292static void _sde_plane_set_danger_lut(struct drm_plane *plane,
293 struct drm_framebuffer *fb)
294{
295 struct sde_plane *psde;
296 const struct sde_format *fmt = NULL;
297 u32 danger_lut, safe_lut;
298
299 if (!plane || !fb) {
300 SDE_ERROR("invalid arguments\n");
301 return;
302 }
303
304 psde = to_sde_plane(plane);
305
306 if (!psde->pipe_hw || !psde->pipe_sblk) {
307 SDE_ERROR("invalid arguments\n");
308 return;
309 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
310 return;
311 }
312
313 if (!psde->is_rt_pipe) {
314 danger_lut = psde->pipe_sblk->danger_lut_nrt;
315 safe_lut = psde->pipe_sblk->safe_lut_nrt;
316 } else {
317 fmt = sde_get_sde_format_ext(
318 fb->pixel_format,
319 fb->modifier,
320 drm_format_num_planes(fb->pixel_format));
321
322 if (SDE_FORMAT_IS_LINEAR(fmt)) {
323 danger_lut = psde->pipe_sblk->danger_lut_linear;
324 safe_lut = psde->pipe_sblk->safe_lut_linear;
325 } else {
326 danger_lut = psde->pipe_sblk->danger_lut_tile;
327 safe_lut = psde->pipe_sblk->safe_lut_tile;
328 }
329 }
330
331 psde->pipe_qos_cfg.danger_lut = danger_lut;
332 psde->pipe_qos_cfg.safe_lut = safe_lut;
333
334 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
335 (fmt) ? fmt->base.pixel_format : 0,
336 (fmt) ? fmt->fetch_mode : 0,
337 psde->pipe_qos_cfg.danger_lut,
338 psde->pipe_qos_cfg.safe_lut);
339
340 SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
341 plane->base.id,
342 psde->pipe - SSPP_VIG0,
343 fmt ? fmt->base.pixel_format : 0,
344 fmt ? fmt->fetch_mode : -1,
345 psde->pipe_qos_cfg.danger_lut,
346 psde->pipe_qos_cfg.safe_lut);
347
348 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
349 &psde->pipe_qos_cfg);
350}
351
352/**
353 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
354 * @plane: Pointer to drm plane
355 * @enable: true to enable QoS control
356 * @flags: QoS control mode (enum sde_plane_qos)
357 */
358static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
359 bool enable, u32 flags)
360{
361 struct sde_plane *psde;
362
363 if (!plane) {
364 SDE_ERROR("invalid arguments\n");
365 return;
366 }
367
368 psde = to_sde_plane(plane);
369
370 if (!psde->pipe_hw || !psde->pipe_sblk) {
371 SDE_ERROR("invalid arguments\n");
372 return;
373 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
374 return;
375 }
376
377 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
378 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
379 psde->pipe_qos_cfg.danger_vblank =
380 psde->pipe_sblk->danger_vblank;
381 psde->pipe_qos_cfg.vblank_en = enable;
382 }
383
384 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
385 /* this feature overrules previous VBLANK_CTRL */
386 psde->pipe_qos_cfg.vblank_en = false;
387 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
388 }
389
390 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
391 psde->pipe_qos_cfg.danger_safe_en = enable;
392
393 if (!psde->is_rt_pipe) {
394 psde->pipe_qos_cfg.vblank_en = false;
395 psde->pipe_qos_cfg.danger_safe_en = false;
396 }
397
398 SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x]\n",
399 plane->base.id,
400 psde->pipe - SSPP_VIG0,
401 psde->pipe_qos_cfg.danger_safe_en,
402 psde->pipe_qos_cfg.vblank_en,
403 psde->pipe_qos_cfg.creq_vblank,
404 psde->pipe_qos_cfg.danger_vblank);
405
406 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
407 &psde->pipe_qos_cfg);
408}
409
Alan Kwong5d324e42016-07-28 22:56:18 -0400410/**
411 * _sde_plane_set_ot_limit - set OT limit for the given plane
412 * @plane: Pointer to drm plane
413 * @crtc: Pointer to drm crtc
414 */
415static void _sde_plane_set_ot_limit(struct drm_plane *plane,
416 struct drm_crtc *crtc)
417{
418 struct sde_plane *psde;
419 struct sde_vbif_set_ot_params ot_params;
420 struct msm_drm_private *priv;
421 struct sde_kms *sde_kms;
422
423 if (!plane || !plane->dev || !crtc) {
424 SDE_ERROR("invalid arguments plane %d crtc %d\n",
425 plane != 0, crtc != 0);
426 return;
427 }
428
429 priv = plane->dev->dev_private;
430 if (!priv || !priv->kms) {
431 SDE_ERROR("invalid KMS reference\n");
432 return;
433 }
434
435 sde_kms = to_sde_kms(priv->kms);
436 psde = to_sde_plane(plane);
437 if (!psde->pipe_hw) {
438 SDE_ERROR("invalid pipe reference\n");
439 return;
440 }
441
442 memset(&ot_params, 0, sizeof(ot_params));
443 ot_params.xin_id = psde->pipe_hw->cap->xin_id;
444 ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
445 ot_params.width = psde->pipe_cfg.src_rect.w;
446 ot_params.height = psde->pipe_cfg.src_rect.h;
447 ot_params.is_wfd = !psde->is_rt_pipe;
448 ot_params.frame_rate = crtc->mode.vrefresh;
449 ot_params.vbif_idx = VBIF_RT;
450 ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
451 ot_params.rd = true;
452
453 sde_vbif_set_ot_limit(sde_kms, &ot_params);
454}
455
Clarence Ipcae1bb62016-07-07 12:07:13 -0400456/* helper to update a state's input fence pointer from the property */
457static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400458 struct sde_plane_state *pstate, uint64_t fd)
459{
460 if (!plane || !pstate)
461 return;
462
463 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400464 if (pstate->input_fence)
465 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400466
467 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400468 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400469
Dhaval Patel47302cf2016-08-18 15:04:28 -0700470 SDE_DEBUG("0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400471}
472
Clarence Ipcae1bb62016-07-07 12:07:13 -0400473int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400474{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400475 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400476 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400477 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400478 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400479
480 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700481 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400482 } else if (!plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700483 SDE_ERROR("invalid plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400484 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400485 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400486 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400487 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400488
Clarence Ipcae1bb62016-07-07 12:07:13 -0400489 if (input_fence) {
490 ret = sde_sync_wait(input_fence, wait_ms);
491 switch (ret) {
492 case 0:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700493 SDE_DEBUG("%s signaled\n", psde->pipe_name);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400494 break;
495 case -ETIME:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700496 SDE_ERROR("timeout on %s, %ums\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400497 psde->pipe_name, wait_ms);
498 psde->is_error = true;
499 break;
500 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700501 SDE_ERROR("error on %s, %d\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400502 psde->pipe_name, ret);
503 psde->is_error = true;
504 break;
505 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400506 } else {
507 ret = 0;
508 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400509 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400510 return ret;
511}
512
Clarence Ipe78efb72016-06-24 18:35:21 -0400513static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400514 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400515 struct sde_hw_pipe_cfg *pipe_cfg,
516 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400517{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400518 struct sde_plane *psde;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400519 int ret, i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400520
Clarence Ipae4e60c2016-06-26 22:44:04 -0400521 if (!plane || !pstate || !pipe_cfg || !fb)
522 return;
523
524 psde = to_sde_plane(plane);
525
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400526 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
527 if (ret) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700528 SDE_ERROR("failed to get format layout, error: %d\n", ret);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400529 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400530 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400531
532 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
533 BIT(SDE_DRM_DEINTERLACE))
534 for (i = 0; i < SDE_MAX_PLANES; ++i)
535 pipe_cfg->layout.plane_pitch[i] <<= 1;
536
537 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
538 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400539}
540
Clarence Ipcb410d42016-06-26 22:52:33 -0400541static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400542 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
543 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400544 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400545 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
546{
547}
548
Clarence Ipcb410d42016-06-26 22:52:33 -0400549/**
550 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
551 * @psde: Pointer to SDE plane object
552 * @src: Source size
553 * @dst: Destination size
554 * @phase_steps: Pointer to output array for phase steps
555 * @filter: Pointer to output array for filter type
556 * @fmt: Pointer to format definition
557 * @chroma_subsampling: Subsampling amount for chroma channel
558 *
559 * Returns: 0 on success
560 */
561static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400562 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400563 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400564 uint32_t chroma_subsampling)
565{
Clarence Ipcb410d42016-06-26 22:52:33 -0400566 if (!psde || !phase_steps || !filter || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700567 SDE_ERROR("invalid arguments\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400568 return -EINVAL;
569 }
570
Clarence Ip4c1d9772016-06-26 09:35:38 -0400571 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400572 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400574 phase_steps[SDE_SSPP_COMP_1_2] =
575 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
576 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
577 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400578
579 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400580 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400581 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400582 (src <= dst) ? SDE_SCALE_FILTER_BIL :
583 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400584
Clarence Ipdbde9832016-06-26 09:48:36 -0400585 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400586 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400587 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
588 } else {
589 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
590 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400591 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400592 }
593 } else {
594 /* disable scaler */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700595 SDE_DEBUG("disable scaler\n");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400596 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
597 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
598 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400599 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400600 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400601}
602
Clarence Ipcb410d42016-06-26 22:52:33 -0400603/**
604 * _sde_plane_setup_pixel_ext - determine default pixel extension values
605 * @psde: Pointer to SDE plane object
606 * @src: Source size
607 * @dst: Destination size
608 * @decimated_src: Source size after decimation, if any
609 * @phase_steps: Pointer to output array for phase steps
610 * @out_src: Output array for pixel extension values
611 * @out_edge1: Output array for pixel extension first edge
612 * @out_edge2: Output array for pixel extension second edge
613 * @filter: Pointer to array for filter type
614 * @fmt: Pointer to format definition
615 * @chroma_subsampling: Subsampling amount for chroma channel
616 * @post_compare: Whether to chroma subsampled source size for comparisions
617 */
618static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400619 uint32_t src, uint32_t dst, uint32_t decimated_src,
620 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400621 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400622 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400623 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400624{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400625 int64_t edge1, edge2, caf;
626 uint32_t src_work;
627 int i, tmp;
628
Clarence Ipcb410d42016-06-26 22:52:33 -0400629 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400630 out_edge2 && filter && fmt) {
631 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400632 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400633 caf = PHASE_STEP_UNIT_SCALE;
634 else
635 caf = 0;
636
637 for (i = 0; i < SDE_MAX_PLANES; i++) {
638 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400639 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400640 src_work /= chroma_subsampling;
641 if (post_compare)
642 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400643 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400644 /* unity */
645 edge1 = 0;
646 edge2 = 0;
647 } else if (dst >= src) {
648 /* upscale */
649 edge1 = (1 << PHASE_RESIDUAL);
650 edge1 -= caf;
651 edge2 = (1 << PHASE_RESIDUAL);
652 edge2 += (dst - 1) * *(phase_steps + i);
653 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
654 edge2 += caf;
655 edge2 = -(edge2);
656 } else {
657 /* downscale */
658 edge1 = 0;
659 edge2 = (dst - 1) * *(phase_steps + i);
660 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
661 edge2 += *(phase_steps + i);
662 edge2 = -(edge2);
663 }
664
665 /* only enable CAF for luma plane */
666 caf = 0;
667
668 /* populate output arrays */
669 *(out_src + i) = src_work;
670
671 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400672 if (edge1 >= 0) {
673 tmp = (uint32_t)edge1;
674 tmp >>= PHASE_STEP_SHIFT;
675 *(out_edge1 + i) = -tmp;
676 } else {
677 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400678 *(out_edge1 + i) =
679 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
680 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400681 }
682 if (edge2 >= 0) {
683 tmp = (uint32_t)edge2;
684 tmp >>= PHASE_STEP_SHIFT;
685 *(out_edge2 + i) = -tmp;
686 } else {
687 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400688 *(out_edge2 + i) =
689 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
690 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400691 }
692 }
693 }
694}
695
Clarence Ip5e2a9222016-06-26 22:38:24 -0400696/**
697 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
698 * sub-structure
699 * @blob_ptr: Pointer to start of incoming blob data
700 * @blob_size: Size of incoming blob data, in bytes
701 * @sub_ptr: Pointer to start of desired sub-structure
702 * @sub_size: Required size of sub-structure, in bytes
703 */
704static int _sde_plane_verify_blob(void *blob_ptr,
705 size_t blob_size,
706 void *sub_ptr,
707 size_t sub_size)
708{
709 /*
710 * Use the blob size provided by drm to check if there are enough
711 * bytes from the start of versioned sub-structures to the end of
712 * blob data:
713 *
714 * e.g.,
715 * blob_ptr --> struct blob_data {
716 * uint32_t version;
717 * sub_ptr --> struct blob_data_v1 v1;
718 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
719 * blob_ptr + blob_size --> };
720 *
721 * It's important to check the actual number of bytes from the start
722 * of the sub-structure to the end of the blob data, and not just rely
723 * on something like,
724 *
725 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
726 *
727 * This is because the start of the sub-structure can vary based on
728 * how the compiler pads the overall structure.
729 */
730 if (blob_ptr && sub_ptr)
731 /* return zero if end of blob >= end of sub-struct */
732 return ((unsigned char *)blob_ptr + blob_size) <
733 ((unsigned char *)sub_ptr + sub_size);
734 return -EINVAL;
735}
736
Clarence Ipe78efb72016-06-24 18:35:21 -0400737static void _sde_plane_setup_csc(struct sde_plane *psde,
738 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400739 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400740{
741 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
742 {
Clarence Ip373f8592016-05-26 00:58:42 -0400743 /* S15.16 format */
744 0x00012A00, 0x00000000, 0x00019880,
745 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
746 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400747 },
Clarence Ip373f8592016-05-26 00:58:42 -0400748 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400749 { 0xfff0, 0xff80, 0xff80,},
750 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400751 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400752 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400753 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400754 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400755 static const struct sde_csc_cfg sde_csc_NOP = {
756 {
Clarence Ip373f8592016-05-26 00:58:42 -0400757 /* identity matrix, S15.16 format */
758 0x10000, 0x00000, 0x00000,
759 0x00000, 0x10000, 0x00000,
760 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400761 },
Clarence Ip373f8592016-05-26 00:58:42 -0400762 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400763 { 0x0, 0x0, 0x0,},
764 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400765 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400766 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
767 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
768 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400769 struct sde_drm_csc *csc = NULL;
770 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400771 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400772
Clarence Ipaa0faf42016-05-30 12:07:48 -0400773 if (!psde || !pstate || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700774 SDE_ERROR("invalid arguments\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400775 return;
776 }
777 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400778 return;
779
Clarence Ip5e2a9222016-06-26 22:38:24 -0400780 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400781 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400782 csc = msm_property_get_blob(&psde->property_info,
783 pstate->property_blobs,
784 &csc_size,
785 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400786 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400787 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400788 memcpy(&psde->csc_cfg,
789 &sde_csc_NOP,
790 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400791 switch (csc->version) {
792 case SDE_DRM_CSC_V1:
793 if (!_sde_plane_verify_blob(csc,
794 csc_size,
795 &csc->v1,
796 sizeof(struct sde_drm_csc_v1))) {
797 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400798 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400799 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400800 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400801 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400802 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400803 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400804 csc->v1.post_bias[i];
805 }
806 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400807 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400808 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400809 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400810 csc->v1.post_clamp[i];
811 }
Clarence Ipb493d762016-07-19 18:49:10 -0400812 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400813 }
814 break;
815 default:
816 break;
817 }
Clarence Ipb493d762016-07-19 18:49:10 -0400818 if (!psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700819 SDE_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400820 }
821
Clarence Ipcae1bb62016-07-07 12:07:13 -0400822 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400823 if (psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700824 SDE_DEBUG("user blob override for csc\n");
Clarence Ipb493d762016-07-19 18:49:10 -0400825 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400826 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400827}
828
Clarence Ipcb410d42016-06-26 22:52:33 -0400829static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400830 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400831 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700832{
Clarence Ipcb410d42016-06-26 22:52:33 -0400833 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400834 struct sde_drm_scaler *sc_u = NULL;
835 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400836 size_t sc_u_size = 0;
837 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
838 uint32_t tmp;
839 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400840
Clarence Ipcb410d42016-06-26 22:52:33 -0400841 if (!psde || !fmt)
842 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400843
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400844 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400845 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400846
Clarence Ip5e2a9222016-06-26 22:38:24 -0400847 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400848 if (pstate)
849 sc_u = msm_property_get_blob(&psde->property_info,
850 pstate->property_blobs,
851 &sc_u_size,
852 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400853 if (sc_u) {
854 switch (sc_u->version) {
855 case SDE_DRM_SCALER_V1:
856 if (!_sde_plane_verify_blob(sc_u,
857 sc_u_size,
858 &sc_u->v1,
859 sizeof(*sc_u1)))
860 sc_u1 = &sc_u->v1;
861 break;
862 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700863 SDE_DEBUG("unrecognized scaler blob v%lld\n",
864 sc_u->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400865 break;
866 }
867 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400868
Clarence Ip04ec67d2016-05-26 01:16:15 -0400869 /* decimation */
870 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
871 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
872 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400873 } else {
874 psde->pipe_cfg.horz_decimation = 0;
875 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400876 }
877
878 /* don't chroma subsample if decimating */
879 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400880 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400881 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400882 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400883
Clarence Ip5e2a9222016-06-26 22:38:24 -0400884 /* update scaler */
885 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
886 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Dhaval Patel47302cf2016-08-18 15:04:28 -0700887 SDE_DEBUG("SCALER3 blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400888 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400889 _sde_plane_setup_scaler3(psde,
890 psde->pipe_cfg.src_rect.w,
891 psde->pipe_cfg.src_rect.h,
892 psde->pipe_cfg.dst_rect.w,
893 psde->pipe_cfg.dst_rect.h,
894 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400895 chroma_subsmpl_h, chroma_subsmpl_v);
896 } else {
897 /* always calculate basic scaler config */
898 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
899 /* populate from user space */
900 for (i = 0; i < SDE_MAX_PLANES; i++) {
901 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
902 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
903 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
904 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400905
Clarence Ip5e2a9222016-06-26 22:38:24 -0400906 pe->horz_filter[i] = sc_u1->horz_filter[i];
907 pe->vert_filter[i] = sc_u1->vert_filter[i];
908 }
909 } else {
910 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400911 _sde_plane_setup_scaler2(psde,
912 psde->pipe_cfg.src_rect.w,
913 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400914 pe->phase_step_x,
915 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400916 _sde_plane_setup_scaler2(psde,
917 psde->pipe_cfg.src_rect.h,
918 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400919 pe->phase_step_y,
920 pe->vert_filter, fmt, chroma_subsmpl_v);
921 }
922 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400923
Clarence Ip5e2a9222016-06-26 22:38:24 -0400924 /* update pixel extensions */
925 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
926 /* populate from user space */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700927 SDE_DEBUG("pixel ext blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400928 for (i = 0; i < SDE_MAX_PLANES; i++) {
929 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
930 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
931 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
932 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
933 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
934 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
935 pe->roi_w[i] = sc_u1->lr.roi[i];
936
937 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
938 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
939 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
940 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
941 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
942 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
943 pe->roi_h[i] = sc_u1->tb.roi[i];
944 }
945 } else {
946 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400947 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400948 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400949 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400950 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400951 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
952 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400953 pe->phase_step_x,
954 pe->roi_w,
955 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400956 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400957 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400958
Clarence Ipcb410d42016-06-26 22:52:33 -0400959 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400960 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400961 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
962 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400963 pe->phase_step_y,
964 pe->roi_h,
965 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400966 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400967 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400968
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400969 for (i = 0; i < SDE_MAX_PLANES; i++) {
970 if (pe->num_ext_pxls_left[i] >= 0)
971 pe->left_rpt[i] =
972 pe->num_ext_pxls_left[i];
973 else
974 pe->left_ftch[i] =
975 pe->num_ext_pxls_left[i];
976
977 if (pe->num_ext_pxls_right[i] >= 0)
978 pe->right_rpt[i] =
979 pe->num_ext_pxls_right[i];
980 else
981 pe->right_ftch[i] =
982 pe->num_ext_pxls_right[i];
983
984 if (pe->num_ext_pxls_top[i] >= 0)
985 pe->top_rpt[i] =
986 pe->num_ext_pxls_top[i];
987 else
988 pe->top_ftch[i] =
989 pe->num_ext_pxls_top[i];
990
991 if (pe->num_ext_pxls_btm[i] >= 0)
992 pe->btm_rpt[i] =
993 pe->num_ext_pxls_btm[i];
994 else
995 pe->btm_ftch[i] =
996 pe->num_ext_pxls_btm[i];
997 }
998 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400999}
1000
Clarence Ipcae1bb62016-07-07 12:07:13 -04001001/**
1002 * _sde_plane_color_fill - enables color fill on plane
1003 * @plane: Pointer to DRM plane object
1004 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
1005 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
1006 * Returns: 0 on success
1007 */
1008static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -04001009 uint32_t color, uint32_t alpha)
1010{
1011 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001012 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -04001013
1014 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001015 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001016 return -EINVAL;
1017 }
1018
1019 psde = to_sde_plane(plane);
1020 if (!psde->pipe_hw) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001021 SDE_ERROR("invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001022 return -EINVAL;
1023 }
1024
Clarence Ipcae1bb62016-07-07 12:07:13 -04001025 DBG("");
1026
Clarence Ipcb410d42016-06-26 22:52:33 -04001027 /*
1028 * select fill format to match user property expectation,
1029 * h/w only supports RGB variants
1030 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001031 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -04001032
1033 /* update sspp */
1034 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
1035 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
1036 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
1037
1038 /* override scaler/decimation if solid fill */
1039 psde->pipe_cfg.src_rect.x = 0;
1040 psde->pipe_cfg.src_rect.y = 0;
1041 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
1042 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
1043
1044 _sde_plane_setup_scaler(psde, fmt, 0);
1045
1046 if (psde->pipe_hw->ops.setup_format)
1047 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
1048 fmt, SDE_SSPP_SOLID_FILL);
1049
1050 if (psde->pipe_hw->ops.setup_rects)
1051 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1052 &psde->pipe_cfg, &psde->pixel_ext);
1053 }
1054
1055 return 0;
1056}
1057
1058static int _sde_plane_mode_set(struct drm_plane *plane,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001059 struct drm_plane_state *state)
Clarence Ipcb410d42016-06-26 22:52:33 -04001060{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001061 uint32_t nplanes, src_flags;
Clarence Ipcb410d42016-06-26 22:52:33 -04001062 struct sde_plane *psde;
1063 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001064 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001065 struct drm_crtc *crtc;
1066 struct drm_framebuffer *fb;
1067 struct sde_rect src, dst;
1068 bool q16_data = true;
Clarence Ipcb410d42016-06-26 22:52:33 -04001069
1070 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001071 SDE_ERROR("invalid plane/state\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001072 return -EINVAL;
1073 }
1074
1075 psde = to_sde_plane(plane);
1076 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -04001077
Dhaval Patel47302cf2016-08-18 15:04:28 -07001078 crtc = state->crtc;
1079 fb = state->fb;
1080 if (!crtc || !fb) {
1081 SDE_ERROR("invalid crtc/fb\n");
1082 return -EINVAL;
1083 }
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001084 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001085 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -04001086
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001087 psde->is_rt_pipe = _sde_plane_is_rt_pipe(plane, crtc);
1088
1089 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1090
Dhaval Patel47302cf2016-08-18 15:04:28 -07001091 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);
Clarence Ipcb410d42016-06-26 22:52:33 -04001095
Dhaval Patel47302cf2016-08-18 15:04:28 -07001096 SDE_DEBUG("%s:FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001097 psde->pipe_name,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001098 fb->base.id, src.x, src.y, src.w, src.h,
1099 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001100 drm_get_format_name(fmt->base.pixel_format),
1101 SDE_FORMAT_IS_UBWC(fmt));
Clarence Ipcb410d42016-06-26 22:52:33 -04001102
1103 /* update format configuration */
1104 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
1105 src_flags = 0;
1106
Clarence Ipcb410d42016-06-26 22:52:33 -04001107 /* flags */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001108 SDE_DEBUG("flags 0x%llX, rotation 0x%llX\n",
Clarence Ipcb410d42016-06-26 22:52:33 -04001109 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
1110 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
1111 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1112 BIT(DRM_REFLECT_X))
1113 src_flags |= SDE_SSPP_FLIP_LR;
1114 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1115 BIT(DRM_REFLECT_Y))
1116 src_flags |= SDE_SSPP_FLIP_UD;
1117 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
1118 BIT(SDE_DRM_DEINTERLACE)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001119 src.h /= 2;
1120 src.y = DIV_ROUND_UP(src.y, 2);
1121 src.y &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -04001122 }
1123
Dhaval Patel47302cf2016-08-18 15:04:28 -07001124 psde->pipe_cfg.src_rect = src;
1125 psde->pipe_cfg.dst_rect = dst;
Clarence Ipcb410d42016-06-26 22:52:33 -04001126
Clarence Ipcb410d42016-06-26 22:52:33 -04001127 /* check for color fill */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001128 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001129 PLANE_PROP_COLOR_FILL);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001130 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1131 /* skip remaining processing on color fill */
1132 return 0;
Clarence Ipcb410d42016-06-26 22:52:33 -04001133
1134 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
1135
1136 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001137
Clarence Ip4c1d9772016-06-26 09:35:38 -04001138 if (psde->pipe_hw->ops.setup_format)
1139 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -04001140 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001141 if (psde->pipe_hw->ops.setup_rects)
1142 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1143 &psde->pipe_cfg, &psde->pixel_ext);
1144
Clarence Ipe78efb72016-06-24 18:35:21 -04001145 /* update sharpening */
1146 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
1147 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
1148 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
1149 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
1150
1151 if (psde->pipe_hw->ops.setup_sharpening)
1152 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
1153 &psde->sharp_cfg);
1154
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001155 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -04001156 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -04001157 _sde_plane_setup_csc(psde, pstate, fmt);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001158 else
1159 psde->csc_ptr = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001160
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001161 _sde_plane_set_qos_lut(plane, fb);
1162 _sde_plane_set_danger_lut(plane, fb);
1163
Alan Kwong5d324e42016-07-28 22:56:18 -04001164 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001165 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
Alan Kwong5d324e42016-07-28 22:56:18 -04001166 _sde_plane_set_ot_limit(plane, crtc);
1167 }
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001168
Clarence Ip5e2a9222016-06-26 22:38:24 -04001169 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001170}
1171
1172static int sde_plane_prepare_fb(struct drm_plane *plane,
1173 const struct drm_plane_state *new_state)
1174{
1175 struct drm_framebuffer *fb = new_state->fb;
1176 struct sde_plane *psde = to_sde_plane(plane);
1177
1178 if (!new_state->fb)
1179 return 0;
1180
Dhaval Patel47302cf2016-08-18 15:04:28 -07001181 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001182 return msm_framebuffer_prepare(fb, psde->mmu_id);
1183}
1184
1185static void sde_plane_cleanup_fb(struct drm_plane *plane,
1186 const struct drm_plane_state *old_state)
1187{
1188 struct drm_framebuffer *fb = old_state->fb;
1189 struct sde_plane *psde = to_sde_plane(plane);
1190
1191 if (!fb)
1192 return;
1193
Dhaval Patel47302cf2016-08-18 15:04:28 -07001194 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001195 msm_framebuffer_cleanup(fb, psde->mmu_id);
1196}
1197
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001198static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
1199 struct drm_plane_state *state,
1200 struct drm_plane_state *old_state)
1201{
1202 struct sde_plane_state *pstate = to_sde_plane_state(state);
1203
Dhaval Patel47302cf2016-08-18 15:04:28 -07001204 /* no need to check it again */
1205 if (pstate->mode_changed)
1206 return;
1207
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001208 if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001209 SDE_DEBUG("%s: pipe enabling/disabling full modeset required\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001210 psde->pipe_name);
1211 pstate->mode_changed = true;
1212 } else if (to_sde_plane_state(old_state)->pending) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001213 SDE_DEBUG("%s: still pending\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001214 pstate->mode_changed = true;
1215 } else if (state->src_w != old_state->src_w ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07001216 state->src_h != old_state->src_h ||
1217 state->src_x != old_state->src_x ||
1218 state->src_y != old_state->src_y) {
1219 SDE_DEBUG("%s: src rect updated\n", psde->pipe_name);
1220 pstate->mode_changed = true;
1221 } else if (state->crtc_w != old_state->crtc_w ||
1222 state->crtc_h != old_state->crtc_h ||
1223 state->crtc_x != old_state->crtc_x ||
1224 state->crtc_y != old_state->crtc_y) {
1225 SDE_DEBUG("%s: crtc rect updated\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001226 pstate->mode_changed = true;
1227 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001228 SDE_DEBUG("%s: format change!\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001229 pstate->mode_changed = true;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001230 } else {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001231 uint64_t *new_mods = state->fb->modifier;
1232 uint64_t *old_mods = old_state->fb->modifier;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001233 uint32_t *new_pitches = state->fb->pitches;
1234 uint32_t *old_pitches = old_state->fb->pitches;
1235 uint32_t *new_offset = state->fb->offsets;
1236 uint32_t *old_offset = old_state->fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001237 int i;
1238
1239 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
1240 if (new_mods[i] != old_mods[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001241 SDE_DEBUG("%s: format modifiers change\"\
1242 plane:%d new_mode:%llu old_mode:%llu\n",
1243 psde->pipe_name, i, new_mods[i],
1244 old_mods[i]);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001245 pstate->mode_changed = true;
1246 break;
1247 }
1248 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001249 for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
1250 if (new_pitches[i] != old_pitches[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001251 SDE_DEBUG("%s: pitches change plane:%d\"\
1252 old_pitches:%u new_pitches:%u\n",
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001253 psde->pipe_name, i, old_pitches[i],
1254 new_pitches[i]);
1255 pstate->mode_changed = true;
1256 break;
1257 }
1258 }
Dhaval Patel47302cf2016-08-18 15:04:28 -07001259 for (i = 0; i < ARRAY_SIZE(state->fb->offsets); i++) {
1260 if (new_offset[i] != old_offset[i]) {
1261 SDE_DEBUG("%s: offset change plane:%d\"\
1262 old_offset:%u new_offset:%u\n",
1263 psde->pipe_name, i, old_offset[i],
1264 new_offset[i]);
1265 pstate->mode_changed = true;
1266 break;
1267 }
1268 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001269 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001270}
1271
Dhaval Patel47302cf2016-08-18 15:04:28 -07001272static bool __get_scale_data(struct sde_plane *psde,
1273 struct sde_plane_state *pstate, struct sde_drm_scaler *sc_u,
1274 size_t *sc_u_size)
1275{
1276 bool valid_flag = false;
1277
1278 sc_u = msm_property_get_blob(&psde->property_info,
1279 pstate->property_blobs,
1280 sc_u_size,
1281 PLANE_PROP_SCALER);
1282 if (sc_u) {
1283 switch (sc_u->version) {
1284 case SDE_DRM_SCALER_V1:
1285 if (!_sde_plane_verify_blob(sc_u, *sc_u_size,
1286 &sc_u->v1, sizeof(struct sde_drm_scaler_v1)))
1287 valid_flag = true;
1288 break;
1289 default:
1290 SDE_DEBUG("unrecognized scaler blob v%lld\n",
1291 sc_u->version);
1292 break;
1293 }
1294 }
1295
1296 return valid_flag;
1297}
1298
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001299static int sde_plane_atomic_check(struct drm_plane *plane,
1300 struct drm_plane_state *state)
1301{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001302 int ret = 0, valid_scale_data;
Clarence Ipdbde9832016-06-26 09:48:36 -04001303 struct sde_plane *psde;
1304 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001305 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -04001306 size_t sc_u_size = 0;
1307 struct sde_drm_scaler *sc_u = NULL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001308 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04001309 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001310 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
1311 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04001312
1313 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001314 SDE_ERROR("invalid plane/state\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001315 ret = -EINVAL;
1316 goto exit;
1317 }
1318
1319 psde = to_sde_plane(plane);
1320 pstate = to_sde_plane_state(state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001321
1322 if (!psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001323 SDE_ERROR("invalid plane catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001324 ret = -EINVAL;
1325 goto exit;
1326 }
1327
Dhaval Patel47302cf2016-08-18 15:04:28 -07001328 valid_scale_data = __get_scale_data(psde, pstate, sc_u, &sc_u_size);
1329 deci_w = valid_scale_data && sc_u ? sc_u->v1.horz_decimate : 0;
1330 deci_h = valid_scale_data && sc_u ? sc_u->v1.vert_decimate : 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04001331
1332 /* src values are in Q16 fixed point, convert to integer */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001333 POPULATE_RECT(&src, state->src_x, state->src_y, state->src_w,
1334 state->src_h, q16_data);
1335 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
1336 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04001337
Dhaval Patel47302cf2016-08-18 15:04:28 -07001338 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
1339 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04001340
Dhaval Patel47302cf2016-08-18 15:04:28 -07001341 max_upscale = psde->pipe_sblk->maxupscale;
1342 max_downscale = psde->pipe_sblk->maxdwnscale;
1343 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04001344
Dhaval Patel47302cf2016-08-18 15:04:28 -07001345 SDE_DEBUG("%s: check (%d -> %d)\n", psde->pipe_name,
1346 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001347
Dhaval Patel47302cf2016-08-18 15:04:28 -07001348 if (!sde_plane_enabled(state))
1349 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04001350
Dhaval Patel47302cf2016-08-18 15:04:28 -07001351 fmt = to_sde_format(msm_framebuffer_format(state->fb));
1352
1353 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
1354
1355 if (SDE_FORMAT_IS_YUV(fmt) &&
1356 (!(psde->features & SDE_SSPP_SCALER) ||
1357 !(psde->features & BIT(SDE_SSPP_CSC)))) {
1358 SDE_ERROR("plane doesn't have scaler/csc capability for yuv\n");
1359 ret = -EINVAL;
1360
1361 /* check src bounds */
1362 } else if (state->fb->width > MAX_IMG_WIDTH ||
1363 state->fb->height > MAX_IMG_HEIGHT ||
1364 src.w < min_src_size || src.h < min_src_size ||
1365 CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
1366 CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
1367 SDE_ERROR("invalid source (%u, %u) -> (%u, %u)\n",
1368 src.x, src.y, src.w, src.h);
1369 ret = -E2BIG;
1370
1371 /* valid yuv image */
1372 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
1373 (src.w & 0x1) || (src.h & 0x1))) {
1374 SDE_ERROR("invalid yuv source (%u, %u) -> (%u, %u)\n",
1375 src.x, src.y, src.w, src.h);
1376 ret = -EINVAL;
1377
1378 /* min dst support */
1379 } else if (dst.w < 0x1 || dst.h < 0x1) {
1380 SDE_ERROR("invalid dest rect (%u, %u) -> (%u, %u)\n",
1381 dst.x, dst.y, dst.w, dst.h);
1382 ret = -EINVAL;
1383
1384 /* decimation validation */
1385 } else if (deci_w || deci_h) {
1386 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1387 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1388 SDE_ERROR("too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001389 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001390 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
1391 SDE_ERROR("decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001392 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001393 }
1394
Dhaval Patel47302cf2016-08-18 15:04:28 -07001395 } else if (!(psde->features & SDE_SSPP_SCALER) &&
1396 ((src.w != dst.w) || (src.h != dst.h))) {
1397 SDE_ERROR("pipe doesn't support scaling %ux%u->%ux%u\n",
1398 src.w, src.h, dst.w, dst.h);
1399 ret = -EINVAL;
1400
1401 /* check decimated source width */
1402 } else if (src_deci_w > max_linewidth) {
1403 SDE_ERROR("invalid source width:%u, deci wid:%u, line wid:%u\n",
1404 src.w, src_deci_w, max_linewidth);
1405 ret = -E2BIG;
1406
1407 /* check max scaler capability */
1408 } else if (((src_deci_w * max_upscale) < dst.w) ||
1409 ((src_deci_h * max_upscale) < dst.h) ||
1410 ((dst.w * max_downscale) < src_deci_w) ||
1411 ((dst.h * max_downscale) < src_deci_h)) {
1412 SDE_ERROR("too much scaling requested %ux%u -> %ux%u\n",
1413 src_deci_w, src_deci_h, dst.w, dst.h);
1414 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001415 }
1416
Dhaval Patel47302cf2016-08-18 15:04:28 -07001417modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001418 if (!ret)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001419 _sde_plane_atomic_check_mode_changed(psde, state, plane->state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001420exit:
1421 return ret;
1422}
1423
Clarence Ipcae1bb62016-07-07 12:07:13 -04001424/**
1425 * sde_plane_flush - final plane operations before commit flush
1426 * @plane: Pointer to drm plane structure
1427 */
1428void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001429{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001430 struct sde_plane *psde;
1431
1432 if (!plane)
1433 return;
1434
1435 psde = to_sde_plane(plane);
1436
1437 /*
1438 * These updates have to be done immediately before the plane flush
1439 * timing, and may not be moved to the atomic_update/mode_set functions.
1440 */
1441 if (psde->is_error)
1442 /* force white frame with 0% alpha pipe output on error */
1443 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1444 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1445 /* force 100% alpha */
1446 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1447 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1448 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1449
1450 /* flag h/w flush complete */
1451 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001452 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001453}
1454
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001455static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001456 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001457{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001458 struct sde_plane *sde_plane;
1459 struct drm_plane_state *state;
1460 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001461
Clarence Ip5e2a9222016-06-26 22:38:24 -04001462 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001463 SDE_ERROR("invalid plane/state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001464 return;
1465 }
1466
1467 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001468 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001469 state = plane->state;
1470 pstate = to_sde_plane_state(state);
1471
Dhaval Patel47302cf2016-08-18 15:04:28 -07001472 SDE_DEBUG("%s: update\n", sde_plane->pipe_name);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001473
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001474 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001475 pstate->pending = true;
1476 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001477 int ret;
1478
Clarence Ip5e2a9222016-06-26 22:38:24 -04001479 pstate->pending = true;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001480 ret = _sde_plane_mode_set(plane, state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001481 /* atomic_check should have ensured that this doesn't fail */
1482 WARN_ON(ret < 0);
1483 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001484 _sde_plane_set_scanout(plane, pstate,
1485 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001486 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001487}
1488
Dhaval Patel47302cf2016-08-18 15:04:28 -07001489
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001490/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001491static void _sde_plane_install_properties(struct drm_plane *plane,
1492 u32 max_blendstages)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001493{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001494 static const struct drm_prop_enum_list e_blend_op[] = {
1495 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1496 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1497 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1498 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1499 };
1500 static const struct drm_prop_enum_list e_src_config[] = {
1501 {SDE_DRM_DEINTERLACE, "deinterlace"}
1502 };
Clarence Ipea3d6262016-07-15 16:20:11 -04001503 const struct sde_format_extended *format_list;
Dhaval Patel4e574842016-08-23 15:11:37 -07001504 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001505 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001506
Clarence Ipaa0faf42016-05-30 12:07:48 -04001507 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001508 SDE_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001509 return;
1510 }
1511
Dhaval Patel47302cf2016-08-18 15:04:28 -07001512 msm_property_install_range(&psde->property_info, "zpos", 0x0, 0,
1513 max_blendstages, STAGE_BASE, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001514
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001515 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07001516 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001517
Dhaval Patel47302cf2016-08-18 15:04:28 -07001518 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001519 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07001520 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001521
1522 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001523 msm_property_install_rotation(&psde->property_info,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001524 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y), PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001525
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001526 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001527 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001528
Dhaval Patel47302cf2016-08-18 15:04:28 -07001529 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
1530 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
1531
1532 if (psde->pipe_hw->ops.setup_solidfill)
1533 msm_property_install_range(&psde->property_info, "color_fill",
1534 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
1535
Clarence Ip4c1d9772016-06-26 09:35:38 -04001536 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001537 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001538 PLANE_PROP_SCALER);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001539
1540 if (psde->features & BIT(SDE_SSPP_CSC))
Clarence Ipaa0faf42016-05-30 12:07:48 -04001541 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001542 PLANE_PROP_CSC);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001543
Dhaval Patel4e574842016-08-23 15:11:37 -07001544 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
1545 if (!info)
1546 return;
1547
1548 msm_property_install_blob(&psde->property_info, "capabilities",
1549 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
1550 sde_kms_info_reset(info);
1551
Clarence Ipea3d6262016-07-15 16:20:11 -04001552 format_list = psde->pipe_sblk->format_list;
1553 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04001554 sde_kms_info_start(info, "pixel_formats");
1555 while (format_list->fourcc_format) {
1556 sde_kms_info_append_format(info,
1557 format_list->fourcc_format,
1558 format_list->modifier);
1559 ++format_list;
1560 }
1561 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04001562 }
Dhaval Patel4e574842016-08-23 15:11:37 -07001563
1564 sde_kms_info_add_keyint(info, "max_linewidth",
1565 psde->pipe_sblk->maxlinewidth);
1566 sde_kms_info_add_keyint(info, "max_upscale",
1567 psde->pipe_sblk->maxupscale);
1568 sde_kms_info_add_keyint(info, "max_downscale",
1569 psde->pipe_sblk->maxdwnscale);
1570 sde_kms_info_add_keyint(info, "max_horizontal_deci",
1571 psde->pipe_sblk->maxhdeciexp);
1572 sde_kms_info_add_keyint(info, "max_vertical_deci",
1573 psde->pipe_sblk->maxvdeciexp);
1574 msm_property_set_blob(&psde->property_info, &psde->blob_info,
1575 info->data, info->len, PLANE_PROP_INFO);
1576
1577 kfree(info);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001578}
1579
1580static int sde_plane_atomic_set_property(struct drm_plane *plane,
1581 struct drm_plane_state *state, struct drm_property *property,
1582 uint64_t val)
1583{
Clarence Ip730e7192016-06-26 22:45:09 -04001584 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001585 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001586 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001587
Clarence Ipaa0faf42016-05-30 12:07:48 -04001588 DBG("");
1589
1590 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001591 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001592 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001593 SDE_ERROR("invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001594 } else {
1595 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001596 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001597 ret = msm_property_atomic_set(&psde->property_info,
1598 pstate->property_values, pstate->property_blobs,
1599 property, val);
1600 if (!ret) {
1601 idx = msm_property_index(&psde->property_info,
1602 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001603 if (idx == PLANE_PROP_INPUT_FENCE)
1604 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001605 }
1606 }
1607
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001608 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001609}
1610
1611static int sde_plane_set_property(struct drm_plane *plane,
1612 struct drm_property *property, uint64_t val)
1613{
Clarence Ip4ce59322016-06-26 22:27:51 -04001614 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001615
Clarence Ipae4e60c2016-06-26 22:44:04 -04001616 return sde_plane_atomic_set_property(plane,
1617 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001618}
1619
1620static int sde_plane_atomic_get_property(struct drm_plane *plane,
1621 const struct drm_plane_state *state,
1622 struct drm_property *property, uint64_t *val)
1623{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001624 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001625 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001626 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001627
Clarence Ipaa0faf42016-05-30 12:07:48 -04001628 DBG("");
1629
1630 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001631 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001632 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001633 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001634 } else {
1635 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001636 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001637 ret = msm_property_atomic_get(&psde->property_info,
1638 pstate->property_values, pstate->property_blobs,
1639 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001640 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001641
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001642 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001643}
1644
1645static void sde_plane_destroy(struct drm_plane *plane)
1646{
Clarence Ip4ce59322016-06-26 22:27:51 -04001647 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001648
Clarence Ip4ce59322016-06-26 22:27:51 -04001649 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001650
Clarence Ip4ce59322016-06-26 22:27:51 -04001651 if (plane) {
1652 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001653
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001654 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1655
Clarence Ip4ce59322016-06-26 22:27:51 -04001656 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001657
Dhaval Patel4e574842016-08-23 15:11:37 -07001658 if (psde->blob_info)
1659 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001660 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001661 mutex_destroy(&psde->lock);
1662
Clarence Ip4ce59322016-06-26 22:27:51 -04001663 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001664
Clarence Ip4ce59322016-06-26 22:27:51 -04001665 /* this will destroy the states as well */
1666 drm_plane_cleanup(plane);
1667
Clarence Ip4c1d9772016-06-26 09:35:38 -04001668 if (psde->pipe_hw)
1669 sde_hw_sspp_destroy(psde->pipe_hw);
1670
Clarence Ip4ce59322016-06-26 22:27:51 -04001671 kfree(psde);
1672 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001673}
1674
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001675static void sde_plane_destroy_state(struct drm_plane *plane,
1676 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001677{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001678 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001679 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001680
Clarence Ipae4e60c2016-06-26 22:44:04 -04001681 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001682 SDE_ERROR("invalid plane/state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001683 return;
1684 }
1685
Clarence Ipaa0faf42016-05-30 12:07:48 -04001686 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001687 pstate = to_sde_plane_state(state);
1688
1689 DBG("");
1690
Clarence Ipe78efb72016-06-24 18:35:21 -04001691 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001692 if (state->fb)
1693 drm_framebuffer_unreference(state->fb);
1694
Clarence Ipae4e60c2016-06-26 22:44:04 -04001695 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001696 if (pstate->input_fence)
1697 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001698
Clarence Ipaa0faf42016-05-30 12:07:48 -04001699 /* destroy value helper */
1700 msm_property_destroy_state(&psde->property_info, pstate,
1701 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001702}
1703
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001704static struct drm_plane_state *
1705sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001706{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001707 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001708 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001709 struct sde_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001710
Clarence Ip730e7192016-06-26 22:45:09 -04001711 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001712 return NULL;
1713
Clarence Ip730e7192016-06-26 22:45:09 -04001714 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001715 psde = to_sde_plane(plane);
1716 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001717 if (!pstate)
1718 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001719
Clarence Ipaa0faf42016-05-30 12:07:48 -04001720 DBG("");
1721
1722 /* duplicate value helper */
1723 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1724 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001725
Clarence Ip730e7192016-06-26 22:45:09 -04001726 /* add ref count for frame buffer */
1727 if (pstate->base.fb)
1728 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001729
Clarence Ip730e7192016-06-26 22:45:09 -04001730 /* add ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001731 if (pstate->input_fence) {
1732 pstate->input_fence = 0;
1733 _sde_plane_set_input_fence(plane, pstate, pstate->
1734 property_values[PLANE_PROP_INPUT_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001735 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001736
Clarence Ip730e7192016-06-26 22:45:09 -04001737 pstate->mode_changed = false;
1738 pstate->pending = false;
1739
1740 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001741}
1742
1743static void sde_plane_reset(struct drm_plane *plane)
1744{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001745 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001746 struct sde_plane_state *pstate;
1747
Clarence Ipae4e60c2016-06-26 22:44:04 -04001748 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001749 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001750 return;
1751 }
1752
Clarence Ip730e7192016-06-26 22:45:09 -04001753 psde = to_sde_plane(plane);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001754 SDE_DEBUG("%s\n", psde->pipe_name);
Clarence Ip730e7192016-06-26 22:45:09 -04001755
Clarence Ipae4e60c2016-06-26 22:44:04 -04001756 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001757 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001758 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001759 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001760 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001761
Clarence Ipaa0faf42016-05-30 12:07:48 -04001762 pstate = msm_property_alloc_state(&psde->property_info);
1763 if (!pstate)
1764 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001765
Clarence Ipaa0faf42016-05-30 12:07:48 -04001766 /* reset value helper */
1767 msm_property_reset_state(&psde->property_info, pstate,
1768 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001769
1770 pstate->base.plane = plane;
1771
1772 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001773}
1774
1775static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001776 .update_plane = drm_atomic_helper_update_plane,
1777 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001778 .destroy = sde_plane_destroy,
1779 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001780 .atomic_set_property = sde_plane_atomic_set_property,
1781 .atomic_get_property = sde_plane_atomic_get_property,
1782 .reset = sde_plane_reset,
1783 .atomic_duplicate_state = sde_plane_duplicate_state,
1784 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001785};
1786
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001787static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1788 .prepare_fb = sde_plane_prepare_fb,
1789 .cleanup_fb = sde_plane_cleanup_fb,
1790 .atomic_check = sde_plane_atomic_check,
1791 .atomic_update = sde_plane_atomic_update,
1792};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001793
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001794enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001795{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001796 struct sde_plane *sde_plane = to_sde_plane(plane);
1797
1798 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001799}
1800
Clarence Ip4ce59322016-06-26 22:27:51 -04001801static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1802{
1803 const struct sde_sspp_sub_blks *sblk = 0;
1804 const struct sde_sspp_cfg *cfg = 0;
1805
1806 if (psde && psde->pipe_hw)
1807 cfg = psde->pipe_hw->cap;
1808 if (cfg)
1809 sblk = cfg->sblk;
1810
1811 if (kms && sblk) {
1812 /* create overall sub-directory for the pipe */
1813 psde->debugfs_root =
1814 debugfs_create_dir(psde->pipe_name,
1815 sde_debugfs_get_root(kms));
1816 if (psde->debugfs_root) {
1817 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001818 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001819 psde->debugfs_root, &psde->features);
1820
1821 /* add register dump support */
1822 sde_debugfs_setup_regset32(&psde->debugfs_src,
1823 sblk->src_blk.base + cfg->base,
1824 sblk->src_blk.len,
1825 kms->mmio);
1826 sde_debugfs_create_regset32("src_blk", 0444,
1827 psde->debugfs_root, &psde->debugfs_src);
1828
1829 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1830 sblk->scaler_blk.base + cfg->base,
1831 sblk->scaler_blk.len,
1832 kms->mmio);
1833 sde_debugfs_create_regset32("scaler_blk", 0444,
1834 psde->debugfs_root,
1835 &psde->debugfs_scaler);
1836
1837 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1838 sblk->csc_blk.base + cfg->base,
1839 sblk->csc_blk.len,
1840 kms->mmio);
1841 sde_debugfs_create_regset32("csc_blk", 0444,
1842 psde->debugfs_root, &psde->debugfs_csc);
1843 }
1844 }
1845}
1846
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001847/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001848struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001849 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001850{
1851 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001852 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001853 struct msm_drm_private *priv;
1854 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001855 enum drm_plane_type type;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001856 int ret = -EINVAL, max_blendstages = 255;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001857
1858 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001859 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001860 goto exit;
1861 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001862
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001863 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001864 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001865 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001866 goto exit;
1867 }
1868
1869 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001870 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001871 goto exit;
1872 }
1873 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001874
Clarence Ip4c1d9772016-06-26 09:35:38 -04001875 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001876 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001877 goto exit;
1878 }
1879
Clarence Ip4ce59322016-06-26 22:27:51 -04001880 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001881 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1882 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001883 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001884 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001885 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001886 }
1887
Clarence Ip4c1d9772016-06-26 09:35:38 -04001888 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001889 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001890 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04001891 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001892
Clarence Ip4c1d9772016-06-26 09:35:38 -04001893 /* initialize underlying h/w driver */
1894 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1895 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001896 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001897 ret = PTR_ERR(psde->pipe_hw);
1898 goto clean_plane;
1899 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001900 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001901 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001902 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001903
1904 /* cache features mask for later */
1905 psde->features = psde->pipe_hw->cap->features;
1906 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04001907 if (!psde->pipe_sblk) {
1908 SDE_ERROR("invalid sblk on pipe %d\n", pipe);
1909 goto clean_sspp;
1910 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001911
Dhaval Patel47302cf2016-08-18 15:04:28 -07001912 if (kms->catalog && kms->catalog->mixer_count && kms->catalog->mixer)
1913 max_blendstages = kms->catalog->mixer[0].sblk->maxblendstages;
1914
Clarence Ip4c1d9772016-06-26 09:35:38 -04001915 /* add plane to DRM framework */
Clarence Ipea3d6262016-07-15 16:20:11 -04001916 psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
1917 psde->formats,
1918 0,
1919 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001920
Clarence Ip4c1d9772016-06-26 09:35:38 -04001921 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001922 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001923 goto clean_sspp;
1924 }
1925
1926 if (psde->features & BIT(SDE_SSPP_CURSOR))
1927 type = DRM_PLANE_TYPE_CURSOR;
1928 else if (primary_plane)
1929 type = DRM_PLANE_TYPE_PRIMARY;
1930 else
1931 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001932 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1933 psde->formats, psde->nformats,
1934 type);
1935 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001936 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001937
Clarence Ip4c1d9772016-06-26 09:35:38 -04001938 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001939 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001940
Clarence Ipaa0faf42016-05-30 12:07:48 -04001941 msm_property_init(&psde->property_info, &plane->base, dev,
1942 priv->plane_property, psde->property_data,
1943 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
1944 sizeof(struct sde_plane_state));
1945
Dhaval Patel47302cf2016-08-18 15:04:28 -07001946 _sde_plane_install_properties(plane, max_blendstages);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001947
Clarence Ip4ce59322016-06-26 22:27:51 -04001948 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001949 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001950
Clarence Ip730e7192016-06-26 22:45:09 -04001951 mutex_init(&psde->lock);
1952
Clarence Ip4ce59322016-06-26 22:27:51 -04001953 _sde_plane_init_debugfs(psde, kms);
1954
Dhaval Patel47302cf2016-08-18 15:04:28 -07001955 DRM_INFO("[%u]successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001956 return plane;
1957
Clarence Ip4c1d9772016-06-26 09:35:38 -04001958clean_sspp:
1959 if (psde && psde->pipe_hw)
1960 sde_hw_sspp_destroy(psde->pipe_hw);
1961clean_plane:
1962 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001963exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001964 return ERR_PTR(ret);
1965}