blob: fc0bce6b63ed9dc7194a8ea3f09bd50ec4fae491 [file] [log] [blame]
Dhaval Patel14d46ce2017-01-17 16:28:12 -08001/*
2 * Copyright (C) 2014-2017 The Linux Foundation. All rights reserved.
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07005 *
Dhaval Patel14d46ce2017-01-17 16:28:12 -08006 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07009 *
Dhaval Patel14d46ce2017-01-17 16:28:12 -080010 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070017 */
Alan Kwong1a00e4d2016-07-18 09:42:30 -040018
19#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
20
Clarence Ip4ce59322016-06-26 22:27:51 -040021#include <linux/debugfs.h>
Alan Kwong4dd64c82017-02-04 18:41:51 -080022#include <linux/dma-buf.h>
Clarence Ip5e2a9222016-06-26 22:38:24 -040023#include <uapi/drm/sde_drm.h>
Benet Clarkd009b1d2016-06-27 14:45:59 -070024#include <uapi/drm/msm_drm_pp.h>
Clarence Ipaa0faf42016-05-30 12:07:48 -040025
26#include "msm_prop.h"
Jeykumar Sankaran2e655032017-02-04 14:05:45 -080027#include "msm_drv.h"
Clarence Ipaa0faf42016-05-30 12:07:48 -040028
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070029#include "sde_kms.h"
Clarence Ipae4e60c2016-06-26 22:44:04 -040030#include "sde_fence.h"
Clarence Ipc475b082016-06-26 09:27:23 -040031#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040032#include "sde_hw_sspp.h"
Jeykumar Sankaran2e655032017-02-04 14:05:45 -080033#include "sde_hw_catalog_format.h"
Alan Kwong1a00e4d2016-07-18 09:42:30 -040034#include "sde_trace.h"
Dhaval Patel48c76022016-09-01 17:51:23 -070035#include "sde_crtc.h"
Lloyd Atkinson8772e202016-09-26 17:52:16 -040036#include "sde_vbif.h"
Alan Kwong83285fb2016-10-21 20:51:17 -040037#include "sde_plane.h"
Benet Clarkd009b1d2016-06-27 14:45:59 -070038#include "sde_color_processing.h"
Alan Kwong4dd64c82017-02-04 18:41:51 -080039#include "sde_hw_rot.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040040
Clarence Ip13a8cf42016-09-29 17:27:47 -040041#define SDE_DEBUG_PLANE(pl, fmt, ...) SDE_DEBUG("plane%d " fmt,\
42 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
43
44#define SDE_ERROR_PLANE(pl, fmt, ...) SDE_ERROR("plane%d " fmt,\
45 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
46
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040047#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
48#define PHASE_STEP_SHIFT 21
49#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
50#define PHASE_RESIDUAL 15
51
Clarence Ipe78efb72016-06-24 18:35:21 -040052#define SHARP_STRENGTH_DEFAULT 32
53#define SHARP_EDGE_THR_DEFAULT 112
54#define SHARP_SMOOTH_THR_DEFAULT 8
55#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040056
Clarence Ip5e2a9222016-06-26 22:38:24 -040057#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070058
Clarence Ipcae1bb62016-07-07 12:07:13 -040059#define SDE_PLANE_COLOR_FILL_FLAG BIT(31)
60
Jeykumar Sankaran2e655032017-02-04 14:05:45 -080061/* multirect rect index */
62enum {
63 R0,
64 R1,
65 R_MAX
66};
67
68#define TX_MODE_BUFFER_LINE_THRES 2
69
Clarence Ip282dad62016-09-27 17:07:35 -040070/* dirty bits for update function */
71#define SDE_PLANE_DIRTY_RECTS 0x1
72#define SDE_PLANE_DIRTY_FORMAT 0x2
73#define SDE_PLANE_DIRTY_SHARPEN 0x4
74#define SDE_PLANE_DIRTY_ALL 0xFFFFFFFF
75
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -070076#define SDE_QSEED3_DEFAULT_PRELOAD_H 0x4
77#define SDE_QSEED3_DEFAULT_PRELOAD_V 0x3
78
Alan Kwong4dd64c82017-02-04 18:41:51 -080079#define DEFAULT_REFRESH_RATE 60
80
Alan Kwong1a00e4d2016-07-18 09:42:30 -040081/**
82 * enum sde_plane_qos - Different qos configurations for each pipe
83 *
84 * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
85 * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
86 * this configuration is mutually exclusive from VBLANK_CTRL.
87 * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
88 */
89enum sde_plane_qos {
90 SDE_PLANE_QOS_VBLANK_CTRL = BIT(0),
91 SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
92 SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
93};
94
Clarence Ip5fc00c52016-09-23 15:03:34 -040095/*
96 * struct sde_plane - local sde plane structure
97 * @csc_cfg: Decoded user configuration for csc
98 * @csc_usr_ptr: Points to csc_cfg if valid user config available
99 * @csc_ptr: Points to sde_csc_cfg structure to use for current
Alan Kwong4dd64c82017-02-04 18:41:51 -0800100 * @catalog: Points to sde catalog structure
101 * @sbuf_mode: force stream buffer mode if set
102 * @sbuf_writeback: fource stream buffer writeback if set
103 * @blob_rot_caps: Pointer to rotator capability blob
Clarence Ip5fc00c52016-09-23 15:03:34 -0400104 */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700105struct sde_plane {
106 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400107
108 int mmu_id;
109
Clarence Ip730e7192016-06-26 22:45:09 -0400110 struct mutex lock;
111
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400112 enum sde_sspp pipe;
113 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700114 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400115 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400116
117 struct sde_hw_pipe *pipe_hw;
118 struct sde_hw_pipe_cfg pipe_cfg;
Clarence Ipe78efb72016-06-24 18:35:21 -0400119 struct sde_hw_sharp_cfg sharp_cfg;
abeykun48f407a2016-08-25 12:06:44 -0400120 struct sde_hw_scaler3_cfg *scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400121 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400122 uint32_t color_fill;
123 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400124 bool is_rt_pipe;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -0800125 bool is_virtual;
Alan Kwong4dd64c82017-02-04 18:41:51 -0800126 struct sde_mdss_cfg *catalog;
127 u32 sbuf_mode;
128 u32 sbuf_writeback;
Clarence Ip4ce59322016-06-26 22:27:51 -0400129
Clarence Ipb43d4592016-09-08 14:21:35 -0400130 struct sde_hw_pixel_ext pixel_ext;
131 bool pixel_ext_usr;
132
Clarence Ip373f8592016-05-26 00:58:42 -0400133 struct sde_csc_cfg csc_cfg;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400134 struct sde_csc_cfg *csc_usr_ptr;
Clarence Ip373f8592016-05-26 00:58:42 -0400135 struct sde_csc_cfg *csc_ptr;
136
Clarence Ip4c1d9772016-06-26 09:35:38 -0400137 const struct sde_sspp_sub_blks *pipe_sblk;
138
Clarence Ip5e2a9222016-06-26 22:38:24 -0400139 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -0400140
Clarence Ipaa0faf42016-05-30 12:07:48 -0400141 struct msm_property_info property_info;
142 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -0700143 struct drm_property_blob *blob_info;
Alan Kwong4dd64c82017-02-04 18:41:51 -0800144 struct drm_property_blob *blob_rot_caps;
Clarence Ip730e7192016-06-26 22:45:09 -0400145
Clarence Ip4ce59322016-06-26 22:27:51 -0400146 /* debugfs related stuff */
147 struct dentry *debugfs_root;
148 struct sde_debugfs_regset32 debugfs_src;
149 struct sde_debugfs_regset32 debugfs_scaler;
150 struct sde_debugfs_regset32 debugfs_csc;
Clarence Ip716ab662017-03-20 06:51:24 -0700151 bool debugfs_default_scale;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700152};
Dhaval Patel47302cf2016-08-18 15:04:28 -0700153
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700154#define to_sde_plane(x) container_of(x, struct sde_plane, base)
155
Alan Kwong4dd64c82017-02-04 18:41:51 -0800156static struct sde_kms *_sde_plane_get_kms(struct drm_plane *plane)
157{
158 struct msm_drm_private *priv;
159
160 if (!plane || !plane->dev)
161 return NULL;
162 priv = plane->dev->dev_private;
163 if (!priv)
164 return NULL;
165 return to_sde_kms(priv->kms);
166}
167
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400168static bool sde_plane_enabled(struct drm_plane_state *state)
169{
Clarence Ipdbde9832016-06-26 09:48:36 -0400170 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400171}
172
Alan Kwong4dd64c82017-02-04 18:41:51 -0800173static bool sde_plane_sspp_enabled(struct drm_plane_state *state)
174{
175 return state && to_sde_plane_state(state)->rot.out_fb && state->crtc;
176}
177
178/**
179 * sde_plane_crtc_enabled - determine if crtc of given plane state is enabled
180 * @state: Pointer to drm plane state
181 * return: true if plane and the associated crtc are both enabled
182 */
183static bool sde_plane_crtc_enabled(struct drm_plane_state *state)
184{
185 return sde_plane_enabled(state) && state->crtc->state &&
186 state->crtc->state->active &&
187 state->crtc->state->enable;
188}
189
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400190/**
191 * _sde_plane_calc_fill_level - calculate fill level of the given source format
192 * @plane: Pointer to drm plane
193 * @fmt: Pointer to source buffer format
194 * @src_wdith: width of source buffer
195 * Return: fill level corresponding to the source buffer/format or 0 if error
196 */
197static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
198 const struct sde_format *fmt, u32 src_width)
199{
200 struct sde_plane *psde;
201 u32 fixed_buff_size;
202 u32 total_fl;
203
204 if (!plane || !fmt) {
205 SDE_ERROR("invalid arguments\n");
206 return 0;
207 }
208
209 psde = to_sde_plane(plane);
210 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
211
212 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
213 if (fmt->chroma_sample == SDE_CHROMA_420) {
214 /* NV12 */
215 total_fl = (fixed_buff_size / 2) /
216 ((src_width + 32) * fmt->bpp);
217 } else {
218 /* non NV12 */
219 total_fl = (fixed_buff_size) /
220 ((src_width + 32) * fmt->bpp);
221 }
222 } else {
223 total_fl = (fixed_buff_size * 2) /
224 ((src_width + 32) * fmt->bpp);
225 }
226
227 SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
228 plane->base.id, psde->pipe - SSPP_VIG0,
229 fmt->base.pixel_format, src_width, total_fl);
230
231 return total_fl;
232}
233
234/**
235 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
236 * @total_fl: fill level
237 * Return: LUT setting corresponding to the fill level
238 */
239static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
240{
241 u32 qos_lut;
242
243 if (total_fl <= 4)
244 qos_lut = 0x1B;
245 else if (total_fl <= 5)
246 qos_lut = 0x5B;
247 else if (total_fl <= 6)
248 qos_lut = 0x15B;
249 else if (total_fl <= 7)
250 qos_lut = 0x55B;
251 else if (total_fl <= 8)
252 qos_lut = 0x155B;
253 else if (total_fl <= 9)
254 qos_lut = 0x555B;
255 else if (total_fl <= 10)
256 qos_lut = 0x1555B;
257 else if (total_fl <= 11)
258 qos_lut = 0x5555B;
259 else if (total_fl <= 12)
260 qos_lut = 0x15555B;
261 else
262 qos_lut = 0x55555B;
263
264 return qos_lut;
265}
266
267/**
268 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
269 * @total_fl: fill level
270 * Return: LUT setting corresponding to the fill level
271 */
272static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
273{
274 u32 qos_lut;
275
276 if (total_fl <= 10)
277 qos_lut = 0x1AAff;
278 else if (total_fl <= 11)
279 qos_lut = 0x5AAFF;
280 else if (total_fl <= 12)
281 qos_lut = 0x15AAFF;
282 else
283 qos_lut = 0x55AAFF;
284
285 return qos_lut;
286}
287
288/**
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400289 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
290 * @plane: Pointer to drm plane
291 * @fb: Pointer to framebuffer associated with the given plane
292 */
293static void _sde_plane_set_qos_lut(struct drm_plane *plane,
294 struct drm_framebuffer *fb)
295{
296 struct sde_plane *psde;
297 const struct sde_format *fmt = NULL;
298 u32 qos_lut;
299 u32 total_fl = 0;
300
301 if (!plane || !fb) {
302 SDE_ERROR("invalid arguments plane %d fb %d\n",
303 plane != 0, fb != 0);
304 return;
305 }
306
307 psde = to_sde_plane(plane);
308
309 if (!psde->pipe_hw || !psde->pipe_sblk) {
310 SDE_ERROR("invalid arguments\n");
311 return;
312 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
313 return;
314 }
315
316 if (!psde->is_rt_pipe) {
317 qos_lut = psde->pipe_sblk->creq_lut_nrt;
318 } else {
319 fmt = sde_get_sde_format_ext(
320 fb->pixel_format,
321 fb->modifier,
322 drm_format_num_planes(fb->pixel_format));
323 total_fl = _sde_plane_calc_fill_level(plane, fmt,
324 psde->pipe_cfg.src_rect.w);
325
326 if (SDE_FORMAT_IS_LINEAR(fmt))
327 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
328 else
329 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
330 }
331
332 psde->pipe_qos_cfg.creq_lut = qos_lut;
333
334 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
335 (fmt) ? fmt->base.pixel_format : 0,
336 psde->is_rt_pipe, total_fl, qos_lut,
337 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
338
339 SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
340 plane->base.id,
341 psde->pipe - SSPP_VIG0,
342 (fmt) ? fmt->base.pixel_format : 0,
343 psde->is_rt_pipe, total_fl, qos_lut);
344
345 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
346}
347
348/**
349 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
350 * @plane: Pointer to drm plane
351 * @fb: Pointer to framebuffer associated with the given plane
352 */
353static void _sde_plane_set_danger_lut(struct drm_plane *plane,
354 struct drm_framebuffer *fb)
355{
356 struct sde_plane *psde;
357 const struct sde_format *fmt = NULL;
358 u32 danger_lut, safe_lut;
359
360 if (!plane || !fb) {
361 SDE_ERROR("invalid arguments\n");
362 return;
363 }
364
365 psde = to_sde_plane(plane);
366
367 if (!psde->pipe_hw || !psde->pipe_sblk) {
368 SDE_ERROR("invalid arguments\n");
369 return;
370 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
371 return;
372 }
373
374 if (!psde->is_rt_pipe) {
375 danger_lut = psde->pipe_sblk->danger_lut_nrt;
376 safe_lut = psde->pipe_sblk->safe_lut_nrt;
377 } else {
378 fmt = sde_get_sde_format_ext(
379 fb->pixel_format,
380 fb->modifier,
381 drm_format_num_planes(fb->pixel_format));
382
383 if (SDE_FORMAT_IS_LINEAR(fmt)) {
384 danger_lut = psde->pipe_sblk->danger_lut_linear;
385 safe_lut = psde->pipe_sblk->safe_lut_linear;
386 } else {
387 danger_lut = psde->pipe_sblk->danger_lut_tile;
388 safe_lut = psde->pipe_sblk->safe_lut_tile;
389 }
390 }
391
392 psde->pipe_qos_cfg.danger_lut = danger_lut;
393 psde->pipe_qos_cfg.safe_lut = safe_lut;
394
395 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
396 (fmt) ? fmt->base.pixel_format : 0,
397 (fmt) ? fmt->fetch_mode : 0,
398 psde->pipe_qos_cfg.danger_lut,
399 psde->pipe_qos_cfg.safe_lut);
400
401 SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
402 plane->base.id,
403 psde->pipe - SSPP_VIG0,
404 fmt ? fmt->base.pixel_format : 0,
405 fmt ? fmt->fetch_mode : -1,
406 psde->pipe_qos_cfg.danger_lut,
407 psde->pipe_qos_cfg.safe_lut);
408
409 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
410 &psde->pipe_qos_cfg);
411}
412
413/**
414 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
415 * @plane: Pointer to drm plane
416 * @enable: true to enable QoS control
417 * @flags: QoS control mode (enum sde_plane_qos)
418 */
419static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
420 bool enable, u32 flags)
421{
422 struct sde_plane *psde;
423
424 if (!plane) {
425 SDE_ERROR("invalid arguments\n");
426 return;
427 }
428
429 psde = to_sde_plane(plane);
430
431 if (!psde->pipe_hw || !psde->pipe_sblk) {
432 SDE_ERROR("invalid arguments\n");
433 return;
434 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
435 return;
436 }
437
438 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
439 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
440 psde->pipe_qos_cfg.danger_vblank =
441 psde->pipe_sblk->danger_vblank;
442 psde->pipe_qos_cfg.vblank_en = enable;
443 }
444
445 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
446 /* this feature overrules previous VBLANK_CTRL */
447 psde->pipe_qos_cfg.vblank_en = false;
448 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
449 }
450
451 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
452 psde->pipe_qos_cfg.danger_safe_en = enable;
453
454 if (!psde->is_rt_pipe) {
455 psde->pipe_qos_cfg.vblank_en = false;
456 psde->pipe_qos_cfg.danger_safe_en = false;
457 }
458
Clarence Ip0d0e96d2016-10-24 18:13:13 -0400459 SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n",
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400460 plane->base.id,
461 psde->pipe - SSPP_VIG0,
462 psde->pipe_qos_cfg.danger_safe_en,
463 psde->pipe_qos_cfg.vblank_en,
464 psde->pipe_qos_cfg.creq_vblank,
Clarence Ip0d0e96d2016-10-24 18:13:13 -0400465 psde->pipe_qos_cfg.danger_vblank,
466 psde->is_rt_pipe);
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400467
468 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
469 &psde->pipe_qos_cfg);
470}
471
Alan Kwongf0fd8512016-10-24 21:39:26 -0400472int sde_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
473{
474 struct sde_plane *psde;
475 struct msm_drm_private *priv;
476 struct sde_kms *sde_kms;
477
478 if (!plane || !plane->dev) {
479 SDE_ERROR("invalid arguments\n");
480 return -EINVAL;
481 }
482
483 priv = plane->dev->dev_private;
484 if (!priv || !priv->kms) {
485 SDE_ERROR("invalid KMS reference\n");
486 return -EINVAL;
487 }
488
489 sde_kms = to_sde_kms(priv->kms);
490 psde = to_sde_plane(plane);
491
492 if (!psde->is_rt_pipe)
493 goto end;
494
495 sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
496
497 _sde_plane_set_qos_ctrl(plane, enable, SDE_PLANE_QOS_PANIC_CTRL);
498
499 sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
500
501end:
502 return 0;
503}
504
Alan Kwong5d324e42016-07-28 22:56:18 -0400505/**
506 * _sde_plane_set_ot_limit - set OT limit for the given plane
507 * @plane: Pointer to drm plane
508 * @crtc: Pointer to drm crtc
509 */
510static void _sde_plane_set_ot_limit(struct drm_plane *plane,
511 struct drm_crtc *crtc)
512{
513 struct sde_plane *psde;
514 struct sde_vbif_set_ot_params ot_params;
515 struct msm_drm_private *priv;
516 struct sde_kms *sde_kms;
517
518 if (!plane || !plane->dev || !crtc) {
519 SDE_ERROR("invalid arguments plane %d crtc %d\n",
520 plane != 0, crtc != 0);
521 return;
522 }
523
524 priv = plane->dev->dev_private;
525 if (!priv || !priv->kms) {
526 SDE_ERROR("invalid KMS reference\n");
527 return;
528 }
529
530 sde_kms = to_sde_kms(priv->kms);
531 psde = to_sde_plane(plane);
532 if (!psde->pipe_hw) {
533 SDE_ERROR("invalid pipe reference\n");
534 return;
535 }
536
537 memset(&ot_params, 0, sizeof(ot_params));
538 ot_params.xin_id = psde->pipe_hw->cap->xin_id;
539 ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
540 ot_params.width = psde->pipe_cfg.src_rect.w;
541 ot_params.height = psde->pipe_cfg.src_rect.h;
542 ot_params.is_wfd = !psde->is_rt_pipe;
543 ot_params.frame_rate = crtc->mode.vrefresh;
544 ot_params.vbif_idx = VBIF_RT;
545 ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
546 ot_params.rd = true;
547
548 sde_vbif_set_ot_limit(sde_kms, &ot_params);
549}
550
Clarence Ipcae1bb62016-07-07 12:07:13 -0400551/* helper to update a state's input fence pointer from the property */
Clarence Ip13a8cf42016-09-29 17:27:47 -0400552static void _sde_plane_set_input_fence(struct sde_plane *psde,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400553 struct sde_plane_state *pstate, uint64_t fd)
554{
Clarence Ip13a8cf42016-09-29 17:27:47 -0400555 if (!psde || !pstate) {
556 SDE_ERROR("invalid arg(s), plane %d state %d\n",
557 psde != 0, pstate != 0);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400558 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -0400559 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400560
561 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400562 if (pstate->input_fence)
563 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400564
565 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400566 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400567
Clarence Ip13a8cf42016-09-29 17:27:47 -0400568 SDE_DEBUG_PLANE(psde, "0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400569}
570
Clarence Ipcae1bb62016-07-07 12:07:13 -0400571int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400572{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400573 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400574 struct sde_plane_state *pstate;
Clarence Ip78a04ed2016-10-04 15:57:45 -0400575 uint32_t prefix;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400576 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400577 int ret = -EINVAL;
Dhaval Patel39323d42017-03-01 23:48:24 -0800578 signed long rc;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400579
580 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700581 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400582 } else if (!plane->state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -0400583 SDE_ERROR_PLANE(to_sde_plane(plane), "invalid state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400584 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400585 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400586 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400587 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400588
Clarence Ipcae1bb62016-07-07 12:07:13 -0400589 if (input_fence) {
Dhaval Patel39323d42017-03-01 23:48:24 -0800590 psde->is_error = false;
Clarence Ip78a04ed2016-10-04 15:57:45 -0400591 prefix = sde_sync_get_name_prefix(input_fence);
Dhaval Patel39323d42017-03-01 23:48:24 -0800592 rc = sde_sync_wait(input_fence, wait_ms);
Clarence Ip78a04ed2016-10-04 15:57:45 -0400593
Lloyd Atkinson5d40d312016-09-06 08:34:13 -0400594 SDE_EVT32(DRMID(plane), -ret, prefix);
Clarence Ip78a04ed2016-10-04 15:57:45 -0400595
Dhaval Patel39323d42017-03-01 23:48:24 -0800596 switch (rc) {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400597 case 0:
Clarence Ip78a04ed2016-10-04 15:57:45 -0400598 SDE_ERROR_PLANE(psde, "%ums timeout on %08X\n",
599 wait_ms, prefix);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400600 psde->is_error = true;
Dhaval Patel39323d42017-03-01 23:48:24 -0800601 ret = -ETIMEDOUT;
602 break;
603 case -ERESTARTSYS:
604 SDE_ERROR_PLANE(psde,
605 "%ums wait interrupted on %08X\n",
606 wait_ms, prefix);
607 psde->is_error = true;
608 ret = -ERESTARTSYS;
609 break;
610 case -EINVAL:
611 SDE_ERROR_PLANE(psde,
612 "invalid fence param for %08X\n",
613 prefix);
614 psde->is_error = true;
615 ret = -EINVAL;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400616 break;
617 default:
Dhaval Patel39323d42017-03-01 23:48:24 -0800618 SDE_DEBUG_PLANE(psde, "signaled\n");
619 ret = 0;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400620 break;
621 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400622 } else {
623 ret = 0;
624 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400625 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400626 return ret;
627}
628
Clarence Ip282dad62016-09-27 17:07:35 -0400629static inline void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400630 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400631 struct sde_hw_pipe_cfg *pipe_cfg,
632 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400633{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400634 struct sde_plane *psde;
Clarence Ip282dad62016-09-27 17:07:35 -0400635 int ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400636
Clarence Ip13a8cf42016-09-29 17:27:47 -0400637 if (!plane || !pstate || !pipe_cfg || !fb) {
638 SDE_ERROR(
639 "invalid arg(s), plane %d state %d cfg %d fb %d\n",
640 plane != 0, pstate != 0, pipe_cfg != 0, fb != 0);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400641 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -0400642 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400643
644 psde = to_sde_plane(plane);
Clarence Ipb6eb2362016-09-08 16:18:13 -0400645 if (!psde->pipe_hw) {
646 SDE_ERROR_PLANE(psde, "invalid pipe_hw\n");
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400647 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400648 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400649
Clarence Ipb6eb2362016-09-08 16:18:13 -0400650 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
651 if (ret == -EAGAIN)
652 SDE_DEBUG_PLANE(psde, "not updating same src addrs\n");
653 else if (ret)
654 SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret);
655 else if (psde->pipe_hw->ops.setup_sourceaddress)
Jeykumar Sankaran2e655032017-02-04 14:05:45 -0800656 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg,
657 pstate->multirect_index);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400658}
659
abeykun48f407a2016-08-25 12:06:44 -0400660static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
661 struct sde_plane_state *pstate)
662{
Clarence Ip3bf8d872017-02-16 15:25:38 -0500663 struct sde_hw_scaler3_cfg *cfg;
abeykun48f407a2016-08-25 12:06:44 -0400664 int ret = 0;
665
Clarence Ip3bf8d872017-02-16 15:25:38 -0500666 if (!psde || !psde->scaler3_cfg) {
667 SDE_ERROR("invalid args\n");
668 return -EINVAL;
669 } else if (!pstate) {
670 /* pstate is expected to be null on forced color fill */
671 SDE_DEBUG("null pstate\n");
672 return -EINVAL;
673 }
674
675 cfg = psde->scaler3_cfg;
676
abeykun48f407a2016-08-25 12:06:44 -0400677 cfg->dir_lut = msm_property_get_blob(
678 &psde->property_info,
679 pstate->property_blobs, &cfg->dir_len,
680 PLANE_PROP_SCALER_LUT_ED);
681 cfg->cir_lut = msm_property_get_blob(
682 &psde->property_info,
683 pstate->property_blobs, &cfg->cir_len,
684 PLANE_PROP_SCALER_LUT_CIR);
685 cfg->sep_lut = msm_property_get_blob(
686 &psde->property_info,
687 pstate->property_blobs, &cfg->sep_len,
688 PLANE_PROP_SCALER_LUT_SEP);
689 if (!cfg->dir_lut || !cfg->cir_lut || !cfg->sep_lut)
690 ret = -ENODATA;
691 return ret;
692}
693
Clarence Ipcb410d42016-06-26 22:52:33 -0400694static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400695 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
696 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400697 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400698 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
699{
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -0700700 uint32_t decimated, i;
701
702 if (!psde || !scale_cfg || !fmt || !chroma_subsmpl_h ||
703 !chroma_subsmpl_v) {
704 SDE_ERROR("psde %pK scale_cfg %pK fmt %pK smp_h %d smp_v %d\n"
705 , psde, scale_cfg, fmt, chroma_subsmpl_h,
706 chroma_subsmpl_v);
707 return;
708 }
709
710 memset(scale_cfg, 0, sizeof(*scale_cfg));
Clarence Ip716ab662017-03-20 06:51:24 -0700711 memset(&psde->pixel_ext, 0, sizeof(struct sde_hw_pixel_ext));
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -0700712
713 decimated = DECIMATED_DIMENSION(src_w,
714 psde->pipe_cfg.horz_decimation);
715 scale_cfg->phase_step_x[SDE_SSPP_COMP_0] =
716 mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_w);
717 decimated = DECIMATED_DIMENSION(src_h,
718 psde->pipe_cfg.vert_decimation);
719 scale_cfg->phase_step_y[SDE_SSPP_COMP_0] =
720 mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_h);
721
722
723 scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2] =
724 scale_cfg->phase_step_y[SDE_SSPP_COMP_0] / chroma_subsmpl_v;
725 scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2] =
726 scale_cfg->phase_step_x[SDE_SSPP_COMP_0] / chroma_subsmpl_h;
727
728 scale_cfg->phase_step_x[SDE_SSPP_COMP_2] =
729 scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2];
730 scale_cfg->phase_step_y[SDE_SSPP_COMP_2] =
731 scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2];
732
733 scale_cfg->phase_step_x[SDE_SSPP_COMP_3] =
734 scale_cfg->phase_step_x[SDE_SSPP_COMP_0];
735 scale_cfg->phase_step_y[SDE_SSPP_COMP_3] =
736 scale_cfg->phase_step_y[SDE_SSPP_COMP_0];
737
738 for (i = 0; i < SDE_MAX_PLANES; i++) {
739 scale_cfg->src_width[i] = DECIMATED_DIMENSION(src_w,
740 psde->pipe_cfg.horz_decimation);
741 scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h,
742 psde->pipe_cfg.vert_decimation);
743 if (SDE_FORMAT_IS_YUV(fmt))
744 scale_cfg->src_width[i] &= ~0x1;
745 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) {
746 scale_cfg->src_width[i] /= chroma_subsmpl_h;
747 scale_cfg->src_height[i] /= chroma_subsmpl_v;
748 }
749 scale_cfg->preload_x[i] = SDE_QSEED3_DEFAULT_PRELOAD_H;
750 scale_cfg->preload_y[i] = SDE_QSEED3_DEFAULT_PRELOAD_V;
751 psde->pixel_ext.num_ext_pxls_top[i] =
752 scale_cfg->src_height[i];
753 psde->pixel_ext.num_ext_pxls_left[i] =
754 scale_cfg->src_width[i];
755 }
756 if (!(SDE_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
757 && (src_w == dst_w))
758 return;
759
760 scale_cfg->dst_width = dst_w;
761 scale_cfg->dst_height = dst_h;
762 scale_cfg->y_rgb_filter_cfg = SDE_SCALE_BIL;
763 scale_cfg->uv_filter_cfg = SDE_SCALE_BIL;
764 scale_cfg->alpha_filter_cfg = SDE_SCALE_ALPHA_BIL;
765 scale_cfg->lut_flag = 0;
766 scale_cfg->blend_cfg = 1;
767 scale_cfg->enable = 1;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400768}
769
Clarence Ipcb410d42016-06-26 22:52:33 -0400770/**
Clarence Ip13a8cf42016-09-29 17:27:47 -0400771 * _sde_plane_setup_scaler2 - determine default scaler phase steps/filter type
Clarence Ipcb410d42016-06-26 22:52:33 -0400772 * @psde: Pointer to SDE plane object
773 * @src: Source size
774 * @dst: Destination size
775 * @phase_steps: Pointer to output array for phase steps
776 * @filter: Pointer to output array for filter type
777 * @fmt: Pointer to format definition
778 * @chroma_subsampling: Subsampling amount for chroma channel
779 *
780 * Returns: 0 on success
781 */
782static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400783 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400784 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400785 uint32_t chroma_subsampling)
786{
Clarence Ipcb410d42016-06-26 22:52:33 -0400787 if (!psde || !phase_steps || !filter || !fmt) {
Clarence Ip13a8cf42016-09-29 17:27:47 -0400788 SDE_ERROR(
789 "invalid arg(s), plane %d phase %d filter %d fmt %d\n",
790 psde != 0, phase_steps != 0, filter != 0, fmt != 0);
Clarence Ipcb410d42016-06-26 22:52:33 -0400791 return -EINVAL;
792 }
793
Clarence Ip4c1d9772016-06-26 09:35:38 -0400794 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400795 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400796 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400797 phase_steps[SDE_SSPP_COMP_1_2] =
798 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
799 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
800 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400801
802 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400803 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400804 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400805 (src <= dst) ? SDE_SCALE_FILTER_BIL :
806 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400807
Clarence Ipdbde9832016-06-26 09:48:36 -0400808 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400809 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400810 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
811 } else {
812 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
813 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400814 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400815 }
816 } else {
817 /* disable scaler */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400818 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
819 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
820 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400821 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400822 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400823}
824
Clarence Ipcb410d42016-06-26 22:52:33 -0400825/**
826 * _sde_plane_setup_pixel_ext - determine default pixel extension values
827 * @psde: Pointer to SDE plane object
828 * @src: Source size
829 * @dst: Destination size
830 * @decimated_src: Source size after decimation, if any
831 * @phase_steps: Pointer to output array for phase steps
832 * @out_src: Output array for pixel extension values
833 * @out_edge1: Output array for pixel extension first edge
834 * @out_edge2: Output array for pixel extension second edge
835 * @filter: Pointer to array for filter type
836 * @fmt: Pointer to format definition
837 * @chroma_subsampling: Subsampling amount for chroma channel
838 * @post_compare: Whether to chroma subsampled source size for comparisions
839 */
840static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400841 uint32_t src, uint32_t dst, uint32_t decimated_src,
842 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400843 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400844 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400845 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400846{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400847 int64_t edge1, edge2, caf;
848 uint32_t src_work;
849 int i, tmp;
850
Clarence Ipcb410d42016-06-26 22:52:33 -0400851 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400852 out_edge2 && filter && fmt) {
853 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400854 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400855 caf = PHASE_STEP_UNIT_SCALE;
856 else
857 caf = 0;
858
859 for (i = 0; i < SDE_MAX_PLANES; i++) {
860 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400861 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400862 src_work /= chroma_subsampling;
863 if (post_compare)
864 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400865 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400866 /* unity */
867 edge1 = 0;
868 edge2 = 0;
869 } else if (dst >= src) {
870 /* upscale */
871 edge1 = (1 << PHASE_RESIDUAL);
872 edge1 -= caf;
873 edge2 = (1 << PHASE_RESIDUAL);
874 edge2 += (dst - 1) * *(phase_steps + i);
875 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
876 edge2 += caf;
877 edge2 = -(edge2);
878 } else {
879 /* downscale */
880 edge1 = 0;
881 edge2 = (dst - 1) * *(phase_steps + i);
882 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
883 edge2 += *(phase_steps + i);
884 edge2 = -(edge2);
885 }
886
887 /* only enable CAF for luma plane */
888 caf = 0;
889
890 /* populate output arrays */
891 *(out_src + i) = src_work;
892
893 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400894 if (edge1 >= 0) {
895 tmp = (uint32_t)edge1;
896 tmp >>= PHASE_STEP_SHIFT;
897 *(out_edge1 + i) = -tmp;
898 } else {
899 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400900 *(out_edge1 + i) =
901 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
902 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400903 }
904 if (edge2 >= 0) {
905 tmp = (uint32_t)edge2;
906 tmp >>= PHASE_STEP_SHIFT;
907 *(out_edge2 + i) = -tmp;
908 } else {
909 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400910 *(out_edge2 + i) =
911 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
912 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400913 }
914 }
915 }
916}
917
Clarence Ip5fc00c52016-09-23 15:03:34 -0400918static inline void _sde_plane_setup_csc(struct sde_plane *psde)
Clarence Ipe78efb72016-06-24 18:35:21 -0400919{
920 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
921 {
Clarence Ip373f8592016-05-26 00:58:42 -0400922 /* S15.16 format */
923 0x00012A00, 0x00000000, 0x00019880,
924 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
925 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400926 },
Clarence Ip373f8592016-05-26 00:58:42 -0400927 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400928 { 0xfff0, 0xff80, 0xff80,},
929 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400930 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400931 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400932 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400933 };
abeykun1c312f62016-08-26 09:47:12 -0400934 static const struct sde_csc_cfg sde_csc10_YUV2RGB_601L = {
935 {
936 /* S15.16 format */
937 0x00012A00, 0x00000000, 0x00019880,
938 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
939 0x00012A00, 0x00020480, 0x00000000,
940 },
941 /* signed bias */
942 { 0xffc0, 0xfe00, 0xfe00,},
943 { 0x0, 0x0, 0x0,},
944 /* unsigned clamp */
945 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
946 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
947 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400948
Clarence Ip5fc00c52016-09-23 15:03:34 -0400949 if (!psde) {
950 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400951 return;
952 }
Clarence Ip5e2a9222016-06-26 22:38:24 -0400953
Clarence Ipcae1bb62016-07-07 12:07:13 -0400954 /* revert to kernel default if override not available */
Clarence Ip5fc00c52016-09-23 15:03:34 -0400955 if (psde->csc_usr_ptr)
956 psde->csc_ptr = psde->csc_usr_ptr;
abeykun1c312f62016-08-26 09:47:12 -0400957 else if (BIT(SDE_SSPP_CSC_10BIT) & psde->features)
958 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc10_YUV2RGB_601L;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400959 else
Clarence Ip373f8592016-05-26 00:58:42 -0400960 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400961
Clarence Ip13a8cf42016-09-29 17:27:47 -0400962 SDE_DEBUG_PLANE(psde, "using 0x%X 0x%X 0x%X...\n",
Clarence Ip5fc00c52016-09-23 15:03:34 -0400963 psde->csc_ptr->csc_mv[0],
964 psde->csc_ptr->csc_mv[1],
965 psde->csc_ptr->csc_mv[2]);
Clarence Ipe78efb72016-06-24 18:35:21 -0400966}
967
Benet Clarkeb1b4462016-06-27 14:43:06 -0700968static void sde_color_process_plane_setup(struct drm_plane *plane)
969{
970 struct sde_plane *psde;
971 struct sde_plane_state *pstate;
972 uint32_t hue, saturation, value, contrast;
Benet Clarkd009b1d2016-06-27 14:45:59 -0700973 struct drm_msm_memcol *memcol = NULL;
974 size_t memcol_sz = 0;
Benet Clarkeb1b4462016-06-27 14:43:06 -0700975
976 psde = to_sde_plane(plane);
977 pstate = to_sde_plane_state(plane->state);
978
979 hue = (uint32_t) sde_plane_get_property(pstate, PLANE_PROP_HUE_ADJUST);
980 if (psde->pipe_hw->ops.setup_pa_hue)
981 psde->pipe_hw->ops.setup_pa_hue(psde->pipe_hw, &hue);
982 saturation = (uint32_t) sde_plane_get_property(pstate,
983 PLANE_PROP_SATURATION_ADJUST);
984 if (psde->pipe_hw->ops.setup_pa_sat)
985 psde->pipe_hw->ops.setup_pa_sat(psde->pipe_hw, &saturation);
986 value = (uint32_t) sde_plane_get_property(pstate,
987 PLANE_PROP_VALUE_ADJUST);
988 if (psde->pipe_hw->ops.setup_pa_val)
989 psde->pipe_hw->ops.setup_pa_val(psde->pipe_hw, &value);
990 contrast = (uint32_t) sde_plane_get_property(pstate,
991 PLANE_PROP_CONTRAST_ADJUST);
992 if (psde->pipe_hw->ops.setup_pa_cont)
993 psde->pipe_hw->ops.setup_pa_cont(psde->pipe_hw, &contrast);
Benet Clarkeb1b4462016-06-27 14:43:06 -0700994
Benet Clarkd009b1d2016-06-27 14:45:59 -0700995 if (psde->pipe_hw->ops.setup_pa_memcolor) {
996 /* Skin memory color setup */
997 memcol = msm_property_get_blob(&psde->property_info,
998 pstate->property_blobs,
999 &memcol_sz,
1000 PLANE_PROP_SKIN_COLOR);
1001 psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
1002 MEMCOLOR_SKIN, memcol);
1003
1004 /* Sky memory color setup */
1005 memcol = msm_property_get_blob(&psde->property_info,
1006 pstate->property_blobs,
1007 &memcol_sz,
1008 PLANE_PROP_SKY_COLOR);
1009 psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
1010 MEMCOLOR_SKY, memcol);
1011
1012 /* Foliage memory color setup */
1013 memcol = msm_property_get_blob(&psde->property_info,
1014 pstate->property_blobs,
1015 &memcol_sz,
1016 PLANE_PROP_FOLIAGE_COLOR);
1017 psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
1018 MEMCOLOR_FOLIAGE, memcol);
1019 }
1020}
Benet Clarkeb1b4462016-06-27 14:43:06 -07001021
Clarence Ipcb410d42016-06-26 22:52:33 -04001022static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001023 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -04001024 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001025{
Clarence Ipb43d4592016-09-08 14:21:35 -04001026 struct sde_hw_pixel_ext *pe;
Clarence Ipcb410d42016-06-26 22:52:33 -04001027 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001028
Clarence Ipb43d4592016-09-08 14:21:35 -04001029 if (!psde || !fmt) {
1030 SDE_ERROR("invalid arg(s), plane %d fmt %d state %d\n",
1031 psde != 0, fmt != 0, pstate != 0);
Clarence Ipcb410d42016-06-26 22:52:33 -04001032 return;
Clarence Ipb43d4592016-09-08 14:21:35 -04001033 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001034
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001035 pe = &(psde->pixel_ext);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001036
Clarence Ipdedbba92016-09-27 17:43:10 -04001037 psde->pipe_cfg.horz_decimation =
1038 sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
1039 psde->pipe_cfg.vert_decimation =
1040 sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
Clarence Ip04ec67d2016-05-26 01:16:15 -04001041
1042 /* don't chroma subsample if decimating */
1043 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001044 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -04001045 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001046 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -04001047
Clarence Ip5e2a9222016-06-26 22:38:24 -04001048 /* update scaler */
1049 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
abeykun48f407a2016-08-25 12:06:44 -04001050 int error;
1051
1052 error = _sde_plane_setup_scaler3_lut(psde, pstate);
Clarence Ip716ab662017-03-20 06:51:24 -07001053 if (error || !psde->pixel_ext_usr ||
1054 psde->debugfs_default_scale) {
Clarence Ipb43d4592016-09-08 14:21:35 -04001055 /* calculate default config for QSEED3 */
Clarence Ipcb410d42016-06-26 22:52:33 -04001056 _sde_plane_setup_scaler3(psde,
1057 psde->pipe_cfg.src_rect.w,
1058 psde->pipe_cfg.src_rect.h,
1059 psde->pipe_cfg.dst_rect.w,
1060 psde->pipe_cfg.dst_rect.h,
abeykun48f407a2016-08-25 12:06:44 -04001061 psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001062 chroma_subsmpl_h, chroma_subsmpl_v);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001063 }
Clarence Ip716ab662017-03-20 06:51:24 -07001064 } else if (!psde->pixel_ext_usr || !pstate ||
1065 psde->debugfs_default_scale) {
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001066 uint32_t deci_dim, i;
1067
Clarence Ipb43d4592016-09-08 14:21:35 -04001068 /* calculate default configuration for QSEED2 */
1069 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001070
Clarence Ip13a8cf42016-09-29 17:27:47 -04001071 SDE_DEBUG_PLANE(psde, "default config\n");
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001072 deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
1073 psde->pipe_cfg.horz_decimation);
Clarence Ipb43d4592016-09-08 14:21:35 -04001074 _sde_plane_setup_scaler2(psde,
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001075 deci_dim,
Clarence Ipb43d4592016-09-08 14:21:35 -04001076 psde->pipe_cfg.dst_rect.w,
1077 pe->phase_step_x,
1078 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001079
Clarence Ipdbde9832016-06-26 09:48:36 -04001080 if (SDE_FORMAT_IS_YUV(fmt))
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001081 deci_dim &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -04001082 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001083 psde->pipe_cfg.dst_rect.w, deci_dim,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001084 pe->phase_step_x,
1085 pe->roi_w,
1086 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -04001087 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001088 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001089
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001090 deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001091 psde->pipe_cfg.vert_decimation);
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001092 _sde_plane_setup_scaler2(psde,
1093 deci_dim,
1094 psde->pipe_cfg.dst_rect.h,
1095 pe->phase_step_y,
1096 pe->vert_filter, fmt, chroma_subsmpl_v);
Clarence Ipcb410d42016-06-26 22:52:33 -04001097 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001098 psde->pipe_cfg.dst_rect.h, deci_dim,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001099 pe->phase_step_y,
1100 pe->roi_h,
1101 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -04001102 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001103 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001104
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001105 for (i = 0; i < SDE_MAX_PLANES; i++) {
1106 if (pe->num_ext_pxls_left[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001107 pe->left_rpt[i] = pe->num_ext_pxls_left[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001108 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001109 pe->left_ftch[i] = pe->num_ext_pxls_left[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001110
1111 if (pe->num_ext_pxls_right[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001112 pe->right_rpt[i] = pe->num_ext_pxls_right[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001113 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001114 pe->right_ftch[i] = pe->num_ext_pxls_right[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001115
1116 if (pe->num_ext_pxls_top[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001117 pe->top_rpt[i] = pe->num_ext_pxls_top[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001118 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001119 pe->top_ftch[i] = pe->num_ext_pxls_top[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001120
1121 if (pe->num_ext_pxls_btm[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001122 pe->btm_rpt[i] = pe->num_ext_pxls_btm[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001123 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001124 pe->btm_ftch[i] = pe->num_ext_pxls_btm[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001125 }
1126 }
Clarence Ipcb410d42016-06-26 22:52:33 -04001127}
1128
Clarence Ipcae1bb62016-07-07 12:07:13 -04001129/**
1130 * _sde_plane_color_fill - enables color fill on plane
Clarence Ip13a8cf42016-09-29 17:27:47 -04001131 * @psde: Pointer to SDE plane object
Clarence Ipcae1bb62016-07-07 12:07:13 -04001132 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
1133 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
1134 * Returns: 0 on success
1135 */
Clarence Ip13a8cf42016-09-29 17:27:47 -04001136static int _sde_plane_color_fill(struct sde_plane *psde,
Clarence Ipcb410d42016-06-26 22:52:33 -04001137 uint32_t color, uint32_t alpha)
1138{
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001139 const struct sde_format *fmt;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001140 const struct drm_plane *plane;
1141 const struct sde_plane_state *pstate;
Clarence Ipcb410d42016-06-26 22:52:33 -04001142
Clarence Ip13a8cf42016-09-29 17:27:47 -04001143 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001144 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001145 return -EINVAL;
1146 }
1147
Clarence Ipcb410d42016-06-26 22:52:33 -04001148 if (!psde->pipe_hw) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04001149 SDE_ERROR_PLANE(psde, "invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001150 return -EINVAL;
1151 }
1152
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001153 plane = &psde->base;
1154 pstate = to_sde_plane_state(plane->state);
1155
Clarence Ip13a8cf42016-09-29 17:27:47 -04001156 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipcae1bb62016-07-07 12:07:13 -04001157
Clarence Ipcb410d42016-06-26 22:52:33 -04001158 /*
1159 * select fill format to match user property expectation,
1160 * h/w only supports RGB variants
1161 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001162 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -04001163
1164 /* update sspp */
1165 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
1166 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001167 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24),
1168 pstate->multirect_index);
Clarence Ipcb410d42016-06-26 22:52:33 -04001169
1170 /* override scaler/decimation if solid fill */
1171 psde->pipe_cfg.src_rect.x = 0;
1172 psde->pipe_cfg.src_rect.y = 0;
1173 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
1174 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
1175
Clarence Ipcb410d42016-06-26 22:52:33 -04001176 if (psde->pipe_hw->ops.setup_format)
1177 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001178 fmt, SDE_SSPP_SOLID_FILL,
1179 pstate->multirect_index);
Clarence Ipcb410d42016-06-26 22:52:33 -04001180
1181 if (psde->pipe_hw->ops.setup_rects)
1182 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
Jeykumar Sankaran9fcfa482017-02-16 16:03:14 -08001183 &psde->pipe_cfg,
1184 pstate->multirect_index);
1185
1186 _sde_plane_setup_scaler(psde, fmt, 0);
1187 if (psde->pipe_hw->ops.setup_pe)
1188 psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
1189 &psde->pixel_ext);
Clarence Ipcb410d42016-06-26 22:52:33 -04001190 }
1191
1192 return 0;
1193}
1194
Alan Kwong4dd64c82017-02-04 18:41:51 -08001195/**
1196 * sde_plane_rot_calc_perfill - calculate rotator start prefill
1197 * @plane: Pointer to drm plane
1198 * return: prefill time in line
1199 */
1200static u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
1201{
1202 struct drm_plane_state *state;
1203 struct drm_crtc_state *cstate;
1204 struct sde_plane_state *pstate;
1205 struct sde_plane_rot_state *rstate;
1206 struct sde_kms *sde_kms;
1207 u32 blocksize = 128;
1208 u32 prefill_line = 0;
1209
1210 if (!plane || !plane->state || !plane->state->fb ||
1211 !plane->state->crtc || !plane->state->crtc->state) {
1212 SDE_ERROR("invalid parameters\n");
1213 return 0;
1214 }
1215
1216 sde_kms = _sde_plane_get_kms(plane);
1217 state = plane->state;
1218 cstate = state->crtc->state;
1219 pstate = to_sde_plane_state(state);
1220 rstate = &pstate->rot;
1221
1222 if (!rstate->rot_hw || !rstate->rot_hw->caps || !rstate->out_src_h ||
1223 !sde_kms || !sde_kms->catalog) {
1224 SDE_ERROR("invalid parameters\n");
1225 return 0;
1226 }
1227
1228 /* if rstate->out_fb_format is TP10, then block size is 96 */
1229
1230 prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
1231
1232 SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
1233
1234 return prefill_line;
1235}
1236
1237/**
1238 * sde_plane_is_sbuf_mode - check if sspp of given plane is in streaming
1239 * buffer mode
1240 * @plane: Pointer to drm plane
1241 * @prefill: Pointer to prefill line count
1242 * return: true if sspp is in stream buffer mode
1243 */
1244bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill)
1245{
1246 struct sde_plane_state *pstate = plane && plane->state ?
1247 to_sde_plane_state(plane->state) : NULL;
1248 struct sde_plane_rot_state *rstate = pstate ? &pstate->rot : NULL;
1249 bool sbuf_mode = rstate ? rstate->out_sbuf : false;
1250
1251 if (prefill && sbuf_mode)
1252 *prefill = sde_plane_rot_calc_prefill(plane);
1253
1254 return sbuf_mode;
1255}
1256
1257/**
1258 * sde_plane_rot_calc_cfg - calculate rotator/sspp configuration by
1259 * enumerating over all planes attached to the same rotator
1260 * @plane: Pointer to drm plane
1261 * @state: Pointer to drm state to be updated
1262 * return: none
1263 */
1264static void sde_plane_rot_calc_cfg(struct drm_plane *plane,
1265 struct drm_plane_state *state)
1266{
1267 struct sde_plane_state *pstate;
1268 struct sde_plane_rot_state *rstate;
1269 struct sde_hw_blk *hw_blk;
1270 struct sde_hw_blk_attachment *attach;
1271 struct drm_rect *in_rot, *out_rot;
1272 u32 dst_x, dst_y, dst_w, dst_h;
1273 int found = 0;
1274 int xpos = 0;
1275
1276 if (!plane || !state || !state->state) {
1277 SDE_ERROR("invalid parameters\n");
1278 return;
1279 }
1280
1281 pstate = to_sde_plane_state(state);
1282 rstate = &pstate->rot;
1283
1284 if (!rstate->rot_hw) {
1285 SDE_ERROR("invalid rotator hw\n");
1286 return;
1287 }
1288
1289 in_rot = &rstate->in_rot_rect;
1290 in_rot->x1 = state->src_x;
1291 in_rot->y1 = state->src_y;
1292 in_rot->x2 = state->src_x + state->src_w;
1293 in_rot->y2 = state->src_y + state->src_h;
1294
1295 out_rot = &rstate->out_rot_rect;
1296 dst_x = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_X);
1297 dst_y = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_Y);
1298 dst_w = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_W);
1299 dst_h = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_H);
1300
1301 if (!dst_w && !dst_h) {
1302 rstate->out_rot_rect = rstate->in_rot_rect;
1303 drm_rect_rotate(&rstate->out_rot_rect, state->fb->width << 16,
1304 state->fb->height << 16, rstate->in_rotation);
1305 } else {
1306 out_rot->x1 = dst_x;
1307 out_rot->y1 = dst_y;
1308 out_rot->x2 = dst_x + dst_w;
1309 out_rot->y2 = dst_y + dst_h;
1310 }
1311
1312 rstate->out_src_rect = rstate->out_rot_rect;
1313
1314 hw_blk = &rstate->rot_hw->base;
1315
1316 /* enumerating over all planes attached to the same rotator */
1317 list_for_each_entry(attach, &hw_blk->attach_list, list) {
1318 struct drm_plane *attached_plane;
1319 struct drm_plane_state *attached_state;
1320 struct sde_plane_state *attached_pstate;
1321 struct sde_plane_rot_state *attached_rstate;
1322 struct drm_rect attached_out_rect;
1323
1324 if (attach->tag != SDE_TAG_ROT_PLANE)
1325 continue;
1326
1327 attached_plane = attach->value;
1328
1329 found++;
1330
1331 /* skip itself */
1332 if (attached_plane == plane)
1333 continue;
1334
1335 attached_state = drm_atomic_get_existing_plane_state(
1336 state->state, attached_plane);
1337
1338 if (!attached_state)
1339 continue;
1340
1341 attached_pstate = to_sde_plane_state(attached_state);
1342 attached_rstate = &attached_pstate->rot;
1343
1344 /* find bounding rotator source roi */
1345 if (attached_state->src_x < in_rot->x1)
1346 in_rot->x1 = attached_state->src_x;
1347
1348 if (attached_state->src_y < in_rot->y1)
1349 in_rot->y1 = attached_state->src_y;
1350
1351 if (attached_state->src_x + attached_state->src_w > in_rot->x2)
1352 in_rot->x2 = attached_state->src_x +
1353 attached_state->src_w;
1354
1355 if (attached_state->src_y + attached_state->src_h > in_rot->y2)
1356 in_rot->y2 = attached_state->src_y +
1357 attached_state->src_h;
1358
1359 /* find bounding rotator destination roi */
1360 dst_x = sde_plane_get_property(attached_pstate,
1361 PLANE_PROP_ROT_DST_X);
1362 dst_y = sde_plane_get_property(attached_pstate,
1363 PLANE_PROP_ROT_DST_Y);
1364 dst_w = sde_plane_get_property(attached_pstate,
1365 PLANE_PROP_ROT_DST_W);
1366 dst_h = sde_plane_get_property(attached_pstate,
1367 PLANE_PROP_ROT_DST_H);
1368 if (!dst_w && !dst_h) {
1369 attached_out_rect.x1 = attached_state->src_x;
1370 attached_out_rect.y1 = attached_state->src_y;
1371 attached_out_rect.x2 = attached_out_rect.x1 +
1372 attached_state->src_w;
1373 attached_out_rect.y2 = attached_out_rect.y1 +
1374 attached_state->src_h;
1375 drm_rect_rotate(&attached_out_rect,
1376 state->fb->width << 16,
1377 state->fb->height << 16,
1378 rstate->in_rotation);
1379 } else {
1380 attached_out_rect.x1 = dst_x;
1381 attached_out_rect.y1 = dst_y;
1382 attached_out_rect.x2 = dst_x + dst_w;
1383 attached_out_rect.y2 = dst_y + dst_h;
1384 }
1385
1386 /* find relative sspp position */
1387 if (attached_out_rect.x1 < rstate->out_src_rect.x1)
1388 xpos++;
1389
1390 if (attached_out_rect.x1 < out_rot->x1)
1391 out_rot->x1 = attached_out_rect.x1;
1392
1393 if (attached_out_rect.y1 < out_rot->y1)
1394 out_rot->y1 = attached_out_rect.y1;
1395
1396 if (attached_out_rect.x2 > out_rot->x2)
1397 out_rot->x2 = attached_out_rect.x2;
1398
1399 if (attached_out_rect.y2 > out_rot->y2)
1400 out_rot->y2 = attached_out_rect.y2;
1401
1402 SDE_DEBUG("plane%d.%u src_x:%d sspp:%dx%d+%d+%d/%dx%d+%d+%d\n",
1403 attached_plane->base.id,
1404 attached_rstate->sequence_id,
1405 attached_rstate->out_src_rect.x1 >> 16,
1406 attached_state->src_w >> 16,
1407 attached_state->src_h >> 16,
1408 attached_state->src_x >> 16,
1409 attached_state->src_y >> 16,
1410 drm_rect_width(&attached_rstate->out_src_rect) >> 16,
1411 drm_rect_height(&attached_rstate->out_src_rect) >> 16,
1412 attached_rstate->out_src_rect.x1 >> 16,
1413 attached_rstate->out_src_rect.y1 >> 16);
1414 }
1415
1416 rstate->out_xpos = xpos;
1417 rstate->nplane = found;
1418
1419 SDE_DEBUG("plane%d.%u xpos:%d/%d rot:%dx%d+%d+%d/%dx%d+%d+%d\n",
1420 plane->base.id, rstate->sequence_id,
1421 rstate->out_xpos, rstate->nplane,
1422 drm_rect_width(in_rot) >> 16,
1423 drm_rect_height(in_rot) >> 16,
1424 in_rot->x1 >> 16, in_rot->y1 >> 16,
1425 drm_rect_width(&rstate->out_rot_rect) >> 16,
1426 drm_rect_height(&rstate->out_rot_rect) >> 16,
1427 rstate->out_rot_rect.x1 >> 16,
1428 rstate->out_rot_rect.y1 >> 16);
1429}
1430
1431/**
1432 * sde_plane_rot_submit_command - commit given state for the rotator stage
1433 * @plane: Pointer to drm plane
1434 * @state: Pointer to the state to be committed
1435 * @hw_cmd: rotator command type
1436 * return: 0 if success; error code otherwise
1437 */
1438static int sde_plane_rot_submit_command(struct drm_plane *plane,
1439 struct drm_plane_state *state, enum sde_hw_rot_cmd_type hw_cmd)
1440{
1441 struct sde_plane *psde = to_sde_plane(plane);
1442 struct sde_plane_state *pstate = to_sde_plane_state(state);
1443 struct sde_plane_rot_state *rstate = &pstate->rot;
1444 struct sde_hw_rot_cmd *rot_cmd;
1445 int ret, i;
1446
1447 if (!plane || !state || !state->fb || !rstate->rot_hw) {
1448 SDE_ERROR("invalid parameters\n");
1449 return -EINVAL;
1450 }
1451
1452 rot_cmd = &rstate->rot_cmd;
1453
1454 rot_cmd->master = (rstate->out_xpos == 0);
1455 rot_cmd->sequence_id = rstate->sequence_id;
1456 rot_cmd->fps = pstate->base.crtc && pstate->base.crtc->state ?
1457 drm_mode_vrefresh(&pstate->base.crtc->state->adjusted_mode) :
1458 DEFAULT_REFRESH_RATE;
1459 rot_cmd->rot90 = rstate->rot90;
1460 rot_cmd->hflip = rstate->hflip;
1461 rot_cmd->vflip = rstate->vflip;
1462 rot_cmd->secure = state->fb->flags & DRM_MODE_FB_SECURE ? true : false;
1463 rot_cmd->dst_writeback = psde->sbuf_writeback;
1464
1465 if (sde_crtc_get_intf_mode(state->crtc) == INTF_MODE_VIDEO)
1466 rot_cmd->video_mode = true;
1467 else
1468 rot_cmd->video_mode = false;
1469
1470 rot_cmd->src_pixel_format = state->fb->pixel_format;
1471 rot_cmd->src_modifier = state->fb->modifier[0];
1472 rot_cmd->src_stride = state->fb->pitches[0];
1473
1474 rot_cmd->src_format = to_sde_format(msm_framebuffer_format(state->fb));
1475 if (!rot_cmd->src_format) {
1476 SDE_ERROR("failed to get src format\n");
1477 return -EINVAL;
1478 }
1479
1480 rot_cmd->src_width = state->fb->width;
1481 rot_cmd->src_height = state->fb->height;
1482 rot_cmd->src_rect_x = rstate->in_rot_rect.x1 >> 16;
1483 rot_cmd->src_rect_y = rstate->in_rot_rect.y1 >> 16;
1484 rot_cmd->src_rect_w = drm_rect_width(&rstate->in_rot_rect) >> 16;
1485 rot_cmd->src_rect_h = drm_rect_height(&rstate->in_rot_rect) >> 16;
1486 rot_cmd->dst_rect_x = rstate->out_rot_rect.x1 >> 16;
1487 rot_cmd->dst_rect_y = rstate->out_rot_rect.y1 >> 16;
1488 rot_cmd->dst_rect_w = drm_rect_width(&rstate->out_rot_rect) >> 16;
1489 rot_cmd->dst_rect_h = drm_rect_height(&rstate->out_rot_rect) >> 16;
1490
1491 if (hw_cmd == SDE_HW_ROT_CMD_COMMIT) {
1492 struct sde_hw_fmt_layout layout;
1493
1494 memset(&layout, 0, sizeof(struct sde_hw_fmt_layout));
1495 sde_format_populate_layout(rstate->mmu_id, state->fb,
1496 &layout);
1497 for (i = 0; i < ARRAY_SIZE(rot_cmd->src_iova); i++) {
1498 rot_cmd->src_iova[i] = layout.plane_addr[i];
1499 rot_cmd->src_len[i] = layout.plane_size[i];
1500 }
1501 rot_cmd->src_planes = layout.num_planes;
1502
1503 memset(&layout, 0, sizeof(struct sde_hw_fmt_layout));
1504 sde_format_populate_layout(rstate->mmu_id, rstate->out_fb,
1505 &layout);
1506 for (i = 0; i < ARRAY_SIZE(rot_cmd->dst_iova); i++) {
1507 rot_cmd->dst_iova[i] = layout.plane_addr[i];
1508 rot_cmd->dst_len[i] = layout.plane_size[i];
1509 }
1510 rot_cmd->dst_planes = layout.num_planes;
1511 }
1512
1513 ret = rstate->rot_hw->ops.commit(rstate->rot_hw, rot_cmd, hw_cmd);
1514 if (ret) {
1515 SDE_ERROR("failed to commit rotator %d\n", ret);
1516 return ret;
1517 }
1518
1519 rstate->out_rotation = rstate->in_rotation;
1520 rstate->out_fb_flags = rot_cmd->dst_modifier ?
1521 DRM_MODE_FB_MODIFIERS : 0;
1522 rstate->out_fb_flags |= rot_cmd->secure ? DRM_MODE_FB_SECURE : 0;
1523 rstate->out_fb_format = rot_cmd->dst_format;
1524 rstate->out_fb_pixel_format = rot_cmd->dst_pixel_format;
1525
1526 for (i = 0; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
1527 rstate->out_fb_modifier[i] = rot_cmd->dst_modifier;
1528
1529 rstate->out_fb_width = drm_rect_width(&rstate->out_rot_rect) >> 16;
1530 rstate->out_fb_height = drm_rect_height(&rstate->out_rot_rect) >> 16;
1531 rstate->out_src_x = rstate->out_src_rect.x1 - rstate->out_rot_rect.x1;
1532 rstate->out_src_y = rstate->out_src_rect.y1 - rstate->out_rot_rect.y1;
1533 rstate->out_src_w = drm_rect_width(&rstate->out_src_rect);
1534 rstate->out_src_h = drm_rect_height(&rstate->out_src_rect);
1535
1536 if (rot_cmd->rot90)
1537 rstate->out_rotation &= ~DRM_ROTATE_90;
1538
1539 if (rot_cmd->hflip)
1540 rstate->out_rotation &= ~DRM_REFLECT_X;
1541
1542 if (rot_cmd->vflip)
1543 rstate->out_rotation &= ~DRM_REFLECT_Y;
1544
1545 SDE_DEBUG(
1546 "plane%d.%d rot:%d/%c%c%c%c/%dx%d/%c%c%c%c/%llx/%dx%d+%d+%d\n",
1547 plane->base.id, rstate->sequence_id, hw_cmd,
1548 rot_cmd->rot90 ? 'r' : '_',
1549 rot_cmd->hflip ? 'h' : '_',
1550 rot_cmd->vflip ? 'v' : '_',
1551 rot_cmd->video_mode ? 'V' : 'C',
1552 state->fb->width, state->fb->height,
1553 state->fb->pixel_format >> 0,
1554 state->fb->pixel_format >> 8,
1555 state->fb->pixel_format >> 16,
1556 state->fb->pixel_format >> 24,
1557 state->fb->modifier[0],
1558 drm_rect_width(&rstate->in_rot_rect) >> 16,
1559 drm_rect_height(&rstate->in_rot_rect) >> 16,
1560 rstate->in_rot_rect.x1 >> 16,
1561 rstate->in_rot_rect.y1 >> 16);
1562
1563 SDE_DEBUG("plane%d.%d sspp:%d/%x/%dx%d/%c%c%c%c/%llx/%dx%d+%d+%d\n",
1564 plane->base.id, rstate->sequence_id, hw_cmd,
1565 rstate->out_rotation,
1566 rstate->out_fb_width, rstate->out_fb_height,
1567 rstate->out_fb_pixel_format >> 0,
1568 rstate->out_fb_pixel_format >> 8,
1569 rstate->out_fb_pixel_format >> 16,
1570 rstate->out_fb_pixel_format >> 24,
1571 rstate->out_fb_modifier[0],
1572 rstate->out_src_w >> 16, rstate->out_src_h >> 16,
1573 rstate->out_src_x >> 16, rstate->out_src_y >> 16);
1574
1575 return ret;
1576}
1577
1578/**
1579 * sde_plane_rot_prepare_fb - prepare framebuffer of the new state
1580 * for rotator (pre-sspp) stage
1581 * @plane: Pointer to drm plane
1582 * @new_state: Pointer to new drm plane state
1583 * return: 0 if success; error code otherwise
1584 */
1585static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
1586 struct drm_plane_state *new_state)
1587{
1588 struct drm_framebuffer *fb = new_state->fb;
1589 struct sde_plane_state *new_pstate = to_sde_plane_state(new_state);
1590 struct sde_plane_rot_state *new_rstate = &new_pstate->rot;
1591 int ret;
1592
1593 SDE_DEBUG("plane%d.%d FB[%u] sbuf:%d rot:%d crtc:%d\n",
1594 plane->base.id,
1595 new_rstate->sequence_id, fb ? fb->base.id : 0,
1596 !!new_rstate->out_sbuf, !!new_rstate->rot_hw,
1597 sde_plane_crtc_enabled(new_state));
1598
1599 if (!new_rstate->out_sbuf || !new_rstate->rot_hw)
1600 return 0;
1601
1602 /* need to re-calc based on all newly validated plane states */
1603 sde_plane_rot_calc_cfg(plane, new_state);
1604
1605 /* check if stream buffer is already attached to rotator */
1606 if (sde_plane_enabled(new_state)) {
1607 struct sde_kms_fbo *fbo;
1608 struct drm_framebuffer *fb;
1609
1610 fbo = sde_hw_blk_lookup_value(&new_rstate->rot_hw->base,
1611 SDE_TAG_ROT_OUT_FBO, 0);
1612 fb = sde_hw_blk_lookup_value(&new_rstate->rot_hw->base,
1613 SDE_TAG_ROT_OUT_FB, 0);
1614 if (fb && fbo) {
1615 SDE_DEBUG("plane%d.%d get fb/fbo\n", plane->base.id,
1616 new_rstate->sequence_id);
1617
1618 new_rstate->out_fbo = fbo;
1619 sde_kms_fbo_reference(new_rstate->out_fbo);
1620 sde_hw_blk_attach(&new_rstate->rot_hw->base,
1621 SDE_TAG_ROT_OUT_FBO,
1622 new_rstate->out_fbo);
1623
1624 new_rstate->out_fb = fb;
1625 drm_framebuffer_reference(new_rstate->out_fb);
1626 sde_hw_blk_attach(&new_rstate->rot_hw->base,
1627 SDE_TAG_ROT_OUT_FB,
1628 new_rstate->out_fb);
1629 }
1630 }
1631
1632 /* release buffer if output format configuration changes */
1633 if (new_rstate->out_fb &&
1634 ((new_rstate->out_fb_height != new_rstate->out_fb->height) ||
1635 (new_rstate->out_fb_width != new_rstate->out_fb->width) ||
1636 (new_rstate->out_fb_pixel_format !=
1637 new_rstate->out_fb->pixel_format) ||
1638 (new_rstate->out_fb_modifier[0] !=
1639 new_rstate->out_fb->modifier[0]) ||
1640 (new_rstate->out_fb_flags != new_rstate->out_fb->flags))) {
1641
1642 SDE_DEBUG("plane%d.%d release fb/fbo\n", plane->base.id,
1643 new_rstate->sequence_id);
1644
1645 sde_hw_blk_detach(&new_rstate->rot_hw->base,
1646 SDE_TAG_ROT_OUT_FB, new_rstate->out_fb);
1647 drm_framebuffer_unreference(new_rstate->out_fb);
1648 new_rstate->out_fb = NULL;
1649 sde_hw_blk_detach(&new_rstate->rot_hw->base,
1650 SDE_TAG_ROT_OUT_FBO, new_rstate->out_fbo);
1651 sde_kms_fbo_unreference(new_rstate->out_fbo);
1652 new_rstate->out_fbo = NULL;
1653 }
1654
1655 /* create new stream buffer if it is not available */
1656 if (sde_plane_enabled(new_state) && !new_rstate->out_fb) {
1657 u32 fb_w = drm_rect_width(&new_rstate->out_rot_rect) >> 16;
1658 u32 fb_h = drm_rect_height(&new_rstate->out_rot_rect) >> 16;
1659
1660 SDE_DEBUG("plane%d.%d allocate fb/fbo\n", plane->base.id,
1661 new_rstate->sequence_id);
1662
1663 if (new_state->fb->flags & DRM_MODE_FB_SECURE)
1664 new_rstate->mmu_id = MSM_SMMU_DOMAIN_SECURE;
1665 else
1666 new_rstate->mmu_id = MSM_SMMU_DOMAIN_UNSECURE;
1667
1668 /* check if out_fb is already attached to rotator */
1669 new_rstate->out_fbo = sde_kms_fbo_alloc(plane->dev, fb_w, fb_h,
1670 new_rstate->out_fb_pixel_format,
1671 new_rstate->out_fb_modifier,
1672 new_rstate->out_fb_flags);
1673 if (!new_rstate->out_fbo) {
1674 SDE_ERROR("failed to allocate inline buffer object\n");
1675 ret = -EINVAL;
1676 goto error_create_fbo;
1677 }
1678
1679 sde_hw_blk_attach(&new_rstate->rot_hw->base,
1680 SDE_TAG_ROT_OUT_FBO, new_rstate->out_fbo);
1681
1682 new_rstate->out_fb = sde_kms_fbo_create_fb(plane->dev,
1683 new_rstate->out_fbo);
1684 if (!new_rstate->out_fb) {
1685 SDE_ERROR("failed to create inline framebuffer\n");
1686 ret = -EINVAL;
1687 goto error_create_fb;
1688 }
1689
1690 sde_hw_blk_attach(&new_rstate->rot_hw->base,
1691 SDE_TAG_ROT_OUT_FB, new_rstate->out_fb);
1692 }
1693
1694 /* prepare rotator input buffer */
1695 ret = msm_framebuffer_prepare(new_state->fb, new_rstate->mmu_id);
1696 if (ret) {
1697 SDE_ERROR("failed to prepare input framebuffer\n");
1698 goto error_prepare_input_buffer;
1699 }
1700
1701 /* prepare rotator output buffer */
1702 if (sde_plane_enabled(new_state) && new_rstate->out_fb) {
1703 SDE_DEBUG("plane%d.%d prepare fb/fbo\n", plane->base.id,
1704 new_rstate->sequence_id);
1705
1706 ret = msm_framebuffer_prepare(new_rstate->out_fb,
1707 new_rstate->mmu_id);
1708 if (ret) {
1709 SDE_ERROR("failed to prepare inline framebuffer\n");
1710 goto error_prepare_output_buffer;
1711 }
1712 }
1713
1714 return 0;
1715
1716error_prepare_output_buffer:
1717 msm_framebuffer_cleanup(new_state->fb, new_rstate->mmu_id);
1718error_prepare_input_buffer:
1719 sde_hw_blk_detach(&new_rstate->rot_hw->base, SDE_TAG_ROT_OUT_FB,
1720 new_rstate->out_fb);
1721 drm_framebuffer_unreference(new_rstate->out_fb);
1722 new_rstate->out_fb = NULL;
1723error_create_fb:
1724 sde_hw_blk_detach(&new_rstate->rot_hw->base, SDE_TAG_ROT_OUT_FBO,
1725 new_rstate->out_fbo);
1726 sde_kms_fbo_unreference(new_rstate->out_fbo);
1727 new_rstate->out_fbo = NULL;
1728error_create_fbo:
1729 return ret;
1730}
1731
1732/**
1733 * sde_plane_rot_cleanup_fb - cleanup framebuffer of previous state for the
1734 * rotator (pre-sspp) stage
1735 * @plane: Pointer to drm plane
1736 * @old_state: Pointer to previous drm plane state
1737 * return: none
1738 */
1739static void sde_plane_rot_cleanup_fb(struct drm_plane *plane,
1740 struct drm_plane_state *old_state)
1741{
1742 struct sde_plane_state *old_pstate = to_sde_plane_state(old_state);
1743 struct sde_plane_rot_state *old_rstate = &old_pstate->rot;
1744 struct sde_hw_rot_cmd *cmd = &old_rstate->rot_cmd;
1745 int ret;
1746
1747 SDE_DEBUG("plane%d.%d FB[%u] sbuf:%d rot:%d crtc:%d\n", plane->base.id,
1748 old_rstate->sequence_id, old_state->fb->base.id,
1749 !!old_rstate->out_sbuf, !!old_rstate->rot_hw,
1750 sde_plane_crtc_enabled(old_state));
1751
1752 if (!old_rstate->out_sbuf || !old_rstate->rot_hw)
1753 return;
1754
1755 if (sde_plane_crtc_enabled(old_state)) {
1756 ret = old_rstate->rot_hw->ops.commit(old_rstate->rot_hw, cmd,
1757 SDE_HW_ROT_CMD_CLEANUP);
1758 if (ret)
1759 SDE_ERROR("failed to cleanup rotator buffers\n");
1760 }
1761
1762 if (sde_plane_enabled(old_state)) {
1763 if (old_rstate->out_fb) {
1764 msm_framebuffer_cleanup(old_rstate->out_fb,
1765 old_rstate->mmu_id);
1766 sde_hw_blk_detach(&old_rstate->rot_hw->base,
1767 SDE_TAG_ROT_OUT_FB,
1768 old_rstate->out_fb);
1769 drm_framebuffer_unreference(old_rstate->out_fb);
1770 old_rstate->out_fb = NULL;
1771 sde_hw_blk_detach(&old_rstate->rot_hw->base,
1772 SDE_TAG_ROT_OUT_FBO,
1773 old_rstate->out_fbo);
1774 sde_kms_fbo_unreference(old_rstate->out_fbo);
1775 old_rstate->out_fbo = NULL;
1776 }
1777
1778 msm_framebuffer_cleanup(old_state->fb, old_rstate->mmu_id);
1779 }
1780}
1781
1782/**
1783 * sde_plane_rot_atomic_check - verify rotator update of the given state
1784 * @plane: Pointer to drm plane
1785 * @state: Pointer to drm plane state to be validated
1786 * return: 0 if success; error code otherwise
1787 */
1788static int sde_plane_rot_atomic_check(struct drm_plane *plane,
1789 struct drm_plane_state *state)
1790{
1791 struct sde_plane *psde;
1792 struct sde_plane_state *pstate, *old_pstate;
1793 struct sde_plane_rot_state *rstate, *old_rstate;
1794 struct sde_hw_blk *hw_blk;
1795 int i, ret = 0;
1796
1797 if (!plane || !state) {
1798 SDE_ERROR("invalid plane/state\n");
1799 return -EINVAL;
1800 }
1801
1802 psde = to_sde_plane(plane);
1803 pstate = to_sde_plane_state(state);
1804 old_pstate = to_sde_plane_state(plane->state);
1805 rstate = &pstate->rot;
1806 old_rstate = &old_pstate->rot;
1807
1808 SDE_DEBUG("plane%d.%d FB[%u] sbuf:%d rot:%d crtc:%d\n", plane->base.id,
1809 rstate->sequence_id, state->fb ? state->fb->base.id : 0,
1810 !!rstate->out_sbuf, !!rstate->rot_hw,
1811 sde_plane_crtc_enabled(state));
1812
1813 rstate->in_rotation = drm_rotation_simplify(
1814 sde_plane_get_property(pstate, PLANE_PROP_ROTATION),
1815 DRM_ROTATE_90 | DRM_REFLECT_X | DRM_REFLECT_Y);
1816 rstate->rot90 = rstate->in_rotation & DRM_ROTATE_90 ? true : false;
1817 rstate->hflip = rstate->in_rotation & DRM_REFLECT_X ? true : false;
1818 rstate->vflip = rstate->in_rotation & DRM_REFLECT_Y ? true : false;
1819 rstate->out_sbuf = psde->sbuf_mode || rstate->rot90;
1820
1821 if ((!sde_plane_enabled(state) || !rstate->out_sbuf) &&
1822 rstate->rot_hw) {
1823
1824 SDE_DEBUG("plane%d.%d release rotator\n",
1825 plane->base.id, rstate->sequence_id);
1826
1827 sde_hw_blk_detach(&rstate->rot_hw->base, SDE_TAG_ROT_IN_FB,
1828 rstate->in_fb);
1829 rstate->in_fb = NULL;
1830 sde_hw_blk_detach(&rstate->rot_hw->base, SDE_TAG_ROT_PLANE,
1831 plane);
1832 sde_hw_rot_put(rstate->rot_hw);
1833 rstate->rot_hw = NULL;
1834
1835 } else if (sde_plane_enabled(state) && rstate->out_sbuf &&
1836 !rstate->rot_hw) {
1837
1838 SDE_DEBUG("plane%d.%d allocate rotator\n",
1839 plane->base.id, rstate->sequence_id);
1840
1841 hw_blk = sde_hw_blk_lookup_blk(SDE_TAG_ROT_IN_FB, state->fb,
1842 SDE_HW_BLK_ROT);
1843 if (hw_blk)
1844 rstate->rot_hw = to_sde_hw_rot(hw_blk);
1845 else
1846 rstate->rot_hw = sde_hw_rot_get(NULL);
1847
1848 if (!rstate->rot_hw) {
1849 SDE_ERROR("plane%d no available rotator\n",
1850 plane->base.id);
1851 return -EINVAL;
1852 }
1853
1854 if (!rstate->rot_hw->ops.commit) {
1855 SDE_ERROR("plane%d invalid rotator ops\n",
1856 plane->base.id);
1857 sde_hw_rot_put(rstate->rot_hw);
1858 rstate->rot_hw = NULL;
1859 return -EINVAL;
1860 }
1861
1862 rstate->in_fb = state->fb;
1863 sde_hw_blk_attach(&rstate->rot_hw->base, SDE_TAG_ROT_IN_FB,
1864 rstate->in_fb);
1865 sde_hw_blk_attach(&rstate->rot_hw->base, SDE_TAG_ROT_PLANE,
1866 plane);
1867
1868 } else if (sde_plane_enabled(state) && rstate->out_sbuf &&
1869 (rstate->in_fb != state->fb)) {
1870
1871 SDE_DEBUG("plane%d.%d update fb\n",
1872 plane->base.id, rstate->sequence_id);
1873
1874 sde_hw_blk_detach(&rstate->rot_hw->base, SDE_TAG_ROT_IN_FB,
1875 rstate->in_fb);
1876 rstate->in_fb = state->fb;
1877 sde_hw_blk_attach(&rstate->rot_hw->base, SDE_TAG_ROT_IN_FB,
1878 rstate->in_fb);
1879 }
1880
1881 if (sde_plane_enabled(state) && rstate->out_sbuf && rstate->rot_hw) {
1882
1883 SDE_DEBUG("plane%d.%d use rotator\n",
1884 plane->base.id, rstate->sequence_id);
1885
1886 sde_plane_rot_calc_cfg(plane, state);
1887
1888 ret = sde_plane_rot_submit_command(plane, state,
1889 SDE_HW_ROT_CMD_VALIDATE);
1890
1891 } else if (sde_plane_enabled(state)) {
1892
1893 SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
1894 rstate->sequence_id);
1895
1896 /* bypass rotator - initialize output setting as input */
1897 rstate->out_rotation = rstate->in_rotation;
1898 rstate->out_fb_pixel_format = state->fb->pixel_format;
1899
1900 for (i = 0.; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
1901 rstate->out_fb_modifier[i] = state->fb->modifier[i];
1902
1903 rstate->out_fb_flags = state->fb->flags;
1904 rstate->out_fb_width = state->fb->width;
1905 rstate->out_fb_height = state->fb->height;
1906 rstate->out_src_x = state->src_x;
1907 rstate->out_src_y = state->src_y;
1908 rstate->out_src_w = state->src_w;
1909 rstate->out_src_h = state->src_h;
1910
1911 rstate->out_fb_format = NULL;
1912 rstate->out_sbuf = false;
1913 rstate->out_fb = state->fb;
1914 }
1915
1916 return ret;
1917}
1918
1919/**
1920 * sde_plane_rot_atomic_update - perform atomic update for rotator stage
1921 * @plane: Pointer to drm plane
1922 * @old_state: Pointer to previous state
1923 * return: none
1924 */
1925static void sde_plane_rot_atomic_update(struct drm_plane *plane,
1926 struct drm_plane_state *old_state)
1927{
1928 struct drm_plane_state *state;
1929 struct sde_plane_state *pstate;
1930 struct sde_plane_rot_state *rstate;
1931
1932 if (!plane || !plane->state) {
1933 SDE_ERROR("invalid plane/state\n");
1934 return;
1935 }
1936
1937 state = plane->state;
1938 pstate = to_sde_plane_state(state);
1939 rstate = &pstate->rot;
1940
1941 SDE_DEBUG("plane%d.%d sbuf:%d rot:%d crtc:%d\n", plane->base.id,
1942 rstate->sequence_id,
1943 !!rstate->out_sbuf, !!rstate->rot_hw,
1944 sde_plane_crtc_enabled(plane->state));
1945
1946 if (!sde_plane_crtc_enabled(state))
1947 return;
1948
1949 if (!rstate->out_sbuf || !rstate->rot_hw)
1950 return;
1951
1952 sde_plane_rot_submit_command(plane, state, SDE_HW_ROT_CMD_COMMIT);
1953}
1954
1955/**
1956 * sde_plane_rot_destroy_state - destroy state for rotator stage
1957 * @plane: Pointer to drm plane
1958 * @state: Pointer to state to be destroyed
1959 * return: none
1960 */
1961static void sde_plane_rot_destroy_state(struct drm_plane *plane,
1962 struct drm_plane_state *state)
1963{
1964 struct sde_plane_state *pstate = to_sde_plane_state(state);
1965 struct sde_plane_rot_state *rstate = &pstate->rot;
1966
1967 SDE_DEBUG("plane%d.%d sbuf:%d rot:%d crtc:%d\n", plane->base.id,
1968 rstate->sequence_id,
1969 !!rstate->out_sbuf, !!rstate->rot_hw,
1970 sde_plane_crtc_enabled(state));
1971
1972 if (rstate->rot_hw) {
1973 sde_hw_blk_detach(&rstate->rot_hw->base, SDE_TAG_ROT_IN_FB,
1974 rstate->in_fb);
1975 rstate->in_fb = NULL;
1976 sde_hw_blk_detach(&rstate->rot_hw->base, SDE_TAG_ROT_PLANE,
1977 plane);
1978 sde_hw_rot_put(rstate->rot_hw);
1979 rstate->rot_hw = NULL;
1980 }
1981}
1982
1983/**
1984 * sde_plane_rot_duplicate_state - duplicate state for rotator stage
1985 * @plane: Pointer to drm plane
1986 * @new_state: Pointer to duplicated state
1987 * return: 0 if success; error code otherwise
1988 */
1989static int sde_plane_rot_duplicate_state(struct drm_plane *plane,
1990 struct drm_plane_state *new_state)
1991{
1992 struct sde_plane_state *pstate = to_sde_plane_state(new_state);
1993 struct sde_plane_rot_state *rstate = &pstate->rot;
1994
1995 rstate->sequence_id++;
1996
1997 SDE_DEBUG("plane%d.%d sbuf:%d rot:%d\n", plane->base.id,
1998 rstate->sequence_id,
1999 !!rstate->out_sbuf, !!rstate->rot_hw);
2000
2001 if (rstate->rot_hw) {
2002 sde_hw_blk_attach(&rstate->rot_hw->base, SDE_TAG_ROT_IN_FB,
2003 rstate->in_fb);
2004 sde_hw_blk_attach(&rstate->rot_hw->base, SDE_TAG_ROT_PLANE,
2005 plane);
2006 sde_hw_rot_get(rstate->rot_hw);
2007 }
2008
2009 rstate->out_fb = NULL;
2010 rstate->out_fbo = NULL;
2011
2012 return 0;
2013}
2014
2015/**
2016 * sde_plane_rot_install_caps - install plane rotator capabilities
2017 * @plane: Pointer to drm plane
2018 * return: none
2019 */
2020static void sde_plane_rot_install_caps(struct drm_plane *plane)
2021{
2022 struct sde_plane *psde = to_sde_plane(plane);
2023 const struct sde_format_extended *format_list;
2024 struct sde_kms_info *info;
2025 struct sde_hw_rot *rot_hw;
2026 const char *downscale_caps;
2027
2028 if (!psde->catalog || !(psde->features & BIT(SDE_SSPP_SBUF)) ||
2029 !psde->catalog->rot_count)
2030 return;
2031
2032 if (psde->blob_rot_caps)
2033 return;
2034
2035 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
2036 if (!info)
2037 return;
2038
2039 rot_hw = sde_hw_rot_get(NULL);
2040 if (!rot_hw || !rot_hw->ops.get_format_caps ||
2041 !rot_hw->ops.get_downscale_caps) {
2042 SDE_ERROR("invalid rotator hw\n");
2043 goto error_rot;
2044 }
2045
2046 sde_kms_info_reset(info);
2047
2048 format_list = rot_hw->ops.get_format_caps(rot_hw);
2049 if (format_list) {
2050 sde_kms_info_start(info, "pixel_formats");
2051 while (format_list->fourcc_format) {
2052 sde_kms_info_append_format(info,
2053 format_list->fourcc_format,
2054 format_list->modifier);
2055 ++format_list;
2056 }
2057 sde_kms_info_stop(info);
2058 }
2059
2060 downscale_caps = rot_hw->ops.get_downscale_caps(rot_hw);
2061 if (downscale_caps) {
2062 sde_kms_info_start(info, "downscale_ratios");
2063 sde_kms_info_append(info, downscale_caps);
2064 sde_kms_info_stop(info);
2065 }
2066
2067 if (rot_hw->ops.get_cache_size)
2068 sde_kms_info_add_keyint(info, "cache_size",
2069 rot_hw->ops.get_cache_size(rot_hw));
2070
2071 msm_property_set_blob(&psde->property_info, &psde->blob_rot_caps,
2072 info->data, info->len, PLANE_PROP_ROT_CAPS_V1);
2073
2074 sde_hw_rot_put(rot_hw);
2075error_rot:
2076 kfree(info);
2077}
2078
2079/**
2080 * sde_plane_rot_install_properties - install plane rotator properties
2081 * @plane: Pointer to drm plane
2082 * @catalog: Pointer to mdss configuration
2083 * return: none
2084 */
2085static void sde_plane_rot_install_properties(struct drm_plane *plane,
2086 struct sde_mdss_cfg *catalog)
2087{
2088 struct sde_plane *psde = to_sde_plane(plane);
2089 unsigned long supported_rotations = DRM_REFLECT_X | DRM_REFLECT_Y;
2090
2091 if (!plane || !psde) {
2092 SDE_ERROR("invalid plane\n");
2093 return;
2094 } else if (!catalog) {
2095 SDE_ERROR("invalid catalog\n");
2096 return;
2097 }
2098
2099 if ((psde->features & BIT(SDE_SSPP_SBUF)) && catalog->rot_count)
2100 supported_rotations |= DRM_ROTATE_0 | DRM_ROTATE_90 |
2101 DRM_ROTATE_180 | DRM_ROTATE_270;
2102
2103 msm_property_install_rotation(&psde->property_info,
2104 supported_rotations, PLANE_PROP_ROTATION);
2105
2106 if (!(psde->features & BIT(SDE_SSPP_SBUF)) || !catalog->rot_count)
2107 return;
2108
2109 msm_property_install_range(&psde->property_info, "rot_dst_x",
2110 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_X);
2111 msm_property_install_range(&psde->property_info, "rot_dst_y",
2112 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_Y);
2113 msm_property_install_range(&psde->property_info, "rot_dst_w",
2114 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_W);
2115 msm_property_install_range(&psde->property_info, "rot_dst_h",
2116 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_H);
2117 msm_property_install_blob(&psde->property_info, "rot_caps_v1",
2118 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_ROT_CAPS_V1);
2119}
2120
2121static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
Dhaval Patel47302cf2016-08-18 15:04:28 -07002122 struct drm_plane_state *state)
Clarence Ipcb410d42016-06-26 22:52:33 -04002123{
Clarence Ipc47a0692016-10-11 10:54:17 -04002124 uint32_t nplanes, src_flags;
Clarence Ipcb410d42016-06-26 22:52:33 -04002125 struct sde_plane *psde;
2126 struct sde_plane_state *pstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002127 struct sde_plane_rot_state *rstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04002128 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002129 struct drm_crtc *crtc;
2130 struct drm_framebuffer *fb;
2131 struct sde_rect src, dst;
2132 bool q16_data = true;
Clarence Ip282dad62016-09-27 17:07:35 -04002133 int idx;
Clarence Ipcb410d42016-06-26 22:52:33 -04002134
Clarence Ip13a8cf42016-09-29 17:27:47 -04002135 if (!plane) {
Clarence Ip282dad62016-09-27 17:07:35 -04002136 SDE_ERROR("invalid plane\n");
2137 return -EINVAL;
2138 } else if (!plane->state) {
2139 SDE_ERROR("invalid plane state\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04002140 return -EINVAL;
2141 }
2142
2143 psde = to_sde_plane(plane);
2144 pstate = to_sde_plane_state(plane->state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002145 rstate = &pstate->rot;
Clarence Ipcb410d42016-06-26 22:52:33 -04002146
Dhaval Patel47302cf2016-08-18 15:04:28 -07002147 crtc = state->crtc;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002148 fb = rstate->out_fb;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002149 if (!crtc || !fb) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002150 SDE_ERROR_PLANE(psde, "invalid crtc %d or fb %d\n",
2151 crtc != 0, fb != 0);
Dhaval Patel47302cf2016-08-18 15:04:28 -07002152 return -EINVAL;
2153 }
Lloyd Atkinson9a673492016-07-05 11:41:57 -04002154 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002155 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -04002156
Alan Kwong4dd64c82017-02-04 18:41:51 -08002157 SDE_DEBUG(
2158 "plane%d.%d sspp:%dx%d/%c%c%c%c/%llx/%dx%d+%d+%d/%x crtc:%dx%d+%d+%d\n",
2159 plane->base.id, rstate->sequence_id,
2160 rstate->out_fb_width, rstate->out_fb_height,
2161 rstate->out_fb_pixel_format >> 0,
2162 rstate->out_fb_pixel_format >> 8,
2163 rstate->out_fb_pixel_format >> 16,
2164 rstate->out_fb_pixel_format >> 24,
2165 rstate->out_fb_modifier[0],
2166 rstate->out_src_w >> 16, rstate->out_src_h >> 16,
2167 rstate->out_src_x >> 16, rstate->out_src_y >> 16,
2168 rstate->out_rotation,
2169 state->crtc_w, state->crtc_h,
2170 state->crtc_x, state->crtc_y);
2171
Clarence Ip282dad62016-09-27 17:07:35 -04002172 /* determine what needs to be refreshed */
2173 while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
2174 switch (idx) {
Clarence Ipb43d4592016-09-08 14:21:35 -04002175 case PLANE_PROP_SCALER_V1:
abeykun48f407a2016-08-25 12:06:44 -04002176 case PLANE_PROP_SCALER_V2:
Clarence Ipdedbba92016-09-27 17:43:10 -04002177 case PLANE_PROP_H_DECIMATE:
2178 case PLANE_PROP_V_DECIMATE:
2179 case PLANE_PROP_SRC_CONFIG:
2180 case PLANE_PROP_ZPOS:
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002181 case PLANE_PROP_EXCL_RECT_V1:
Clarence Ip282dad62016-09-27 17:07:35 -04002182 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
2183 break;
Clarence Ip5fc00c52016-09-23 15:03:34 -04002184 case PLANE_PROP_CSC_V1:
Clarence Ip282dad62016-09-27 17:07:35 -04002185 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
2186 break;
2187 case PLANE_PROP_COLOR_FILL:
2188 /* potentially need to refresh everything */
2189 pstate->dirty = SDE_PLANE_DIRTY_ALL;
2190 break;
2191 case PLANE_PROP_ROTATION:
2192 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
2193 break;
Clarence Ip282dad62016-09-27 17:07:35 -04002194 case PLANE_PROP_INFO:
2195 case PLANE_PROP_ALPHA:
2196 case PLANE_PROP_INPUT_FENCE:
2197 case PLANE_PROP_BLEND_OP:
2198 /* no special action required */
2199 break;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002200 case PLANE_PROP_ROT_DST_X:
2201 case PLANE_PROP_ROT_DST_Y:
2202 case PLANE_PROP_ROT_DST_W:
2203 case PLANE_PROP_ROT_DST_H:
2204 /* handled by rotator atomic update */
2205 break;
Clarence Ip282dad62016-09-27 17:07:35 -04002206 default:
2207 /* unknown property, refresh everything */
2208 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
2209 SDE_ERROR("executing full mode set, prp_idx %d\n", idx);
2210 break;
2211 }
Clarence Ipcb410d42016-06-26 22:52:33 -04002212 }
2213
Clarence Ip282dad62016-09-27 17:07:35 -04002214 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
2215 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
Clarence Ipcb410d42016-06-26 22:52:33 -04002216
2217 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
2218
Clarence Ip282dad62016-09-27 17:07:35 -04002219 /* early out if nothing dirty */
2220 if (!pstate->dirty)
2221 return 0;
2222 pstate->pending = true;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002223
Dhaval Patel4d424602017-02-18 19:40:14 -08002224 psde->is_rt_pipe = (sde_crtc_get_client_type(crtc) != NRT_CLIENT);
Clarence Ip282dad62016-09-27 17:07:35 -04002225 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
2226
2227 /* update roi config */
2228 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) {
Alan Kwong4dd64c82017-02-04 18:41:51 -08002229 POPULATE_RECT(&src, rstate->out_src_x, rstate->out_src_y,
2230 rstate->out_src_w, rstate->out_src_h, q16_data);
Clarence Ip282dad62016-09-27 17:07:35 -04002231 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
2232 state->crtc_w, state->crtc_h, !q16_data);
2233
Clarence Ip13a8cf42016-09-29 17:27:47 -04002234 SDE_DEBUG_PLANE(psde,
Alan Kwong4dd64c82017-02-04 18:41:51 -08002235 "FB[%u] %u,%u,%ux%u->crtc%u %d,%d,%ux%u, %c%c%c%c ubwc %d\n",
Clarence Ip282dad62016-09-27 17:07:35 -04002236 fb->base.id, src.x, src.y, src.w, src.h,
2237 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
Alan Kwong4dd64c82017-02-04 18:41:51 -08002238 fmt->base.pixel_format >> 0,
2239 fmt->base.pixel_format >> 8,
2240 fmt->base.pixel_format >> 16,
2241 fmt->base.pixel_format >> 24,
Clarence Ip282dad62016-09-27 17:07:35 -04002242 SDE_FORMAT_IS_UBWC(fmt));
2243
2244 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
2245 BIT(SDE_DRM_DEINTERLACE)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002246 SDE_DEBUG_PLANE(psde, "deinterlace\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002247 for (idx = 0; idx < SDE_MAX_PLANES; ++idx)
2248 psde->pipe_cfg.layout.plane_pitch[idx] <<= 1;
2249 src.h /= 2;
2250 src.y = DIV_ROUND_UP(src.y, 2);
2251 src.y &= ~0x1;
2252 }
2253
2254 psde->pipe_cfg.src_rect = src;
2255 psde->pipe_cfg.dst_rect = dst;
2256
2257 /* check for color fill */
2258 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
2259 PLANE_PROP_COLOR_FILL);
2260 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) {
2261 /* skip remaining processing on color fill */
2262 pstate->dirty = 0x0;
2263 } else if (psde->pipe_hw->ops.setup_rects) {
Clarence Ip282dad62016-09-27 17:07:35 -04002264 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
Jeykumar Sankaran9fcfa482017-02-16 16:03:14 -08002265 &psde->pipe_cfg,
2266 pstate->multirect_index);
Clarence Ip282dad62016-09-27 17:07:35 -04002267 }
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002268
Jeykumar Sankaran9fcfa482017-02-16 16:03:14 -08002269 _sde_plane_setup_scaler(psde, fmt, pstate);
2270 if (psde->pipe_hw->ops.setup_pe)
2271 psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
2272 &psde->pixel_ext);
2273
2274 if (psde->pipe_hw->ops.setup_scaler)
2275 psde->pipe_hw->ops.setup_scaler(psde->pipe_hw,
2276 &psde->pipe_cfg, &psde->pixel_ext,
2277 psde->scaler3_cfg);
2278
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002279 /* update excl rect */
2280 if (psde->pipe_hw->ops.setup_excl_rect)
2281 psde->pipe_hw->ops.setup_excl_rect(psde->pipe_hw,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002282 &pstate->excl_rect,
2283 pstate->multirect_index);
2284
2285 if (psde->pipe_hw->ops.setup_multirect)
2286 psde->pipe_hw->ops.setup_multirect(
2287 psde->pipe_hw,
2288 pstate->multirect_index,
2289 pstate->multirect_mode);
Dhaval Patel48c76022016-09-01 17:51:23 -07002290 }
2291
Clarence Ip282dad62016-09-27 17:07:35 -04002292 if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
2293 psde->pipe_hw->ops.setup_format) {
2294 src_flags = 0x0;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002295 SDE_DEBUG_PLANE(psde, "rotation 0x%X\n", rstate->out_rotation);
2296 if (rstate->out_rotation & DRM_REFLECT_X)
Clarence Ip282dad62016-09-27 17:07:35 -04002297 src_flags |= SDE_SSPP_FLIP_LR;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002298 if (rstate->out_rotation & DRM_REFLECT_Y)
Clarence Ip282dad62016-09-27 17:07:35 -04002299 src_flags |= SDE_SSPP_FLIP_UD;
2300
2301 /* update format */
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002302 psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, src_flags,
2303 pstate->multirect_index);
Clarence Ip282dad62016-09-27 17:07:35 -04002304
Alan Kwong4dd64c82017-02-04 18:41:51 -08002305 if (psde->pipe_hw->ops.setup_sys_cache) {
2306 if (rstate->out_sbuf) {
2307 if (rstate->nplane < 2)
2308 pstate->sc_cfg.op_mode =
2309 SDE_PIPE_SC_OP_MODE_INLINE_SINGLE;
2310 else if (rstate->out_xpos == 0)
2311 pstate->sc_cfg.op_mode =
2312 SDE_PIPE_SC_OP_MODE_INLINE_LEFT;
2313 else
2314 pstate->sc_cfg.op_mode =
2315 SDE_PIPE_SC_OP_MODE_INLINE_RIGHT;
2316
2317 pstate->sc_cfg.rd_en = true;
2318 pstate->sc_cfg.rd_scid =
2319 rstate->rot_hw->caps->scid;
2320 pstate->sc_cfg.rd_noallocate = true;
2321 pstate->sc_cfg.rd_op_type =
2322 SDE_PIPE_SC_RD_OP_TYPE_CACHEABLE;
2323 } else {
2324 pstate->sc_cfg.op_mode =
2325 SDE_PIPE_SC_OP_MODE_OFFLINE;
2326 pstate->sc_cfg.rd_en = false;
2327 pstate->sc_cfg.rd_scid = 0;
2328 pstate->sc_cfg.rd_noallocate = false;
2329 pstate->sc_cfg.rd_op_type =
2330 SDE_PIPE_SC_RD_OP_TYPE_CACHEABLE;
2331 }
2332
2333 psde->pipe_hw->ops.setup_sys_cache(
2334 psde->pipe_hw, &pstate->sc_cfg);
2335 }
2336
Clarence Ip282dad62016-09-27 17:07:35 -04002337 /* update csc */
2338 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip5fc00c52016-09-23 15:03:34 -04002339 _sde_plane_setup_csc(psde);
Clarence Ip282dad62016-09-27 17:07:35 -04002340 else
2341 psde->csc_ptr = 0;
2342 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002343
Benet Clarkeb1b4462016-06-27 14:43:06 -07002344 sde_color_process_plane_setup(plane);
2345
Clarence Ipe78efb72016-06-24 18:35:21 -04002346 /* update sharpening */
Clarence Ip282dad62016-09-27 17:07:35 -04002347 if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) &&
2348 psde->pipe_hw->ops.setup_sharpening) {
2349 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
2350 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
2351 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
2352 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
Clarence Ipe78efb72016-06-24 18:35:21 -04002353
Clarence Ipe78efb72016-06-24 18:35:21 -04002354 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
Clarence Ip282dad62016-09-27 17:07:35 -04002355 &psde->sharp_cfg);
2356 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002357
Alan Kwong1a00e4d2016-07-18 09:42:30 -04002358 _sde_plane_set_qos_lut(plane, fb);
2359 _sde_plane_set_danger_lut(plane, fb);
2360
Alan Kwong5d324e42016-07-28 22:56:18 -04002361 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04002362 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
Alan Kwong5d324e42016-07-28 22:56:18 -04002363 _sde_plane_set_ot_limit(plane, crtc);
2364 }
Alan Kwong1a00e4d2016-07-18 09:42:30 -04002365
Clarence Ip282dad62016-09-27 17:07:35 -04002366 /* clear dirty */
2367 pstate->dirty = 0x0;
2368
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002369 /* clear multirect mode*/
2370 pstate->multirect_index = SDE_SSPP_RECT_SOLO;
2371 pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE;
2372 return 0;
2373}
2374
2375int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane)
2376{
2377 struct sde_plane_state *pstate[R_MAX];
2378 const struct drm_plane_state *drm_state[R_MAX];
2379 struct sde_rect src[R_MAX], dst[R_MAX];
2380 struct sde_plane *sde_plane[R_MAX];
2381 const struct sde_format *fmt[R_MAX];
2382 bool q16_data = true;
2383 int i, max_sspp_linewidth;
2384 int buffer_lines = TX_MODE_BUFFER_LINE_THRES;
2385
2386 for (i = 0; i < R_MAX; i++) {
2387 const struct msm_format *msm_fmt;
2388
2389 drm_state[i] = i ? plane->r1 : plane->r0;
2390 pstate[i] = to_sde_plane_state(drm_state[i]);
2391 sde_plane[i] = to_sde_plane(drm_state[i]->plane);
2392
2393 if (pstate[i] == NULL) {
2394 SDE_ERROR("SDE plane state of plane id %d is NULL\n",
2395 drm_state[i]->plane->base.id);
2396 return -EINVAL;
2397 }
2398
2399 POPULATE_RECT(&src[i], drm_state[i]->src_x, drm_state[i]->src_y,
2400 drm_state[i]->src_w, drm_state[i]->src_h, q16_data);
2401 POPULATE_RECT(&dst[i], drm_state[i]->crtc_x,
2402 drm_state[i]->crtc_y, drm_state[i]->crtc_w,
2403 drm_state[i]->crtc_h, !q16_data);
2404
2405 if (src[i].w != dst[i].w || src[i].h != dst[i].h) {
2406 SDE_ERROR_PLANE(sde_plane[i],
2407 "scaling is not supported in multirect mode\n");
2408 return -EINVAL;
2409 }
2410
2411 msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
2412 fmt[i] = to_sde_format(msm_fmt);
2413 if (SDE_FORMAT_IS_YUV(fmt[i])) {
2414 SDE_ERROR_PLANE(sde_plane[i],
2415 "Unsupported format for multirect mode\n");
2416 return -EINVAL;
2417 }
2418 }
2419
2420 max_sspp_linewidth = sde_plane[R0]->pipe_sblk->maxlinewidth;
2421
2422 /* Validate RECT's and set the mode */
2423
2424 /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
2425 if (src[R0].w <= max_sspp_linewidth/2 &&
2426 src[R1].w <= max_sspp_linewidth/2) {
2427 if (dst[R0].x <= dst[R1].x) {
2428 pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
2429 pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
2430 } else {
2431 pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
2432 pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
2433 }
2434
2435 pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
2436 pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
2437 goto done;
2438 }
2439
2440 /* TIME_MX Mode */
2441 if (SDE_FORMAT_IS_UBWC(fmt[R0]))
2442 buffer_lines = 2 * fmt[R0]->tile_height;
2443
2444 if (dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) {
2445 pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
2446 pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
2447 } else if (dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines) {
2448 pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
2449 pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
2450 } else {
2451 SDE_ERROR(
2452 "No multirect mode possible for the planes (%d - %d)\n",
2453 drm_state[R0]->plane->base.id,
2454 drm_state[R1]->plane->base.id);
2455 return -EINVAL;
2456 }
2457
2458 pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
2459 pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
2460done:
Clarence Ip5e2a9222016-06-26 22:38:24 -04002461 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002462}
2463
Alan Kwong4dd64c82017-02-04 18:41:51 -08002464/**
2465 * sde_plane_get_ctl_flush - get control flush for the given plane
2466 * @plane: Pointer to drm plane structure
2467 * @ctl: Pointer to hardware control driver
2468 * @flush: Pointer to flush control word
2469 */
2470void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
2471 u32 *flush)
2472{
2473 struct sde_plane_state *pstate;
2474 struct sde_plane_rot_state *rstate;
2475 u32 bitmask;
2476
2477 if (!plane || !flush) {
2478 SDE_ERROR("invalid parameters\n");
2479 return;
2480 }
2481
2482 pstate = to_sde_plane_state(plane->state);
2483 rstate = &pstate->rot;
2484
2485 bitmask = ctl->ops.get_bitmask_sspp(ctl, sde_plane_pipe(plane));
2486
2487 if (sde_plane_is_sbuf_mode(plane, NULL) && rstate->rot_hw &&
2488 ctl->ops.get_bitmask_rot)
2489 ctl->ops.get_bitmask_rot(ctl, &bitmask, rstate->rot_hw->idx);
2490
2491 *flush = bitmask;
2492}
2493
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002494static int sde_plane_prepare_fb(struct drm_plane *plane,
Dhaval Patel04c7e8e2016-09-26 20:14:31 -07002495 struct drm_plane_state *new_state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002496{
2497 struct drm_framebuffer *fb = new_state->fb;
2498 struct sde_plane *psde = to_sde_plane(plane);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002499 struct sde_plane_rot_state *new_rstate;
2500 int ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002501
2502 if (!new_state->fb)
2503 return 0;
2504
Clarence Ip13a8cf42016-09-29 17:27:47 -04002505 SDE_DEBUG_PLANE(psde, "FB[%u]\n", fb->base.id);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002506
2507 ret = sde_plane_rot_prepare_fb(plane, new_state);
2508 if (ret) {
2509 SDE_ERROR("failed to prepare rot framebuffer\n");
2510 return ret;
2511 }
2512
2513 new_rstate = &to_sde_plane_state(new_state)->rot;
2514
2515 ret = msm_framebuffer_prepare(new_rstate->out_fb, new_rstate->mmu_id);
2516 if (ret) {
2517 SDE_ERROR("failed to prepare framebuffer\n");
2518 return ret;
2519 }
2520
2521 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002522}
2523
2524static void sde_plane_cleanup_fb(struct drm_plane *plane,
Dhaval Patel04c7e8e2016-09-26 20:14:31 -07002525 struct drm_plane_state *old_state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002526{
Alan Kwong4dd64c82017-02-04 18:41:51 -08002527 struct sde_plane *psde = to_sde_plane(plane);
2528 struct sde_plane_rot_state *old_rstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002529
Alan Kwong4dd64c82017-02-04 18:41:51 -08002530 if (!old_state->fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002531 return;
2532
Alan Kwong4dd64c82017-02-04 18:41:51 -08002533 SDE_DEBUG_PLANE(psde, "FB[%u]\n", old_state->fb->base.id);
2534
2535 old_rstate = &to_sde_plane_state(old_state)->rot;
2536
2537 msm_framebuffer_cleanup(old_rstate->out_fb, old_rstate->mmu_id);
2538
2539 sde_plane_rot_cleanup_fb(plane, old_state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002540}
2541
Alan Kwong4dd64c82017-02-04 18:41:51 -08002542static void _sde_plane_sspp_atomic_check_mode_changed(struct sde_plane *psde,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002543 struct drm_plane_state *state,
2544 struct drm_plane_state *old_state)
2545{
2546 struct sde_plane_state *pstate = to_sde_plane_state(state);
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002547 struct sde_plane_state *old_pstate = to_sde_plane_state(old_state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002548 struct sde_plane_rot_state *rstate = &pstate->rot;
2549 struct sde_plane_rot_state *old_rstate = &old_pstate->rot;
2550 struct drm_framebuffer *fb, *old_fb;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002551
Dhaval Patel47302cf2016-08-18 15:04:28 -07002552 /* no need to check it again */
Clarence Ip282dad62016-09-27 17:07:35 -04002553 if (pstate->dirty == SDE_PLANE_DIRTY_ALL)
Dhaval Patel47302cf2016-08-18 15:04:28 -07002554 return;
2555
Clarence Ip282dad62016-09-27 17:07:35 -04002556 if (!sde_plane_enabled(state) || !sde_plane_enabled(old_state)
2557 || psde->is_error) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002558 SDE_DEBUG_PLANE(psde,
2559 "enabling/disabling full modeset required\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002560 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002561 } else if (to_sde_plane_state(old_state)->pending) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002562 SDE_DEBUG_PLANE(psde, "still pending\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002563 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002564 } else if (rstate->out_src_w != old_rstate->out_src_w ||
2565 rstate->out_src_h != old_rstate->out_src_h ||
2566 rstate->out_src_x != old_rstate->out_src_x ||
2567 rstate->out_src_y != old_rstate->out_src_y) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002568 SDE_DEBUG_PLANE(psde, "src rect updated\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002569 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002570 } else if (state->crtc_w != old_state->crtc_w ||
2571 state->crtc_h != old_state->crtc_h ||
2572 state->crtc_x != old_state->crtc_x ||
2573 state->crtc_y != old_state->crtc_y) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002574 SDE_DEBUG_PLANE(psde, "crtc rect updated\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002575 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002576 } else if (pstate->excl_rect.w != old_pstate->excl_rect.w ||
2577 pstate->excl_rect.h != old_pstate->excl_rect.h ||
2578 pstate->excl_rect.x != old_pstate->excl_rect.x ||
2579 pstate->excl_rect.y != old_pstate->excl_rect.y) {
2580 SDE_DEBUG_PLANE(psde, "excl rect updated\n");
2581 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002582 } else if (pstate->multirect_index != old_pstate->multirect_index ||
2583 pstate->multirect_mode != old_pstate->multirect_mode) {
2584 SDE_DEBUG_PLANE(psde, "multirect config updated\n");
2585 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Clarence Ip282dad62016-09-27 17:07:35 -04002586 }
2587
Alan Kwong4dd64c82017-02-04 18:41:51 -08002588 fb = rstate->out_fb;
2589 old_fb = old_rstate->out_fb;
2590
2591 if (!fb || !old_fb) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002592 SDE_DEBUG_PLANE(psde, "can't compare fb handles\n");
Alan Kwong4dd64c82017-02-04 18:41:51 -08002593 } else if (fb->pixel_format != old_fb->pixel_format) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002594 SDE_DEBUG_PLANE(psde, "format change\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002595 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002596 } else {
Alan Kwong4dd64c82017-02-04 18:41:51 -08002597 uint64_t *new_mods = fb->modifier;
2598 uint64_t *old_mods = old_fb->modifier;
2599 uint32_t *new_pitches = fb->pitches;
2600 uint32_t *old_pitches = old_fb->pitches;
2601 uint32_t *new_offset = fb->offsets;
2602 uint32_t *old_offset = old_fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002603 int i;
2604
Alan Kwong4dd64c82017-02-04 18:41:51 -08002605 for (i = 0; i < ARRAY_SIZE(fb->modifier); i++) {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002606 if (new_mods[i] != old_mods[i]) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002607 SDE_DEBUG_PLANE(psde,
2608 "format modifiers change\"\
Dhaval Patel47302cf2016-08-18 15:04:28 -07002609 plane:%d new_mode:%llu old_mode:%llu\n",
Clarence Ip13a8cf42016-09-29 17:27:47 -04002610 i, new_mods[i], old_mods[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04002611 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
2612 SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002613 break;
2614 }
2615 }
Alan Kwong4dd64c82017-02-04 18:41:51 -08002616 for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) {
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04002617 if (new_pitches[i] != old_pitches[i]) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002618 SDE_DEBUG_PLANE(psde,
2619 "pitches change plane:%d\"\
Dhaval Patel47302cf2016-08-18 15:04:28 -07002620 old_pitches:%u new_pitches:%u\n",
Clarence Ip13a8cf42016-09-29 17:27:47 -04002621 i, old_pitches[i], new_pitches[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04002622 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04002623 break;
2624 }
2625 }
Alan Kwong4dd64c82017-02-04 18:41:51 -08002626 for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07002627 if (new_offset[i] != old_offset[i]) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002628 SDE_DEBUG_PLANE(psde,
2629 "offset change plane:%d\"\
Dhaval Patel47302cf2016-08-18 15:04:28 -07002630 old_offset:%u new_offset:%u\n",
Clarence Ip13a8cf42016-09-29 17:27:47 -04002631 i, old_offset[i], new_offset[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04002632 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
2633 SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002634 break;
2635 }
2636 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04002637 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002638}
2639
Alan Kwong4dd64c82017-02-04 18:41:51 -08002640static int sde_plane_sspp_atomic_check(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002641 struct drm_plane_state *state)
2642{
Clarence Ipdedbba92016-09-27 17:43:10 -04002643 int ret = 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04002644 struct sde_plane *psde;
2645 struct sde_plane_state *pstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002646 struct sde_plane_rot_state *rstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04002647 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002648 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04002649 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002650 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
2651 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04002652
2653 if (!plane || !state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002654 SDE_ERROR("invalid arg(s), plane %d state %d\n",
2655 plane != 0, state != 0);
Clarence Ipdbde9832016-06-26 09:48:36 -04002656 ret = -EINVAL;
2657 goto exit;
2658 }
2659
2660 psde = to_sde_plane(plane);
2661 pstate = to_sde_plane_state(state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002662 rstate = &pstate->rot;
Clarence Ipdbde9832016-06-26 09:48:36 -04002663
2664 if (!psde->pipe_sblk) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002665 SDE_ERROR_PLANE(psde, "invalid catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04002666 ret = -EINVAL;
2667 goto exit;
2668 }
2669
Clarence Ipdedbba92016-09-27 17:43:10 -04002670 deci_w = sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
2671 deci_h = sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
Clarence Ipdbde9832016-06-26 09:48:36 -04002672
2673 /* src values are in Q16 fixed point, convert to integer */
Alan Kwong4dd64c82017-02-04 18:41:51 -08002674 POPULATE_RECT(&src, rstate->out_src_x, rstate->out_src_y,
2675 rstate->out_src_w, rstate->out_src_h, q16_data);
Dhaval Patel47302cf2016-08-18 15:04:28 -07002676 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
2677 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04002678
Dhaval Patel47302cf2016-08-18 15:04:28 -07002679 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
2680 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04002681
Dhaval Patel47302cf2016-08-18 15:04:28 -07002682 max_upscale = psde->pipe_sblk->maxupscale;
2683 max_downscale = psde->pipe_sblk->maxdwnscale;
2684 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04002685
Clarence Ip13a8cf42016-09-29 17:27:47 -04002686 SDE_DEBUG_PLANE(psde, "check %d -> %d\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002687 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002688
Dhaval Patel47302cf2016-08-18 15:04:28 -07002689 if (!sde_plane_enabled(state))
2690 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04002691
Alan Kwong4dd64c82017-02-04 18:41:51 -08002692 SDE_DEBUG(
2693 "plane%d.%u sspp:%x/%dx%d/%c%c%c%c/%llx/%dx%d+%d+%d crtc:%dx%d+%d+%d\n",
2694 plane->base.id, rstate->sequence_id,
2695 rstate->out_rotation,
2696 rstate->out_fb_width, rstate->out_fb_height,
2697 rstate->out_fb_pixel_format >> 0,
2698 rstate->out_fb_pixel_format >> 8,
2699 rstate->out_fb_pixel_format >> 16,
2700 rstate->out_fb_pixel_format >> 24,
2701 rstate->out_fb_modifier[0],
2702 rstate->out_src_w >> 16, rstate->out_src_h >> 16,
2703 rstate->out_src_x >> 16, rstate->out_src_y >> 16,
2704 state->crtc_w, state->crtc_h,
2705 state->crtc_x, state->crtc_y);
2706
Dhaval Patel47302cf2016-08-18 15:04:28 -07002707 fmt = to_sde_format(msm_framebuffer_format(state->fb));
2708
2709 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
2710
2711 if (SDE_FORMAT_IS_YUV(fmt) &&
2712 (!(psde->features & SDE_SSPP_SCALER) ||
abeykun1c312f62016-08-26 09:47:12 -04002713 !(psde->features & (BIT(SDE_SSPP_CSC)
2714 | BIT(SDE_SSPP_CSC_10BIT))))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002715 SDE_ERROR_PLANE(psde,
2716 "plane doesn't have scaler/csc for yuv\n");
Dhaval Patel47302cf2016-08-18 15:04:28 -07002717 ret = -EINVAL;
2718
2719 /* check src bounds */
Alan Kwong4dd64c82017-02-04 18:41:51 -08002720 } else if (rstate->out_fb_width > MAX_IMG_WIDTH ||
2721 rstate->out_fb_height > MAX_IMG_HEIGHT ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07002722 src.w < min_src_size || src.h < min_src_size ||
Alan Kwong4dd64c82017-02-04 18:41:51 -08002723 CHECK_LAYER_BOUNDS(src.x, src.w, rstate->out_fb_width) ||
2724 CHECK_LAYER_BOUNDS(src.y, src.h, rstate->out_fb_height)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002725 SDE_ERROR_PLANE(psde, "invalid source %u, %u, %ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002726 src.x, src.y, src.w, src.h);
2727 ret = -E2BIG;
2728
2729 /* valid yuv image */
2730 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
2731 (src.w & 0x1) || (src.h & 0x1))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002732 SDE_ERROR_PLANE(psde, "invalid yuv source %u, %u, %ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002733 src.x, src.y, src.w, src.h);
2734 ret = -EINVAL;
2735
2736 /* min dst support */
2737 } else if (dst.w < 0x1 || dst.h < 0x1) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002738 SDE_ERROR_PLANE(psde, "invalid dest rect %u, %u, %ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002739 dst.x, dst.y, dst.w, dst.h);
2740 ret = -EINVAL;
2741
2742 /* decimation validation */
2743 } else if (deci_w || deci_h) {
2744 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
2745 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002746 SDE_ERROR_PLANE(psde,
2747 "too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04002748 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002749 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002750 SDE_ERROR_PLANE(psde,
2751 "decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04002752 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002753 }
2754
Dhaval Patel47302cf2016-08-18 15:04:28 -07002755 } else if (!(psde->features & SDE_SSPP_SCALER) &&
2756 ((src.w != dst.w) || (src.h != dst.h))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002757 SDE_ERROR_PLANE(psde,
2758 "pipe doesn't support scaling %ux%u->%ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002759 src.w, src.h, dst.w, dst.h);
2760 ret = -EINVAL;
2761
2762 /* check decimated source width */
2763 } else if (src_deci_w > max_linewidth) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002764 SDE_ERROR_PLANE(psde,
2765 "invalid src w:%u, deci w:%u, line w:%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002766 src.w, src_deci_w, max_linewidth);
2767 ret = -E2BIG;
2768
2769 /* check max scaler capability */
2770 } else if (((src_deci_w * max_upscale) < dst.w) ||
2771 ((src_deci_h * max_upscale) < dst.h) ||
2772 ((dst.w * max_downscale) < src_deci_w) ||
2773 ((dst.h * max_downscale) < src_deci_h)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002774 SDE_ERROR_PLANE(psde,
2775 "too much scaling requested %ux%u->%ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002776 src_deci_w, src_deci_h, dst.w, dst.h);
2777 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002778 }
2779
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002780 /* check excl rect configs */
2781 if (pstate->excl_rect.w && pstate->excl_rect.h) {
2782 struct sde_rect intersect;
2783
2784 /*
2785 * Check exclusion rect against src rect.
2786 * Cropping is not required as hardware will consider only the
2787 * intersecting region with the src rect.
2788 */
2789 sde_kms_rect_intersect(&intersect, &src, &pstate->excl_rect);
2790 if (!intersect.w || !intersect.h || SDE_FORMAT_IS_YUV(fmt)) {
2791 SDE_ERROR_PLANE(psde,
2792 "invalid excl_rect:{%d,%d,%d,%d} src:{%d,%d,%d,%d}, fmt:%s\n",
2793 pstate->excl_rect.x, pstate->excl_rect.y,
2794 pstate->excl_rect.w, pstate->excl_rect.h,
2795 src.x, src.y, src.w, src.h,
2796 drm_get_format_name(fmt->base.pixel_format));
2797 ret = -EINVAL;
2798 }
2799 }
2800
Dhaval Patel47302cf2016-08-18 15:04:28 -07002801modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002802 if (!ret)
Alan Kwong4dd64c82017-02-04 18:41:51 -08002803 _sde_plane_sspp_atomic_check_mode_changed(psde,
2804 state, plane->state);
2805exit:
2806 return ret;
2807}
2808
2809static int sde_plane_atomic_check(struct drm_plane *plane,
2810 struct drm_plane_state *state)
2811{
2812 int ret = 0;
2813 struct sde_plane *psde;
2814 struct sde_plane_state *pstate;
2815
2816 if (!plane || !state) {
2817 SDE_ERROR("invalid arg(s), plane %d state %d\n",
2818 plane != 0, state != 0);
2819 ret = -EINVAL;
2820 goto exit;
2821 }
2822
2823 psde = to_sde_plane(plane);
2824 pstate = to_sde_plane_state(state);
2825
2826 SDE_DEBUG_PLANE(psde, "\n");
2827
2828 ret = sde_plane_rot_atomic_check(plane, state);
2829 if (ret)
2830 goto exit;
2831
2832 ret = sde_plane_sspp_atomic_check(plane, state);
2833
Clarence Ipdbde9832016-06-26 09:48:36 -04002834exit:
2835 return ret;
2836}
2837
Clarence Ipcae1bb62016-07-07 12:07:13 -04002838/**
2839 * sde_plane_flush - final plane operations before commit flush
2840 * @plane: Pointer to drm plane structure
2841 */
2842void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04002843{
Clarence Ipcae1bb62016-07-07 12:07:13 -04002844 struct sde_plane *psde;
2845
Clarence Ip13a8cf42016-09-29 17:27:47 -04002846 if (!plane) {
2847 SDE_ERROR("invalid plane\n");
Clarence Ipcae1bb62016-07-07 12:07:13 -04002848 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -04002849 }
Clarence Ipcae1bb62016-07-07 12:07:13 -04002850
2851 psde = to_sde_plane(plane);
2852
2853 /*
2854 * These updates have to be done immediately before the plane flush
2855 * timing, and may not be moved to the atomic_update/mode_set functions.
2856 */
2857 if (psde->is_error)
Clarence Ip3bf8d872017-02-16 15:25:38 -05002858 /* force white frame with 100% alpha pipe output on error */
2859 _sde_plane_color_fill(psde, 0xFFFFFF, 0xFF);
Clarence Ipcae1bb62016-07-07 12:07:13 -04002860 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
2861 /* force 100% alpha */
Clarence Ip13a8cf42016-09-29 17:27:47 -04002862 _sde_plane_color_fill(psde, psde->color_fill, 0xFF);
Clarence Ipcae1bb62016-07-07 12:07:13 -04002863 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
2864 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
2865
2866 /* flag h/w flush complete */
2867 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04002868 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002869}
2870
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002871static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04002872 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002873{
Clarence Ip13a8cf42016-09-29 17:27:47 -04002874 struct sde_plane *psde;
Clarence Ip5e2a9222016-06-26 22:38:24 -04002875 struct drm_plane_state *state;
2876 struct sde_plane_state *pstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002877 struct sde_plane_state *old_pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002878
Clarence Ip13a8cf42016-09-29 17:27:47 -04002879 if (!plane) {
2880 SDE_ERROR("invalid plane\n");
2881 return;
2882 } else if (!plane->state) {
2883 SDE_ERROR("invalid plane state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04002884 return;
2885 }
2886
Clarence Ip13a8cf42016-09-29 17:27:47 -04002887 psde = to_sde_plane(plane);
2888 psde->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04002889 state = plane->state;
2890 pstate = to_sde_plane_state(state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002891 old_pstate = to_sde_plane_state(old_state);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002892
Clarence Ip13a8cf42016-09-29 17:27:47 -04002893 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04002894
Alan Kwong4dd64c82017-02-04 18:41:51 -08002895 sde_plane_rot_atomic_update(plane, old_state);
2896
2897 if (!sde_plane_sspp_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04002898 pstate->pending = true;
Clarence Ip282dad62016-09-27 17:07:35 -04002899 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002900 int ret;
2901
Alan Kwong4dd64c82017-02-04 18:41:51 -08002902 ret = sde_plane_sspp_atomic_update(plane, state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002903 /* atomic_check should have ensured that this doesn't fail */
2904 WARN_ON(ret < 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002905 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002906}
2907
Dhaval Patel47302cf2016-08-18 15:04:28 -07002908
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002909/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07002910static void _sde_plane_install_properties(struct drm_plane *plane,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002911 struct sde_mdss_cfg *catalog, u32 master_plane_id)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002912{
Clarence Ip5e2a9222016-06-26 22:38:24 -04002913 static const struct drm_prop_enum_list e_blend_op[] = {
2914 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
2915 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
2916 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
2917 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
2918 };
2919 static const struct drm_prop_enum_list e_src_config[] = {
2920 {SDE_DRM_DEINTERLACE, "deinterlace"}
2921 };
Clarence Ipea3d6262016-07-15 16:20:11 -04002922 const struct sde_format_extended *format_list;
Dhaval Patel4e574842016-08-23 15:11:37 -07002923 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04002924 struct sde_plane *psde = to_sde_plane(plane);
Clarence Ipc47a0692016-10-11 10:54:17 -04002925 int zpos_max = 255;
2926 int zpos_def = 0;
Benet Clarkeb1b4462016-06-27 14:43:06 -07002927 char feature_name[256];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002928
Clarence Ip13a8cf42016-09-29 17:27:47 -04002929 if (!plane || !psde) {
2930 SDE_ERROR("invalid plane\n");
2931 return;
2932 } else if (!psde->pipe_hw || !psde->pipe_sblk) {
2933 SDE_ERROR("invalid plane, pipe_hw %d pipe_sblk %d\n",
2934 psde->pipe_hw != 0, psde->pipe_sblk != 0);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002935 return;
Clarence Ipc47a0692016-10-11 10:54:17 -04002936 } else if (!catalog) {
2937 SDE_ERROR("invalid catalog\n");
2938 return;
Clarence Ip5e2a9222016-06-26 22:38:24 -04002939 }
2940
Alan Kwong4dd64c82017-02-04 18:41:51 -08002941 psde->catalog = catalog;
2942
Clarence Ipc47a0692016-10-11 10:54:17 -04002943 if (sde_is_custom_client()) {
Clarence Ip649989a2016-10-21 14:28:34 -04002944 if (catalog->mixer_count && catalog->mixer &&
2945 catalog->mixer[0].sblk->maxblendstages) {
2946 zpos_max = catalog->mixer[0].sblk->maxblendstages - 1;
2947 if (zpos_max > SDE_STAGE_MAX - SDE_STAGE_0 - 1)
2948 zpos_max = SDE_STAGE_MAX - SDE_STAGE_0 - 1;
2949 }
Clarence Ipc47a0692016-10-11 10:54:17 -04002950 } else if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
2951 /* reserve zpos == 0 for primary planes */
2952 zpos_def = drm_plane_index(plane) + 1;
2953 }
2954
2955 msm_property_install_range(&psde->property_info, "zpos",
2956 0x0, 0, zpos_max, zpos_def, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002957
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04002958 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002959 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002960
Dhaval Patel47302cf2016-08-18 15:04:28 -07002961 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04002962 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07002963 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002964
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002965 if (!master_plane_id) {
2966 if (psde->pipe_sblk->maxhdeciexp) {
2967 msm_property_install_range(&psde->property_info,
2968 "h_decimate", 0x0, 0,
2969 psde->pipe_sblk->maxhdeciexp, 0,
2970 PLANE_PROP_H_DECIMATE);
2971 }
Clarence Ipdedbba92016-09-27 17:43:10 -04002972
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002973 if (psde->pipe_sblk->maxvdeciexp) {
2974 msm_property_install_range(&psde->property_info,
2975 "v_decimate", 0x0, 0,
2976 psde->pipe_sblk->maxvdeciexp, 0,
2977 PLANE_PROP_V_DECIMATE);
2978 }
Clarence Ipdedbba92016-09-27 17:43:10 -04002979
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002980 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
2981 msm_property_install_volatile_range(
2982 &psde->property_info, "scaler_v2",
2983 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2);
2984 msm_property_install_blob(&psde->property_info,
2985 "lut_ed", 0, PLANE_PROP_SCALER_LUT_ED);
2986 msm_property_install_blob(&psde->property_info,
2987 "lut_cir", 0,
2988 PLANE_PROP_SCALER_LUT_CIR);
2989 msm_property_install_blob(&psde->property_info,
2990 "lut_sep", 0,
2991 PLANE_PROP_SCALER_LUT_SEP);
2992 } else if (psde->features & SDE_SSPP_SCALER) {
2993 msm_property_install_volatile_range(
2994 &psde->property_info, "scaler_v1", 0x0,
2995 0, ~0, 0, PLANE_PROP_SCALER_V1);
2996 }
Clarence Ipb43d4592016-09-08 14:21:35 -04002997
Dhaval Patel0aee0972017-02-08 19:00:58 -08002998 if (psde->features & BIT(SDE_SSPP_CSC) ||
2999 psde->features & BIT(SDE_SSPP_CSC_10BIT))
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003000 msm_property_install_volatile_range(
3001 &psde->property_info, "csc_v1", 0x0,
3002 0, ~0, 0, PLANE_PROP_CSC_V1);
Clarence Ip5fc00c52016-09-23 15:03:34 -04003003
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003004 if (psde->features & BIT(SDE_SSPP_HSIC)) {
3005 snprintf(feature_name, sizeof(feature_name), "%s%d",
3006 "SDE_SSPP_HUE_V",
3007 psde->pipe_sblk->hsic_blk.version >> 16);
3008 msm_property_install_range(&psde->property_info,
3009 feature_name, 0, 0, 0xFFFFFFFF, 0,
3010 PLANE_PROP_HUE_ADJUST);
3011 snprintf(feature_name, sizeof(feature_name), "%s%d",
3012 "SDE_SSPP_SATURATION_V",
3013 psde->pipe_sblk->hsic_blk.version >> 16);
3014 msm_property_install_range(&psde->property_info,
3015 feature_name, 0, 0, 0xFFFFFFFF, 0,
3016 PLANE_PROP_SATURATION_ADJUST);
3017 snprintf(feature_name, sizeof(feature_name), "%s%d",
3018 "SDE_SSPP_VALUE_V",
3019 psde->pipe_sblk->hsic_blk.version >> 16);
3020 msm_property_install_range(&psde->property_info,
3021 feature_name, 0, 0, 0xFFFFFFFF, 0,
3022 PLANE_PROP_VALUE_ADJUST);
3023 snprintf(feature_name, sizeof(feature_name), "%s%d",
3024 "SDE_SSPP_CONTRAST_V",
3025 psde->pipe_sblk->hsic_blk.version >> 16);
3026 msm_property_install_range(&psde->property_info,
3027 feature_name, 0, 0, 0xFFFFFFFF, 0,
3028 PLANE_PROP_CONTRAST_ADJUST);
3029 }
Benet Clarkeb1b4462016-06-27 14:43:06 -07003030 }
3031
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003032 if (psde->features & BIT(SDE_SSPP_EXCL_RECT))
3033 msm_property_install_volatile_range(&psde->property_info,
3034 "excl_rect_v1", 0x0, 0, ~0, 0, PLANE_PROP_EXCL_RECT_V1);
3035
Alan Kwong4dd64c82017-02-04 18:41:51 -08003036 sde_plane_rot_install_properties(plane, catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003037
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04003038 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07003039 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003040
Dhaval Patel47302cf2016-08-18 15:04:28 -07003041 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
3042 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
3043
3044 if (psde->pipe_hw->ops.setup_solidfill)
3045 msm_property_install_range(&psde->property_info, "color_fill",
3046 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
3047
Dhaval Patel4e574842016-08-23 15:11:37 -07003048 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003049 if (!info) {
3050 SDE_ERROR("failed to allocate info memory\n");
Dhaval Patel4e574842016-08-23 15:11:37 -07003051 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003052 }
Dhaval Patel4e574842016-08-23 15:11:37 -07003053
3054 msm_property_install_blob(&psde->property_info, "capabilities",
3055 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
3056 sde_kms_info_reset(info);
3057
Clarence Ipea3d6262016-07-15 16:20:11 -04003058 format_list = psde->pipe_sblk->format_list;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003059
3060 if (master_plane_id) {
3061 sde_kms_info_add_keyint(info, "primary_smart_plane_id",
3062 master_plane_id);
3063 format_list = plane_formats;
3064 }
3065
Clarence Ipea3d6262016-07-15 16:20:11 -04003066 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04003067 sde_kms_info_start(info, "pixel_formats");
3068 while (format_list->fourcc_format) {
3069 sde_kms_info_append_format(info,
3070 format_list->fourcc_format,
3071 format_list->modifier);
3072 ++format_list;
3073 }
3074 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04003075 }
Dhaval Patel4e574842016-08-23 15:11:37 -07003076
3077 sde_kms_info_add_keyint(info, "max_linewidth",
3078 psde->pipe_sblk->maxlinewidth);
3079 sde_kms_info_add_keyint(info, "max_upscale",
3080 psde->pipe_sblk->maxupscale);
3081 sde_kms_info_add_keyint(info, "max_downscale",
3082 psde->pipe_sblk->maxdwnscale);
3083 sde_kms_info_add_keyint(info, "max_horizontal_deci",
3084 psde->pipe_sblk->maxhdeciexp);
3085 sde_kms_info_add_keyint(info, "max_vertical_deci",
3086 psde->pipe_sblk->maxvdeciexp);
3087 msm_property_set_blob(&psde->property_info, &psde->blob_info,
3088 info->data, info->len, PLANE_PROP_INFO);
3089
3090 kfree(info);
Benet Clarkd009b1d2016-06-27 14:45:59 -07003091
3092 if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) {
3093 snprintf(feature_name, sizeof(feature_name), "%s%d",
3094 "SDE_SSPP_SKIN_COLOR_V",
3095 psde->pipe_sblk->memcolor_blk.version >> 16);
3096 msm_property_install_blob(&psde->property_info, feature_name, 0,
3097 PLANE_PROP_SKIN_COLOR);
3098 snprintf(feature_name, sizeof(feature_name), "%s%d",
3099 "SDE_SSPP_SKY_COLOR_V",
3100 psde->pipe_sblk->memcolor_blk.version >> 16);
3101 msm_property_install_blob(&psde->property_info, feature_name, 0,
3102 PLANE_PROP_SKY_COLOR);
3103 snprintf(feature_name, sizeof(feature_name), "%s%d",
3104 "SDE_SSPP_FOLIAGE_COLOR_V",
3105 psde->pipe_sblk->memcolor_blk.version >> 16);
3106 msm_property_install_blob(&psde->property_info, feature_name, 0,
3107 PLANE_PROP_FOLIAGE_COLOR);
3108 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003109}
3110
Clarence Ip5fc00c52016-09-23 15:03:34 -04003111static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr)
3112{
3113 struct sde_drm_csc_v1 csc_v1;
3114 int i;
3115
3116 if (!psde) {
3117 SDE_ERROR("invalid plane\n");
3118 return;
3119 }
3120
3121 psde->csc_usr_ptr = NULL;
3122 if (!usr_ptr) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003123 SDE_DEBUG_PLANE(psde, "csc data removed\n");
Clarence Ip5fc00c52016-09-23 15:03:34 -04003124 return;
3125 }
3126
3127 if (copy_from_user(&csc_v1, usr_ptr, sizeof(csc_v1))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003128 SDE_ERROR_PLANE(psde, "failed to copy csc data\n");
Clarence Ip5fc00c52016-09-23 15:03:34 -04003129 return;
3130 }
3131
Clarence Ipb43d4592016-09-08 14:21:35 -04003132 /* populate from user space */
Clarence Ip5fc00c52016-09-23 15:03:34 -04003133 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
3134 psde->csc_cfg.csc_mv[i] = csc_v1.ctm_coeff[i] >> 16;
3135 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
3136 psde->csc_cfg.csc_pre_bv[i] = csc_v1.pre_bias[i];
3137 psde->csc_cfg.csc_post_bv[i] = csc_v1.post_bias[i];
3138 }
3139 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
3140 psde->csc_cfg.csc_pre_lv[i] = csc_v1.pre_clamp[i];
3141 psde->csc_cfg.csc_post_lv[i] = csc_v1.post_clamp[i];
3142 }
3143 psde->csc_usr_ptr = &psde->csc_cfg;
3144}
3145
Clarence Ipb43d4592016-09-08 14:21:35 -04003146static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, void *usr)
3147{
3148 struct sde_drm_scaler_v1 scale_v1;
3149 struct sde_hw_pixel_ext *pe;
3150 int i;
3151
3152 if (!psde) {
3153 SDE_ERROR("invalid plane\n");
3154 return;
3155 }
3156
3157 psde->pixel_ext_usr = false;
3158 if (!usr) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003159 SDE_DEBUG_PLANE(psde, "scale data removed\n");
Clarence Ipb43d4592016-09-08 14:21:35 -04003160 return;
3161 }
3162
3163 if (copy_from_user(&scale_v1, usr, sizeof(scale_v1))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003164 SDE_ERROR_PLANE(psde, "failed to copy scale data\n");
Clarence Ipb43d4592016-09-08 14:21:35 -04003165 return;
3166 }
3167
3168 /* populate from user space */
3169 pe = &(psde->pixel_ext);
3170 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
3171 for (i = 0; i < SDE_MAX_PLANES; i++) {
3172 pe->init_phase_x[i] = scale_v1.init_phase_x[i];
3173 pe->phase_step_x[i] = scale_v1.phase_step_x[i];
3174 pe->init_phase_y[i] = scale_v1.init_phase_y[i];
3175 pe->phase_step_y[i] = scale_v1.phase_step_y[i];
3176
3177 pe->horz_filter[i] = scale_v1.horz_filter[i];
3178 pe->vert_filter[i] = scale_v1.vert_filter[i];
3179 }
3180 for (i = 0; i < SDE_MAX_PLANES; i++) {
abeykun41060122016-11-28 13:02:01 -05003181 pe->left_ftch[i] = scale_v1.pe.left_ftch[i];
3182 pe->right_ftch[i] = scale_v1.pe.right_ftch[i];
3183 pe->left_rpt[i] = scale_v1.pe.left_rpt[i];
3184 pe->right_rpt[i] = scale_v1.pe.right_rpt[i];
3185 pe->roi_w[i] = scale_v1.pe.num_ext_pxls_lr[i];
Clarence Ipb43d4592016-09-08 14:21:35 -04003186
abeykun41060122016-11-28 13:02:01 -05003187 pe->top_ftch[i] = scale_v1.pe.top_ftch[i];
3188 pe->btm_ftch[i] = scale_v1.pe.btm_ftch[i];
3189 pe->top_rpt[i] = scale_v1.pe.top_rpt[i];
3190 pe->btm_rpt[i] = scale_v1.pe.btm_rpt[i];
3191 pe->roi_h[i] = scale_v1.pe.num_ext_pxls_tb[i];
Clarence Ipb43d4592016-09-08 14:21:35 -04003192 }
abeykun41060122016-11-28 13:02:01 -05003193
Clarence Ipb43d4592016-09-08 14:21:35 -04003194 psde->pixel_ext_usr = true;
3195
Clarence Ip13a8cf42016-09-29 17:27:47 -04003196 SDE_DEBUG_PLANE(psde, "user property data copied\n");
Clarence Ipb43d4592016-09-08 14:21:35 -04003197}
3198
abeykun48f407a2016-08-25 12:06:44 -04003199static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
3200 struct sde_plane_state *pstate, void *usr)
3201{
3202 struct sde_drm_scaler_v2 scale_v2;
3203 struct sde_hw_pixel_ext *pe;
3204 int i;
3205 struct sde_hw_scaler3_cfg *cfg;
3206
3207 if (!psde) {
3208 SDE_ERROR("invalid plane\n");
3209 return;
3210 }
3211
3212 cfg = psde->scaler3_cfg;
3213 psde->pixel_ext_usr = false;
3214 if (!usr) {
3215 SDE_DEBUG_PLANE(psde, "scale data removed\n");
3216 return;
3217 }
3218
3219 if (copy_from_user(&scale_v2, usr, sizeof(scale_v2))) {
3220 SDE_ERROR_PLANE(psde, "failed to copy scale data\n");
3221 return;
3222 }
3223
3224 /* populate from user space */
3225 pe = &(psde->pixel_ext);
3226 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
3227 cfg->enable = scale_v2.enable;
3228 cfg->dir_en = scale_v2.dir_en;
3229 for (i = 0; i < SDE_MAX_PLANES; i++) {
3230 cfg->init_phase_x[i] = scale_v2.init_phase_x[i];
3231 cfg->phase_step_x[i] = scale_v2.phase_step_x[i];
3232 cfg->init_phase_y[i] = scale_v2.init_phase_y[i];
3233 cfg->phase_step_y[i] = scale_v2.phase_step_y[i];
3234
3235 cfg->preload_x[i] = scale_v2.preload_x[i];
3236 cfg->preload_y[i] = scale_v2.preload_y[i];
3237 cfg->src_width[i] = scale_v2.src_width[i];
3238 cfg->src_height[i] = scale_v2.src_height[i];
3239 }
3240 cfg->dst_width = scale_v2.dst_width;
3241 cfg->dst_height = scale_v2.dst_height;
3242
3243 cfg->y_rgb_filter_cfg = scale_v2.y_rgb_filter_cfg;
3244 cfg->uv_filter_cfg = scale_v2.uv_filter_cfg;
3245 cfg->alpha_filter_cfg = scale_v2.alpha_filter_cfg;
3246 cfg->blend_cfg = scale_v2.blend_cfg;
3247
3248 cfg->lut_flag = scale_v2.lut_flag;
3249 cfg->dir_lut_idx = scale_v2.dir_lut_idx;
3250 cfg->y_rgb_cir_lut_idx = scale_v2.y_rgb_cir_lut_idx;
3251 cfg->uv_cir_lut_idx = scale_v2.uv_cir_lut_idx;
3252 cfg->y_rgb_sep_lut_idx = scale_v2.y_rgb_sep_lut_idx;
3253 cfg->uv_sep_lut_idx = scale_v2.uv_sep_lut_idx;
3254
3255 cfg->de.enable = scale_v2.de.enable;
3256 cfg->de.sharpen_level1 = scale_v2.de.sharpen_level1;
3257 cfg->de.sharpen_level2 = scale_v2.de.sharpen_level2;
3258 cfg->de.clip = scale_v2.de.clip;
3259 cfg->de.limit = scale_v2.de.limit;
3260 cfg->de.thr_quiet = scale_v2.de.thr_quiet;
3261 cfg->de.thr_dieout = scale_v2.de.thr_dieout;
3262 cfg->de.thr_low = scale_v2.de.thr_low;
3263 cfg->de.thr_high = scale_v2.de.thr_high;
3264 cfg->de.prec_shift = scale_v2.de.prec_shift;
3265 for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
3266 cfg->de.adjust_a[i] = scale_v2.de.adjust_a[i];
3267 cfg->de.adjust_b[i] = scale_v2.de.adjust_b[i];
3268 cfg->de.adjust_c[i] = scale_v2.de.adjust_c[i];
3269 }
3270 for (i = 0; i < SDE_MAX_PLANES; i++) {
abeykun41060122016-11-28 13:02:01 -05003271 pe->left_ftch[i] = scale_v2.pe.left_ftch[i];
3272 pe->right_ftch[i] = scale_v2.pe.right_ftch[i];
3273 pe->left_rpt[i] = scale_v2.pe.left_rpt[i];
3274 pe->right_rpt[i] = scale_v2.pe.right_rpt[i];
3275 pe->roi_w[i] = scale_v2.pe.num_ext_pxls_lr[i];
abeykun48f407a2016-08-25 12:06:44 -04003276
abeykun41060122016-11-28 13:02:01 -05003277 pe->top_ftch[i] = scale_v2.pe.top_ftch[i];
3278 pe->btm_ftch[i] = scale_v2.pe.btm_ftch[i];
3279 pe->top_rpt[i] = scale_v2.pe.top_rpt[i];
3280 pe->btm_rpt[i] = scale_v2.pe.btm_rpt[i];
3281 pe->roi_h[i] = scale_v2.pe.num_ext_pxls_tb[i];
abeykun48f407a2016-08-25 12:06:44 -04003282 }
3283 psde->pixel_ext_usr = true;
3284
3285 SDE_DEBUG_PLANE(psde, "user property data copied\n");
3286}
3287
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003288static void _sde_plane_set_excl_rect_v1(struct sde_plane *psde,
3289 struct sde_plane_state *pstate, void *usr_ptr)
3290{
3291 struct drm_clip_rect excl_rect_v1;
3292
3293 if (!psde) {
3294 SDE_ERROR("invalid plane\n");
3295 return;
3296 }
3297
3298 if (!usr_ptr) {
3299 SDE_DEBUG_PLANE(psde, "excl rect data removed\n");
3300 return;
3301 }
3302
3303 if (copy_from_user(&excl_rect_v1, usr_ptr, sizeof(excl_rect_v1))) {
3304 SDE_ERROR_PLANE(psde, "failed to copy excl rect data\n");
3305 return;
3306 }
3307
3308 /* populate from user space */
3309 pstate->excl_rect.x = excl_rect_v1.x1;
3310 pstate->excl_rect.y = excl_rect_v1.y1;
3311 pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1 + 1;
3312 pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1 + 1;
3313}
3314
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003315static int sde_plane_atomic_set_property(struct drm_plane *plane,
3316 struct drm_plane_state *state, struct drm_property *property,
3317 uint64_t val)
3318{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003319 struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003320 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04003321 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003322
Clarence Ip13a8cf42016-09-29 17:27:47 -04003323 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003324
3325 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003326 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003327 } else if (!state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003328 SDE_ERROR_PLANE(psde, "invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003329 } else {
Clarence Ip4c1d9772016-06-26 09:35:38 -04003330 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003331 ret = msm_property_atomic_set(&psde->property_info,
3332 pstate->property_values, pstate->property_blobs,
3333 property, val);
3334 if (!ret) {
3335 idx = msm_property_index(&psde->property_info,
3336 property);
Clarence Ip5fc00c52016-09-23 15:03:34 -04003337 switch (idx) {
3338 case PLANE_PROP_INPUT_FENCE:
Clarence Ip13a8cf42016-09-29 17:27:47 -04003339 _sde_plane_set_input_fence(psde, pstate, val);
Clarence Ip5fc00c52016-09-23 15:03:34 -04003340 break;
3341 case PLANE_PROP_CSC_V1:
3342 _sde_plane_set_csc_v1(psde, (void *)val);
3343 break;
Clarence Ipb43d4592016-09-08 14:21:35 -04003344 case PLANE_PROP_SCALER_V1:
3345 _sde_plane_set_scaler_v1(psde, (void *)val);
3346 break;
abeykun48f407a2016-08-25 12:06:44 -04003347 case PLANE_PROP_SCALER_V2:
3348 _sde_plane_set_scaler_v2(psde, pstate,
3349 (void *)val);
3350 break;
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003351 case PLANE_PROP_EXCL_RECT_V1:
3352 _sde_plane_set_excl_rect_v1(psde, pstate,
3353 (void *)val);
3354 break;
Clarence Ip5fc00c52016-09-23 15:03:34 -04003355 default:
3356 /* nothing to do */
3357 break;
3358 }
Clarence Ipe78efb72016-06-24 18:35:21 -04003359 }
3360 }
3361
Alan Kwong4dd64c82017-02-04 18:41:51 -08003362 SDE_DEBUG_PLANE(psde, "%s[%d] <= 0x%llx ret=%d\n",
3363 property->name, property->base.id, val, ret);
3364
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003365 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003366}
3367
3368static int sde_plane_set_property(struct drm_plane *plane,
3369 struct drm_property *property, uint64_t val)
3370{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003371 SDE_DEBUG("\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04003372
Clarence Ipae4e60c2016-06-26 22:44:04 -04003373 return sde_plane_atomic_set_property(plane,
3374 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003375}
3376
3377static int sde_plane_atomic_get_property(struct drm_plane *plane,
3378 const struct drm_plane_state *state,
3379 struct drm_property *property, uint64_t *val)
3380{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003381 struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003382 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04003383 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003384
Clarence Ipaa0faf42016-05-30 12:07:48 -04003385 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003386 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003387 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003388 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003389 } else {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003390 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04003391 pstate = to_sde_plane_state(state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08003392 sde_plane_rot_install_caps(plane);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003393 ret = msm_property_atomic_get(&psde->property_info,
3394 pstate->property_values, pstate->property_blobs,
3395 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04003396 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003397
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003398 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003399}
3400
3401static void sde_plane_destroy(struct drm_plane *plane)
3402{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003403 struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003404
Clarence Ip13a8cf42016-09-29 17:27:47 -04003405 SDE_DEBUG_PLANE(psde, "\n");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003406
Clarence Ip13a8cf42016-09-29 17:27:47 -04003407 if (psde) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04003408 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
3409
Dhaval Patel4e574842016-08-23 15:11:37 -07003410 if (psde->blob_info)
3411 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003412 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04003413 mutex_destroy(&psde->lock);
3414
Clarence Ip4ce59322016-06-26 22:27:51 -04003415 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003416
Clarence Ip4ce59322016-06-26 22:27:51 -04003417 /* this will destroy the states as well */
3418 drm_plane_cleanup(plane);
3419
Clarence Ip4c1d9772016-06-26 09:35:38 -04003420 if (psde->pipe_hw)
3421 sde_hw_sspp_destroy(psde->pipe_hw);
3422
Clarence Ip4ce59322016-06-26 22:27:51 -04003423 kfree(psde);
3424 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003425}
3426
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003427static void sde_plane_destroy_state(struct drm_plane *plane,
3428 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003429{
Clarence Ipaa0faf42016-05-30 12:07:48 -04003430 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04003431 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04003432
Clarence Ipae4e60c2016-06-26 22:44:04 -04003433 if (!plane || !state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003434 SDE_ERROR("invalid arg(s), plane %d state %d\n",
3435 plane != 0, state != 0);
Clarence Ipae4e60c2016-06-26 22:44:04 -04003436 return;
3437 }
3438
Clarence Ipaa0faf42016-05-30 12:07:48 -04003439 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04003440 pstate = to_sde_plane_state(state);
3441
Clarence Ip13a8cf42016-09-29 17:27:47 -04003442 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003443
Alan Kwong4dd64c82017-02-04 18:41:51 -08003444 sde_plane_rot_destroy_state(plane, &pstate->base);
3445
Clarence Ipe78efb72016-06-24 18:35:21 -04003446 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003447 if (state->fb)
3448 drm_framebuffer_unreference(state->fb);
3449
Clarence Ipae4e60c2016-06-26 22:44:04 -04003450 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04003451 if (pstate->input_fence)
3452 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04003453
Clarence Ipaa0faf42016-05-30 12:07:48 -04003454 /* destroy value helper */
3455 msm_property_destroy_state(&psde->property_info, pstate,
3456 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003457}
3458
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003459static struct drm_plane_state *
3460sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003461{
Clarence Ipaa0faf42016-05-30 12:07:48 -04003462 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003463 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04003464 struct sde_plane_state *old_state;
Clarence Ip17e908b2016-09-29 15:58:00 -04003465 uint64_t input_fence_default;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003466
Clarence Ip13a8cf42016-09-29 17:27:47 -04003467 if (!plane) {
3468 SDE_ERROR("invalid plane\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003469 return NULL;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003470 } else if (!plane->state) {
3471 SDE_ERROR("invalid plane state\n");
3472 return NULL;
3473 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003474
Clarence Ip730e7192016-06-26 22:45:09 -04003475 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003476 psde = to_sde_plane(plane);
3477 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003478 if (!pstate) {
3479 SDE_ERROR_PLANE(psde, "failed to allocate state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003480 return NULL;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003481 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003482
Clarence Ip13a8cf42016-09-29 17:27:47 -04003483 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003484
3485 /* duplicate value helper */
3486 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
3487 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04003488
Clarence Ip730e7192016-06-26 22:45:09 -04003489 /* add ref count for frame buffer */
3490 if (pstate->base.fb)
3491 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003492
Clarence Ip17e908b2016-09-29 15:58:00 -04003493 /* clear out any input fence */
3494 pstate->input_fence = 0;
3495 input_fence_default = msm_property_get_default(
3496 &psde->property_info, PLANE_PROP_INPUT_FENCE);
3497 msm_property_set_property(&psde->property_info, pstate->property_values,
3498 PLANE_PROP_INPUT_FENCE, input_fence_default);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003499
Clarence Ip282dad62016-09-27 17:07:35 -04003500 pstate->dirty = 0x0;
Clarence Ip730e7192016-06-26 22:45:09 -04003501 pstate->pending = false;
3502
Alan Kwong4dd64c82017-02-04 18:41:51 -08003503 sde_plane_rot_duplicate_state(plane, &pstate->base);
3504
Clarence Ip730e7192016-06-26 22:45:09 -04003505 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003506}
3507
3508static void sde_plane_reset(struct drm_plane *plane)
3509{
Clarence Ipae4e60c2016-06-26 22:44:04 -04003510 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003511 struct sde_plane_state *pstate;
3512
Clarence Ipae4e60c2016-06-26 22:44:04 -04003513 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003514 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04003515 return;
3516 }
3517
Clarence Ip730e7192016-06-26 22:45:09 -04003518 psde = to_sde_plane(plane);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003519 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003520
Clarence Ipae4e60c2016-06-26 22:44:04 -04003521 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04003522 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04003523 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003524 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04003525 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003526
Clarence Ipaa0faf42016-05-30 12:07:48 -04003527 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003528 if (!pstate) {
3529 SDE_ERROR_PLANE(psde, "failed to allocate state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003530 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003531 }
Clarence Ip730e7192016-06-26 22:45:09 -04003532
Clarence Ipaa0faf42016-05-30 12:07:48 -04003533 /* reset value helper */
3534 msm_property_reset_state(&psde->property_info, pstate,
3535 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003536
3537 pstate->base.plane = plane;
3538
3539 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003540}
3541
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003542#ifdef CONFIG_DEBUG_FS
Alan Kwongf0fd8512016-10-24 21:39:26 -04003543static ssize_t _sde_plane_danger_read(struct file *file,
3544 char __user *buff, size_t count, loff_t *ppos)
3545{
3546 struct sde_kms *kms = file->private_data;
3547 struct sde_mdss_cfg *cfg = kms->catalog;
3548 int len = 0;
3549 char buf[40] = {'\0'};
3550
3551 if (!cfg)
3552 return -ENODEV;
3553
3554 if (*ppos)
3555 return 0; /* the end */
3556
3557 len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);
3558 if (len < 0 || len >= sizeof(buf))
3559 return 0;
3560
3561 if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
3562 return -EFAULT;
3563
3564 *ppos += len; /* increase offset */
3565
3566 return len;
3567}
3568
3569static void _sde_plane_set_danger_state(struct sde_kms *kms, bool enable)
3570{
3571 struct drm_plane *plane;
3572
3573 drm_for_each_plane(plane, kms->dev) {
3574 if (plane->fb && plane->state) {
3575 sde_plane_danger_signal_ctrl(plane, enable);
3576 SDE_DEBUG("plane:%d img:%dx%d ",
3577 plane->base.id, plane->fb->width,
3578 plane->fb->height);
3579 SDE_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",
3580 plane->state->src_x >> 16,
3581 plane->state->src_y >> 16,
3582 plane->state->src_w >> 16,
3583 plane->state->src_h >> 16,
3584 plane->state->crtc_x, plane->state->crtc_y,
3585 plane->state->crtc_w, plane->state->crtc_h);
3586 } else {
3587 SDE_DEBUG("Inactive plane:%d\n", plane->base.id);
3588 }
3589 }
3590}
3591
3592static ssize_t _sde_plane_danger_write(struct file *file,
3593 const char __user *user_buf, size_t count, loff_t *ppos)
3594{
3595 struct sde_kms *kms = file->private_data;
3596 struct sde_mdss_cfg *cfg = kms->catalog;
3597 int disable_panic;
3598 char buf[10];
3599
3600 if (!cfg)
3601 return -EFAULT;
3602
3603 if (count >= sizeof(buf))
3604 return -EFAULT;
3605
3606 if (copy_from_user(buf, user_buf, count))
3607 return -EFAULT;
3608
3609 buf[count] = 0; /* end of string */
3610
3611 if (kstrtoint(buf, 0, &disable_panic))
3612 return -EFAULT;
3613
3614 if (disable_panic) {
3615 /* Disable panic signal for all active pipes */
3616 SDE_DEBUG("Disabling danger:\n");
3617 _sde_plane_set_danger_state(kms, false);
3618 kms->has_danger_ctrl = false;
3619 } else {
3620 /* Enable panic signal for all active pipes */
3621 SDE_DEBUG("Enabling danger:\n");
3622 kms->has_danger_ctrl = true;
3623 _sde_plane_set_danger_state(kms, true);
3624 }
3625
3626 return count;
3627}
3628
3629static const struct file_operations sde_plane_danger_enable = {
3630 .open = simple_open,
3631 .read = _sde_plane_danger_read,
3632 .write = _sde_plane_danger_write,
3633};
3634
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003635static int _sde_plane_init_debugfs(struct drm_plane *plane)
Clarence Ip4ce59322016-06-26 22:27:51 -04003636{
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003637 struct sde_plane *psde;
3638 struct sde_kms *kms;
3639 struct msm_drm_private *priv;
Clarence Ip4ce59322016-06-26 22:27:51 -04003640 const struct sde_sspp_sub_blks *sblk = 0;
3641 const struct sde_sspp_cfg *cfg = 0;
3642
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003643 if (!plane || !plane->dev) {
3644 SDE_ERROR("invalid arguments\n");
3645 return -EINVAL;
3646 }
3647
3648 priv = plane->dev->dev_private;
3649 if (!priv || !priv->kms) {
3650 SDE_ERROR("invalid KMS reference\n");
3651 return -EINVAL;
3652 }
3653
3654 kms = to_sde_kms(priv->kms);
3655 psde = to_sde_plane(plane);
3656
Clarence Ip4ce59322016-06-26 22:27:51 -04003657 if (psde && psde->pipe_hw)
3658 cfg = psde->pipe_hw->cap;
3659 if (cfg)
3660 sblk = cfg->sblk;
3661
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003662 if (!sblk)
3663 return 0;
Clarence Ip4ce59322016-06-26 22:27:51 -04003664
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003665 /* create overall sub-directory for the pipe */
3666 psde->debugfs_root =
3667 debugfs_create_dir(psde->pipe_name,
3668 sde_debugfs_get_root(kms));
Clarence Ip4ce59322016-06-26 22:27:51 -04003669
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003670 if (!psde->debugfs_root)
3671 return -ENOMEM;
Clarence Ip4ce59322016-06-26 22:27:51 -04003672
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003673 /* don't error check these */
3674 debugfs_create_x32("features", 0644,
3675 psde->debugfs_root, &psde->features);
Alan Kwongf0fd8512016-10-24 21:39:26 -04003676
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003677 /* add register dump support */
3678 sde_debugfs_setup_regset32(&psde->debugfs_src,
3679 sblk->src_blk.base + cfg->base,
3680 sblk->src_blk.len,
3681 kms);
3682 sde_debugfs_create_regset32("src_blk", 0444,
3683 psde->debugfs_root, &psde->debugfs_src);
Alan Kwongf0fd8512016-10-24 21:39:26 -04003684
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003685 if (cfg->features & BIT(SDE_SSPP_SCALER_QSEED3) ||
3686 cfg->features & BIT(SDE_SSPP_SCALER_QSEED2)) {
3687 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
3688 sblk->scaler_blk.base + cfg->base,
3689 sblk->scaler_blk.len,
3690 kms);
3691 sde_debugfs_create_regset32("scaler_blk", 0444,
3692 psde->debugfs_root,
3693 &psde->debugfs_scaler);
Clarence Ip716ab662017-03-20 06:51:24 -07003694 debugfs_create_bool("default_scaling",
3695 0644,
3696 psde->debugfs_root,
3697 &psde->debugfs_default_scale);
Clarence Ip4ce59322016-06-26 22:27:51 -04003698 }
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003699
3700 if (cfg->features & BIT(SDE_SSPP_CSC) ||
3701 cfg->features & BIT(SDE_SSPP_CSC_10BIT)) {
3702 sde_debugfs_setup_regset32(&psde->debugfs_csc,
3703 sblk->csc_blk.base + cfg->base,
3704 sblk->csc_blk.len,
3705 kms);
3706 sde_debugfs_create_regset32("csc_blk", 0444,
3707 psde->debugfs_root, &psde->debugfs_csc);
3708 }
3709
3710 debugfs_create_u32("xin_id",
3711 0444,
3712 psde->debugfs_root,
3713 (u32 *) &cfg->xin_id);
3714 debugfs_create_u32("clk_ctrl",
3715 0444,
3716 psde->debugfs_root,
3717 (u32 *) &cfg->clk_ctrl);
3718 debugfs_create_x32("creq_vblank",
3719 0644,
3720 psde->debugfs_root,
3721 (u32 *) &sblk->creq_vblank);
3722 debugfs_create_x32("danger_vblank",
3723 0644,
3724 psde->debugfs_root,
3725 (u32 *) &sblk->danger_vblank);
3726
3727 debugfs_create_file("disable_danger",
3728 0644,
3729 psde->debugfs_root,
3730 kms, &sde_plane_danger_enable);
Alan Kwong4dd64c82017-02-04 18:41:51 -08003731 debugfs_create_u32("sbuf_mode",
3732 0644,
3733 psde->debugfs_root, &psde->sbuf_mode);
3734 debugfs_create_u32("sbuf_writeback",
3735 0644,
3736 psde->debugfs_root,
3737 &psde->sbuf_writeback);
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003738
3739 return 0;
3740}
3741
3742static void _sde_plane_destroy_debugfs(struct drm_plane *plane)
3743{
3744 struct sde_plane *psde;
3745
3746 if (!plane)
3747 return;
3748 psde = to_sde_plane(plane);
3749
3750 debugfs_remove_recursive(psde->debugfs_root);
3751}
3752#else
3753static int _sde_plane_init_debugfs(struct drm_plane *plane)
3754{
3755 return 0;
3756}
3757static void _sde_plane_destroy_debugfs(struct drm_plane *plane)
3758{
3759}
3760#endif
3761
3762static int sde_plane_late_register(struct drm_plane *plane)
3763{
3764 return _sde_plane_init_debugfs(plane);
3765}
3766
3767static void sde_plane_early_unregister(struct drm_plane *plane)
3768{
3769 _sde_plane_destroy_debugfs(plane);
3770}
3771
3772static const struct drm_plane_funcs sde_plane_funcs = {
3773 .update_plane = drm_atomic_helper_update_plane,
3774 .disable_plane = drm_atomic_helper_disable_plane,
3775 .destroy = sde_plane_destroy,
3776 .set_property = sde_plane_set_property,
3777 .atomic_set_property = sde_plane_atomic_set_property,
3778 .atomic_get_property = sde_plane_atomic_get_property,
3779 .reset = sde_plane_reset,
3780 .atomic_duplicate_state = sde_plane_duplicate_state,
3781 .atomic_destroy_state = sde_plane_destroy_state,
3782 .late_register = sde_plane_late_register,
3783 .early_unregister = sde_plane_early_unregister,
3784};
3785
3786static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
3787 .prepare_fb = sde_plane_prepare_fb,
3788 .cleanup_fb = sde_plane_cleanup_fb,
3789 .atomic_check = sde_plane_atomic_check,
3790 .atomic_update = sde_plane_atomic_update,
3791};
3792
3793enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
3794{
3795 return plane ? to_sde_plane(plane)->pipe : SSPP_NONE;
3796}
3797
3798bool is_sde_plane_virtual(struct drm_plane *plane)
3799{
3800 return plane ? to_sde_plane(plane)->is_virtual : false;
Clarence Ip4ce59322016-06-26 22:27:51 -04003801}
3802
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003803/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04003804struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip2bbf7b32016-09-23 15:07:16 -04003805 uint32_t pipe, bool primary_plane,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003806 unsigned long possible_crtcs, u32 master_plane_id)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003807{
3808 struct drm_plane *plane = NULL;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003809 const struct sde_format_extended *format_list;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003810 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003811 struct msm_drm_private *priv;
3812 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003813 enum drm_plane_type type;
Clarence Ipc47a0692016-10-11 10:54:17 -04003814 int ret = -EINVAL;
Clarence Ip4c1d9772016-06-26 09:35:38 -04003815
3816 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003817 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04003818 goto exit;
3819 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003820
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003821 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04003822 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003823 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04003824 goto exit;
3825 }
3826
3827 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003828 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04003829 goto exit;
3830 }
3831 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003832
Clarence Ip4c1d9772016-06-26 09:35:38 -04003833 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003834 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04003835 goto exit;
3836 }
3837
Clarence Ip4ce59322016-06-26 22:27:51 -04003838 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003839 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
3840 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003841 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003842 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04003843 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003844 }
3845
Clarence Ip4c1d9772016-06-26 09:35:38 -04003846 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003847 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003848 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04003849 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003850 psde->is_virtual = (master_plane_id != 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003851
Clarence Ip4c1d9772016-06-26 09:35:38 -04003852 /* initialize underlying h/w driver */
3853 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
3854 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003855 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04003856 ret = PTR_ERR(psde->pipe_hw);
3857 goto clean_plane;
3858 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003859 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04003860 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003861 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04003862
3863 /* cache features mask for later */
3864 psde->features = psde->pipe_hw->cap->features;
3865 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04003866 if (!psde->pipe_sblk) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003867 SDE_ERROR("[%u]invalid sblk\n", pipe);
Clarence Ipea3d6262016-07-15 16:20:11 -04003868 goto clean_sspp;
3869 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04003870
abeykun48f407a2016-08-25 12:06:44 -04003871 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
3872 psde->scaler3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg),
3873 GFP_KERNEL);
3874 if (!psde->scaler3_cfg) {
3875 SDE_ERROR("[%u]failed to allocate scale struct\n",
3876 pipe);
3877 ret = -ENOMEM;
3878 goto clean_sspp;
3879 }
3880 }
3881
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003882 format_list = psde->pipe_sblk->format_list;
3883
3884 if (master_plane_id)
3885 format_list = plane_formats;
3886
3887 psde->nformats = sde_populate_formats(plane_formats,
3888 psde->formats,
3889 0,
3890 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003891
Clarence Ip4c1d9772016-06-26 09:35:38 -04003892 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003893 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04003894 goto clean_sspp;
3895 }
3896
3897 if (psde->features & BIT(SDE_SSPP_CURSOR))
3898 type = DRM_PLANE_TYPE_CURSOR;
3899 else if (primary_plane)
3900 type = DRM_PLANE_TYPE_PRIMARY;
3901 else
3902 type = DRM_PLANE_TYPE_OVERLAY;
Dhaval Patel04c7e8e2016-09-26 20:14:31 -07003903 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
3904 psde->formats, psde->nformats,
3905 type, NULL);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003906 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04003907 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003908
Clarence Ip4c1d9772016-06-26 09:35:38 -04003909 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003910 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003911
Clarence Ipaa0faf42016-05-30 12:07:48 -04003912 msm_property_init(&psde->property_info, &plane->base, dev,
3913 priv->plane_property, psde->property_data,
3914 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
3915 sizeof(struct sde_plane_state));
3916
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003917 _sde_plane_install_properties(plane, kms->catalog, master_plane_id);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003918
Clarence Ip4ce59322016-06-26 22:27:51 -04003919 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04003920 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04003921
Clarence Ip730e7192016-06-26 22:45:09 -04003922 mutex_init(&psde->lock);
3923
Dhaval Patel82c8dbc2017-02-18 23:15:10 -08003924 SDE_DEBUG("%s created for pipe %u\n", psde->pipe_name, pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003925 return plane;
3926
Clarence Ip4c1d9772016-06-26 09:35:38 -04003927clean_sspp:
3928 if (psde && psde->pipe_hw)
3929 sde_hw_sspp_destroy(psde->pipe_hw);
abeykun48f407a2016-08-25 12:06:44 -04003930
3931 if (psde && psde->scaler3_cfg)
3932 kfree(psde->scaler3_cfg);
Clarence Ip4c1d9772016-06-26 09:35:38 -04003933clean_plane:
3934 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04003935exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003936 return ERR_PTR(ret);
3937}