blob: 1721c67032da2e660ce39c133b55ab30e4cf942b [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 Ip56902792017-03-17 15:22:07 -040041static bool suspend_blank = true;
42module_param(suspend_blank, bool, 0400);
43MODULE_PARM_DESC(suspend_blank,
44 "If set, active planes will force their outputs to black,\n"
45 "by temporarily enabling the color fill, when recovering\n"
46 "from a system resume instead of attempting to display the\n"
47 "last provided frame buffer.");
48
Clarence Ip13a8cf42016-09-29 17:27:47 -040049#define SDE_DEBUG_PLANE(pl, fmt, ...) SDE_DEBUG("plane%d " fmt,\
50 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
51
52#define SDE_ERROR_PLANE(pl, fmt, ...) SDE_ERROR("plane%d " fmt,\
53 (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__)
54
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040055#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
56#define PHASE_STEP_SHIFT 21
57#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
58#define PHASE_RESIDUAL 15
59
Clarence Ipe78efb72016-06-24 18:35:21 -040060#define SHARP_STRENGTH_DEFAULT 32
61#define SHARP_EDGE_THR_DEFAULT 112
62#define SHARP_SMOOTH_THR_DEFAULT 8
63#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040064
Clarence Ip5e2a9222016-06-26 22:38:24 -040065#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070066
Clarence Ipcae1bb62016-07-07 12:07:13 -040067#define SDE_PLANE_COLOR_FILL_FLAG BIT(31)
68
Jeykumar Sankaran2e655032017-02-04 14:05:45 -080069/* multirect rect index */
70enum {
71 R0,
72 R1,
73 R_MAX
74};
75
76#define TX_MODE_BUFFER_LINE_THRES 2
77
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -070078#define SDE_QSEED3_DEFAULT_PRELOAD_H 0x4
79#define SDE_QSEED3_DEFAULT_PRELOAD_V 0x3
80
Alan Kwong4dd64c82017-02-04 18:41:51 -080081#define DEFAULT_REFRESH_RATE 60
82
Alan Kwong1a00e4d2016-07-18 09:42:30 -040083/**
84 * enum sde_plane_qos - Different qos configurations for each pipe
85 *
86 * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
87 * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
88 * this configuration is mutually exclusive from VBLANK_CTRL.
89 * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
90 */
91enum sde_plane_qos {
92 SDE_PLANE_QOS_VBLANK_CTRL = BIT(0),
93 SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
94 SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
95};
96
Clarence Ip5fc00c52016-09-23 15:03:34 -040097/*
98 * struct sde_plane - local sde plane structure
99 * @csc_cfg: Decoded user configuration for csc
100 * @csc_usr_ptr: Points to csc_cfg if valid user config available
101 * @csc_ptr: Points to sde_csc_cfg structure to use for current
Alan Kwong4dd64c82017-02-04 18:41:51 -0800102 * @catalog: Points to sde catalog structure
103 * @sbuf_mode: force stream buffer mode if set
Veera Sundaram Sankaran82916e02017-03-29 18:44:22 -0700104 * @sbuf_writeback: force stream buffer writeback if set
105 * @revalidate: force revalidation of all the plane properties
Alan Kwong4dd64c82017-02-04 18:41:51 -0800106 * @blob_rot_caps: Pointer to rotator capability blob
Clarence Ip5fc00c52016-09-23 15:03:34 -0400107 */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700108struct sde_plane {
109 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400110
111 int mmu_id;
112
Clarence Ip730e7192016-06-26 22:45:09 -0400113 struct mutex lock;
114
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400115 enum sde_sspp pipe;
116 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700117 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400118 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400119
120 struct sde_hw_pipe *pipe_hw;
121 struct sde_hw_pipe_cfg pipe_cfg;
Clarence Ipe78efb72016-06-24 18:35:21 -0400122 struct sde_hw_sharp_cfg sharp_cfg;
abeykun48f407a2016-08-25 12:06:44 -0400123 struct sde_hw_scaler3_cfg *scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400124 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400125 uint32_t color_fill;
126 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400127 bool is_rt_pipe;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -0800128 bool is_virtual;
Alan Kwong4dd64c82017-02-04 18:41:51 -0800129 struct sde_mdss_cfg *catalog;
130 u32 sbuf_mode;
131 u32 sbuf_writeback;
Veera Sundaram Sankaran82916e02017-03-29 18:44:22 -0700132 bool revalidate;
Clarence Ip4ce59322016-06-26 22:27:51 -0400133
Clarence Ipb43d4592016-09-08 14:21:35 -0400134 struct sde_hw_pixel_ext pixel_ext;
135 bool pixel_ext_usr;
136
Clarence Ip373f8592016-05-26 00:58:42 -0400137 struct sde_csc_cfg csc_cfg;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400138 struct sde_csc_cfg *csc_usr_ptr;
Clarence Ip373f8592016-05-26 00:58:42 -0400139 struct sde_csc_cfg *csc_ptr;
140
Clarence Ip4c1d9772016-06-26 09:35:38 -0400141 const struct sde_sspp_sub_blks *pipe_sblk;
142
Clarence Ip5e2a9222016-06-26 22:38:24 -0400143 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -0400144
Clarence Ipaa0faf42016-05-30 12:07:48 -0400145 struct msm_property_info property_info;
146 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -0700147 struct drm_property_blob *blob_info;
Alan Kwong4dd64c82017-02-04 18:41:51 -0800148 struct drm_property_blob *blob_rot_caps;
Clarence Ip730e7192016-06-26 22:45:09 -0400149
Clarence Ip4ce59322016-06-26 22:27:51 -0400150 /* debugfs related stuff */
151 struct dentry *debugfs_root;
152 struct sde_debugfs_regset32 debugfs_src;
153 struct sde_debugfs_regset32 debugfs_scaler;
154 struct sde_debugfs_regset32 debugfs_csc;
Clarence Ip716ab662017-03-20 06:51:24 -0700155 bool debugfs_default_scale;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700156};
Dhaval Patel47302cf2016-08-18 15:04:28 -0700157
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700158#define to_sde_plane(x) container_of(x, struct sde_plane, base)
159
Alan Kwong4dd64c82017-02-04 18:41:51 -0800160static struct sde_kms *_sde_plane_get_kms(struct drm_plane *plane)
161{
162 struct msm_drm_private *priv;
163
164 if (!plane || !plane->dev)
165 return NULL;
166 priv = plane->dev->dev_private;
167 if (!priv)
168 return NULL;
169 return to_sde_kms(priv->kms);
170}
171
Alan Kwong4aacd532017-02-04 18:51:33 -0800172/**
173 * _sde_plane_get_crtc_state - obtain crtc state attached to given plane state
174 * @pstate: Pointer to drm plane state
175 * return: Pointer to crtc state if success; pointer error, otherwise
176 */
177static struct drm_crtc_state *_sde_plane_get_crtc_state(
178 struct drm_plane_state *pstate)
179{
180 struct drm_crtc_state *cstate;
181
182 if (!pstate || !pstate->crtc)
183 return NULL;
184
185 if (pstate->state)
186 cstate = drm_atomic_get_crtc_state(pstate->state, pstate->crtc);
187 else
188 cstate = pstate->crtc->state;
189
190 return cstate;
191}
192
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400193static bool sde_plane_enabled(struct drm_plane_state *state)
194{
Clarence Ipdbde9832016-06-26 09:48:36 -0400195 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400196}
197
Alan Kwong4dd64c82017-02-04 18:41:51 -0800198static bool sde_plane_sspp_enabled(struct drm_plane_state *state)
199{
200 return state && to_sde_plane_state(state)->rot.out_fb && state->crtc;
201}
202
203/**
204 * sde_plane_crtc_enabled - determine if crtc of given plane state is enabled
205 * @state: Pointer to drm plane state
206 * return: true if plane and the associated crtc are both enabled
207 */
208static bool sde_plane_crtc_enabled(struct drm_plane_state *state)
209{
210 return sde_plane_enabled(state) && state->crtc->state &&
211 state->crtc->state->active &&
212 state->crtc->state->enable;
213}
214
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400215/**
216 * _sde_plane_calc_fill_level - calculate fill level of the given source format
217 * @plane: Pointer to drm plane
218 * @fmt: Pointer to source buffer format
219 * @src_wdith: width of source buffer
220 * Return: fill level corresponding to the source buffer/format or 0 if error
221 */
222static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
223 const struct sde_format *fmt, u32 src_width)
224{
225 struct sde_plane *psde;
226 u32 fixed_buff_size;
227 u32 total_fl;
228
229 if (!plane || !fmt) {
230 SDE_ERROR("invalid arguments\n");
231 return 0;
232 }
233
234 psde = to_sde_plane(plane);
235 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
236
237 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
238 if (fmt->chroma_sample == SDE_CHROMA_420) {
239 /* NV12 */
240 total_fl = (fixed_buff_size / 2) /
241 ((src_width + 32) * fmt->bpp);
242 } else {
243 /* non NV12 */
244 total_fl = (fixed_buff_size) /
245 ((src_width + 32) * fmt->bpp);
246 }
247 } else {
248 total_fl = (fixed_buff_size * 2) /
249 ((src_width + 32) * fmt->bpp);
250 }
251
Dhaval Patel6c666622017-03-21 23:02:59 -0700252 SDE_DEBUG("plane%u: pnum:%d fmt: %4.4s w:%u fl:%u\n",
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400253 plane->base.id, psde->pipe - SSPP_VIG0,
Dhaval Patel6c666622017-03-21 23:02:59 -0700254 (char *)&fmt->base.pixel_format,
255 src_width, total_fl);
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400256
257 return total_fl;
258}
259
260/**
261 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
262 * @total_fl: fill level
263 * Return: LUT setting corresponding to the fill level
264 */
265static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
266{
267 u32 qos_lut;
268
269 if (total_fl <= 4)
270 qos_lut = 0x1B;
271 else if (total_fl <= 5)
272 qos_lut = 0x5B;
273 else if (total_fl <= 6)
274 qos_lut = 0x15B;
275 else if (total_fl <= 7)
276 qos_lut = 0x55B;
277 else if (total_fl <= 8)
278 qos_lut = 0x155B;
279 else if (total_fl <= 9)
280 qos_lut = 0x555B;
281 else if (total_fl <= 10)
282 qos_lut = 0x1555B;
283 else if (total_fl <= 11)
284 qos_lut = 0x5555B;
285 else if (total_fl <= 12)
286 qos_lut = 0x15555B;
287 else
288 qos_lut = 0x55555B;
289
290 return qos_lut;
291}
292
293/**
294 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
295 * @total_fl: fill level
296 * Return: LUT setting corresponding to the fill level
297 */
298static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
299{
300 u32 qos_lut;
301
302 if (total_fl <= 10)
303 qos_lut = 0x1AAff;
304 else if (total_fl <= 11)
305 qos_lut = 0x5AAFF;
306 else if (total_fl <= 12)
307 qos_lut = 0x15AAFF;
308 else
309 qos_lut = 0x55AAFF;
310
311 return qos_lut;
312}
313
314/**
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400315 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
316 * @plane: Pointer to drm plane
317 * @fb: Pointer to framebuffer associated with the given plane
318 */
319static void _sde_plane_set_qos_lut(struct drm_plane *plane,
320 struct drm_framebuffer *fb)
321{
322 struct sde_plane *psde;
323 const struct sde_format *fmt = NULL;
324 u32 qos_lut;
325 u32 total_fl = 0;
326
327 if (!plane || !fb) {
328 SDE_ERROR("invalid arguments plane %d fb %d\n",
329 plane != 0, fb != 0);
330 return;
331 }
332
333 psde = to_sde_plane(plane);
334
335 if (!psde->pipe_hw || !psde->pipe_sblk) {
336 SDE_ERROR("invalid arguments\n");
337 return;
338 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
339 return;
340 }
341
342 if (!psde->is_rt_pipe) {
343 qos_lut = psde->pipe_sblk->creq_lut_nrt;
344 } else {
345 fmt = sde_get_sde_format_ext(
346 fb->pixel_format,
347 fb->modifier,
348 drm_format_num_planes(fb->pixel_format));
349 total_fl = _sde_plane_calc_fill_level(plane, fmt,
350 psde->pipe_cfg.src_rect.w);
351
352 if (SDE_FORMAT_IS_LINEAR(fmt))
353 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
354 else
355 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
356 }
357
358 psde->pipe_qos_cfg.creq_lut = qos_lut;
359
360 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
361 (fmt) ? fmt->base.pixel_format : 0,
362 psde->is_rt_pipe, total_fl, qos_lut,
363 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
364
Dhaval Patel6c666622017-03-21 23:02:59 -0700365 SDE_DEBUG("plane%u: pnum:%d fmt: %4.4s rt:%d fl:%u lut:0x%x\n",
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400366 plane->base.id,
367 psde->pipe - SSPP_VIG0,
Dhaval Patel6c666622017-03-21 23:02:59 -0700368 fmt ? (char *)&fmt->base.pixel_format : NULL,
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400369 psde->is_rt_pipe, total_fl, qos_lut);
370
371 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
372}
373
374/**
375 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
376 * @plane: Pointer to drm plane
377 * @fb: Pointer to framebuffer associated with the given plane
378 */
379static void _sde_plane_set_danger_lut(struct drm_plane *plane,
380 struct drm_framebuffer *fb)
381{
382 struct sde_plane *psde;
383 const struct sde_format *fmt = NULL;
384 u32 danger_lut, safe_lut;
385
386 if (!plane || !fb) {
387 SDE_ERROR("invalid arguments\n");
388 return;
389 }
390
391 psde = to_sde_plane(plane);
392
393 if (!psde->pipe_hw || !psde->pipe_sblk) {
394 SDE_ERROR("invalid arguments\n");
395 return;
396 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
397 return;
398 }
399
400 if (!psde->is_rt_pipe) {
401 danger_lut = psde->pipe_sblk->danger_lut_nrt;
402 safe_lut = psde->pipe_sblk->safe_lut_nrt;
403 } else {
404 fmt = sde_get_sde_format_ext(
405 fb->pixel_format,
406 fb->modifier,
407 drm_format_num_planes(fb->pixel_format));
408
409 if (SDE_FORMAT_IS_LINEAR(fmt)) {
410 danger_lut = psde->pipe_sblk->danger_lut_linear;
411 safe_lut = psde->pipe_sblk->safe_lut_linear;
412 } else {
413 danger_lut = psde->pipe_sblk->danger_lut_tile;
414 safe_lut = psde->pipe_sblk->safe_lut_tile;
415 }
416 }
417
418 psde->pipe_qos_cfg.danger_lut = danger_lut;
419 psde->pipe_qos_cfg.safe_lut = safe_lut;
420
421 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
422 (fmt) ? fmt->base.pixel_format : 0,
423 (fmt) ? fmt->fetch_mode : 0,
424 psde->pipe_qos_cfg.danger_lut,
425 psde->pipe_qos_cfg.safe_lut);
426
Dhaval Patel6c666622017-03-21 23:02:59 -0700427 SDE_DEBUG("plane%u: pnum:%d fmt: %4.4s mode:%d luts[0x%x, 0x%x]\n",
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400428 plane->base.id,
429 psde->pipe - SSPP_VIG0,
Dhaval Patel6c666622017-03-21 23:02:59 -0700430 fmt ? (char *)&fmt->base.pixel_format : NULL,
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400431 fmt ? fmt->fetch_mode : -1,
432 psde->pipe_qos_cfg.danger_lut,
433 psde->pipe_qos_cfg.safe_lut);
434
435 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
436 &psde->pipe_qos_cfg);
437}
438
439/**
440 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
441 * @plane: Pointer to drm plane
442 * @enable: true to enable QoS control
443 * @flags: QoS control mode (enum sde_plane_qos)
444 */
445static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
446 bool enable, u32 flags)
447{
448 struct sde_plane *psde;
449
450 if (!plane) {
451 SDE_ERROR("invalid arguments\n");
452 return;
453 }
454
455 psde = to_sde_plane(plane);
456
457 if (!psde->pipe_hw || !psde->pipe_sblk) {
458 SDE_ERROR("invalid arguments\n");
459 return;
460 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
461 return;
462 }
463
464 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
465 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
466 psde->pipe_qos_cfg.danger_vblank =
467 psde->pipe_sblk->danger_vblank;
468 psde->pipe_qos_cfg.vblank_en = enable;
469 }
470
471 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
472 /* this feature overrules previous VBLANK_CTRL */
473 psde->pipe_qos_cfg.vblank_en = false;
474 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
475 }
476
477 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
478 psde->pipe_qos_cfg.danger_safe_en = enable;
479
480 if (!psde->is_rt_pipe) {
481 psde->pipe_qos_cfg.vblank_en = false;
482 psde->pipe_qos_cfg.danger_safe_en = false;
483 }
484
Clarence Ip0d0e96d2016-10-24 18:13:13 -0400485 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 -0400486 plane->base.id,
487 psde->pipe - SSPP_VIG0,
488 psde->pipe_qos_cfg.danger_safe_en,
489 psde->pipe_qos_cfg.vblank_en,
490 psde->pipe_qos_cfg.creq_vblank,
Clarence Ip0d0e96d2016-10-24 18:13:13 -0400491 psde->pipe_qos_cfg.danger_vblank,
492 psde->is_rt_pipe);
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400493
494 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
495 &psde->pipe_qos_cfg);
496}
497
Veera Sundaram Sankaran82916e02017-03-29 18:44:22 -0700498void sde_plane_set_revalidate(struct drm_plane *plane, bool enable)
499{
500 struct sde_plane *psde;
501
502 if (!plane)
503 return;
504
505 psde = to_sde_plane(plane);
506 psde->revalidate = enable;
507}
508
Alan Kwongf0fd8512016-10-24 21:39:26 -0400509int sde_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
510{
511 struct sde_plane *psde;
512 struct msm_drm_private *priv;
513 struct sde_kms *sde_kms;
514
515 if (!plane || !plane->dev) {
516 SDE_ERROR("invalid arguments\n");
517 return -EINVAL;
518 }
519
520 priv = plane->dev->dev_private;
521 if (!priv || !priv->kms) {
522 SDE_ERROR("invalid KMS reference\n");
523 return -EINVAL;
524 }
525
526 sde_kms = to_sde_kms(priv->kms);
527 psde = to_sde_plane(plane);
528
529 if (!psde->is_rt_pipe)
530 goto end;
531
532 sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
533
534 _sde_plane_set_qos_ctrl(plane, enable, SDE_PLANE_QOS_PANIC_CTRL);
535
536 sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
537
538end:
539 return 0;
540}
541
Alan Kwong5d324e42016-07-28 22:56:18 -0400542/**
543 * _sde_plane_set_ot_limit - set OT limit for the given plane
544 * @plane: Pointer to drm plane
545 * @crtc: Pointer to drm crtc
546 */
547static void _sde_plane_set_ot_limit(struct drm_plane *plane,
548 struct drm_crtc *crtc)
549{
550 struct sde_plane *psde;
551 struct sde_vbif_set_ot_params ot_params;
552 struct msm_drm_private *priv;
553 struct sde_kms *sde_kms;
554
555 if (!plane || !plane->dev || !crtc) {
556 SDE_ERROR("invalid arguments plane %d crtc %d\n",
557 plane != 0, crtc != 0);
558 return;
559 }
560
561 priv = plane->dev->dev_private;
562 if (!priv || !priv->kms) {
563 SDE_ERROR("invalid KMS reference\n");
564 return;
565 }
566
567 sde_kms = to_sde_kms(priv->kms);
568 psde = to_sde_plane(plane);
569 if (!psde->pipe_hw) {
570 SDE_ERROR("invalid pipe reference\n");
571 return;
572 }
573
574 memset(&ot_params, 0, sizeof(ot_params));
575 ot_params.xin_id = psde->pipe_hw->cap->xin_id;
576 ot_params.num = psde->pipe_hw->idx - SSPP_NONE;
577 ot_params.width = psde->pipe_cfg.src_rect.w;
578 ot_params.height = psde->pipe_cfg.src_rect.h;
579 ot_params.is_wfd = !psde->is_rt_pipe;
580 ot_params.frame_rate = crtc->mode.vrefresh;
581 ot_params.vbif_idx = VBIF_RT;
582 ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl;
583 ot_params.rd = true;
584
585 sde_vbif_set_ot_limit(sde_kms, &ot_params);
586}
587
Clarence Ipcae1bb62016-07-07 12:07:13 -0400588/* helper to update a state's input fence pointer from the property */
Clarence Ip13a8cf42016-09-29 17:27:47 -0400589static void _sde_plane_set_input_fence(struct sde_plane *psde,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400590 struct sde_plane_state *pstate, uint64_t fd)
591{
Clarence Ip13a8cf42016-09-29 17:27:47 -0400592 if (!psde || !pstate) {
593 SDE_ERROR("invalid arg(s), plane %d state %d\n",
594 psde != 0, pstate != 0);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400595 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -0400596 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400597
598 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400599 if (pstate->input_fence)
600 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400601
602 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400603 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400604
Clarence Ip13a8cf42016-09-29 17:27:47 -0400605 SDE_DEBUG_PLANE(psde, "0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400606}
607
Clarence Ipcae1bb62016-07-07 12:07:13 -0400608int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400609{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400610 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400611 struct sde_plane_state *pstate;
Clarence Ip78a04ed2016-10-04 15:57:45 -0400612 uint32_t prefix;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400613 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400614 int ret = -EINVAL;
Dhaval Patel39323d42017-03-01 23:48:24 -0800615 signed long rc;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400616
617 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700618 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400619 } else if (!plane->state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -0400620 SDE_ERROR_PLANE(to_sde_plane(plane), "invalid state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400621 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400622 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400623 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400624 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400625
Clarence Ipcae1bb62016-07-07 12:07:13 -0400626 if (input_fence) {
Dhaval Patel39323d42017-03-01 23:48:24 -0800627 psde->is_error = false;
Clarence Ip78a04ed2016-10-04 15:57:45 -0400628 prefix = sde_sync_get_name_prefix(input_fence);
Dhaval Patel39323d42017-03-01 23:48:24 -0800629 rc = sde_sync_wait(input_fence, wait_ms);
Clarence Ip78a04ed2016-10-04 15:57:45 -0400630
Dhaval Patel39323d42017-03-01 23:48:24 -0800631 switch (rc) {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400632 case 0:
Clarence Ip78a04ed2016-10-04 15:57:45 -0400633 SDE_ERROR_PLANE(psde, "%ums timeout on %08X\n",
634 wait_ms, prefix);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400635 psde->is_error = true;
Dhaval Patel39323d42017-03-01 23:48:24 -0800636 ret = -ETIMEDOUT;
637 break;
638 case -ERESTARTSYS:
639 SDE_ERROR_PLANE(psde,
640 "%ums wait interrupted on %08X\n",
641 wait_ms, prefix);
642 psde->is_error = true;
643 ret = -ERESTARTSYS;
644 break;
645 case -EINVAL:
646 SDE_ERROR_PLANE(psde,
647 "invalid fence param for %08X\n",
648 prefix);
649 psde->is_error = true;
650 ret = -EINVAL;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400651 break;
652 default:
Dhaval Patel39323d42017-03-01 23:48:24 -0800653 SDE_DEBUG_PLANE(psde, "signaled\n");
654 ret = 0;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400655 break;
656 }
Dhaval Patel6c666622017-03-21 23:02:59 -0700657
658 SDE_EVT32_VERBOSE(DRMID(plane), -ret, prefix);
Clarence Ipcb410d42016-06-26 22:52:33 -0400659 } else {
660 ret = 0;
661 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400662 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400663 return ret;
664}
665
Clarence Ip282dad62016-09-27 17:07:35 -0400666static inline void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400667 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400668 struct sde_hw_pipe_cfg *pipe_cfg,
669 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400670{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400671 struct sde_plane *psde;
Clarence Ip282dad62016-09-27 17:07:35 -0400672 int ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400673
Clarence Ip13a8cf42016-09-29 17:27:47 -0400674 if (!plane || !pstate || !pipe_cfg || !fb) {
675 SDE_ERROR(
676 "invalid arg(s), plane %d state %d cfg %d fb %d\n",
677 plane != 0, pstate != 0, pipe_cfg != 0, fb != 0);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400678 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -0400679 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400680
681 psde = to_sde_plane(plane);
Clarence Ipb6eb2362016-09-08 16:18:13 -0400682 if (!psde->pipe_hw) {
683 SDE_ERROR_PLANE(psde, "invalid pipe_hw\n");
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400684 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400685 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400686
Clarence Ipb6eb2362016-09-08 16:18:13 -0400687 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
688 if (ret == -EAGAIN)
689 SDE_DEBUG_PLANE(psde, "not updating same src addrs\n");
690 else if (ret)
691 SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret);
692 else if (psde->pipe_hw->ops.setup_sourceaddress)
Jeykumar Sankaran2e655032017-02-04 14:05:45 -0800693 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg,
694 pstate->multirect_index);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400695}
696
abeykun48f407a2016-08-25 12:06:44 -0400697static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde,
698 struct sde_plane_state *pstate)
699{
Clarence Ip3bf8d872017-02-16 15:25:38 -0500700 struct sde_hw_scaler3_cfg *cfg;
abeykun48f407a2016-08-25 12:06:44 -0400701 int ret = 0;
702
Clarence Ip3bf8d872017-02-16 15:25:38 -0500703 if (!psde || !psde->scaler3_cfg) {
704 SDE_ERROR("invalid args\n");
705 return -EINVAL;
706 } else if (!pstate) {
707 /* pstate is expected to be null on forced color fill */
708 SDE_DEBUG("null pstate\n");
709 return -EINVAL;
710 }
711
712 cfg = psde->scaler3_cfg;
713
abeykun48f407a2016-08-25 12:06:44 -0400714 cfg->dir_lut = msm_property_get_blob(
715 &psde->property_info,
716 pstate->property_blobs, &cfg->dir_len,
717 PLANE_PROP_SCALER_LUT_ED);
718 cfg->cir_lut = msm_property_get_blob(
719 &psde->property_info,
720 pstate->property_blobs, &cfg->cir_len,
721 PLANE_PROP_SCALER_LUT_CIR);
722 cfg->sep_lut = msm_property_get_blob(
723 &psde->property_info,
724 pstate->property_blobs, &cfg->sep_len,
725 PLANE_PROP_SCALER_LUT_SEP);
726 if (!cfg->dir_lut || !cfg->cir_lut || !cfg->sep_lut)
727 ret = -ENODATA;
728 return ret;
729}
730
Clarence Ipcb410d42016-06-26 22:52:33 -0400731static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400732 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
733 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400734 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400735 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
736{
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -0700737 uint32_t decimated, i;
738
739 if (!psde || !scale_cfg || !fmt || !chroma_subsmpl_h ||
740 !chroma_subsmpl_v) {
741 SDE_ERROR("psde %pK scale_cfg %pK fmt %pK smp_h %d smp_v %d\n"
742 , psde, scale_cfg, fmt, chroma_subsmpl_h,
743 chroma_subsmpl_v);
744 return;
745 }
746
747 memset(scale_cfg, 0, sizeof(*scale_cfg));
Clarence Ip716ab662017-03-20 06:51:24 -0700748 memset(&psde->pixel_ext, 0, sizeof(struct sde_hw_pixel_ext));
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -0700749
750 decimated = DECIMATED_DIMENSION(src_w,
751 psde->pipe_cfg.horz_decimation);
752 scale_cfg->phase_step_x[SDE_SSPP_COMP_0] =
753 mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_w);
754 decimated = DECIMATED_DIMENSION(src_h,
755 psde->pipe_cfg.vert_decimation);
756 scale_cfg->phase_step_y[SDE_SSPP_COMP_0] =
757 mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_h);
758
759
760 scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2] =
761 scale_cfg->phase_step_y[SDE_SSPP_COMP_0] / chroma_subsmpl_v;
762 scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2] =
763 scale_cfg->phase_step_x[SDE_SSPP_COMP_0] / chroma_subsmpl_h;
764
765 scale_cfg->phase_step_x[SDE_SSPP_COMP_2] =
766 scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2];
767 scale_cfg->phase_step_y[SDE_SSPP_COMP_2] =
768 scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2];
769
770 scale_cfg->phase_step_x[SDE_SSPP_COMP_3] =
771 scale_cfg->phase_step_x[SDE_SSPP_COMP_0];
772 scale_cfg->phase_step_y[SDE_SSPP_COMP_3] =
773 scale_cfg->phase_step_y[SDE_SSPP_COMP_0];
774
775 for (i = 0; i < SDE_MAX_PLANES; i++) {
776 scale_cfg->src_width[i] = DECIMATED_DIMENSION(src_w,
777 psde->pipe_cfg.horz_decimation);
778 scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h,
779 psde->pipe_cfg.vert_decimation);
Gopikrishnaiah Anandanf4c34292016-10-20 15:42:04 -0700780 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) {
781 scale_cfg->src_width[i] /= chroma_subsmpl_h;
782 scale_cfg->src_height[i] /= chroma_subsmpl_v;
783 }
784 scale_cfg->preload_x[i] = SDE_QSEED3_DEFAULT_PRELOAD_H;
785 scale_cfg->preload_y[i] = SDE_QSEED3_DEFAULT_PRELOAD_V;
786 psde->pixel_ext.num_ext_pxls_top[i] =
787 scale_cfg->src_height[i];
788 psde->pixel_ext.num_ext_pxls_left[i] =
789 scale_cfg->src_width[i];
790 }
791 if (!(SDE_FORMAT_IS_YUV(fmt)) && (src_h == dst_h)
792 && (src_w == dst_w))
793 return;
794
795 scale_cfg->dst_width = dst_w;
796 scale_cfg->dst_height = dst_h;
797 scale_cfg->y_rgb_filter_cfg = SDE_SCALE_BIL;
798 scale_cfg->uv_filter_cfg = SDE_SCALE_BIL;
799 scale_cfg->alpha_filter_cfg = SDE_SCALE_ALPHA_BIL;
800 scale_cfg->lut_flag = 0;
801 scale_cfg->blend_cfg = 1;
802 scale_cfg->enable = 1;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400803}
804
Clarence Ipcb410d42016-06-26 22:52:33 -0400805/**
Clarence Ip13a8cf42016-09-29 17:27:47 -0400806 * _sde_plane_setup_scaler2 - determine default scaler phase steps/filter type
Clarence Ipcb410d42016-06-26 22:52:33 -0400807 * @psde: Pointer to SDE plane object
808 * @src: Source size
809 * @dst: Destination size
810 * @phase_steps: Pointer to output array for phase steps
811 * @filter: Pointer to output array for filter type
812 * @fmt: Pointer to format definition
813 * @chroma_subsampling: Subsampling amount for chroma channel
814 *
815 * Returns: 0 on success
816 */
817static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400818 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400819 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400820 uint32_t chroma_subsampling)
821{
Clarence Ipcb410d42016-06-26 22:52:33 -0400822 if (!psde || !phase_steps || !filter || !fmt) {
Clarence Ip13a8cf42016-09-29 17:27:47 -0400823 SDE_ERROR(
824 "invalid arg(s), plane %d phase %d filter %d fmt %d\n",
825 psde != 0, phase_steps != 0, filter != 0, fmt != 0);
Clarence Ipcb410d42016-06-26 22:52:33 -0400826 return -EINVAL;
827 }
828
Clarence Ip4c1d9772016-06-26 09:35:38 -0400829 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400830 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400831 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400832 phase_steps[SDE_SSPP_COMP_1_2] =
833 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
834 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
835 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400836
837 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400838 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400839 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400840 (src <= dst) ? SDE_SCALE_FILTER_BIL :
841 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400842
Clarence Ipdbde9832016-06-26 09:48:36 -0400843 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400844 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400845 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
846 } else {
847 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
848 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400849 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400850 }
851 } else {
852 /* disable scaler */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400853 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
854 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
855 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400856 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400857 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400858}
859
Clarence Ipcb410d42016-06-26 22:52:33 -0400860/**
861 * _sde_plane_setup_pixel_ext - determine default pixel extension values
862 * @psde: Pointer to SDE plane object
863 * @src: Source size
864 * @dst: Destination size
865 * @decimated_src: Source size after decimation, if any
866 * @phase_steps: Pointer to output array for phase steps
867 * @out_src: Output array for pixel extension values
868 * @out_edge1: Output array for pixel extension first edge
869 * @out_edge2: Output array for pixel extension second edge
870 * @filter: Pointer to array for filter type
871 * @fmt: Pointer to format definition
872 * @chroma_subsampling: Subsampling amount for chroma channel
873 * @post_compare: Whether to chroma subsampled source size for comparisions
874 */
875static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400876 uint32_t src, uint32_t dst, uint32_t decimated_src,
877 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400878 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400879 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400880 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400881{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400882 int64_t edge1, edge2, caf;
883 uint32_t src_work;
884 int i, tmp;
885
Clarence Ipcb410d42016-06-26 22:52:33 -0400886 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400887 out_edge2 && filter && fmt) {
888 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400889 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400890 caf = PHASE_STEP_UNIT_SCALE;
891 else
892 caf = 0;
893
894 for (i = 0; i < SDE_MAX_PLANES; i++) {
895 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400896 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400897 src_work /= chroma_subsampling;
898 if (post_compare)
899 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400900 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400901 /* unity */
902 edge1 = 0;
903 edge2 = 0;
904 } else if (dst >= src) {
905 /* upscale */
906 edge1 = (1 << PHASE_RESIDUAL);
907 edge1 -= caf;
908 edge2 = (1 << PHASE_RESIDUAL);
909 edge2 += (dst - 1) * *(phase_steps + i);
910 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
911 edge2 += caf;
912 edge2 = -(edge2);
913 } else {
914 /* downscale */
915 edge1 = 0;
916 edge2 = (dst - 1) * *(phase_steps + i);
917 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
918 edge2 += *(phase_steps + i);
919 edge2 = -(edge2);
920 }
921
922 /* only enable CAF for luma plane */
923 caf = 0;
924
925 /* populate output arrays */
926 *(out_src + i) = src_work;
927
928 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400929 if (edge1 >= 0) {
930 tmp = (uint32_t)edge1;
931 tmp >>= PHASE_STEP_SHIFT;
932 *(out_edge1 + i) = -tmp;
933 } else {
934 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400935 *(out_edge1 + i) =
936 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
937 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400938 }
939 if (edge2 >= 0) {
940 tmp = (uint32_t)edge2;
941 tmp >>= PHASE_STEP_SHIFT;
942 *(out_edge2 + i) = -tmp;
943 } else {
944 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400945 *(out_edge2 + i) =
946 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
947 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400948 }
949 }
950 }
951}
952
Clarence Ip5fc00c52016-09-23 15:03:34 -0400953static inline void _sde_plane_setup_csc(struct sde_plane *psde)
Clarence Ipe78efb72016-06-24 18:35:21 -0400954{
955 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
956 {
Clarence Ip373f8592016-05-26 00:58:42 -0400957 /* S15.16 format */
958 0x00012A00, 0x00000000, 0x00019880,
959 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
960 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400961 },
Clarence Ip373f8592016-05-26 00:58:42 -0400962 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400963 { 0xfff0, 0xff80, 0xff80,},
964 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400965 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400966 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400967 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400968 };
abeykun1c312f62016-08-26 09:47:12 -0400969 static const struct sde_csc_cfg sde_csc10_YUV2RGB_601L = {
970 {
971 /* S15.16 format */
972 0x00012A00, 0x00000000, 0x00019880,
973 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
974 0x00012A00, 0x00020480, 0x00000000,
975 },
976 /* signed bias */
977 { 0xffc0, 0xfe00, 0xfe00,},
978 { 0x0, 0x0, 0x0,},
979 /* unsigned clamp */
980 { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,},
981 { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,},
982 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400983
Clarence Ip5fc00c52016-09-23 15:03:34 -0400984 if (!psde) {
985 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400986 return;
987 }
Clarence Ip5e2a9222016-06-26 22:38:24 -0400988
Clarence Ipcae1bb62016-07-07 12:07:13 -0400989 /* revert to kernel default if override not available */
Clarence Ip5fc00c52016-09-23 15:03:34 -0400990 if (psde->csc_usr_ptr)
991 psde->csc_ptr = psde->csc_usr_ptr;
abeykun1c312f62016-08-26 09:47:12 -0400992 else if (BIT(SDE_SSPP_CSC_10BIT) & psde->features)
993 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc10_YUV2RGB_601L;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400994 else
Clarence Ip373f8592016-05-26 00:58:42 -0400995 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ip5fc00c52016-09-23 15:03:34 -0400996
Clarence Ip13a8cf42016-09-29 17:27:47 -0400997 SDE_DEBUG_PLANE(psde, "using 0x%X 0x%X 0x%X...\n",
Clarence Ip5fc00c52016-09-23 15:03:34 -0400998 psde->csc_ptr->csc_mv[0],
999 psde->csc_ptr->csc_mv[1],
1000 psde->csc_ptr->csc_mv[2]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001001}
1002
Benet Clarkeb1b4462016-06-27 14:43:06 -07001003static void sde_color_process_plane_setup(struct drm_plane *plane)
1004{
1005 struct sde_plane *psde;
1006 struct sde_plane_state *pstate;
1007 uint32_t hue, saturation, value, contrast;
Benet Clarkd009b1d2016-06-27 14:45:59 -07001008 struct drm_msm_memcol *memcol = NULL;
1009 size_t memcol_sz = 0;
Benet Clarkeb1b4462016-06-27 14:43:06 -07001010
1011 psde = to_sde_plane(plane);
1012 pstate = to_sde_plane_state(plane->state);
1013
1014 hue = (uint32_t) sde_plane_get_property(pstate, PLANE_PROP_HUE_ADJUST);
1015 if (psde->pipe_hw->ops.setup_pa_hue)
1016 psde->pipe_hw->ops.setup_pa_hue(psde->pipe_hw, &hue);
1017 saturation = (uint32_t) sde_plane_get_property(pstate,
1018 PLANE_PROP_SATURATION_ADJUST);
1019 if (psde->pipe_hw->ops.setup_pa_sat)
1020 psde->pipe_hw->ops.setup_pa_sat(psde->pipe_hw, &saturation);
1021 value = (uint32_t) sde_plane_get_property(pstate,
1022 PLANE_PROP_VALUE_ADJUST);
1023 if (psde->pipe_hw->ops.setup_pa_val)
1024 psde->pipe_hw->ops.setup_pa_val(psde->pipe_hw, &value);
1025 contrast = (uint32_t) sde_plane_get_property(pstate,
1026 PLANE_PROP_CONTRAST_ADJUST);
1027 if (psde->pipe_hw->ops.setup_pa_cont)
1028 psde->pipe_hw->ops.setup_pa_cont(psde->pipe_hw, &contrast);
Benet Clarkeb1b4462016-06-27 14:43:06 -07001029
Benet Clarkd009b1d2016-06-27 14:45:59 -07001030 if (psde->pipe_hw->ops.setup_pa_memcolor) {
1031 /* Skin memory color setup */
1032 memcol = msm_property_get_blob(&psde->property_info,
1033 pstate->property_blobs,
1034 &memcol_sz,
1035 PLANE_PROP_SKIN_COLOR);
1036 psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
1037 MEMCOLOR_SKIN, memcol);
1038
1039 /* Sky memory color setup */
1040 memcol = msm_property_get_blob(&psde->property_info,
1041 pstate->property_blobs,
1042 &memcol_sz,
1043 PLANE_PROP_SKY_COLOR);
1044 psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
1045 MEMCOLOR_SKY, memcol);
1046
1047 /* Foliage memory color setup */
1048 memcol = msm_property_get_blob(&psde->property_info,
1049 pstate->property_blobs,
1050 &memcol_sz,
1051 PLANE_PROP_FOLIAGE_COLOR);
1052 psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw,
1053 MEMCOLOR_FOLIAGE, memcol);
1054 }
1055}
Benet Clarkeb1b4462016-06-27 14:43:06 -07001056
Clarence Ipcb410d42016-06-26 22:52:33 -04001057static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001058 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -04001059 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001060{
Clarence Ipb43d4592016-09-08 14:21:35 -04001061 struct sde_hw_pixel_ext *pe;
Clarence Ipcb410d42016-06-26 22:52:33 -04001062 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001063
Clarence Ipb43d4592016-09-08 14:21:35 -04001064 if (!psde || !fmt) {
1065 SDE_ERROR("invalid arg(s), plane %d fmt %d state %d\n",
1066 psde != 0, fmt != 0, pstate != 0);
Clarence Ipcb410d42016-06-26 22:52:33 -04001067 return;
Clarence Ipb43d4592016-09-08 14:21:35 -04001068 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001069
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001070 pe = &(psde->pixel_ext);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001071
Clarence Ipdedbba92016-09-27 17:43:10 -04001072 psde->pipe_cfg.horz_decimation =
1073 sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
1074 psde->pipe_cfg.vert_decimation =
1075 sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
Clarence Ip04ec67d2016-05-26 01:16:15 -04001076
1077 /* don't chroma subsample if decimating */
1078 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001079 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -04001080 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001081 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -04001082
Clarence Ip5e2a9222016-06-26 22:38:24 -04001083 /* update scaler */
1084 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
abeykun48f407a2016-08-25 12:06:44 -04001085 int error;
1086
1087 error = _sde_plane_setup_scaler3_lut(psde, pstate);
Clarence Ip716ab662017-03-20 06:51:24 -07001088 if (error || !psde->pixel_ext_usr ||
1089 psde->debugfs_default_scale) {
Clarence Ipb43d4592016-09-08 14:21:35 -04001090 /* calculate default config for QSEED3 */
Clarence Ipcb410d42016-06-26 22:52:33 -04001091 _sde_plane_setup_scaler3(psde,
1092 psde->pipe_cfg.src_rect.w,
1093 psde->pipe_cfg.src_rect.h,
1094 psde->pipe_cfg.dst_rect.w,
1095 psde->pipe_cfg.dst_rect.h,
abeykun48f407a2016-08-25 12:06:44 -04001096 psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001097 chroma_subsmpl_h, chroma_subsmpl_v);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001098 }
Clarence Ip716ab662017-03-20 06:51:24 -07001099 } else if (!psde->pixel_ext_usr || !pstate ||
1100 psde->debugfs_default_scale) {
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001101 uint32_t deci_dim, i;
1102
Clarence Ipb43d4592016-09-08 14:21:35 -04001103 /* calculate default configuration for QSEED2 */
1104 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001105
Clarence Ip13a8cf42016-09-29 17:27:47 -04001106 SDE_DEBUG_PLANE(psde, "default config\n");
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001107 deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
1108 psde->pipe_cfg.horz_decimation);
Clarence Ipb43d4592016-09-08 14:21:35 -04001109 _sde_plane_setup_scaler2(psde,
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001110 deci_dim,
Clarence Ipb43d4592016-09-08 14:21:35 -04001111 psde->pipe_cfg.dst_rect.w,
1112 pe->phase_step_x,
1113 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001114
Clarence Ipdbde9832016-06-26 09:48:36 -04001115 if (SDE_FORMAT_IS_YUV(fmt))
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001116 deci_dim &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -04001117 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001118 psde->pipe_cfg.dst_rect.w, deci_dim,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001119 pe->phase_step_x,
1120 pe->roi_w,
1121 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -04001122 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001123 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001124
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001125 deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001126 psde->pipe_cfg.vert_decimation);
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001127 _sde_plane_setup_scaler2(psde,
1128 deci_dim,
1129 psde->pipe_cfg.dst_rect.h,
1130 pe->phase_step_y,
1131 pe->vert_filter, fmt, chroma_subsmpl_v);
Clarence Ipcb410d42016-06-26 22:52:33 -04001132 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
Lloyd Atkinsoncd43ca62016-11-29 14:13:11 -05001133 psde->pipe_cfg.dst_rect.h, deci_dim,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001134 pe->phase_step_y,
1135 pe->roi_h,
1136 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -04001137 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001138 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001139
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001140 for (i = 0; i < SDE_MAX_PLANES; i++) {
1141 if (pe->num_ext_pxls_left[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001142 pe->left_rpt[i] = pe->num_ext_pxls_left[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001143 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001144 pe->left_ftch[i] = pe->num_ext_pxls_left[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001145
1146 if (pe->num_ext_pxls_right[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001147 pe->right_rpt[i] = pe->num_ext_pxls_right[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001148 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001149 pe->right_ftch[i] = pe->num_ext_pxls_right[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001150
1151 if (pe->num_ext_pxls_top[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001152 pe->top_rpt[i] = pe->num_ext_pxls_top[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001153 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001154 pe->top_ftch[i] = pe->num_ext_pxls_top[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001155
1156 if (pe->num_ext_pxls_btm[i] >= 0)
Clarence Ipb43d4592016-09-08 14:21:35 -04001157 pe->btm_rpt[i] = pe->num_ext_pxls_btm[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001158 else
Clarence Ipb43d4592016-09-08 14:21:35 -04001159 pe->btm_ftch[i] = pe->num_ext_pxls_btm[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001160 }
1161 }
Clarence Ipcb410d42016-06-26 22:52:33 -04001162}
1163
Clarence Ipcae1bb62016-07-07 12:07:13 -04001164/**
1165 * _sde_plane_color_fill - enables color fill on plane
Clarence Ip13a8cf42016-09-29 17:27:47 -04001166 * @psde: Pointer to SDE plane object
Clarence Ipcae1bb62016-07-07 12:07:13 -04001167 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
1168 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
1169 * Returns: 0 on success
1170 */
Clarence Ip13a8cf42016-09-29 17:27:47 -04001171static int _sde_plane_color_fill(struct sde_plane *psde,
Clarence Ipcb410d42016-06-26 22:52:33 -04001172 uint32_t color, uint32_t alpha)
1173{
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001174 const struct sde_format *fmt;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001175 const struct drm_plane *plane;
1176 const struct sde_plane_state *pstate;
Clarence Ipcb410d42016-06-26 22:52:33 -04001177
Clarence Ip13a8cf42016-09-29 17:27:47 -04001178 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001179 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001180 return -EINVAL;
1181 }
1182
Clarence Ipcb410d42016-06-26 22:52:33 -04001183 if (!psde->pipe_hw) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04001184 SDE_ERROR_PLANE(psde, "invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001185 return -EINVAL;
1186 }
1187
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001188 plane = &psde->base;
1189 pstate = to_sde_plane_state(plane->state);
1190
Clarence Ip13a8cf42016-09-29 17:27:47 -04001191 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipcae1bb62016-07-07 12:07:13 -04001192
Clarence Ipcb410d42016-06-26 22:52:33 -04001193 /*
1194 * select fill format to match user property expectation,
1195 * h/w only supports RGB variants
1196 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001197 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -04001198
1199 /* update sspp */
1200 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
1201 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001202 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24),
1203 pstate->multirect_index);
Clarence Ipcb410d42016-06-26 22:52:33 -04001204
1205 /* override scaler/decimation if solid fill */
1206 psde->pipe_cfg.src_rect.x = 0;
1207 psde->pipe_cfg.src_rect.y = 0;
1208 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
1209 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
Dhaval Patele4b6bb22017-03-27 17:22:21 -07001210 _sde_plane_setup_scaler(psde, fmt, 0);
Clarence Ipcb410d42016-06-26 22:52:33 -04001211
Clarence Ipcb410d42016-06-26 22:52:33 -04001212 if (psde->pipe_hw->ops.setup_format)
1213 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08001214 fmt, SDE_SSPP_SOLID_FILL,
1215 pstate->multirect_index);
Clarence Ipcb410d42016-06-26 22:52:33 -04001216
1217 if (psde->pipe_hw->ops.setup_rects)
1218 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
Jeykumar Sankaran9fcfa482017-02-16 16:03:14 -08001219 &psde->pipe_cfg,
1220 pstate->multirect_index);
1221
Jeykumar Sankaran9fcfa482017-02-16 16:03:14 -08001222 if (psde->pipe_hw->ops.setup_pe)
1223 psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
1224 &psde->pixel_ext);
Clarence Ipcb410d42016-06-26 22:52:33 -04001225 }
1226
1227 return 0;
1228}
1229
Alan Kwong4dd64c82017-02-04 18:41:51 -08001230/**
Alan Kwongcdb2f282017-03-18 13:42:06 -07001231 * _sde_plane_fb_get/put - framebuffer callback for crtc res ops
1232 */
1233static void *_sde_plane_fb_get(void *fb, u32 type, u64 tag)
1234{
1235 drm_framebuffer_reference(fb);
1236 return fb;
1237}
1238static void _sde_plane_fb_put(void *fb)
1239{
1240 drm_framebuffer_unreference(fb);
1241}
1242static struct sde_crtc_res_ops fb_res_ops = {
1243 .put = _sde_plane_fb_put,
1244 .get = _sde_plane_fb_get,
1245};
1246
1247/**
1248 * _sde_plane_fbo_get/put - framebuffer object callback for crtc res ops
1249 */
1250static void *_sde_plane_fbo_get(void *fbo, u32 type, u64 tag)
1251{
1252 sde_kms_fbo_reference(fbo);
1253 return fbo;
1254}
1255static void _sde_plane_fbo_put(void *fbo)
1256{
1257 sde_kms_fbo_unreference(fbo);
1258}
1259static struct sde_crtc_res_ops fbo_res_ops = {
1260 .put = _sde_plane_fbo_put,
1261 .get = _sde_plane_fbo_get,
1262};
1263
1264/**
Alan Kwong4aacd532017-02-04 18:51:33 -08001265 * sde_plane_rot_calc_prefill - calculate rotator start prefill
Alan Kwong4dd64c82017-02-04 18:41:51 -08001266 * @plane: Pointer to drm plane
1267 * return: prefill time in line
1268 */
1269static u32 sde_plane_rot_calc_prefill(struct drm_plane *plane)
1270{
1271 struct drm_plane_state *state;
1272 struct drm_crtc_state *cstate;
1273 struct sde_plane_state *pstate;
1274 struct sde_plane_rot_state *rstate;
1275 struct sde_kms *sde_kms;
1276 u32 blocksize = 128;
1277 u32 prefill_line = 0;
1278
1279 if (!plane || !plane->state || !plane->state->fb ||
1280 !plane->state->crtc || !plane->state->crtc->state) {
1281 SDE_ERROR("invalid parameters\n");
1282 return 0;
1283 }
1284
1285 sde_kms = _sde_plane_get_kms(plane);
1286 state = plane->state;
1287 cstate = state->crtc->state;
1288 pstate = to_sde_plane_state(state);
1289 rstate = &pstate->rot;
1290
1291 if (!rstate->rot_hw || !rstate->rot_hw->caps || !rstate->out_src_h ||
1292 !sde_kms || !sde_kms->catalog) {
1293 SDE_ERROR("invalid parameters\n");
1294 return 0;
1295 }
1296
Alan Kwong4aacd532017-02-04 18:51:33 -08001297 sde_format_get_block_size(rstate->out_fb_format, &blocksize,
1298 &blocksize);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001299 prefill_line = blocksize + sde_kms->catalog->sbuf_headroom;
1300
1301 SDE_DEBUG("plane%d prefill:%u\n", plane->base.id, prefill_line);
1302
1303 return prefill_line;
1304}
1305
1306/**
1307 * sde_plane_is_sbuf_mode - check if sspp of given plane is in streaming
1308 * buffer mode
1309 * @plane: Pointer to drm plane
1310 * @prefill: Pointer to prefill line count
1311 * return: true if sspp is in stream buffer mode
1312 */
1313bool sde_plane_is_sbuf_mode(struct drm_plane *plane, u32 *prefill)
1314{
1315 struct sde_plane_state *pstate = plane && plane->state ?
1316 to_sde_plane_state(plane->state) : NULL;
1317 struct sde_plane_rot_state *rstate = pstate ? &pstate->rot : NULL;
1318 bool sbuf_mode = rstate ? rstate->out_sbuf : false;
1319
1320 if (prefill && sbuf_mode)
1321 *prefill = sde_plane_rot_calc_prefill(plane);
1322
1323 return sbuf_mode;
1324}
1325
1326/**
1327 * sde_plane_rot_calc_cfg - calculate rotator/sspp configuration by
1328 * enumerating over all planes attached to the same rotator
1329 * @plane: Pointer to drm plane
1330 * @state: Pointer to drm state to be updated
1331 * return: none
1332 */
1333static void sde_plane_rot_calc_cfg(struct drm_plane *plane,
1334 struct drm_plane_state *state)
1335{
1336 struct sde_plane_state *pstate;
1337 struct sde_plane_rot_state *rstate;
1338 struct sde_hw_blk *hw_blk;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001339 struct drm_crtc_state *cstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001340 struct drm_rect *in_rot, *out_rot;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001341 struct drm_plane *attached_plane;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001342 u32 dst_x, dst_y, dst_w, dst_h;
1343 int found = 0;
1344 int xpos = 0;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001345 int ret;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001346
1347 if (!plane || !state || !state->state) {
1348 SDE_ERROR("invalid parameters\n");
1349 return;
1350 }
1351
Alan Kwongcdb2f282017-03-18 13:42:06 -07001352 cstate = _sde_plane_get_crtc_state(state);
1353 if (IS_ERR_OR_NULL(cstate)) {
1354 ret = PTR_ERR(cstate);
1355 SDE_ERROR("invalid crtc state %d\n", ret);
1356 return;
1357 }
1358
Alan Kwong4dd64c82017-02-04 18:41:51 -08001359 pstate = to_sde_plane_state(state);
1360 rstate = &pstate->rot;
1361
1362 if (!rstate->rot_hw) {
1363 SDE_ERROR("invalid rotator hw\n");
1364 return;
1365 }
1366
1367 in_rot = &rstate->in_rot_rect;
1368 in_rot->x1 = state->src_x;
1369 in_rot->y1 = state->src_y;
1370 in_rot->x2 = state->src_x + state->src_w;
1371 in_rot->y2 = state->src_y + state->src_h;
1372
1373 out_rot = &rstate->out_rot_rect;
1374 dst_x = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_X);
1375 dst_y = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_Y);
1376 dst_w = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_W);
1377 dst_h = sde_plane_get_property(pstate, PLANE_PROP_ROT_DST_H);
1378
1379 if (!dst_w && !dst_h) {
1380 rstate->out_rot_rect = rstate->in_rot_rect;
1381 drm_rect_rotate(&rstate->out_rot_rect, state->fb->width << 16,
1382 state->fb->height << 16, rstate->in_rotation);
1383 } else {
1384 out_rot->x1 = dst_x;
1385 out_rot->y1 = dst_y;
1386 out_rot->x2 = dst_x + dst_w;
1387 out_rot->y2 = dst_y + dst_h;
1388 }
1389
1390 rstate->out_src_rect = rstate->out_rot_rect;
1391
1392 hw_blk = &rstate->rot_hw->base;
1393
1394 /* enumerating over all planes attached to the same rotator */
Alan Kwongcdb2f282017-03-18 13:42:06 -07001395 drm_atomic_crtc_state_for_each_plane(attached_plane, cstate) {
Alan Kwong4dd64c82017-02-04 18:41:51 -08001396 struct drm_plane_state *attached_state;
1397 struct sde_plane_state *attached_pstate;
1398 struct sde_plane_rot_state *attached_rstate;
1399 struct drm_rect attached_out_rect;
1400
Alan Kwong4dd64c82017-02-04 18:41:51 -08001401 attached_state = drm_atomic_get_existing_plane_state(
1402 state->state, attached_plane);
1403
1404 if (!attached_state)
1405 continue;
1406
1407 attached_pstate = to_sde_plane_state(attached_state);
1408 attached_rstate = &attached_pstate->rot;
1409
Alan Kwongcdb2f282017-03-18 13:42:06 -07001410 if (attached_rstate->rot_hw != rstate->rot_hw)
1411 continue;
1412
1413 found++;
1414
1415 /* skip itself */
1416 if (attached_plane == plane)
1417 continue;
1418
Alan Kwong4dd64c82017-02-04 18:41:51 -08001419 /* find bounding rotator source roi */
1420 if (attached_state->src_x < in_rot->x1)
1421 in_rot->x1 = attached_state->src_x;
1422
1423 if (attached_state->src_y < in_rot->y1)
1424 in_rot->y1 = attached_state->src_y;
1425
1426 if (attached_state->src_x + attached_state->src_w > in_rot->x2)
1427 in_rot->x2 = attached_state->src_x +
1428 attached_state->src_w;
1429
1430 if (attached_state->src_y + attached_state->src_h > in_rot->y2)
1431 in_rot->y2 = attached_state->src_y +
1432 attached_state->src_h;
1433
1434 /* find bounding rotator destination roi */
1435 dst_x = sde_plane_get_property(attached_pstate,
1436 PLANE_PROP_ROT_DST_X);
1437 dst_y = sde_plane_get_property(attached_pstate,
1438 PLANE_PROP_ROT_DST_Y);
1439 dst_w = sde_plane_get_property(attached_pstate,
1440 PLANE_PROP_ROT_DST_W);
1441 dst_h = sde_plane_get_property(attached_pstate,
1442 PLANE_PROP_ROT_DST_H);
1443 if (!dst_w && !dst_h) {
1444 attached_out_rect.x1 = attached_state->src_x;
1445 attached_out_rect.y1 = attached_state->src_y;
1446 attached_out_rect.x2 = attached_out_rect.x1 +
1447 attached_state->src_w;
1448 attached_out_rect.y2 = attached_out_rect.y1 +
1449 attached_state->src_h;
1450 drm_rect_rotate(&attached_out_rect,
1451 state->fb->width << 16,
1452 state->fb->height << 16,
1453 rstate->in_rotation);
1454 } else {
1455 attached_out_rect.x1 = dst_x;
1456 attached_out_rect.y1 = dst_y;
1457 attached_out_rect.x2 = dst_x + dst_w;
1458 attached_out_rect.y2 = dst_y + dst_h;
1459 }
1460
1461 /* find relative sspp position */
1462 if (attached_out_rect.x1 < rstate->out_src_rect.x1)
1463 xpos++;
1464
1465 if (attached_out_rect.x1 < out_rot->x1)
1466 out_rot->x1 = attached_out_rect.x1;
1467
1468 if (attached_out_rect.y1 < out_rot->y1)
1469 out_rot->y1 = attached_out_rect.y1;
1470
1471 if (attached_out_rect.x2 > out_rot->x2)
1472 out_rot->x2 = attached_out_rect.x2;
1473
1474 if (attached_out_rect.y2 > out_rot->y2)
1475 out_rot->y2 = attached_out_rect.y2;
1476
1477 SDE_DEBUG("plane%d.%u src_x:%d sspp:%dx%d+%d+%d/%dx%d+%d+%d\n",
1478 attached_plane->base.id,
1479 attached_rstate->sequence_id,
1480 attached_rstate->out_src_rect.x1 >> 16,
1481 attached_state->src_w >> 16,
1482 attached_state->src_h >> 16,
1483 attached_state->src_x >> 16,
1484 attached_state->src_y >> 16,
1485 drm_rect_width(&attached_rstate->out_src_rect) >> 16,
1486 drm_rect_height(&attached_rstate->out_src_rect) >> 16,
1487 attached_rstate->out_src_rect.x1 >> 16,
1488 attached_rstate->out_src_rect.y1 >> 16);
1489 }
1490
1491 rstate->out_xpos = xpos;
1492 rstate->nplane = found;
1493
1494 SDE_DEBUG("plane%d.%u xpos:%d/%d rot:%dx%d+%d+%d/%dx%d+%d+%d\n",
1495 plane->base.id, rstate->sequence_id,
1496 rstate->out_xpos, rstate->nplane,
1497 drm_rect_width(in_rot) >> 16,
1498 drm_rect_height(in_rot) >> 16,
1499 in_rot->x1 >> 16, in_rot->y1 >> 16,
1500 drm_rect_width(&rstate->out_rot_rect) >> 16,
1501 drm_rect_height(&rstate->out_rot_rect) >> 16,
1502 rstate->out_rot_rect.x1 >> 16,
1503 rstate->out_rot_rect.y1 >> 16);
1504}
1505
1506/**
1507 * sde_plane_rot_submit_command - commit given state for the rotator stage
1508 * @plane: Pointer to drm plane
1509 * @state: Pointer to the state to be committed
1510 * @hw_cmd: rotator command type
1511 * return: 0 if success; error code otherwise
1512 */
1513static int sde_plane_rot_submit_command(struct drm_plane *plane,
1514 struct drm_plane_state *state, enum sde_hw_rot_cmd_type hw_cmd)
1515{
1516 struct sde_plane *psde = to_sde_plane(plane);
1517 struct sde_plane_state *pstate = to_sde_plane_state(state);
1518 struct sde_plane_rot_state *rstate = &pstate->rot;
1519 struct sde_hw_rot_cmd *rot_cmd;
Alan Kwong4aacd532017-02-04 18:51:33 -08001520 struct drm_crtc_state *cstate;
1521 struct sde_crtc_state *sde_cstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001522 int ret, i;
1523
1524 if (!plane || !state || !state->fb || !rstate->rot_hw) {
1525 SDE_ERROR("invalid parameters\n");
1526 return -EINVAL;
1527 }
1528
Alan Kwong4aacd532017-02-04 18:51:33 -08001529 cstate = _sde_plane_get_crtc_state(state);
1530 if (IS_ERR_OR_NULL(cstate)) {
1531 SDE_ERROR("invalid crtc state %ld\n", PTR_ERR(cstate));
1532 return -EINVAL;
1533 }
1534 sde_cstate = to_sde_crtc_state(cstate);
1535
Alan Kwong4dd64c82017-02-04 18:41:51 -08001536 rot_cmd = &rstate->rot_cmd;
1537
1538 rot_cmd->master = (rstate->out_xpos == 0);
1539 rot_cmd->sequence_id = rstate->sequence_id;
1540 rot_cmd->fps = pstate->base.crtc && pstate->base.crtc->state ?
1541 drm_mode_vrefresh(&pstate->base.crtc->state->adjusted_mode) :
1542 DEFAULT_REFRESH_RATE;
1543 rot_cmd->rot90 = rstate->rot90;
1544 rot_cmd->hflip = rstate->hflip;
1545 rot_cmd->vflip = rstate->vflip;
1546 rot_cmd->secure = state->fb->flags & DRM_MODE_FB_SECURE ? true : false;
Alan Kwong4aacd532017-02-04 18:51:33 -08001547 rot_cmd->prefill_bw = sde_crtc_get_property(sde_cstate,
1548 CRTC_PROP_ROT_PREFILL_BW);
Alan Kwong8c176bf2017-02-09 19:34:32 -08001549 rot_cmd->clkrate = sde_crtc_get_property(sde_cstate,
1550 CRTC_PROP_ROT_CLK);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001551 rot_cmd->dst_writeback = psde->sbuf_writeback;
1552
1553 if (sde_crtc_get_intf_mode(state->crtc) == INTF_MODE_VIDEO)
1554 rot_cmd->video_mode = true;
1555 else
1556 rot_cmd->video_mode = false;
1557
1558 rot_cmd->src_pixel_format = state->fb->pixel_format;
1559 rot_cmd->src_modifier = state->fb->modifier[0];
1560 rot_cmd->src_stride = state->fb->pitches[0];
1561
1562 rot_cmd->src_format = to_sde_format(msm_framebuffer_format(state->fb));
1563 if (!rot_cmd->src_format) {
1564 SDE_ERROR("failed to get src format\n");
1565 return -EINVAL;
1566 }
1567
1568 rot_cmd->src_width = state->fb->width;
1569 rot_cmd->src_height = state->fb->height;
1570 rot_cmd->src_rect_x = rstate->in_rot_rect.x1 >> 16;
1571 rot_cmd->src_rect_y = rstate->in_rot_rect.y1 >> 16;
1572 rot_cmd->src_rect_w = drm_rect_width(&rstate->in_rot_rect) >> 16;
1573 rot_cmd->src_rect_h = drm_rect_height(&rstate->in_rot_rect) >> 16;
1574 rot_cmd->dst_rect_x = rstate->out_rot_rect.x1 >> 16;
1575 rot_cmd->dst_rect_y = rstate->out_rot_rect.y1 >> 16;
1576 rot_cmd->dst_rect_w = drm_rect_width(&rstate->out_rot_rect) >> 16;
1577 rot_cmd->dst_rect_h = drm_rect_height(&rstate->out_rot_rect) >> 16;
1578
1579 if (hw_cmd == SDE_HW_ROT_CMD_COMMIT) {
1580 struct sde_hw_fmt_layout layout;
1581
1582 memset(&layout, 0, sizeof(struct sde_hw_fmt_layout));
1583 sde_format_populate_layout(rstate->mmu_id, state->fb,
1584 &layout);
1585 for (i = 0; i < ARRAY_SIZE(rot_cmd->src_iova); i++) {
1586 rot_cmd->src_iova[i] = layout.plane_addr[i];
1587 rot_cmd->src_len[i] = layout.plane_size[i];
1588 }
1589 rot_cmd->src_planes = layout.num_planes;
1590
1591 memset(&layout, 0, sizeof(struct sde_hw_fmt_layout));
1592 sde_format_populate_layout(rstate->mmu_id, rstate->out_fb,
1593 &layout);
1594 for (i = 0; i < ARRAY_SIZE(rot_cmd->dst_iova); i++) {
1595 rot_cmd->dst_iova[i] = layout.plane_addr[i];
1596 rot_cmd->dst_len[i] = layout.plane_size[i];
1597 }
1598 rot_cmd->dst_planes = layout.num_planes;
1599 }
1600
1601 ret = rstate->rot_hw->ops.commit(rstate->rot_hw, rot_cmd, hw_cmd);
1602 if (ret) {
1603 SDE_ERROR("failed to commit rotator %d\n", ret);
1604 return ret;
1605 }
1606
1607 rstate->out_rotation = rstate->in_rotation;
1608 rstate->out_fb_flags = rot_cmd->dst_modifier ?
1609 DRM_MODE_FB_MODIFIERS : 0;
1610 rstate->out_fb_flags |= rot_cmd->secure ? DRM_MODE_FB_SECURE : 0;
1611 rstate->out_fb_format = rot_cmd->dst_format;
1612 rstate->out_fb_pixel_format = rot_cmd->dst_pixel_format;
1613
1614 for (i = 0; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
1615 rstate->out_fb_modifier[i] = rot_cmd->dst_modifier;
1616
1617 rstate->out_fb_width = drm_rect_width(&rstate->out_rot_rect) >> 16;
1618 rstate->out_fb_height = drm_rect_height(&rstate->out_rot_rect) >> 16;
1619 rstate->out_src_x = rstate->out_src_rect.x1 - rstate->out_rot_rect.x1;
1620 rstate->out_src_y = rstate->out_src_rect.y1 - rstate->out_rot_rect.y1;
1621 rstate->out_src_w = drm_rect_width(&rstate->out_src_rect);
1622 rstate->out_src_h = drm_rect_height(&rstate->out_src_rect);
1623
1624 if (rot_cmd->rot90)
1625 rstate->out_rotation &= ~DRM_ROTATE_90;
1626
1627 if (rot_cmd->hflip)
1628 rstate->out_rotation &= ~DRM_REFLECT_X;
1629
1630 if (rot_cmd->vflip)
1631 rstate->out_rotation &= ~DRM_REFLECT_Y;
1632
1633 SDE_DEBUG(
Dhaval Patel6c666622017-03-21 23:02:59 -07001634 "plane%d.%d rot:%d/%c%c%c%c/%dx%d/%4.4s/%llx/%dx%d+%d+%d\n",
Alan Kwong4dd64c82017-02-04 18:41:51 -08001635 plane->base.id, rstate->sequence_id, hw_cmd,
1636 rot_cmd->rot90 ? 'r' : '_',
1637 rot_cmd->hflip ? 'h' : '_',
1638 rot_cmd->vflip ? 'v' : '_',
1639 rot_cmd->video_mode ? 'V' : 'C',
1640 state->fb->width, state->fb->height,
Dhaval Patel6c666622017-03-21 23:02:59 -07001641 (char *) &state->fb->pixel_format,
Alan Kwong4dd64c82017-02-04 18:41:51 -08001642 state->fb->modifier[0],
1643 drm_rect_width(&rstate->in_rot_rect) >> 16,
1644 drm_rect_height(&rstate->in_rot_rect) >> 16,
1645 rstate->in_rot_rect.x1 >> 16,
1646 rstate->in_rot_rect.y1 >> 16);
1647
Dhaval Patel6c666622017-03-21 23:02:59 -07001648 SDE_DEBUG("plane%d.%d sspp:%d/%x/%dx%d/%4.4s/%llx/%dx%d+%d+%d\n",
Alan Kwong4dd64c82017-02-04 18:41:51 -08001649 plane->base.id, rstate->sequence_id, hw_cmd,
1650 rstate->out_rotation,
1651 rstate->out_fb_width, rstate->out_fb_height,
Dhaval Patel6c666622017-03-21 23:02:59 -07001652 (char *) &rstate->out_fb_pixel_format,
Alan Kwong4dd64c82017-02-04 18:41:51 -08001653 rstate->out_fb_modifier[0],
1654 rstate->out_src_w >> 16, rstate->out_src_h >> 16,
1655 rstate->out_src_x >> 16, rstate->out_src_y >> 16);
1656
1657 return ret;
1658}
1659
1660/**
1661 * sde_plane_rot_prepare_fb - prepare framebuffer of the new state
1662 * for rotator (pre-sspp) stage
1663 * @plane: Pointer to drm plane
1664 * @new_state: Pointer to new drm plane state
1665 * return: 0 if success; error code otherwise
1666 */
1667static int sde_plane_rot_prepare_fb(struct drm_plane *plane,
1668 struct drm_plane_state *new_state)
1669{
1670 struct drm_framebuffer *fb = new_state->fb;
1671 struct sde_plane_state *new_pstate = to_sde_plane_state(new_state);
1672 struct sde_plane_rot_state *new_rstate = &new_pstate->rot;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001673 struct drm_crtc_state *cstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001674 int ret;
1675
1676 SDE_DEBUG("plane%d.%d FB[%u] sbuf:%d rot:%d crtc:%d\n",
1677 plane->base.id,
1678 new_rstate->sequence_id, fb ? fb->base.id : 0,
1679 !!new_rstate->out_sbuf, !!new_rstate->rot_hw,
1680 sde_plane_crtc_enabled(new_state));
1681
1682 if (!new_rstate->out_sbuf || !new_rstate->rot_hw)
1683 return 0;
1684
Alan Kwongcdb2f282017-03-18 13:42:06 -07001685 cstate = _sde_plane_get_crtc_state(new_state);
1686 if (IS_ERR(cstate)) {
1687 ret = PTR_ERR(cstate);
1688 SDE_ERROR("invalid crtc state %d\n", ret);
1689 return ret;
1690 }
1691
Alan Kwong4dd64c82017-02-04 18:41:51 -08001692 /* need to re-calc based on all newly validated plane states */
1693 sde_plane_rot_calc_cfg(plane, new_state);
1694
1695 /* check if stream buffer is already attached to rotator */
1696 if (sde_plane_enabled(new_state)) {
1697 struct sde_kms_fbo *fbo;
1698 struct drm_framebuffer *fb;
1699
Alan Kwongcdb2f282017-03-18 13:42:06 -07001700 fbo = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
1701 (u64) &new_rstate->rot_hw->base);
1702 fb = sde_crtc_res_get(cstate, SDE_CRTC_RES_ROT_OUT_FB,
1703 (u64) &new_rstate->rot_hw->base);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001704 if (fb && fbo) {
1705 SDE_DEBUG("plane%d.%d get fb/fbo\n", plane->base.id,
1706 new_rstate->sequence_id);
Alan Kwongcdb2f282017-03-18 13:42:06 -07001707 } else if (fbo) {
1708 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
1709 (u64) &new_rstate->rot_hw->base);
1710 fbo = NULL;
1711 } else if (fb) {
1712 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
1713 (u64) &new_rstate->rot_hw->base);
1714 fb = NULL;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001715 }
Alan Kwongcdb2f282017-03-18 13:42:06 -07001716
1717 new_rstate->out_fbo = fbo;
1718 new_rstate->out_fb = fb;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001719 }
1720
1721 /* release buffer if output format configuration changes */
1722 if (new_rstate->out_fb &&
1723 ((new_rstate->out_fb_height != new_rstate->out_fb->height) ||
1724 (new_rstate->out_fb_width != new_rstate->out_fb->width) ||
1725 (new_rstate->out_fb_pixel_format !=
1726 new_rstate->out_fb->pixel_format) ||
1727 (new_rstate->out_fb_modifier[0] !=
1728 new_rstate->out_fb->modifier[0]) ||
1729 (new_rstate->out_fb_flags != new_rstate->out_fb->flags))) {
1730
1731 SDE_DEBUG("plane%d.%d release fb/fbo\n", plane->base.id,
1732 new_rstate->sequence_id);
1733
Alan Kwongcdb2f282017-03-18 13:42:06 -07001734 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
1735 (u64) &new_rstate->rot_hw->base);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001736 new_rstate->out_fb = NULL;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001737 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
1738 (u64) &new_rstate->rot_hw->base);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001739 new_rstate->out_fbo = NULL;
1740 }
1741
1742 /* create new stream buffer if it is not available */
1743 if (sde_plane_enabled(new_state) && !new_rstate->out_fb) {
1744 u32 fb_w = drm_rect_width(&new_rstate->out_rot_rect) >> 16;
1745 u32 fb_h = drm_rect_height(&new_rstate->out_rot_rect) >> 16;
1746
1747 SDE_DEBUG("plane%d.%d allocate fb/fbo\n", plane->base.id,
1748 new_rstate->sequence_id);
1749
1750 if (new_state->fb->flags & DRM_MODE_FB_SECURE)
1751 new_rstate->mmu_id = MSM_SMMU_DOMAIN_SECURE;
1752 else
1753 new_rstate->mmu_id = MSM_SMMU_DOMAIN_UNSECURE;
1754
1755 /* check if out_fb is already attached to rotator */
1756 new_rstate->out_fbo = sde_kms_fbo_alloc(plane->dev, fb_w, fb_h,
1757 new_rstate->out_fb_pixel_format,
1758 new_rstate->out_fb_modifier,
1759 new_rstate->out_fb_flags);
1760 if (!new_rstate->out_fbo) {
1761 SDE_ERROR("failed to allocate inline buffer object\n");
1762 ret = -EINVAL;
1763 goto error_create_fbo;
1764 }
1765
Alan Kwongcdb2f282017-03-18 13:42:06 -07001766 ret = sde_crtc_res_add(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
1767 (u64) &new_rstate->rot_hw->base,
1768 new_rstate->out_fbo, &fbo_res_ops);
1769 if (ret) {
1770 SDE_ERROR("failed to add crtc resource\n");
1771 goto error_create_fbo_res;
1772 }
Alan Kwong4dd64c82017-02-04 18:41:51 -08001773
1774 new_rstate->out_fb = sde_kms_fbo_create_fb(plane->dev,
1775 new_rstate->out_fbo);
1776 if (!new_rstate->out_fb) {
1777 SDE_ERROR("failed to create inline framebuffer\n");
1778 ret = -EINVAL;
1779 goto error_create_fb;
1780 }
1781
Alan Kwongcdb2f282017-03-18 13:42:06 -07001782 ret = sde_crtc_res_add(cstate, SDE_CRTC_RES_ROT_OUT_FB,
1783 (u64) &new_rstate->rot_hw->base,
1784 new_rstate->out_fb, &fb_res_ops);
1785 if (ret) {
1786 SDE_ERROR("failed to add crtc resource %d\n", ret);
1787 goto error_create_fb_res;
1788 }
Alan Kwong4dd64c82017-02-04 18:41:51 -08001789 }
1790
1791 /* prepare rotator input buffer */
1792 ret = msm_framebuffer_prepare(new_state->fb, new_rstate->mmu_id);
1793 if (ret) {
1794 SDE_ERROR("failed to prepare input framebuffer\n");
1795 goto error_prepare_input_buffer;
1796 }
1797
1798 /* prepare rotator output buffer */
1799 if (sde_plane_enabled(new_state) && new_rstate->out_fb) {
1800 SDE_DEBUG("plane%d.%d prepare fb/fbo\n", plane->base.id,
1801 new_rstate->sequence_id);
1802
1803 ret = msm_framebuffer_prepare(new_rstate->out_fb,
1804 new_rstate->mmu_id);
1805 if (ret) {
1806 SDE_ERROR("failed to prepare inline framebuffer\n");
1807 goto error_prepare_output_buffer;
1808 }
1809 }
1810
1811 return 0;
1812
1813error_prepare_output_buffer:
1814 msm_framebuffer_cleanup(new_state->fb, new_rstate->mmu_id);
1815error_prepare_input_buffer:
Alan Kwongcdb2f282017-03-18 13:42:06 -07001816 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
1817 (u64) &new_rstate->rot_hw->base);
1818error_create_fb_res:
Alan Kwong4dd64c82017-02-04 18:41:51 -08001819 new_rstate->out_fb = NULL;
1820error_create_fb:
Alan Kwongcdb2f282017-03-18 13:42:06 -07001821 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
1822 (u64) &new_rstate->rot_hw->base);
1823error_create_fbo_res:
Alan Kwong4dd64c82017-02-04 18:41:51 -08001824 new_rstate->out_fbo = NULL;
1825error_create_fbo:
1826 return ret;
1827}
1828
1829/**
1830 * sde_plane_rot_cleanup_fb - cleanup framebuffer of previous state for the
1831 * rotator (pre-sspp) stage
1832 * @plane: Pointer to drm plane
1833 * @old_state: Pointer to previous drm plane state
1834 * return: none
1835 */
1836static void sde_plane_rot_cleanup_fb(struct drm_plane *plane,
1837 struct drm_plane_state *old_state)
1838{
1839 struct sde_plane_state *old_pstate = to_sde_plane_state(old_state);
1840 struct sde_plane_rot_state *old_rstate = &old_pstate->rot;
1841 struct sde_hw_rot_cmd *cmd = &old_rstate->rot_cmd;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001842 struct drm_crtc_state *cstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001843 int ret;
1844
1845 SDE_DEBUG("plane%d.%d FB[%u] sbuf:%d rot:%d crtc:%d\n", plane->base.id,
1846 old_rstate->sequence_id, old_state->fb->base.id,
1847 !!old_rstate->out_sbuf, !!old_rstate->rot_hw,
1848 sde_plane_crtc_enabled(old_state));
1849
1850 if (!old_rstate->out_sbuf || !old_rstate->rot_hw)
1851 return;
1852
Alan Kwongcdb2f282017-03-18 13:42:06 -07001853 cstate = _sde_plane_get_crtc_state(old_state);
1854 if (IS_ERR(cstate)) {
1855 ret = PTR_ERR(cstate);
1856 SDE_ERROR("invalid crtc state %d\n", ret);
1857 return;
1858 }
1859
Alan Kwong4dd64c82017-02-04 18:41:51 -08001860 if (sde_plane_crtc_enabled(old_state)) {
1861 ret = old_rstate->rot_hw->ops.commit(old_rstate->rot_hw, cmd,
1862 SDE_HW_ROT_CMD_CLEANUP);
1863 if (ret)
1864 SDE_ERROR("failed to cleanup rotator buffers\n");
1865 }
1866
1867 if (sde_plane_enabled(old_state)) {
1868 if (old_rstate->out_fb) {
1869 msm_framebuffer_cleanup(old_rstate->out_fb,
1870 old_rstate->mmu_id);
Alan Kwongcdb2f282017-03-18 13:42:06 -07001871 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FB,
1872 (u64) &old_rstate->rot_hw->base);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001873 old_rstate->out_fb = NULL;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001874 sde_crtc_res_put(cstate, SDE_CRTC_RES_ROT_OUT_FBO,
1875 (u64) &old_rstate->rot_hw->base);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001876 old_rstate->out_fbo = NULL;
1877 }
1878
1879 msm_framebuffer_cleanup(old_state->fb, old_rstate->mmu_id);
1880 }
1881}
1882
1883/**
1884 * sde_plane_rot_atomic_check - verify rotator update of the given state
1885 * @plane: Pointer to drm plane
1886 * @state: Pointer to drm plane state to be validated
1887 * return: 0 if success; error code otherwise
1888 */
1889static int sde_plane_rot_atomic_check(struct drm_plane *plane,
1890 struct drm_plane_state *state)
1891{
1892 struct sde_plane *psde;
1893 struct sde_plane_state *pstate, *old_pstate;
1894 struct sde_plane_rot_state *rstate, *old_rstate;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001895 struct drm_crtc_state *cstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001896 struct sde_hw_blk *hw_blk;
1897 int i, ret = 0;
1898
1899 if (!plane || !state) {
1900 SDE_ERROR("invalid plane/state\n");
1901 return -EINVAL;
1902 }
1903
1904 psde = to_sde_plane(plane);
1905 pstate = to_sde_plane_state(state);
1906 old_pstate = to_sde_plane_state(plane->state);
1907 rstate = &pstate->rot;
1908 old_rstate = &old_pstate->rot;
1909
Alan Kwongcdb2f282017-03-18 13:42:06 -07001910 /* cstate will be null if crtc is disconnected from plane */
1911 cstate = _sde_plane_get_crtc_state(state);
1912 if (IS_ERR(cstate)) {
1913 ret = PTR_ERR(cstate);
1914 SDE_ERROR("invalid crtc state %d\n", ret);
1915 return ret;
1916 }
1917
Alan Kwong4dd64c82017-02-04 18:41:51 -08001918 SDE_DEBUG("plane%d.%d FB[%u] sbuf:%d rot:%d crtc:%d\n", plane->base.id,
1919 rstate->sequence_id, state->fb ? state->fb->base.id : 0,
1920 !!rstate->out_sbuf, !!rstate->rot_hw,
1921 sde_plane_crtc_enabled(state));
1922
1923 rstate->in_rotation = drm_rotation_simplify(
1924 sde_plane_get_property(pstate, PLANE_PROP_ROTATION),
Alan Kwong709150c2017-04-03 08:44:31 -07001925 DRM_ROTATE_0 | DRM_ROTATE_90 |
1926 DRM_REFLECT_X | DRM_REFLECT_Y);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001927 rstate->rot90 = rstate->in_rotation & DRM_ROTATE_90 ? true : false;
1928 rstate->hflip = rstate->in_rotation & DRM_REFLECT_X ? true : false;
1929 rstate->vflip = rstate->in_rotation & DRM_REFLECT_Y ? true : false;
1930 rstate->out_sbuf = psde->sbuf_mode || rstate->rot90;
1931
Alan Kwongcdb2f282017-03-18 13:42:06 -07001932 if (sde_plane_enabled(state) && rstate->out_sbuf) {
1933 SDE_DEBUG("plane%d.%d acquire rotator\n",
Alan Kwong4dd64c82017-02-04 18:41:51 -08001934 plane->base.id, rstate->sequence_id);
1935
Alan Kwongcdb2f282017-03-18 13:42:06 -07001936 hw_blk = sde_crtc_res_get(cstate, SDE_HW_BLK_ROT,
1937 (u64) state->fb);
1938 if (!hw_blk) {
Alan Kwong4dd64c82017-02-04 18:41:51 -08001939 SDE_ERROR("plane%d no available rotator\n",
1940 plane->base.id);
1941 return -EINVAL;
1942 }
1943
Alan Kwongcdb2f282017-03-18 13:42:06 -07001944 rstate->rot_hw = to_sde_hw_rot(hw_blk);
1945
Alan Kwong4dd64c82017-02-04 18:41:51 -08001946 if (!rstate->rot_hw->ops.commit) {
1947 SDE_ERROR("plane%d invalid rotator ops\n",
1948 plane->base.id);
Alan Kwongcdb2f282017-03-18 13:42:06 -07001949 sde_crtc_res_put(cstate,
1950 SDE_HW_BLK_ROT, (u64) state->fb);
Alan Kwong4dd64c82017-02-04 18:41:51 -08001951 rstate->rot_hw = NULL;
1952 return -EINVAL;
1953 }
1954
1955 rstate->in_fb = state->fb;
Alan Kwongcdb2f282017-03-18 13:42:06 -07001956 } else {
1957 rstate->in_fb = NULL;
1958 rstate->rot_hw = NULL;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001959 }
1960
1961 if (sde_plane_enabled(state) && rstate->out_sbuf && rstate->rot_hw) {
1962
1963 SDE_DEBUG("plane%d.%d use rotator\n",
1964 plane->base.id, rstate->sequence_id);
1965
1966 sde_plane_rot_calc_cfg(plane, state);
1967
1968 ret = sde_plane_rot_submit_command(plane, state,
1969 SDE_HW_ROT_CMD_VALIDATE);
1970
Clarence Ip4475d582017-04-18 11:36:00 -04001971 } else {
Alan Kwong4dd64c82017-02-04 18:41:51 -08001972
1973 SDE_DEBUG("plane%d.%d bypass rotator\n", plane->base.id,
1974 rstate->sequence_id);
1975
1976 /* bypass rotator - initialize output setting as input */
Clarence Ip4475d582017-04-18 11:36:00 -04001977 for (i = 0; i < ARRAY_SIZE(rstate->out_fb_modifier); i++)
1978 rstate->out_fb_modifier[i] = state->fb ?
1979 state->fb->modifier[i] : 0x0;
1980
1981 if (state->fb) {
1982 rstate->out_fb_pixel_format = state->fb->pixel_format;
1983 rstate->out_fb_flags = state->fb->flags;
1984 rstate->out_fb_width = state->fb->width;
1985 rstate->out_fb_height = state->fb->height;
1986 } else {
1987 rstate->out_fb_pixel_format = 0x0;
1988 rstate->out_fb_flags = 0x0;
1989 rstate->out_fb_width = 0;
1990 rstate->out_fb_height = 0;
1991 }
1992
Alan Kwong4dd64c82017-02-04 18:41:51 -08001993 rstate->out_rotation = rstate->in_rotation;
Alan Kwong4dd64c82017-02-04 18:41:51 -08001994 rstate->out_src_x = state->src_x;
1995 rstate->out_src_y = state->src_y;
1996 rstate->out_src_w = state->src_w;
1997 rstate->out_src_h = state->src_h;
1998
1999 rstate->out_fb_format = NULL;
2000 rstate->out_sbuf = false;
2001 rstate->out_fb = state->fb;
2002 }
2003
2004 return ret;
2005}
2006
2007/**
2008 * sde_plane_rot_atomic_update - perform atomic update for rotator stage
2009 * @plane: Pointer to drm plane
2010 * @old_state: Pointer to previous state
2011 * return: none
2012 */
2013static void sde_plane_rot_atomic_update(struct drm_plane *plane,
2014 struct drm_plane_state *old_state)
2015{
2016 struct drm_plane_state *state;
2017 struct sde_plane_state *pstate;
2018 struct sde_plane_rot_state *rstate;
2019
2020 if (!plane || !plane->state) {
2021 SDE_ERROR("invalid plane/state\n");
2022 return;
2023 }
2024
2025 state = plane->state;
2026 pstate = to_sde_plane_state(state);
2027 rstate = &pstate->rot;
2028
2029 SDE_DEBUG("plane%d.%d sbuf:%d rot:%d crtc:%d\n", plane->base.id,
2030 rstate->sequence_id,
2031 !!rstate->out_sbuf, !!rstate->rot_hw,
2032 sde_plane_crtc_enabled(plane->state));
2033
2034 if (!sde_plane_crtc_enabled(state))
2035 return;
2036
2037 if (!rstate->out_sbuf || !rstate->rot_hw)
2038 return;
2039
2040 sde_plane_rot_submit_command(plane, state, SDE_HW_ROT_CMD_COMMIT);
2041}
2042
2043/**
Clarence Ipddbf7752017-05-21 18:07:30 -04002044 * sde_plane_rot_flush - perform final flush related rotator options
2045 * @plane: Pointer to drm plane
2046 * @pstate: Pointer to sde plane state
2047 */
2048static void sde_plane_rot_flush(struct drm_plane *plane,
2049 struct sde_plane_state *pstate)
2050{
2051 if (!plane || !pstate || !pstate->rot.rot_hw ||
2052 !pstate->rot.rot_hw->ops.commit)
2053 return;
2054
2055 pstate->rot.rot_hw->ops.commit(pstate->rot.rot_hw,
2056 &pstate->rot.rot_cmd,
2057 SDE_HW_ROT_CMD_START);
2058}
2059
2060/**
Alan Kwong4dd64c82017-02-04 18:41:51 -08002061 * sde_plane_rot_destroy_state - destroy state for rotator stage
2062 * @plane: Pointer to drm plane
2063 * @state: Pointer to state to be destroyed
2064 * return: none
2065 */
2066static void sde_plane_rot_destroy_state(struct drm_plane *plane,
2067 struct drm_plane_state *state)
2068{
2069 struct sde_plane_state *pstate = to_sde_plane_state(state);
2070 struct sde_plane_rot_state *rstate = &pstate->rot;
2071
2072 SDE_DEBUG("plane%d.%d sbuf:%d rot:%d crtc:%d\n", plane->base.id,
2073 rstate->sequence_id,
2074 !!rstate->out_sbuf, !!rstate->rot_hw,
2075 sde_plane_crtc_enabled(state));
Alan Kwong4dd64c82017-02-04 18:41:51 -08002076}
2077
2078/**
2079 * sde_plane_rot_duplicate_state - duplicate state for rotator stage
2080 * @plane: Pointer to drm plane
2081 * @new_state: Pointer to duplicated state
2082 * return: 0 if success; error code otherwise
2083 */
2084static int sde_plane_rot_duplicate_state(struct drm_plane *plane,
2085 struct drm_plane_state *new_state)
2086{
2087 struct sde_plane_state *pstate = to_sde_plane_state(new_state);
2088 struct sde_plane_rot_state *rstate = &pstate->rot;
Alan Kwongcdb2f282017-03-18 13:42:06 -07002089 struct drm_crtc_state *cstate;
2090 int ret;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002091
2092 rstate->sequence_id++;
2093
2094 SDE_DEBUG("plane%d.%d sbuf:%d rot:%d\n", plane->base.id,
2095 rstate->sequence_id,
2096 !!rstate->out_sbuf, !!rstate->rot_hw);
2097
Alan Kwongcdb2f282017-03-18 13:42:06 -07002098 cstate = _sde_plane_get_crtc_state(new_state);
2099 if (IS_ERR(cstate)) {
2100 ret = PTR_ERR(cstate);
2101 SDE_ERROR("invalid crtc state %d\n", ret);
2102 return -EINVAL;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002103 }
2104
Alan Kwongcdb2f282017-03-18 13:42:06 -07002105 if (rstate->rot_hw && cstate)
2106 sde_crtc_res_get(cstate, SDE_HW_BLK_ROT, (u64) rstate->in_fb);
2107 else if (rstate->rot_hw && !cstate)
2108 SDE_ERROR("plane%d.%d zombie rotator hw\n",
2109 plane->base.id, rstate->sequence_id);
2110
Alan Kwong4dd64c82017-02-04 18:41:51 -08002111 rstate->out_fb = NULL;
2112 rstate->out_fbo = NULL;
2113
2114 return 0;
2115}
2116
2117/**
2118 * sde_plane_rot_install_caps - install plane rotator capabilities
2119 * @plane: Pointer to drm plane
2120 * return: none
2121 */
2122static void sde_plane_rot_install_caps(struct drm_plane *plane)
2123{
2124 struct sde_plane *psde = to_sde_plane(plane);
2125 const struct sde_format_extended *format_list;
2126 struct sde_kms_info *info;
2127 struct sde_hw_rot *rot_hw;
2128 const char *downscale_caps;
2129
2130 if (!psde->catalog || !(psde->features & BIT(SDE_SSPP_SBUF)) ||
2131 !psde->catalog->rot_count)
2132 return;
2133
2134 if (psde->blob_rot_caps)
2135 return;
2136
2137 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
2138 if (!info)
2139 return;
2140
2141 rot_hw = sde_hw_rot_get(NULL);
2142 if (!rot_hw || !rot_hw->ops.get_format_caps ||
2143 !rot_hw->ops.get_downscale_caps) {
2144 SDE_ERROR("invalid rotator hw\n");
2145 goto error_rot;
2146 }
2147
2148 sde_kms_info_reset(info);
2149
2150 format_list = rot_hw->ops.get_format_caps(rot_hw);
2151 if (format_list) {
2152 sde_kms_info_start(info, "pixel_formats");
2153 while (format_list->fourcc_format) {
2154 sde_kms_info_append_format(info,
2155 format_list->fourcc_format,
2156 format_list->modifier);
2157 ++format_list;
2158 }
2159 sde_kms_info_stop(info);
2160 }
2161
2162 downscale_caps = rot_hw->ops.get_downscale_caps(rot_hw);
2163 if (downscale_caps) {
2164 sde_kms_info_start(info, "downscale_ratios");
2165 sde_kms_info_append(info, downscale_caps);
2166 sde_kms_info_stop(info);
2167 }
2168
2169 if (rot_hw->ops.get_cache_size)
2170 sde_kms_info_add_keyint(info, "cache_size",
2171 rot_hw->ops.get_cache_size(rot_hw));
2172
Alan Kwong1a915802017-03-31 12:55:46 -07002173 if (rot_hw->ops.get_maxlinewidth)
2174 sde_kms_info_add_keyint(info, "max_linewidth",
2175 rot_hw->ops.get_maxlinewidth(rot_hw));
2176
Alan Kwong4dd64c82017-02-04 18:41:51 -08002177 msm_property_set_blob(&psde->property_info, &psde->blob_rot_caps,
2178 info->data, info->len, PLANE_PROP_ROT_CAPS_V1);
2179
2180 sde_hw_rot_put(rot_hw);
2181error_rot:
2182 kfree(info);
2183}
2184
2185/**
2186 * sde_plane_rot_install_properties - install plane rotator properties
2187 * @plane: Pointer to drm plane
2188 * @catalog: Pointer to mdss configuration
2189 * return: none
2190 */
2191static void sde_plane_rot_install_properties(struct drm_plane *plane,
2192 struct sde_mdss_cfg *catalog)
2193{
2194 struct sde_plane *psde = to_sde_plane(plane);
Alan Kwong709150c2017-04-03 08:44:31 -07002195 unsigned long supported_rotations = DRM_ROTATE_0 | DRM_REFLECT_X |
2196 DRM_REFLECT_Y;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002197
2198 if (!plane || !psde) {
2199 SDE_ERROR("invalid plane\n");
2200 return;
2201 } else if (!catalog) {
2202 SDE_ERROR("invalid catalog\n");
2203 return;
2204 }
2205
2206 if ((psde->features & BIT(SDE_SSPP_SBUF)) && catalog->rot_count)
2207 supported_rotations |= DRM_ROTATE_0 | DRM_ROTATE_90 |
2208 DRM_ROTATE_180 | DRM_ROTATE_270;
2209
2210 msm_property_install_rotation(&psde->property_info,
2211 supported_rotations, PLANE_PROP_ROTATION);
2212
2213 if (!(psde->features & BIT(SDE_SSPP_SBUF)) || !catalog->rot_count)
2214 return;
2215
2216 msm_property_install_range(&psde->property_info, "rot_dst_x",
2217 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_X);
2218 msm_property_install_range(&psde->property_info, "rot_dst_y",
2219 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_Y);
2220 msm_property_install_range(&psde->property_info, "rot_dst_w",
2221 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_W);
2222 msm_property_install_range(&psde->property_info, "rot_dst_h",
2223 0, 0, U64_MAX, 0, PLANE_PROP_ROT_DST_H);
2224 msm_property_install_blob(&psde->property_info, "rot_caps_v1",
2225 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_ROT_CAPS_V1);
2226}
2227
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002228void sde_plane_clear_multirect(const struct drm_plane_state *drm_state)
Clarence Ipcb410d42016-06-26 22:52:33 -04002229{
Clarence Ipcb410d42016-06-26 22:52:33 -04002230 struct sde_plane_state *pstate;
Clarence Ipcb410d42016-06-26 22:52:33 -04002231
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002232 if (!drm_state)
2233 return;
Clarence Ipcb410d42016-06-26 22:52:33 -04002234
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002235 pstate = to_sde_plane_state(drm_state);
Clarence Ipcb410d42016-06-26 22:52:33 -04002236
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002237 pstate->multirect_index = SDE_SSPP_RECT_SOLO;
2238 pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002239}
2240
2241int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane)
2242{
2243 struct sde_plane_state *pstate[R_MAX];
2244 const struct drm_plane_state *drm_state[R_MAX];
2245 struct sde_rect src[R_MAX], dst[R_MAX];
2246 struct sde_plane *sde_plane[R_MAX];
2247 const struct sde_format *fmt[R_MAX];
2248 bool q16_data = true;
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002249 int i, buffer_lines = TX_MODE_BUFFER_LINE_THRES;
2250 bool parallel_fetch_qualified = true;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002251
2252 for (i = 0; i < R_MAX; i++) {
2253 const struct msm_format *msm_fmt;
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002254 int width_threshold;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002255
2256 drm_state[i] = i ? plane->r1 : plane->r0;
2257 pstate[i] = to_sde_plane_state(drm_state[i]);
2258 sde_plane[i] = to_sde_plane(drm_state[i]->plane);
2259
2260 if (pstate[i] == NULL) {
2261 SDE_ERROR("SDE plane state of plane id %d is NULL\n",
2262 drm_state[i]->plane->base.id);
2263 return -EINVAL;
2264 }
2265
2266 POPULATE_RECT(&src[i], drm_state[i]->src_x, drm_state[i]->src_y,
2267 drm_state[i]->src_w, drm_state[i]->src_h, q16_data);
2268 POPULATE_RECT(&dst[i], drm_state[i]->crtc_x,
2269 drm_state[i]->crtc_y, drm_state[i]->crtc_w,
2270 drm_state[i]->crtc_h, !q16_data);
2271
2272 if (src[i].w != dst[i].w || src[i].h != dst[i].h) {
2273 SDE_ERROR_PLANE(sde_plane[i],
2274 "scaling is not supported in multirect mode\n");
2275 return -EINVAL;
2276 }
2277
2278 msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
2279 fmt[i] = to_sde_format(msm_fmt);
2280 if (SDE_FORMAT_IS_YUV(fmt[i])) {
2281 SDE_ERROR_PLANE(sde_plane[i],
2282 "Unsupported format for multirect mode\n");
2283 return -EINVAL;
2284 }
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002285
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002286 /**
2287 * SSPP PD_MEM is split half - one for each RECT.
2288 * Tiled formats need 5 lines of buffering while fetching
2289 * whereas linear formats need only 2 lines.
2290 * So we cannot support more than half of the supported SSPP
2291 * width for tiled formats.
2292 */
2293 width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth;
2294 if (SDE_FORMAT_IS_UBWC(fmt[i]))
2295 width_threshold /= 2;
2296
2297 if (parallel_fetch_qualified && src[i].w > width_threshold)
2298 parallel_fetch_qualified = false;
2299
2300 }
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002301
2302 /* Validate RECT's and set the mode */
2303
2304 /* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002305 if (parallel_fetch_qualified) {
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08002306 if (dst[R0].x <= dst[R1].x) {
2307 pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
2308 pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
2309 } else {
2310 pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
2311 pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
2312 }
2313
2314 pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
2315 pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
2316 goto done;
2317 }
2318
2319 /* TIME_MX Mode */
2320 if (SDE_FORMAT_IS_UBWC(fmt[R0]))
2321 buffer_lines = 2 * fmt[R0]->tile_height;
2322
2323 if (dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) {
2324 pstate[R0]->multirect_index = SDE_SSPP_RECT_0;
2325 pstate[R1]->multirect_index = SDE_SSPP_RECT_1;
2326 } else if (dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines) {
2327 pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
2328 pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
2329 } else {
2330 SDE_ERROR(
2331 "No multirect mode possible for the planes (%d - %d)\n",
2332 drm_state[R0]->plane->base.id,
2333 drm_state[R1]->plane->base.id);
2334 return -EINVAL;
2335 }
2336
2337 pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
2338 pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
2339done:
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002340 SDE_DEBUG_PLANE(sde_plane[R0], "R0: %d - %d\n",
2341 pstate[R0]->multirect_mode, pstate[R0]->multirect_index);
2342 SDE_DEBUG_PLANE(sde_plane[R1], "R1: %d - %d\n",
2343 pstate[R1]->multirect_mode, pstate[R1]->multirect_index);
Clarence Ip5e2a9222016-06-26 22:38:24 -04002344 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002345}
2346
Alan Kwong4dd64c82017-02-04 18:41:51 -08002347/**
2348 * sde_plane_get_ctl_flush - get control flush for the given plane
2349 * @plane: Pointer to drm plane structure
2350 * @ctl: Pointer to hardware control driver
2351 * @flush: Pointer to flush control word
2352 */
2353void sde_plane_get_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl,
2354 u32 *flush)
2355{
2356 struct sde_plane_state *pstate;
2357 struct sde_plane_rot_state *rstate;
2358 u32 bitmask;
2359
2360 if (!plane || !flush) {
2361 SDE_ERROR("invalid parameters\n");
2362 return;
2363 }
2364
2365 pstate = to_sde_plane_state(plane->state);
2366 rstate = &pstate->rot;
2367
2368 bitmask = ctl->ops.get_bitmask_sspp(ctl, sde_plane_pipe(plane));
2369
2370 if (sde_plane_is_sbuf_mode(plane, NULL) && rstate->rot_hw &&
2371 ctl->ops.get_bitmask_rot)
2372 ctl->ops.get_bitmask_rot(ctl, &bitmask, rstate->rot_hw->idx);
2373
2374 *flush = bitmask;
2375}
2376
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002377static int sde_plane_prepare_fb(struct drm_plane *plane,
Dhaval Patel04c7e8e2016-09-26 20:14:31 -07002378 struct drm_plane_state *new_state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002379{
2380 struct drm_framebuffer *fb = new_state->fb;
2381 struct sde_plane *psde = to_sde_plane(plane);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002382 struct sde_plane_rot_state *new_rstate;
2383 int ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002384
2385 if (!new_state->fb)
2386 return 0;
2387
Clarence Ip13a8cf42016-09-29 17:27:47 -04002388 SDE_DEBUG_PLANE(psde, "FB[%u]\n", fb->base.id);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002389
2390 ret = sde_plane_rot_prepare_fb(plane, new_state);
2391 if (ret) {
2392 SDE_ERROR("failed to prepare rot framebuffer\n");
2393 return ret;
2394 }
2395
2396 new_rstate = &to_sde_plane_state(new_state)->rot;
2397
2398 ret = msm_framebuffer_prepare(new_rstate->out_fb, new_rstate->mmu_id);
2399 if (ret) {
2400 SDE_ERROR("failed to prepare framebuffer\n");
2401 return ret;
2402 }
2403
2404 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002405}
2406
2407static void sde_plane_cleanup_fb(struct drm_plane *plane,
Dhaval Patel04c7e8e2016-09-26 20:14:31 -07002408 struct drm_plane_state *old_state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002409{
Alan Kwong4dd64c82017-02-04 18:41:51 -08002410 struct sde_plane *psde = to_sde_plane(plane);
2411 struct sde_plane_rot_state *old_rstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002412
Alan Kwong4dd64c82017-02-04 18:41:51 -08002413 if (!old_state->fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002414 return;
2415
Alan Kwong4dd64c82017-02-04 18:41:51 -08002416 SDE_DEBUG_PLANE(psde, "FB[%u]\n", old_state->fb->base.id);
2417
2418 old_rstate = &to_sde_plane_state(old_state)->rot;
2419
2420 msm_framebuffer_cleanup(old_rstate->out_fb, old_rstate->mmu_id);
2421
2422 sde_plane_rot_cleanup_fb(plane, old_state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002423}
2424
Alan Kwong4dd64c82017-02-04 18:41:51 -08002425static void _sde_plane_sspp_atomic_check_mode_changed(struct sde_plane *psde,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002426 struct drm_plane_state *state,
2427 struct drm_plane_state *old_state)
2428{
2429 struct sde_plane_state *pstate = to_sde_plane_state(state);
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002430 struct sde_plane_state *old_pstate = to_sde_plane_state(old_state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002431 struct sde_plane_rot_state *rstate = &pstate->rot;
2432 struct sde_plane_rot_state *old_rstate = &old_pstate->rot;
2433 struct drm_framebuffer *fb, *old_fb;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002434
Dhaval Patel47302cf2016-08-18 15:04:28 -07002435 /* no need to check it again */
Clarence Ip282dad62016-09-27 17:07:35 -04002436 if (pstate->dirty == SDE_PLANE_DIRTY_ALL)
Dhaval Patel47302cf2016-08-18 15:04:28 -07002437 return;
2438
Clarence Ip282dad62016-09-27 17:07:35 -04002439 if (!sde_plane_enabled(state) || !sde_plane_enabled(old_state)
2440 || psde->is_error) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002441 SDE_DEBUG_PLANE(psde,
2442 "enabling/disabling full modeset required\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002443 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002444 } else if (to_sde_plane_state(old_state)->pending) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002445 SDE_DEBUG_PLANE(psde, "still pending\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002446 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002447 } else if (pstate->multirect_index != old_pstate->multirect_index ||
2448 pstate->multirect_mode != old_pstate->multirect_mode) {
2449 SDE_DEBUG_PLANE(psde, "multirect config updated\n");
2450 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002451 } else if (rstate->out_src_w != old_rstate->out_src_w ||
2452 rstate->out_src_h != old_rstate->out_src_h ||
2453 rstate->out_src_x != old_rstate->out_src_x ||
2454 rstate->out_src_y != old_rstate->out_src_y) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002455 SDE_DEBUG_PLANE(psde, "src rect updated\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002456 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002457 } else if (state->crtc_w != old_state->crtc_w ||
2458 state->crtc_h != old_state->crtc_h ||
2459 state->crtc_x != old_state->crtc_x ||
2460 state->crtc_y != old_state->crtc_y) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002461 SDE_DEBUG_PLANE(psde, "crtc rect updated\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002462 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002463 } else if (pstate->excl_rect.w != old_pstate->excl_rect.w ||
2464 pstate->excl_rect.h != old_pstate->excl_rect.h ||
2465 pstate->excl_rect.x != old_pstate->excl_rect.x ||
2466 pstate->excl_rect.y != old_pstate->excl_rect.y) {
Veera Sundaram Sankaran58e12812017-05-05 11:51:09 -07002467 SDE_DEBUG_PLANE(psde, "excl_rect updated\n");
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002468 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Clarence Ip282dad62016-09-27 17:07:35 -04002469 }
2470
Alan Kwong4dd64c82017-02-04 18:41:51 -08002471 fb = rstate->out_fb;
2472 old_fb = old_rstate->out_fb;
2473
2474 if (!fb || !old_fb) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002475 SDE_DEBUG_PLANE(psde, "can't compare fb handles\n");
Alan Kwong4dd64c82017-02-04 18:41:51 -08002476 } else if (fb->pixel_format != old_fb->pixel_format) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002477 SDE_DEBUG_PLANE(psde, "format change\n");
Clarence Ip282dad62016-09-27 17:07:35 -04002478 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002479 } else {
Alan Kwong4dd64c82017-02-04 18:41:51 -08002480 uint64_t *new_mods = fb->modifier;
2481 uint64_t *old_mods = old_fb->modifier;
2482 uint32_t *new_pitches = fb->pitches;
2483 uint32_t *old_pitches = old_fb->pitches;
2484 uint32_t *new_offset = fb->offsets;
2485 uint32_t *old_offset = old_fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002486 int i;
2487
Alan Kwong4dd64c82017-02-04 18:41:51 -08002488 for (i = 0; i < ARRAY_SIZE(fb->modifier); i++) {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002489 if (new_mods[i] != old_mods[i]) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002490 SDE_DEBUG_PLANE(psde,
2491 "format modifiers change\"\
Dhaval Patel47302cf2016-08-18 15:04:28 -07002492 plane:%d new_mode:%llu old_mode:%llu\n",
Clarence Ip13a8cf42016-09-29 17:27:47 -04002493 i, new_mods[i], old_mods[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04002494 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
2495 SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002496 break;
2497 }
2498 }
Alan Kwong4dd64c82017-02-04 18:41:51 -08002499 for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) {
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04002500 if (new_pitches[i] != old_pitches[i]) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002501 SDE_DEBUG_PLANE(psde,
2502 "pitches change plane:%d\"\
Dhaval Patel47302cf2016-08-18 15:04:28 -07002503 old_pitches:%u new_pitches:%u\n",
Clarence Ip13a8cf42016-09-29 17:27:47 -04002504 i, old_pitches[i], new_pitches[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04002505 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04002506 break;
2507 }
2508 }
Alan Kwong4dd64c82017-02-04 18:41:51 -08002509 for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07002510 if (new_offset[i] != old_offset[i]) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002511 SDE_DEBUG_PLANE(psde,
2512 "offset change plane:%d\"\
Dhaval Patel47302cf2016-08-18 15:04:28 -07002513 old_offset:%u new_offset:%u\n",
Clarence Ip13a8cf42016-09-29 17:27:47 -04002514 i, old_offset[i], new_offset[i]);
Clarence Ip282dad62016-09-27 17:07:35 -04002515 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT |
2516 SDE_PLANE_DIRTY_RECTS;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002517 break;
2518 }
2519 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04002520 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002521}
2522
Alan Kwong4dd64c82017-02-04 18:41:51 -08002523static int sde_plane_sspp_atomic_check(struct drm_plane *plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002524 struct drm_plane_state *state)
2525{
Clarence Ipdedbba92016-09-27 17:43:10 -04002526 int ret = 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04002527 struct sde_plane *psde;
2528 struct sde_plane_state *pstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08002529 struct sde_plane_rot_state *rstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04002530 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002531 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04002532 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002533 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
2534 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04002535
2536 if (!plane || !state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002537 SDE_ERROR("invalid arg(s), plane %d state %d\n",
2538 plane != 0, state != 0);
Clarence Ipdbde9832016-06-26 09:48:36 -04002539 ret = -EINVAL;
2540 goto exit;
2541 }
2542
2543 psde = to_sde_plane(plane);
2544 pstate = to_sde_plane_state(state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08002545 rstate = &pstate->rot;
Clarence Ipdbde9832016-06-26 09:48:36 -04002546
2547 if (!psde->pipe_sblk) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002548 SDE_ERROR_PLANE(psde, "invalid catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04002549 ret = -EINVAL;
2550 goto exit;
2551 }
2552
Clarence Ipdedbba92016-09-27 17:43:10 -04002553 deci_w = sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE);
2554 deci_h = sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE);
Clarence Ipdbde9832016-06-26 09:48:36 -04002555
2556 /* src values are in Q16 fixed point, convert to integer */
Alan Kwong4dd64c82017-02-04 18:41:51 -08002557 POPULATE_RECT(&src, rstate->out_src_x, rstate->out_src_y,
2558 rstate->out_src_w, rstate->out_src_h, q16_data);
Dhaval Patel47302cf2016-08-18 15:04:28 -07002559 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
2560 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04002561
Dhaval Patel47302cf2016-08-18 15:04:28 -07002562 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
2563 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04002564
Dhaval Patel47302cf2016-08-18 15:04:28 -07002565 max_upscale = psde->pipe_sblk->maxupscale;
2566 max_downscale = psde->pipe_sblk->maxdwnscale;
2567 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04002568
Clarence Ip13a8cf42016-09-29 17:27:47 -04002569 SDE_DEBUG_PLANE(psde, "check %d -> %d\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002570 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002571
Dhaval Patel47302cf2016-08-18 15:04:28 -07002572 if (!sde_plane_enabled(state))
2573 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04002574
Alan Kwong4dd64c82017-02-04 18:41:51 -08002575 SDE_DEBUG(
Dhaval Patel6c666622017-03-21 23:02:59 -07002576 "plane%d.%u sspp:%x/%dx%d/%4.4s/%llx/%dx%d+%d+%d crtc:%dx%d+%d+%d\n",
Alan Kwong4dd64c82017-02-04 18:41:51 -08002577 plane->base.id, rstate->sequence_id,
2578 rstate->out_rotation,
2579 rstate->out_fb_width, rstate->out_fb_height,
Dhaval Patel6c666622017-03-21 23:02:59 -07002580 (char *) &rstate->out_fb_pixel_format,
Alan Kwong4dd64c82017-02-04 18:41:51 -08002581 rstate->out_fb_modifier[0],
2582 rstate->out_src_w >> 16, rstate->out_src_h >> 16,
2583 rstate->out_src_x >> 16, rstate->out_src_y >> 16,
2584 state->crtc_w, state->crtc_h,
2585 state->crtc_x, state->crtc_y);
2586
Dhaval Patel47302cf2016-08-18 15:04:28 -07002587 fmt = to_sde_format(msm_framebuffer_format(state->fb));
2588
2589 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
2590
2591 if (SDE_FORMAT_IS_YUV(fmt) &&
2592 (!(psde->features & SDE_SSPP_SCALER) ||
abeykun1c312f62016-08-26 09:47:12 -04002593 !(psde->features & (BIT(SDE_SSPP_CSC)
2594 | BIT(SDE_SSPP_CSC_10BIT))))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002595 SDE_ERROR_PLANE(psde,
2596 "plane doesn't have scaler/csc for yuv\n");
Dhaval Patel47302cf2016-08-18 15:04:28 -07002597 ret = -EINVAL;
2598
2599 /* check src bounds */
Alan Kwong4dd64c82017-02-04 18:41:51 -08002600 } else if (rstate->out_fb_width > MAX_IMG_WIDTH ||
2601 rstate->out_fb_height > MAX_IMG_HEIGHT ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07002602 src.w < min_src_size || src.h < min_src_size ||
Alan Kwong4dd64c82017-02-04 18:41:51 -08002603 CHECK_LAYER_BOUNDS(src.x, src.w, rstate->out_fb_width) ||
2604 CHECK_LAYER_BOUNDS(src.y, src.h, rstate->out_fb_height)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002605 SDE_ERROR_PLANE(psde, "invalid source %u, %u, %ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002606 src.x, src.y, src.w, src.h);
2607 ret = -E2BIG;
2608
2609 /* valid yuv image */
2610 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
2611 (src.w & 0x1) || (src.h & 0x1))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002612 SDE_ERROR_PLANE(psde, "invalid yuv source %u, %u, %ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002613 src.x, src.y, src.w, src.h);
2614 ret = -EINVAL;
2615
2616 /* min dst support */
2617 } else if (dst.w < 0x1 || dst.h < 0x1) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002618 SDE_ERROR_PLANE(psde, "invalid dest rect %u, %u, %ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002619 dst.x, dst.y, dst.w, dst.h);
2620 ret = -EINVAL;
2621
2622 /* decimation validation */
2623 } else if (deci_w || deci_h) {
2624 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
2625 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002626 SDE_ERROR_PLANE(psde,
2627 "too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04002628 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07002629 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002630 SDE_ERROR_PLANE(psde,
2631 "decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04002632 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002633 }
2634
Dhaval Patel47302cf2016-08-18 15:04:28 -07002635 } else if (!(psde->features & SDE_SSPP_SCALER) &&
2636 ((src.w != dst.w) || (src.h != dst.h))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002637 SDE_ERROR_PLANE(psde,
2638 "pipe doesn't support scaling %ux%u->%ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002639 src.w, src.h, dst.w, dst.h);
2640 ret = -EINVAL;
2641
2642 /* check decimated source width */
2643 } else if (src_deci_w > max_linewidth) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002644 SDE_ERROR_PLANE(psde,
2645 "invalid src w:%u, deci w:%u, line w:%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002646 src.w, src_deci_w, max_linewidth);
2647 ret = -E2BIG;
2648
2649 /* check max scaler capability */
2650 } else if (((src_deci_w * max_upscale) < dst.w) ||
2651 ((src_deci_h * max_upscale) < dst.h) ||
2652 ((dst.w * max_downscale) < src_deci_w) ||
2653 ((dst.h * max_downscale) < src_deci_h)) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002654 SDE_ERROR_PLANE(psde,
2655 "too much scaling requested %ux%u->%ux%u\n",
Dhaval Patel47302cf2016-08-18 15:04:28 -07002656 src_deci_w, src_deci_h, dst.w, dst.h);
2657 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04002658 }
2659
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002660 /* check excl rect configs */
2661 if (pstate->excl_rect.w && pstate->excl_rect.h) {
2662 struct sde_rect intersect;
2663
2664 /*
2665 * Check exclusion rect against src rect.
Dhaval Patela8d6bc62017-05-10 17:40:18 -07002666 * it must intersect with source rect.
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002667 */
Lloyd Atkinsone0e11e22017-01-17 12:08:48 -05002668 sde_kms_rect_intersect(&src, &pstate->excl_rect, &intersect);
Dhaval Patela8d6bc62017-05-10 17:40:18 -07002669 if (intersect.w != pstate->excl_rect.w ||
2670 intersect.h != pstate->excl_rect.h ||
2671 SDE_FORMAT_IS_YUV(fmt)) {
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002672 SDE_ERROR_PLANE(psde,
Dhaval Patel6c666622017-03-21 23:02:59 -07002673 "invalid excl_rect:{%d,%d,%d,%d} src:{%d,%d,%d,%d}, fmt: %4.4s\n",
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002674 pstate->excl_rect.x, pstate->excl_rect.y,
2675 pstate->excl_rect.w, pstate->excl_rect.h,
2676 src.x, src.y, src.w, src.h,
Dhaval Patel6c666622017-03-21 23:02:59 -07002677 (char *)&fmt->base.pixel_format);
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002678 ret = -EINVAL;
2679 }
Veera Sundaram Sankaran58e12812017-05-05 11:51:09 -07002680 SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
2681 pstate->excl_rect.x, pstate->excl_rect.y,
2682 pstate->excl_rect.w, pstate->excl_rect.h);
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08002683 }
2684
Dhaval Patel47302cf2016-08-18 15:04:28 -07002685modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04002686 if (!ret)
Alan Kwong4dd64c82017-02-04 18:41:51 -08002687 _sde_plane_sspp_atomic_check_mode_changed(psde,
2688 state, plane->state);
2689exit:
2690 return ret;
2691}
2692
2693static int sde_plane_atomic_check(struct drm_plane *plane,
2694 struct drm_plane_state *state)
2695{
2696 int ret = 0;
2697 struct sde_plane *psde;
2698 struct sde_plane_state *pstate;
2699
2700 if (!plane || !state) {
2701 SDE_ERROR("invalid arg(s), plane %d state %d\n",
2702 plane != 0, state != 0);
2703 ret = -EINVAL;
2704 goto exit;
2705 }
2706
2707 psde = to_sde_plane(plane);
2708 pstate = to_sde_plane_state(state);
2709
2710 SDE_DEBUG_PLANE(psde, "\n");
2711
2712 ret = sde_plane_rot_atomic_check(plane, state);
2713 if (ret)
2714 goto exit;
2715
2716 ret = sde_plane_sspp_atomic_check(plane, state);
2717
Clarence Ipdbde9832016-06-26 09:48:36 -04002718exit:
2719 return ret;
2720}
2721
Clarence Ipcae1bb62016-07-07 12:07:13 -04002722/**
2723 * sde_plane_flush - final plane operations before commit flush
2724 * @plane: Pointer to drm plane structure
2725 */
2726void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04002727{
Clarence Ipcae1bb62016-07-07 12:07:13 -04002728 struct sde_plane *psde;
Clarence Ipddbf7752017-05-21 18:07:30 -04002729 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -04002730
Clarence Ipddbf7752017-05-21 18:07:30 -04002731 if (!plane || !plane->state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04002732 SDE_ERROR("invalid plane\n");
Clarence Ipcae1bb62016-07-07 12:07:13 -04002733 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -04002734 }
Clarence Ipcae1bb62016-07-07 12:07:13 -04002735
2736 psde = to_sde_plane(plane);
Clarence Ipddbf7752017-05-21 18:07:30 -04002737 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -04002738
2739 /*
2740 * These updates have to be done immediately before the plane flush
2741 * timing, and may not be moved to the atomic_update/mode_set functions.
2742 */
2743 if (psde->is_error)
Clarence Ip3bf8d872017-02-16 15:25:38 -05002744 /* force white frame with 100% alpha pipe output on error */
2745 _sde_plane_color_fill(psde, 0xFFFFFF, 0xFF);
Clarence Ipcae1bb62016-07-07 12:07:13 -04002746 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
2747 /* force 100% alpha */
Clarence Ip13a8cf42016-09-29 17:27:47 -04002748 _sde_plane_color_fill(psde, psde->color_fill, 0xFF);
Clarence Ipcae1bb62016-07-07 12:07:13 -04002749 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
2750 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
2751
Clarence Ip56902792017-03-17 15:22:07 -04002752 /* force black color fill during suspend */
2753 if (msm_is_suspend_state(plane->dev) && suspend_blank)
2754 _sde_plane_color_fill(psde, 0x0, 0x0);
2755
Clarence Ipcae1bb62016-07-07 12:07:13 -04002756 /* flag h/w flush complete */
2757 if (plane->state)
Clarence Ipddbf7752017-05-21 18:07:30 -04002758 pstate->pending = false;
2759
2760 /* signal inline rotator start */
2761 sde_plane_rot_flush(plane, pstate);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002762}
2763
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07002764static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
2765 struct drm_plane_state *old_state)
2766{
2767 uint32_t nplanes, src_flags;
2768 struct sde_plane *psde;
2769 struct drm_plane_state *state;
2770 struct sde_plane_state *pstate;
2771 struct sde_plane_state *old_pstate;
2772 struct sde_plane_rot_state *rstate;
2773 const struct sde_format *fmt;
2774 struct drm_crtc *crtc;
2775 struct drm_framebuffer *fb;
2776 struct sde_rect src, dst;
2777 const struct sde_rect *crtc_roi;
2778 bool q16_data = true;
2779 int idx;
2780
2781 if (!plane) {
2782 SDE_ERROR("invalid plane\n");
2783 return -EINVAL;
2784 } else if (!plane->state) {
2785 SDE_ERROR("invalid plane state\n");
2786 return -EINVAL;
2787 } else if (!old_state) {
2788 SDE_ERROR("invalid old state\n");
2789 return -EINVAL;
2790 }
2791
2792 psde = to_sde_plane(plane);
2793 state = plane->state;
2794
2795 pstate = to_sde_plane_state(state);
2796 rstate = &pstate->rot;
2797
2798 old_pstate = to_sde_plane_state(old_state);
2799
2800 crtc = state->crtc;
2801 fb = rstate->out_fb;
2802 if (!crtc || !fb) {
2803 SDE_ERROR_PLANE(psde, "invalid crtc %d or fb %d\n",
2804 crtc != 0, fb != 0);
2805 return -EINVAL;
2806 }
2807 fmt = to_sde_format(msm_framebuffer_format(fb));
2808 nplanes = fmt->num_planes;
2809
2810 SDE_DEBUG(
2811 "plane%d.%d sspp:%dx%d/%4.4s/%llx/%dx%d+%d+%d/%x crtc:%dx%d+%d+%d\n",
2812 plane->base.id, rstate->sequence_id,
2813 rstate->out_fb_width, rstate->out_fb_height,
2814 (char *) &rstate->out_fb_pixel_format,
2815 rstate->out_fb_modifier[0],
2816 rstate->out_src_w >> 16, rstate->out_src_h >> 16,
2817 rstate->out_src_x >> 16, rstate->out_src_y >> 16,
2818 rstate->out_rotation,
2819 state->crtc_w, state->crtc_h,
2820 state->crtc_x, state->crtc_y);
2821
2822 /* force reprogramming of all the parameters, if the flag is set */
2823 if (psde->revalidate) {
2824 SDE_DEBUG("plane:%d - reconfigure all the parameters\n",
2825 plane->base.id);
2826 pstate->dirty = SDE_PLANE_DIRTY_ALL;
2827 psde->revalidate = false;
2828 }
2829
2830 /* determine what needs to be refreshed */
2831 while ((idx = msm_property_pop_dirty(&psde->property_info)) >= 0) {
2832 switch (idx) {
2833 case PLANE_PROP_SCALER_V1:
2834 case PLANE_PROP_SCALER_V2:
2835 case PLANE_PROP_H_DECIMATE:
2836 case PLANE_PROP_V_DECIMATE:
2837 case PLANE_PROP_SRC_CONFIG:
2838 case PLANE_PROP_ZPOS:
2839 case PLANE_PROP_EXCL_RECT_V1:
2840 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
2841 break;
2842 case PLANE_PROP_CSC_V1:
2843 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
2844 break;
2845 case PLANE_PROP_COLOR_FILL:
2846 /* potentially need to refresh everything */
2847 pstate->dirty = SDE_PLANE_DIRTY_ALL;
2848 break;
2849 case PLANE_PROP_ROTATION:
2850 pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
2851 break;
2852 case PLANE_PROP_INFO:
2853 case PLANE_PROP_ALPHA:
2854 case PLANE_PROP_INPUT_FENCE:
2855 case PLANE_PROP_BLEND_OP:
2856 /* no special action required */
2857 break;
2858 case PLANE_PROP_ROT_DST_X:
2859 case PLANE_PROP_ROT_DST_Y:
2860 case PLANE_PROP_ROT_DST_W:
2861 case PLANE_PROP_ROT_DST_H:
2862 /* handled by rotator atomic update */
2863 break;
2864 default:
2865 /* unknown property, refresh everything */
2866 pstate->dirty |= SDE_PLANE_DIRTY_ALL;
2867 SDE_ERROR("executing full mode set, prp_idx %d\n", idx);
2868 break;
2869 }
2870 }
2871
2872 /**
2873 * since plane_atomic_check is invoked before crtc_atomic_check
2874 * in the commit sequence, all the parameters for updating the
2875 * plane dirty flag will not be available during
2876 * plane_atomic_check as some features params are updated
2877 * in crtc_atomic_check (eg.:sDMA). So check for mode_change
2878 * before sspp update.
2879 */
2880 _sde_plane_sspp_atomic_check_mode_changed(psde, state,
2881 old_state);
2882
2883 /* re-program the output rects always in the case of partial update */
2884 sde_crtc_get_crtc_roi(crtc->state, &crtc_roi);
2885 if (!sde_kms_rect_is_null(crtc_roi))
2886 pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
2887
2888 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
2889 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
2890
2891 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
2892
2893 /* early out if nothing dirty */
2894 if (!pstate->dirty)
2895 return 0;
2896 pstate->pending = true;
2897
2898 psde->is_rt_pipe = (sde_crtc_get_client_type(crtc) != NRT_CLIENT);
2899 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
2900
2901 /* update roi config */
2902 if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) {
2903 POPULATE_RECT(&src, rstate->out_src_x, rstate->out_src_y,
2904 rstate->out_src_w, rstate->out_src_h, q16_data);
2905 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
2906 state->crtc_w, state->crtc_h, !q16_data);
2907
2908 SDE_DEBUG_PLANE(psde,
2909 "FB[%u] %u,%u,%ux%u->crtc%u %d,%d,%ux%u, %4.4s ubwc %d\n",
2910 fb->base.id, src.x, src.y, src.w, src.h,
2911 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
2912 (char *)&fmt->base.pixel_format,
2913 SDE_FORMAT_IS_UBWC(fmt));
2914
2915 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
2916 BIT(SDE_DRM_DEINTERLACE)) {
2917 SDE_DEBUG_PLANE(psde, "deinterlace\n");
2918 for (idx = 0; idx < SDE_MAX_PLANES; ++idx)
2919 psde->pipe_cfg.layout.plane_pitch[idx] <<= 1;
2920 src.h /= 2;
2921 src.y = DIV_ROUND_UP(src.y, 2);
2922 src.y &= ~0x1;
2923 }
2924
2925 /*
2926 * adjust layer mixer position of the sspp in the presence
2927 * of a partial update to the active lm origin
2928 */
2929 dst.x -= crtc_roi->x;
2930 dst.y -= crtc_roi->y;
2931
2932 psde->pipe_cfg.src_rect = src;
2933 psde->pipe_cfg.dst_rect = dst;
2934
2935 _sde_plane_setup_scaler(psde, fmt, pstate);
2936
2937 /* check for color fill */
2938 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
2939 PLANE_PROP_COLOR_FILL);
2940 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) {
2941 /* skip remaining processing on color fill */
2942 pstate->dirty = 0x0;
2943 } else if (psde->pipe_hw->ops.setup_rects) {
2944 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
2945 &psde->pipe_cfg,
2946 pstate->multirect_index);
2947 }
2948
2949 if (psde->pipe_hw->ops.setup_pe)
2950 psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
2951 &psde->pixel_ext);
2952
2953 /**
2954 * when programmed in multirect mode, scalar block will be
2955 * bypassed. Still we need to update alpha and bitwidth
2956 * ONLY for RECT0
2957 */
2958 if (psde->pipe_hw->ops.setup_scaler &&
2959 pstate->multirect_index != SDE_SSPP_RECT_1)
2960 psde->pipe_hw->ops.setup_scaler(psde->pipe_hw,
2961 &psde->pipe_cfg, &psde->pixel_ext,
2962 psde->scaler3_cfg);
2963
2964 /* update excl rect */
2965 if (psde->pipe_hw->ops.setup_excl_rect)
2966 psde->pipe_hw->ops.setup_excl_rect(psde->pipe_hw,
2967 &pstate->excl_rect,
2968 pstate->multirect_index);
2969
2970 if (psde->pipe_hw->ops.setup_multirect)
2971 psde->pipe_hw->ops.setup_multirect(
2972 psde->pipe_hw,
2973 pstate->multirect_index,
2974 pstate->multirect_mode);
2975 }
2976
2977 if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT) &&
2978 psde->pipe_hw->ops.setup_format) {
2979 src_flags = 0x0;
2980 SDE_DEBUG_PLANE(psde, "rotation 0x%X\n", rstate->out_rotation);
2981 if (rstate->out_rotation & DRM_REFLECT_X)
2982 src_flags |= SDE_SSPP_FLIP_LR;
2983 if (rstate->out_rotation & DRM_REFLECT_Y)
2984 src_flags |= SDE_SSPP_FLIP_UD;
2985
2986 /* update format */
2987 psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, src_flags,
2988 pstate->multirect_index);
2989
2990 if (psde->pipe_hw->ops.setup_sys_cache) {
2991 if (rstate->out_sbuf) {
2992 if (rstate->nplane < 2)
2993 pstate->sc_cfg.op_mode =
2994 SDE_PIPE_SC_OP_MODE_INLINE_SINGLE;
2995 else if (rstate->out_xpos == 0)
2996 pstate->sc_cfg.op_mode =
2997 SDE_PIPE_SC_OP_MODE_INLINE_LEFT;
2998 else
2999 pstate->sc_cfg.op_mode =
3000 SDE_PIPE_SC_OP_MODE_INLINE_RIGHT;
3001
3002 pstate->sc_cfg.rd_en = true;
3003 pstate->sc_cfg.rd_scid =
3004 rstate->rot_hw->caps->scid;
3005 pstate->sc_cfg.rd_noallocate = true;
3006 pstate->sc_cfg.rd_op_type =
3007 SDE_PIPE_SC_RD_OP_TYPE_CACHEABLE;
3008 } else {
3009 pstate->sc_cfg.op_mode =
3010 SDE_PIPE_SC_OP_MODE_OFFLINE;
3011 pstate->sc_cfg.rd_en = false;
3012 pstate->sc_cfg.rd_scid = 0;
3013 pstate->sc_cfg.rd_noallocate = false;
3014 pstate->sc_cfg.rd_op_type =
3015 SDE_PIPE_SC_RD_OP_TYPE_CACHEABLE;
3016 }
3017
3018 psde->pipe_hw->ops.setup_sys_cache(
3019 psde->pipe_hw, &pstate->sc_cfg);
3020 }
3021
3022 /* update csc */
3023 if (SDE_FORMAT_IS_YUV(fmt))
3024 _sde_plane_setup_csc(psde);
3025 else
3026 psde->csc_ptr = 0;
3027 }
3028
3029 sde_color_process_plane_setup(plane);
3030
3031 /* update sharpening */
3032 if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) &&
3033 psde->pipe_hw->ops.setup_sharpening) {
3034 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
3035 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
3036 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
3037 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
3038
3039 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
3040 &psde->sharp_cfg);
3041 }
3042
3043 _sde_plane_set_qos_lut(plane, fb);
3044 _sde_plane_set_danger_lut(plane, fb);
3045
3046 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
3047 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
3048 _sde_plane_set_ot_limit(plane, crtc);
3049 }
3050
3051 /* clear dirty */
3052 pstate->dirty = 0x0;
3053
3054 return 0;
3055}
3056
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003057static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04003058 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003059{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003060 struct sde_plane *psde;
Clarence Ip5e2a9222016-06-26 22:38:24 -04003061 struct drm_plane_state *state;
3062 struct sde_plane_state *pstate;
Alan Kwong4dd64c82017-02-04 18:41:51 -08003063 struct sde_plane_state *old_pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003064
Clarence Ip13a8cf42016-09-29 17:27:47 -04003065 if (!plane) {
3066 SDE_ERROR("invalid plane\n");
3067 return;
3068 } else if (!plane->state) {
3069 SDE_ERROR("invalid plane state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04003070 return;
3071 }
3072
Clarence Ip13a8cf42016-09-29 17:27:47 -04003073 psde = to_sde_plane(plane);
3074 psde->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04003075 state = plane->state;
3076 pstate = to_sde_plane_state(state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08003077 old_pstate = to_sde_plane_state(old_state);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003078
Clarence Ip13a8cf42016-09-29 17:27:47 -04003079 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04003080
Alan Kwong4dd64c82017-02-04 18:41:51 -08003081 sde_plane_rot_atomic_update(plane, old_state);
3082
3083 if (!sde_plane_sspp_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04003084 pstate->pending = true;
Clarence Ip282dad62016-09-27 17:07:35 -04003085 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003086 int ret;
3087
Jeykumar Sankarane964dc72017-05-10 19:26:43 -07003088 ret = sde_plane_sspp_atomic_update(plane, old_state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003089 /* atomic_check should have ensured that this doesn't fail */
3090 WARN_ON(ret < 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003091 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003092}
3093
Dhaval Patel47302cf2016-08-18 15:04:28 -07003094
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003095/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07003096static void _sde_plane_install_properties(struct drm_plane *plane,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003097 struct sde_mdss_cfg *catalog, u32 master_plane_id)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003098{
Clarence Ip5e2a9222016-06-26 22:38:24 -04003099 static const struct drm_prop_enum_list e_blend_op[] = {
3100 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
3101 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
3102 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
3103 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
3104 };
3105 static const struct drm_prop_enum_list e_src_config[] = {
3106 {SDE_DRM_DEINTERLACE, "deinterlace"}
3107 };
Clarence Ipea3d6262016-07-15 16:20:11 -04003108 const struct sde_format_extended *format_list;
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07003109 struct sde_format_extended *virt_format_list = NULL;
Dhaval Patel4e574842016-08-23 15:11:37 -07003110 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04003111 struct sde_plane *psde = to_sde_plane(plane);
Clarence Ipc47a0692016-10-11 10:54:17 -04003112 int zpos_max = 255;
3113 int zpos_def = 0;
Benet Clarkeb1b4462016-06-27 14:43:06 -07003114 char feature_name[256];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003115
Clarence Ip13a8cf42016-09-29 17:27:47 -04003116 if (!plane || !psde) {
3117 SDE_ERROR("invalid plane\n");
3118 return;
3119 } else if (!psde->pipe_hw || !psde->pipe_sblk) {
3120 SDE_ERROR("invalid plane, pipe_hw %d pipe_sblk %d\n",
3121 psde->pipe_hw != 0, psde->pipe_sblk != 0);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003122 return;
Clarence Ipc47a0692016-10-11 10:54:17 -04003123 } else if (!catalog) {
3124 SDE_ERROR("invalid catalog\n");
3125 return;
Clarence Ip5e2a9222016-06-26 22:38:24 -04003126 }
3127
Alan Kwong4dd64c82017-02-04 18:41:51 -08003128 psde->catalog = catalog;
3129
Clarence Ipc47a0692016-10-11 10:54:17 -04003130 if (sde_is_custom_client()) {
Clarence Ip649989a2016-10-21 14:28:34 -04003131 if (catalog->mixer_count && catalog->mixer &&
3132 catalog->mixer[0].sblk->maxblendstages) {
3133 zpos_max = catalog->mixer[0].sblk->maxblendstages - 1;
3134 if (zpos_max > SDE_STAGE_MAX - SDE_STAGE_0 - 1)
3135 zpos_max = SDE_STAGE_MAX - SDE_STAGE_0 - 1;
3136 }
Clarence Ipc47a0692016-10-11 10:54:17 -04003137 } else if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
3138 /* reserve zpos == 0 for primary planes */
3139 zpos_def = drm_plane_index(plane) + 1;
3140 }
3141
3142 msm_property_install_range(&psde->property_info, "zpos",
3143 0x0, 0, zpos_max, zpos_def, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003144
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04003145 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07003146 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003147
Dhaval Patel47302cf2016-08-18 15:04:28 -07003148 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04003149 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07003150 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003151
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003152 if (!master_plane_id) {
3153 if (psde->pipe_sblk->maxhdeciexp) {
3154 msm_property_install_range(&psde->property_info,
3155 "h_decimate", 0x0, 0,
3156 psde->pipe_sblk->maxhdeciexp, 0,
3157 PLANE_PROP_H_DECIMATE);
3158 }
Clarence Ipdedbba92016-09-27 17:43:10 -04003159
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003160 if (psde->pipe_sblk->maxvdeciexp) {
3161 msm_property_install_range(&psde->property_info,
3162 "v_decimate", 0x0, 0,
3163 psde->pipe_sblk->maxvdeciexp, 0,
3164 PLANE_PROP_V_DECIMATE);
3165 }
Clarence Ipdedbba92016-09-27 17:43:10 -04003166
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003167 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
3168 msm_property_install_volatile_range(
3169 &psde->property_info, "scaler_v2",
3170 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2);
3171 msm_property_install_blob(&psde->property_info,
3172 "lut_ed", 0, PLANE_PROP_SCALER_LUT_ED);
3173 msm_property_install_blob(&psde->property_info,
3174 "lut_cir", 0,
3175 PLANE_PROP_SCALER_LUT_CIR);
3176 msm_property_install_blob(&psde->property_info,
3177 "lut_sep", 0,
3178 PLANE_PROP_SCALER_LUT_SEP);
3179 } else if (psde->features & SDE_SSPP_SCALER) {
3180 msm_property_install_volatile_range(
3181 &psde->property_info, "scaler_v1", 0x0,
3182 0, ~0, 0, PLANE_PROP_SCALER_V1);
3183 }
Clarence Ipb43d4592016-09-08 14:21:35 -04003184
Dhaval Patel0aee0972017-02-08 19:00:58 -08003185 if (psde->features & BIT(SDE_SSPP_CSC) ||
3186 psde->features & BIT(SDE_SSPP_CSC_10BIT))
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003187 msm_property_install_volatile_range(
3188 &psde->property_info, "csc_v1", 0x0,
3189 0, ~0, 0, PLANE_PROP_CSC_V1);
Clarence Ip5fc00c52016-09-23 15:03:34 -04003190
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003191 if (psde->features & BIT(SDE_SSPP_HSIC)) {
3192 snprintf(feature_name, sizeof(feature_name), "%s%d",
3193 "SDE_SSPP_HUE_V",
3194 psde->pipe_sblk->hsic_blk.version >> 16);
3195 msm_property_install_range(&psde->property_info,
3196 feature_name, 0, 0, 0xFFFFFFFF, 0,
3197 PLANE_PROP_HUE_ADJUST);
3198 snprintf(feature_name, sizeof(feature_name), "%s%d",
3199 "SDE_SSPP_SATURATION_V",
3200 psde->pipe_sblk->hsic_blk.version >> 16);
3201 msm_property_install_range(&psde->property_info,
3202 feature_name, 0, 0, 0xFFFFFFFF, 0,
3203 PLANE_PROP_SATURATION_ADJUST);
3204 snprintf(feature_name, sizeof(feature_name), "%s%d",
3205 "SDE_SSPP_VALUE_V",
3206 psde->pipe_sblk->hsic_blk.version >> 16);
3207 msm_property_install_range(&psde->property_info,
3208 feature_name, 0, 0, 0xFFFFFFFF, 0,
3209 PLANE_PROP_VALUE_ADJUST);
3210 snprintf(feature_name, sizeof(feature_name), "%s%d",
3211 "SDE_SSPP_CONTRAST_V",
3212 psde->pipe_sblk->hsic_blk.version >> 16);
3213 msm_property_install_range(&psde->property_info,
3214 feature_name, 0, 0, 0xFFFFFFFF, 0,
3215 PLANE_PROP_CONTRAST_ADJUST);
3216 }
Benet Clarkeb1b4462016-06-27 14:43:06 -07003217 }
3218
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003219 if (psde->features & BIT(SDE_SSPP_EXCL_RECT))
3220 msm_property_install_volatile_range(&psde->property_info,
3221 "excl_rect_v1", 0x0, 0, ~0, 0, PLANE_PROP_EXCL_RECT_V1);
3222
Alan Kwong4dd64c82017-02-04 18:41:51 -08003223 sde_plane_rot_install_properties(plane, catalog);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003224
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04003225 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07003226 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04003227
Dhaval Patel47302cf2016-08-18 15:04:28 -07003228 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
3229 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
3230
3231 if (psde->pipe_hw->ops.setup_solidfill)
3232 msm_property_install_range(&psde->property_info, "color_fill",
3233 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
3234
Dhaval Patel4e574842016-08-23 15:11:37 -07003235 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003236 if (!info) {
3237 SDE_ERROR("failed to allocate info memory\n");
Dhaval Patel4e574842016-08-23 15:11:37 -07003238 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003239 }
Dhaval Patel4e574842016-08-23 15:11:37 -07003240
3241 msm_property_install_blob(&psde->property_info, "capabilities",
3242 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
3243 sde_kms_info_reset(info);
3244
Clarence Ipea3d6262016-07-15 16:20:11 -04003245 format_list = psde->pipe_sblk->format_list;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003246
3247 if (master_plane_id) {
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07003248 int index, array_size;
3249
3250 array_size = ARRAY_SIZE(plane_formats)
3251 + ARRAY_SIZE(rgb_10bit_formats);
3252 virt_format_list = kcalloc(array_size,
3253 sizeof(struct sde_format_extended), GFP_KERNEL);
3254 if (!virt_format_list) {
3255 SDE_ERROR(
3256 "failed to allocate virtual pipe format list\n");
3257 return;
3258 }
3259
3260 index = sde_copy_formats(virt_format_list, array_size,
3261 0, plane_formats, ARRAY_SIZE(plane_formats));
3262 sde_copy_formats(virt_format_list, array_size,
3263 index, rgb_10bit_formats,
3264 ARRAY_SIZE(rgb_10bit_formats));
3265
3266 format_list = virt_format_list;
3267
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003268 sde_kms_info_add_keyint(info, "primary_smart_plane_id",
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07003269 master_plane_id);
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08003270 }
3271
Clarence Ipea3d6262016-07-15 16:20:11 -04003272 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04003273 sde_kms_info_start(info, "pixel_formats");
3274 while (format_list->fourcc_format) {
3275 sde_kms_info_append_format(info,
3276 format_list->fourcc_format,
3277 format_list->modifier);
3278 ++format_list;
3279 }
3280 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04003281 }
Dhaval Patel4e574842016-08-23 15:11:37 -07003282
3283 sde_kms_info_add_keyint(info, "max_linewidth",
3284 psde->pipe_sblk->maxlinewidth);
3285 sde_kms_info_add_keyint(info, "max_upscale",
3286 psde->pipe_sblk->maxupscale);
3287 sde_kms_info_add_keyint(info, "max_downscale",
3288 psde->pipe_sblk->maxdwnscale);
3289 sde_kms_info_add_keyint(info, "max_horizontal_deci",
3290 psde->pipe_sblk->maxhdeciexp);
3291 sde_kms_info_add_keyint(info, "max_vertical_deci",
3292 psde->pipe_sblk->maxvdeciexp);
Alan Kwong6259a382017-04-04 06:18:02 -07003293 sde_kms_info_add_keyint(info, "max_per_pipe_bw",
3294 psde->pipe_sblk->max_per_pipe_bw * 1000LL);
Dhaval Patel4e574842016-08-23 15:11:37 -07003295 msm_property_set_blob(&psde->property_info, &psde->blob_info,
3296 info->data, info->len, PLANE_PROP_INFO);
3297
3298 kfree(info);
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07003299 kfree(virt_format_list);
Benet Clarkd009b1d2016-06-27 14:45:59 -07003300
3301 if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) {
3302 snprintf(feature_name, sizeof(feature_name), "%s%d",
3303 "SDE_SSPP_SKIN_COLOR_V",
3304 psde->pipe_sblk->memcolor_blk.version >> 16);
3305 msm_property_install_blob(&psde->property_info, feature_name, 0,
3306 PLANE_PROP_SKIN_COLOR);
3307 snprintf(feature_name, sizeof(feature_name), "%s%d",
3308 "SDE_SSPP_SKY_COLOR_V",
3309 psde->pipe_sblk->memcolor_blk.version >> 16);
3310 msm_property_install_blob(&psde->property_info, feature_name, 0,
3311 PLANE_PROP_SKY_COLOR);
3312 snprintf(feature_name, sizeof(feature_name), "%s%d",
3313 "SDE_SSPP_FOLIAGE_COLOR_V",
3314 psde->pipe_sblk->memcolor_blk.version >> 16);
3315 msm_property_install_blob(&psde->property_info, feature_name, 0,
3316 PLANE_PROP_FOLIAGE_COLOR);
3317 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003318}
3319
Clarence Ip5fc00c52016-09-23 15:03:34 -04003320static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, void *usr_ptr)
3321{
3322 struct sde_drm_csc_v1 csc_v1;
3323 int i;
3324
3325 if (!psde) {
3326 SDE_ERROR("invalid plane\n");
3327 return;
3328 }
3329
3330 psde->csc_usr_ptr = NULL;
3331 if (!usr_ptr) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003332 SDE_DEBUG_PLANE(psde, "csc data removed\n");
Clarence Ip5fc00c52016-09-23 15:03:34 -04003333 return;
3334 }
3335
3336 if (copy_from_user(&csc_v1, usr_ptr, sizeof(csc_v1))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003337 SDE_ERROR_PLANE(psde, "failed to copy csc data\n");
Clarence Ip5fc00c52016-09-23 15:03:34 -04003338 return;
3339 }
3340
Clarence Ipb43d4592016-09-08 14:21:35 -04003341 /* populate from user space */
Clarence Ip5fc00c52016-09-23 15:03:34 -04003342 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
3343 psde->csc_cfg.csc_mv[i] = csc_v1.ctm_coeff[i] >> 16;
3344 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
3345 psde->csc_cfg.csc_pre_bv[i] = csc_v1.pre_bias[i];
3346 psde->csc_cfg.csc_post_bv[i] = csc_v1.post_bias[i];
3347 }
3348 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
3349 psde->csc_cfg.csc_pre_lv[i] = csc_v1.pre_clamp[i];
3350 psde->csc_cfg.csc_post_lv[i] = csc_v1.post_clamp[i];
3351 }
3352 psde->csc_usr_ptr = &psde->csc_cfg;
3353}
3354
Clarence Ipb43d4592016-09-08 14:21:35 -04003355static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, void *usr)
3356{
3357 struct sde_drm_scaler_v1 scale_v1;
3358 struct sde_hw_pixel_ext *pe;
3359 int i;
3360
3361 if (!psde) {
3362 SDE_ERROR("invalid plane\n");
3363 return;
3364 }
3365
3366 psde->pixel_ext_usr = false;
3367 if (!usr) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003368 SDE_DEBUG_PLANE(psde, "scale data removed\n");
Clarence Ipb43d4592016-09-08 14:21:35 -04003369 return;
3370 }
3371
3372 if (copy_from_user(&scale_v1, usr, sizeof(scale_v1))) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003373 SDE_ERROR_PLANE(psde, "failed to copy scale data\n");
Clarence Ipb43d4592016-09-08 14:21:35 -04003374 return;
3375 }
3376
3377 /* populate from user space */
3378 pe = &(psde->pixel_ext);
3379 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
3380 for (i = 0; i < SDE_MAX_PLANES; i++) {
3381 pe->init_phase_x[i] = scale_v1.init_phase_x[i];
3382 pe->phase_step_x[i] = scale_v1.phase_step_x[i];
3383 pe->init_phase_y[i] = scale_v1.init_phase_y[i];
3384 pe->phase_step_y[i] = scale_v1.phase_step_y[i];
3385
3386 pe->horz_filter[i] = scale_v1.horz_filter[i];
3387 pe->vert_filter[i] = scale_v1.vert_filter[i];
3388 }
3389 for (i = 0; i < SDE_MAX_PLANES; i++) {
abeykun41060122016-11-28 13:02:01 -05003390 pe->left_ftch[i] = scale_v1.pe.left_ftch[i];
3391 pe->right_ftch[i] = scale_v1.pe.right_ftch[i];
3392 pe->left_rpt[i] = scale_v1.pe.left_rpt[i];
3393 pe->right_rpt[i] = scale_v1.pe.right_rpt[i];
3394 pe->roi_w[i] = scale_v1.pe.num_ext_pxls_lr[i];
Clarence Ipb43d4592016-09-08 14:21:35 -04003395
abeykun41060122016-11-28 13:02:01 -05003396 pe->top_ftch[i] = scale_v1.pe.top_ftch[i];
3397 pe->btm_ftch[i] = scale_v1.pe.btm_ftch[i];
3398 pe->top_rpt[i] = scale_v1.pe.top_rpt[i];
3399 pe->btm_rpt[i] = scale_v1.pe.btm_rpt[i];
3400 pe->roi_h[i] = scale_v1.pe.num_ext_pxls_tb[i];
Clarence Ipb43d4592016-09-08 14:21:35 -04003401 }
abeykun41060122016-11-28 13:02:01 -05003402
Clarence Ipb43d4592016-09-08 14:21:35 -04003403 psde->pixel_ext_usr = true;
3404
Clarence Ip13a8cf42016-09-29 17:27:47 -04003405 SDE_DEBUG_PLANE(psde, "user property data copied\n");
Clarence Ipb43d4592016-09-08 14:21:35 -04003406}
3407
abeykun48f407a2016-08-25 12:06:44 -04003408static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde,
3409 struct sde_plane_state *pstate, void *usr)
3410{
3411 struct sde_drm_scaler_v2 scale_v2;
3412 struct sde_hw_pixel_ext *pe;
3413 int i;
3414 struct sde_hw_scaler3_cfg *cfg;
3415
3416 if (!psde) {
3417 SDE_ERROR("invalid plane\n");
3418 return;
3419 }
3420
3421 cfg = psde->scaler3_cfg;
3422 psde->pixel_ext_usr = false;
3423 if (!usr) {
3424 SDE_DEBUG_PLANE(psde, "scale data removed\n");
3425 return;
3426 }
3427
3428 if (copy_from_user(&scale_v2, usr, sizeof(scale_v2))) {
3429 SDE_ERROR_PLANE(psde, "failed to copy scale data\n");
3430 return;
3431 }
3432
3433 /* populate from user space */
3434 pe = &(psde->pixel_ext);
3435 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
3436 cfg->enable = scale_v2.enable;
3437 cfg->dir_en = scale_v2.dir_en;
3438 for (i = 0; i < SDE_MAX_PLANES; i++) {
3439 cfg->init_phase_x[i] = scale_v2.init_phase_x[i];
3440 cfg->phase_step_x[i] = scale_v2.phase_step_x[i];
3441 cfg->init_phase_y[i] = scale_v2.init_phase_y[i];
3442 cfg->phase_step_y[i] = scale_v2.phase_step_y[i];
3443
3444 cfg->preload_x[i] = scale_v2.preload_x[i];
3445 cfg->preload_y[i] = scale_v2.preload_y[i];
3446 cfg->src_width[i] = scale_v2.src_width[i];
3447 cfg->src_height[i] = scale_v2.src_height[i];
3448 }
3449 cfg->dst_width = scale_v2.dst_width;
3450 cfg->dst_height = scale_v2.dst_height;
3451
3452 cfg->y_rgb_filter_cfg = scale_v2.y_rgb_filter_cfg;
3453 cfg->uv_filter_cfg = scale_v2.uv_filter_cfg;
3454 cfg->alpha_filter_cfg = scale_v2.alpha_filter_cfg;
3455 cfg->blend_cfg = scale_v2.blend_cfg;
3456
3457 cfg->lut_flag = scale_v2.lut_flag;
3458 cfg->dir_lut_idx = scale_v2.dir_lut_idx;
3459 cfg->y_rgb_cir_lut_idx = scale_v2.y_rgb_cir_lut_idx;
3460 cfg->uv_cir_lut_idx = scale_v2.uv_cir_lut_idx;
3461 cfg->y_rgb_sep_lut_idx = scale_v2.y_rgb_sep_lut_idx;
3462 cfg->uv_sep_lut_idx = scale_v2.uv_sep_lut_idx;
3463
3464 cfg->de.enable = scale_v2.de.enable;
3465 cfg->de.sharpen_level1 = scale_v2.de.sharpen_level1;
3466 cfg->de.sharpen_level2 = scale_v2.de.sharpen_level2;
3467 cfg->de.clip = scale_v2.de.clip;
3468 cfg->de.limit = scale_v2.de.limit;
3469 cfg->de.thr_quiet = scale_v2.de.thr_quiet;
3470 cfg->de.thr_dieout = scale_v2.de.thr_dieout;
3471 cfg->de.thr_low = scale_v2.de.thr_low;
3472 cfg->de.thr_high = scale_v2.de.thr_high;
3473 cfg->de.prec_shift = scale_v2.de.prec_shift;
3474 for (i = 0; i < SDE_MAX_DE_CURVES; i++) {
3475 cfg->de.adjust_a[i] = scale_v2.de.adjust_a[i];
3476 cfg->de.adjust_b[i] = scale_v2.de.adjust_b[i];
3477 cfg->de.adjust_c[i] = scale_v2.de.adjust_c[i];
3478 }
3479 for (i = 0; i < SDE_MAX_PLANES; i++) {
abeykun41060122016-11-28 13:02:01 -05003480 pe->left_ftch[i] = scale_v2.pe.left_ftch[i];
3481 pe->right_ftch[i] = scale_v2.pe.right_ftch[i];
3482 pe->left_rpt[i] = scale_v2.pe.left_rpt[i];
3483 pe->right_rpt[i] = scale_v2.pe.right_rpt[i];
3484 pe->roi_w[i] = scale_v2.pe.num_ext_pxls_lr[i];
abeykun48f407a2016-08-25 12:06:44 -04003485
abeykun41060122016-11-28 13:02:01 -05003486 pe->top_ftch[i] = scale_v2.pe.top_ftch[i];
3487 pe->btm_ftch[i] = scale_v2.pe.btm_ftch[i];
3488 pe->top_rpt[i] = scale_v2.pe.top_rpt[i];
3489 pe->btm_rpt[i] = scale_v2.pe.btm_rpt[i];
3490 pe->roi_h[i] = scale_v2.pe.num_ext_pxls_tb[i];
abeykun48f407a2016-08-25 12:06:44 -04003491 }
3492 psde->pixel_ext_usr = true;
3493
3494 SDE_DEBUG_PLANE(psde, "user property data copied\n");
3495}
3496
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003497static void _sde_plane_set_excl_rect_v1(struct sde_plane *psde,
3498 struct sde_plane_state *pstate, void *usr_ptr)
3499{
3500 struct drm_clip_rect excl_rect_v1;
3501
3502 if (!psde) {
3503 SDE_ERROR("invalid plane\n");
3504 return;
3505 }
3506
3507 if (!usr_ptr) {
Veera Sundaram Sankaran58e12812017-05-05 11:51:09 -07003508 SDE_DEBUG_PLANE(psde, "invalid excl_rect user data\n");
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003509 return;
3510 }
3511
3512 if (copy_from_user(&excl_rect_v1, usr_ptr, sizeof(excl_rect_v1))) {
Veera Sundaram Sankaran58e12812017-05-05 11:51:09 -07003513 SDE_ERROR_PLANE(psde, "failed to copy excl_rect data\n");
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003514 return;
3515 }
3516
3517 /* populate from user space */
3518 pstate->excl_rect.x = excl_rect_v1.x1;
3519 pstate->excl_rect.y = excl_rect_v1.y1;
Veera Sundaram Sankaran58e12812017-05-05 11:51:09 -07003520 pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1;
3521 pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1;
3522
3523 SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n",
3524 pstate->excl_rect.x, pstate->excl_rect.y,
3525 pstate->excl_rect.w, pstate->excl_rect.h);
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003526}
3527
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003528static int sde_plane_atomic_set_property(struct drm_plane *plane,
3529 struct drm_plane_state *state, struct drm_property *property,
3530 uint64_t val)
3531{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003532 struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003533 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04003534 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003535
Clarence Ip13a8cf42016-09-29 17:27:47 -04003536 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003537
3538 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003539 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003540 } else if (!state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003541 SDE_ERROR_PLANE(psde, "invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003542 } else {
Clarence Ip4c1d9772016-06-26 09:35:38 -04003543 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003544 ret = msm_property_atomic_set(&psde->property_info,
3545 pstate->property_values, pstate->property_blobs,
3546 property, val);
3547 if (!ret) {
3548 idx = msm_property_index(&psde->property_info,
3549 property);
Clarence Ip5fc00c52016-09-23 15:03:34 -04003550 switch (idx) {
3551 case PLANE_PROP_INPUT_FENCE:
Clarence Ip13a8cf42016-09-29 17:27:47 -04003552 _sde_plane_set_input_fence(psde, pstate, val);
Clarence Ip5fc00c52016-09-23 15:03:34 -04003553 break;
3554 case PLANE_PROP_CSC_V1:
3555 _sde_plane_set_csc_v1(psde, (void *)val);
3556 break;
Clarence Ipb43d4592016-09-08 14:21:35 -04003557 case PLANE_PROP_SCALER_V1:
3558 _sde_plane_set_scaler_v1(psde, (void *)val);
3559 break;
abeykun48f407a2016-08-25 12:06:44 -04003560 case PLANE_PROP_SCALER_V2:
3561 _sde_plane_set_scaler_v2(psde, pstate,
3562 (void *)val);
3563 break;
Veera Sundaram Sankaran02dd6ac2016-12-22 15:08:29 -08003564 case PLANE_PROP_EXCL_RECT_V1:
3565 _sde_plane_set_excl_rect_v1(psde, pstate,
3566 (void *)val);
3567 break;
Clarence Ip5fc00c52016-09-23 15:03:34 -04003568 default:
3569 /* nothing to do */
3570 break;
3571 }
Clarence Ipe78efb72016-06-24 18:35:21 -04003572 }
3573 }
3574
Alan Kwong4dd64c82017-02-04 18:41:51 -08003575 SDE_DEBUG_PLANE(psde, "%s[%d] <= 0x%llx ret=%d\n",
3576 property->name, property->base.id, val, ret);
3577
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003578 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003579}
3580
3581static int sde_plane_set_property(struct drm_plane *plane,
3582 struct drm_property *property, uint64_t val)
3583{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003584 SDE_DEBUG("\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04003585
Clarence Ipae4e60c2016-06-26 22:44:04 -04003586 return sde_plane_atomic_set_property(plane,
3587 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003588}
3589
3590static int sde_plane_atomic_get_property(struct drm_plane *plane,
3591 const struct drm_plane_state *state,
3592 struct drm_property *property, uint64_t *val)
3593{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003594 struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003595 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04003596 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003597
Clarence Ipaa0faf42016-05-30 12:07:48 -04003598 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003599 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003600 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003601 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003602 } else {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003603 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ip4c1d9772016-06-26 09:35:38 -04003604 pstate = to_sde_plane_state(state);
Alan Kwong4dd64c82017-02-04 18:41:51 -08003605 sde_plane_rot_install_caps(plane);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003606 ret = msm_property_atomic_get(&psde->property_info,
3607 pstate->property_values, pstate->property_blobs,
3608 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04003609 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003610
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003611 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003612}
3613
3614static void sde_plane_destroy(struct drm_plane *plane)
3615{
Clarence Ip13a8cf42016-09-29 17:27:47 -04003616 struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003617
Clarence Ip13a8cf42016-09-29 17:27:47 -04003618 SDE_DEBUG_PLANE(psde, "\n");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003619
Clarence Ip13a8cf42016-09-29 17:27:47 -04003620 if (psde) {
Alan Kwong1a00e4d2016-07-18 09:42:30 -04003621 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
3622
Dhaval Patel4e574842016-08-23 15:11:37 -07003623 if (psde->blob_info)
3624 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003625 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04003626 mutex_destroy(&psde->lock);
3627
Clarence Ip4ce59322016-06-26 22:27:51 -04003628 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003629
Clarence Ip4ce59322016-06-26 22:27:51 -04003630 /* this will destroy the states as well */
3631 drm_plane_cleanup(plane);
3632
Clarence Ip4c1d9772016-06-26 09:35:38 -04003633 if (psde->pipe_hw)
3634 sde_hw_sspp_destroy(psde->pipe_hw);
3635
Clarence Ip4ce59322016-06-26 22:27:51 -04003636 kfree(psde);
3637 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003638}
3639
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003640static void sde_plane_destroy_state(struct drm_plane *plane,
3641 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003642{
Clarence Ipaa0faf42016-05-30 12:07:48 -04003643 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04003644 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04003645
Clarence Ipae4e60c2016-06-26 22:44:04 -04003646 if (!plane || !state) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04003647 SDE_ERROR("invalid arg(s), plane %d state %d\n",
3648 plane != 0, state != 0);
Clarence Ipae4e60c2016-06-26 22:44:04 -04003649 return;
3650 }
3651
Clarence Ipaa0faf42016-05-30 12:07:48 -04003652 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04003653 pstate = to_sde_plane_state(state);
3654
Clarence Ip13a8cf42016-09-29 17:27:47 -04003655 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003656
Alan Kwong4dd64c82017-02-04 18:41:51 -08003657 sde_plane_rot_destroy_state(plane, &pstate->base);
3658
Clarence Ipe78efb72016-06-24 18:35:21 -04003659 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003660 if (state->fb)
3661 drm_framebuffer_unreference(state->fb);
3662
Clarence Ipae4e60c2016-06-26 22:44:04 -04003663 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04003664 if (pstate->input_fence)
3665 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04003666
Clarence Ipaa0faf42016-05-30 12:07:48 -04003667 /* destroy value helper */
3668 msm_property_destroy_state(&psde->property_info, pstate,
3669 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003670}
3671
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003672static struct drm_plane_state *
3673sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003674{
Clarence Ipaa0faf42016-05-30 12:07:48 -04003675 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003676 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04003677 struct sde_plane_state *old_state;
Clarence Ip17e908b2016-09-29 15:58:00 -04003678 uint64_t input_fence_default;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003679
Clarence Ip13a8cf42016-09-29 17:27:47 -04003680 if (!plane) {
3681 SDE_ERROR("invalid plane\n");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003682 return NULL;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003683 } else if (!plane->state) {
3684 SDE_ERROR("invalid plane state\n");
3685 return NULL;
3686 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003687
Clarence Ip730e7192016-06-26 22:45:09 -04003688 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003689 psde = to_sde_plane(plane);
3690 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003691 if (!pstate) {
3692 SDE_ERROR_PLANE(psde, "failed to allocate state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003693 return NULL;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003694 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003695
Clarence Ip13a8cf42016-09-29 17:27:47 -04003696 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003697
3698 /* duplicate value helper */
3699 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
3700 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04003701
Clarence Ip17e908b2016-09-29 15:58:00 -04003702 /* clear out any input fence */
3703 pstate->input_fence = 0;
3704 input_fence_default = msm_property_get_default(
3705 &psde->property_info, PLANE_PROP_INPUT_FENCE);
3706 msm_property_set_property(&psde->property_info, pstate->property_values,
3707 PLANE_PROP_INPUT_FENCE, input_fence_default);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003708
Clarence Ip282dad62016-09-27 17:07:35 -04003709 pstate->dirty = 0x0;
Clarence Ip730e7192016-06-26 22:45:09 -04003710 pstate->pending = false;
3711
Alan Kwongcdb2f282017-03-18 13:42:06 -07003712 __drm_atomic_helper_plane_duplicate_state(plane, &pstate->base);
3713
Alan Kwong4dd64c82017-02-04 18:41:51 -08003714 sde_plane_rot_duplicate_state(plane, &pstate->base);
3715
Clarence Ip730e7192016-06-26 22:45:09 -04003716 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003717}
3718
3719static void sde_plane_reset(struct drm_plane *plane)
3720{
Clarence Ipae4e60c2016-06-26 22:44:04 -04003721 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003722 struct sde_plane_state *pstate;
3723
Clarence Ipae4e60c2016-06-26 22:44:04 -04003724 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07003725 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04003726 return;
3727 }
3728
Clarence Ip730e7192016-06-26 22:45:09 -04003729 psde = to_sde_plane(plane);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003730 SDE_DEBUG_PLANE(psde, "\n");
Clarence Ip730e7192016-06-26 22:45:09 -04003731
Clarence Ipae4e60c2016-06-26 22:44:04 -04003732 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04003733 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04003734 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04003735 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04003736 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003737
Clarence Ipaa0faf42016-05-30 12:07:48 -04003738 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip13a8cf42016-09-29 17:27:47 -04003739 if (!pstate) {
3740 SDE_ERROR_PLANE(psde, "failed to allocate state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04003741 return;
Clarence Ip13a8cf42016-09-29 17:27:47 -04003742 }
Clarence Ip730e7192016-06-26 22:45:09 -04003743
Clarence Ipaa0faf42016-05-30 12:07:48 -04003744 /* reset value helper */
3745 msm_property_reset_state(&psde->property_info, pstate,
3746 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04003747
3748 pstate->base.plane = plane;
3749
3750 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07003751}
3752
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003753#ifdef CONFIG_DEBUG_FS
Alan Kwongf0fd8512016-10-24 21:39:26 -04003754static ssize_t _sde_plane_danger_read(struct file *file,
3755 char __user *buff, size_t count, loff_t *ppos)
3756{
3757 struct sde_kms *kms = file->private_data;
3758 struct sde_mdss_cfg *cfg = kms->catalog;
3759 int len = 0;
3760 char buf[40] = {'\0'};
3761
3762 if (!cfg)
3763 return -ENODEV;
3764
3765 if (*ppos)
3766 return 0; /* the end */
3767
3768 len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);
3769 if (len < 0 || len >= sizeof(buf))
3770 return 0;
3771
3772 if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
3773 return -EFAULT;
3774
3775 *ppos += len; /* increase offset */
3776
3777 return len;
3778}
3779
3780static void _sde_plane_set_danger_state(struct sde_kms *kms, bool enable)
3781{
3782 struct drm_plane *plane;
3783
3784 drm_for_each_plane(plane, kms->dev) {
3785 if (plane->fb && plane->state) {
3786 sde_plane_danger_signal_ctrl(plane, enable);
3787 SDE_DEBUG("plane:%d img:%dx%d ",
3788 plane->base.id, plane->fb->width,
3789 plane->fb->height);
3790 SDE_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",
3791 plane->state->src_x >> 16,
3792 plane->state->src_y >> 16,
3793 plane->state->src_w >> 16,
3794 plane->state->src_h >> 16,
3795 plane->state->crtc_x, plane->state->crtc_y,
3796 plane->state->crtc_w, plane->state->crtc_h);
3797 } else {
3798 SDE_DEBUG("Inactive plane:%d\n", plane->base.id);
3799 }
3800 }
3801}
3802
3803static ssize_t _sde_plane_danger_write(struct file *file,
3804 const char __user *user_buf, size_t count, loff_t *ppos)
3805{
3806 struct sde_kms *kms = file->private_data;
3807 struct sde_mdss_cfg *cfg = kms->catalog;
3808 int disable_panic;
3809 char buf[10];
3810
3811 if (!cfg)
3812 return -EFAULT;
3813
3814 if (count >= sizeof(buf))
3815 return -EFAULT;
3816
3817 if (copy_from_user(buf, user_buf, count))
3818 return -EFAULT;
3819
3820 buf[count] = 0; /* end of string */
3821
3822 if (kstrtoint(buf, 0, &disable_panic))
3823 return -EFAULT;
3824
3825 if (disable_panic) {
3826 /* Disable panic signal for all active pipes */
3827 SDE_DEBUG("Disabling danger:\n");
3828 _sde_plane_set_danger_state(kms, false);
3829 kms->has_danger_ctrl = false;
3830 } else {
3831 /* Enable panic signal for all active pipes */
3832 SDE_DEBUG("Enabling danger:\n");
3833 kms->has_danger_ctrl = true;
3834 _sde_plane_set_danger_state(kms, true);
3835 }
3836
3837 return count;
3838}
3839
3840static const struct file_operations sde_plane_danger_enable = {
3841 .open = simple_open,
3842 .read = _sde_plane_danger_read,
3843 .write = _sde_plane_danger_write,
3844};
3845
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003846static int _sde_plane_init_debugfs(struct drm_plane *plane)
Clarence Ip4ce59322016-06-26 22:27:51 -04003847{
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003848 struct sde_plane *psde;
3849 struct sde_kms *kms;
3850 struct msm_drm_private *priv;
Clarence Ip4ce59322016-06-26 22:27:51 -04003851 const struct sde_sspp_sub_blks *sblk = 0;
3852 const struct sde_sspp_cfg *cfg = 0;
3853
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003854 if (!plane || !plane->dev) {
3855 SDE_ERROR("invalid arguments\n");
3856 return -EINVAL;
3857 }
3858
3859 priv = plane->dev->dev_private;
3860 if (!priv || !priv->kms) {
3861 SDE_ERROR("invalid KMS reference\n");
3862 return -EINVAL;
3863 }
3864
3865 kms = to_sde_kms(priv->kms);
3866 psde = to_sde_plane(plane);
3867
Clarence Ip4ce59322016-06-26 22:27:51 -04003868 if (psde && psde->pipe_hw)
3869 cfg = psde->pipe_hw->cap;
3870 if (cfg)
3871 sblk = cfg->sblk;
3872
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003873 if (!sblk)
3874 return 0;
Clarence Ip4ce59322016-06-26 22:27:51 -04003875
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003876 /* create overall sub-directory for the pipe */
3877 psde->debugfs_root =
3878 debugfs_create_dir(psde->pipe_name,
Lloyd Atkinson09e64bf2017-04-13 14:09:59 -07003879 plane->dev->primary->debugfs_root);
Clarence Ip4ce59322016-06-26 22:27:51 -04003880
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003881 if (!psde->debugfs_root)
3882 return -ENOMEM;
Clarence Ip4ce59322016-06-26 22:27:51 -04003883
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003884 /* don't error check these */
3885 debugfs_create_x32("features", 0644,
3886 psde->debugfs_root, &psde->features);
Alan Kwongf0fd8512016-10-24 21:39:26 -04003887
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003888 /* add register dump support */
3889 sde_debugfs_setup_regset32(&psde->debugfs_src,
3890 sblk->src_blk.base + cfg->base,
3891 sblk->src_blk.len,
3892 kms);
3893 sde_debugfs_create_regset32("src_blk", 0444,
3894 psde->debugfs_root, &psde->debugfs_src);
Alan Kwongf0fd8512016-10-24 21:39:26 -04003895
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003896 if (cfg->features & BIT(SDE_SSPP_SCALER_QSEED3) ||
3897 cfg->features & BIT(SDE_SSPP_SCALER_QSEED2)) {
3898 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
3899 sblk->scaler_blk.base + cfg->base,
3900 sblk->scaler_blk.len,
3901 kms);
3902 sde_debugfs_create_regset32("scaler_blk", 0444,
3903 psde->debugfs_root,
3904 &psde->debugfs_scaler);
Clarence Ip716ab662017-03-20 06:51:24 -07003905 debugfs_create_bool("default_scaling",
3906 0644,
3907 psde->debugfs_root,
3908 &psde->debugfs_default_scale);
Clarence Ip4ce59322016-06-26 22:27:51 -04003909 }
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003910
3911 if (cfg->features & BIT(SDE_SSPP_CSC) ||
3912 cfg->features & BIT(SDE_SSPP_CSC_10BIT)) {
3913 sde_debugfs_setup_regset32(&psde->debugfs_csc,
3914 sblk->csc_blk.base + cfg->base,
3915 sblk->csc_blk.len,
3916 kms);
3917 sde_debugfs_create_regset32("csc_blk", 0444,
3918 psde->debugfs_root, &psde->debugfs_csc);
3919 }
3920
3921 debugfs_create_u32("xin_id",
3922 0444,
3923 psde->debugfs_root,
3924 (u32 *) &cfg->xin_id);
3925 debugfs_create_u32("clk_ctrl",
3926 0444,
3927 psde->debugfs_root,
3928 (u32 *) &cfg->clk_ctrl);
3929 debugfs_create_x32("creq_vblank",
3930 0644,
3931 psde->debugfs_root,
3932 (u32 *) &sblk->creq_vblank);
3933 debugfs_create_x32("danger_vblank",
3934 0644,
3935 psde->debugfs_root,
3936 (u32 *) &sblk->danger_vblank);
3937
3938 debugfs_create_file("disable_danger",
3939 0644,
3940 psde->debugfs_root,
3941 kms, &sde_plane_danger_enable);
Alan Kwong4dd64c82017-02-04 18:41:51 -08003942 debugfs_create_u32("sbuf_mode",
3943 0644,
3944 psde->debugfs_root, &psde->sbuf_mode);
3945 debugfs_create_u32("sbuf_writeback",
3946 0644,
3947 psde->debugfs_root,
3948 &psde->sbuf_writeback);
Lloyd Atkinsonb020e0f2017-03-14 08:05:18 -07003949
3950 return 0;
3951}
3952
3953static void _sde_plane_destroy_debugfs(struct drm_plane *plane)
3954{
3955 struct sde_plane *psde;
3956
3957 if (!plane)
3958 return;
3959 psde = to_sde_plane(plane);
3960
3961 debugfs_remove_recursive(psde->debugfs_root);
3962}
3963#else
3964static int _sde_plane_init_debugfs(struct drm_plane *plane)
3965{
3966 return 0;
3967}
3968static void _sde_plane_destroy_debugfs(struct drm_plane *plane)
3969{
3970}
3971#endif
3972
3973static int sde_plane_late_register(struct drm_plane *plane)
3974{
3975 return _sde_plane_init_debugfs(plane);
3976}
3977
3978static void sde_plane_early_unregister(struct drm_plane *plane)
3979{
3980 _sde_plane_destroy_debugfs(plane);
3981}
3982
3983static const struct drm_plane_funcs sde_plane_funcs = {
3984 .update_plane = drm_atomic_helper_update_plane,
3985 .disable_plane = drm_atomic_helper_disable_plane,
3986 .destroy = sde_plane_destroy,
3987 .set_property = sde_plane_set_property,
3988 .atomic_set_property = sde_plane_atomic_set_property,
3989 .atomic_get_property = sde_plane_atomic_get_property,
3990 .reset = sde_plane_reset,
3991 .atomic_duplicate_state = sde_plane_duplicate_state,
3992 .atomic_destroy_state = sde_plane_destroy_state,
3993 .late_register = sde_plane_late_register,
3994 .early_unregister = sde_plane_early_unregister,
3995};
3996
3997static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
3998 .prepare_fb = sde_plane_prepare_fb,
3999 .cleanup_fb = sde_plane_cleanup_fb,
4000 .atomic_check = sde_plane_atomic_check,
4001 .atomic_update = sde_plane_atomic_update,
4002};
4003
4004enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
4005{
4006 return plane ? to_sde_plane(plane)->pipe : SSPP_NONE;
4007}
4008
4009bool is_sde_plane_virtual(struct drm_plane *plane)
4010{
4011 return plane ? to_sde_plane(plane)->is_virtual : false;
Clarence Ip4ce59322016-06-26 22:27:51 -04004012}
4013
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004014/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04004015struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip2bbf7b32016-09-23 15:07:16 -04004016 uint32_t pipe, bool primary_plane,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004017 unsigned long possible_crtcs, u32 master_plane_id)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004018{
4019 struct drm_plane *plane = NULL;
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004020 const struct sde_format_extended *format_list;
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07004021 struct sde_format_extended *virt_format_list = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004022 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004023 struct msm_drm_private *priv;
4024 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004025 enum drm_plane_type type;
Clarence Ipc47a0692016-10-11 10:54:17 -04004026 int ret = -EINVAL;
Clarence Ip4c1d9772016-06-26 09:35:38 -04004027
4028 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004029 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04004030 goto exit;
4031 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004032
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004033 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04004034 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004035 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04004036 goto exit;
4037 }
4038
4039 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004040 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04004041 goto exit;
4042 }
4043 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004044
Clarence Ip4c1d9772016-06-26 09:35:38 -04004045 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004046 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04004047 goto exit;
4048 }
4049
Clarence Ip4ce59322016-06-26 22:27:51 -04004050 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004051 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
4052 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004053 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004054 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04004055 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004056 }
4057
Clarence Ip4c1d9772016-06-26 09:35:38 -04004058 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004059 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004060 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04004061 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004062 psde->is_virtual = (master_plane_id != 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004063
Clarence Ip4c1d9772016-06-26 09:35:38 -04004064 /* initialize underlying h/w driver */
4065 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
4066 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004067 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04004068 ret = PTR_ERR(psde->pipe_hw);
4069 goto clean_plane;
4070 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004071 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04004072 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004073 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04004074
4075 /* cache features mask for later */
4076 psde->features = psde->pipe_hw->cap->features;
4077 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04004078 if (!psde->pipe_sblk) {
Clarence Ip13a8cf42016-09-29 17:27:47 -04004079 SDE_ERROR("[%u]invalid sblk\n", pipe);
Clarence Ipea3d6262016-07-15 16:20:11 -04004080 goto clean_sspp;
4081 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04004082
abeykun48f407a2016-08-25 12:06:44 -04004083 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
4084 psde->scaler3_cfg = kzalloc(sizeof(struct sde_hw_scaler3_cfg),
4085 GFP_KERNEL);
4086 if (!psde->scaler3_cfg) {
4087 SDE_ERROR("[%u]failed to allocate scale struct\n",
4088 pipe);
4089 ret = -ENOMEM;
4090 goto clean_sspp;
4091 }
4092 }
4093
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004094 format_list = psde->pipe_sblk->format_list;
4095
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07004096 if (master_plane_id) {
4097 int index, array_size;
4098
4099 array_size = ARRAY_SIZE(plane_formats)
4100 + ARRAY_SIZE(rgb_10bit_formats);
4101 virt_format_list = kcalloc(array_size,
4102 sizeof(struct sde_format_extended),
4103 GFP_KERNEL);
4104 if (!virt_format_list) {
4105 SDE_ERROR(
4106 "failed to allocate virtual pipe format list\n");
4107 goto clean_sspp;
4108 }
4109
4110 index = sde_copy_formats(virt_format_list, array_size,
4111 0, plane_formats, ARRAY_SIZE(plane_formats));
4112 sde_copy_formats(virt_format_list, array_size,
4113 index, rgb_10bit_formats,
4114 ARRAY_SIZE(rgb_10bit_formats));
4115
4116 format_list = virt_format_list;
4117 }
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004118
Jeykumar Sankaran6d343142017-03-15 18:41:10 -07004119 psde->nformats = sde_populate_formats(format_list,
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004120 psde->formats,
4121 0,
4122 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004123
Clarence Ip4c1d9772016-06-26 09:35:38 -04004124 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07004125 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04004126 goto clean_sspp;
4127 }
4128
4129 if (psde->features & BIT(SDE_SSPP_CURSOR))
4130 type = DRM_PLANE_TYPE_CURSOR;
4131 else if (primary_plane)
4132 type = DRM_PLANE_TYPE_PRIMARY;
4133 else
4134 type = DRM_PLANE_TYPE_OVERLAY;
Dhaval Patel04c7e8e2016-09-26 20:14:31 -07004135 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
4136 psde->formats, psde->nformats,
4137 type, NULL);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004138 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04004139 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004140
Clarence Ip4c1d9772016-06-26 09:35:38 -04004141 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04004142 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004143
Clarence Ipaa0faf42016-05-30 12:07:48 -04004144 msm_property_init(&psde->property_info, &plane->base, dev,
4145 priv->plane_property, psde->property_data,
4146 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
4147 sizeof(struct sde_plane_state));
4148
Jeykumar Sankaran2e655032017-02-04 14:05:45 -08004149 _sde_plane_install_properties(plane, kms->catalog, master_plane_id);
Clarence Ip5e2a9222016-06-26 22:38:24 -04004150
Clarence Ip4ce59322016-06-26 22:27:51 -04004151 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04004152 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04004153
Clarence Ip730e7192016-06-26 22:45:09 -04004154 mutex_init(&psde->lock);
4155
Dhaval Patel82c8dbc2017-02-18 23:15:10 -08004156 SDE_DEBUG("%s created for pipe %u\n", psde->pipe_name, pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004157 return plane;
4158
Clarence Ip4c1d9772016-06-26 09:35:38 -04004159clean_sspp:
4160 if (psde && psde->pipe_hw)
4161 sde_hw_sspp_destroy(psde->pipe_hw);
abeykun48f407a2016-08-25 12:06:44 -04004162
4163 if (psde && psde->scaler3_cfg)
4164 kfree(psde->scaler3_cfg);
Clarence Ip4c1d9772016-06-26 09:35:38 -04004165clean_plane:
4166 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04004167exit:
Jeykumar Sankaranf55e65b2017-05-10 21:46:14 -07004168 kfree(virt_format_list);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07004169 return ERR_PTR(ret);
4170}