blob: a67f63d3b31f14a4a8ca21d993a0c0169ee0a993 [file] [log] [blame]
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
Alan Kwong1a00e4d2016-07-18 09:42:30 -040012
13#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
14
Clarence Ip4ce59322016-06-26 22:27:51 -040015#include <linux/debugfs.h>
Clarence Ip5e2a9222016-06-26 22:38:24 -040016#include <uapi/drm/sde_drm.h>
Clarence Ipaa0faf42016-05-30 12:07:48 -040017
18#include "msm_prop.h"
19
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070020#include "sde_kms.h"
Clarence Ipae4e60c2016-06-26 22:44:04 -040021#include "sde_fence.h"
Clarence Ipc475b082016-06-26 09:27:23 -040022#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040023#include "sde_hw_sspp.h"
Alan Kwong1a00e4d2016-07-18 09:42:30 -040024#include "sde_trace.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040025
26#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
27#define PHASE_STEP_SHIFT 21
28#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
29#define PHASE_RESIDUAL 15
30
Clarence Ipe78efb72016-06-24 18:35:21 -040031#define SHARP_STRENGTH_DEFAULT 32
32#define SHARP_EDGE_THR_DEFAULT 112
33#define SHARP_SMOOTH_THR_DEFAULT 8
34#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040035
Clarence Ip5e2a9222016-06-26 22:38:24 -040036#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070037
Clarence Ipcae1bb62016-07-07 12:07:13 -040038#define SDE_PLANE_COLOR_FILL_FLAG BIT(31)
39
Alan Kwong1a00e4d2016-07-18 09:42:30 -040040/**
41 * enum sde_plane_qos - Different qos configurations for each pipe
42 *
43 * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe.
44 * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe.
45 * this configuration is mutually exclusive from VBLANK_CTRL.
46 * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe.
47 */
48enum sde_plane_qos {
49 SDE_PLANE_QOS_VBLANK_CTRL = BIT(0),
50 SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1),
51 SDE_PLANE_QOS_PANIC_CTRL = BIT(2),
52};
53
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070054struct sde_plane {
55 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040056
57 int mmu_id;
58
Clarence Ip730e7192016-06-26 22:45:09 -040059 struct mutex lock;
60
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040061 enum sde_sspp pipe;
62 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070063 uint32_t nformats;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -040064 uint32_t formats[64];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040065
66 struct sde_hw_pipe *pipe_hw;
67 struct sde_hw_pipe_cfg pipe_cfg;
68 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040069 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040070 struct sde_hw_scaler3_cfg scaler3_cfg;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040071 struct sde_hw_pipe_qos_cfg pipe_qos_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -040072 uint32_t color_fill;
73 bool is_error;
Alan Kwong1a00e4d2016-07-18 09:42:30 -040074 bool is_rt_pipe;
Clarence Ip4ce59322016-06-26 22:27:51 -040075
Clarence Ip373f8592016-05-26 00:58:42 -040076 struct sde_csc_cfg csc_cfg;
77 struct sde_csc_cfg *csc_ptr;
78
Clarence Ip4c1d9772016-06-26 09:35:38 -040079 const struct sde_sspp_sub_blks *pipe_sblk;
80
Clarence Ip5e2a9222016-06-26 22:38:24 -040081 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040082
Clarence Ipaa0faf42016-05-30 12:07:48 -040083 struct msm_property_info property_info;
84 struct msm_property_data property_data[PLANE_PROP_COUNT];
Dhaval Patel4e574842016-08-23 15:11:37 -070085 struct drm_property_blob *blob_info;
Clarence Ip730e7192016-06-26 22:45:09 -040086
Clarence Ip4ce59322016-06-26 22:27:51 -040087 /* debugfs related stuff */
88 struct dentry *debugfs_root;
89 struct sde_debugfs_regset32 debugfs_src;
90 struct sde_debugfs_regset32 debugfs_scaler;
91 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070092};
Dhaval Patel47302cf2016-08-18 15:04:28 -070093
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070094#define to_sde_plane(x) container_of(x, struct sde_plane, base)
95
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040096static bool sde_plane_enabled(struct drm_plane_state *state)
97{
Clarence Ipdbde9832016-06-26 09:48:36 -040098 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040099}
100
Alan Kwong1a00e4d2016-07-18 09:42:30 -0400101/**
102 * _sde_plane_calc_fill_level - calculate fill level of the given source format
103 * @plane: Pointer to drm plane
104 * @fmt: Pointer to source buffer format
105 * @src_wdith: width of source buffer
106 * Return: fill level corresponding to the source buffer/format or 0 if error
107 */
108static inline int _sde_plane_calc_fill_level(struct drm_plane *plane,
109 const struct sde_format *fmt, u32 src_width)
110{
111 struct sde_plane *psde;
112 u32 fixed_buff_size;
113 u32 total_fl;
114
115 if (!plane || !fmt) {
116 SDE_ERROR("invalid arguments\n");
117 return 0;
118 }
119
120 psde = to_sde_plane(plane);
121 fixed_buff_size = psde->pipe_sblk->pixel_ram_size;
122
123 if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) {
124 if (fmt->chroma_sample == SDE_CHROMA_420) {
125 /* NV12 */
126 total_fl = (fixed_buff_size / 2) /
127 ((src_width + 32) * fmt->bpp);
128 } else {
129 /* non NV12 */
130 total_fl = (fixed_buff_size) /
131 ((src_width + 32) * fmt->bpp);
132 }
133 } else {
134 total_fl = (fixed_buff_size * 2) /
135 ((src_width + 32) * fmt->bpp);
136 }
137
138 SDE_DEBUG("plane%u: pnum:%d fmt:%x w:%u fl:%u\n",
139 plane->base.id, psde->pipe - SSPP_VIG0,
140 fmt->base.pixel_format, src_width, total_fl);
141
142 return total_fl;
143}
144
145/**
146 * _sde_plane_get_qos_lut_linear - get linear LUT mapping
147 * @total_fl: fill level
148 * Return: LUT setting corresponding to the fill level
149 */
150static inline u32 _sde_plane_get_qos_lut_linear(u32 total_fl)
151{
152 u32 qos_lut;
153
154 if (total_fl <= 4)
155 qos_lut = 0x1B;
156 else if (total_fl <= 5)
157 qos_lut = 0x5B;
158 else if (total_fl <= 6)
159 qos_lut = 0x15B;
160 else if (total_fl <= 7)
161 qos_lut = 0x55B;
162 else if (total_fl <= 8)
163 qos_lut = 0x155B;
164 else if (total_fl <= 9)
165 qos_lut = 0x555B;
166 else if (total_fl <= 10)
167 qos_lut = 0x1555B;
168 else if (total_fl <= 11)
169 qos_lut = 0x5555B;
170 else if (total_fl <= 12)
171 qos_lut = 0x15555B;
172 else
173 qos_lut = 0x55555B;
174
175 return qos_lut;
176}
177
178/**
179 * _sde_plane_get_qos_lut_macrotile - get macrotile LUT mapping
180 * @total_fl: fill level
181 * Return: LUT setting corresponding to the fill level
182 */
183static inline u32 _sde_plane_get_qos_lut_macrotile(u32 total_fl)
184{
185 u32 qos_lut;
186
187 if (total_fl <= 10)
188 qos_lut = 0x1AAff;
189 else if (total_fl <= 11)
190 qos_lut = 0x5AAFF;
191 else if (total_fl <= 12)
192 qos_lut = 0x15AAFF;
193 else
194 qos_lut = 0x55AAFF;
195
196 return qos_lut;
197}
198
199/**
200 * _sde_plane_is_rt_pipe - check if the given plane requires real-time QoS
201 * @plane: Pointer to drm plane
202 * @crtc: Pointer to drm crtc associated with the given plane
203 */
204static bool _sde_plane_is_rt_pipe(struct drm_plane *plane,
205 struct drm_crtc *crtc)
206{
207 struct sde_plane *psde = to_sde_plane(plane);
208 struct drm_connector *connector;
209 bool is_rt = false;
210
211 /* check if this plane has a physical connector interface */
212 drm_for_each_connector(connector, plane->dev)
213 if (connector->state &&
214 (connector->state->crtc == crtc) &&
215 (connector->connector_type
216 != DRM_MODE_CONNECTOR_VIRTUAL)) {
217 is_rt = true;
218 break;
219 }
220
221 SDE_DEBUG("plane%u: pnum:%d rt:%d\n",
222 plane->base.id, psde->pipe - SSPP_VIG0, is_rt);
223
224 return is_rt;
225}
226
227/**
228 * _sde_plane_set_qos_lut - set QoS LUT of the given plane
229 * @plane: Pointer to drm plane
230 * @fb: Pointer to framebuffer associated with the given plane
231 */
232static void _sde_plane_set_qos_lut(struct drm_plane *plane,
233 struct drm_framebuffer *fb)
234{
235 struct sde_plane *psde;
236 const struct sde_format *fmt = NULL;
237 u32 qos_lut;
238 u32 total_fl = 0;
239
240 if (!plane || !fb) {
241 SDE_ERROR("invalid arguments plane %d fb %d\n",
242 plane != 0, fb != 0);
243 return;
244 }
245
246 psde = to_sde_plane(plane);
247
248 if (!psde->pipe_hw || !psde->pipe_sblk) {
249 SDE_ERROR("invalid arguments\n");
250 return;
251 } else if (!psde->pipe_hw->ops.setup_creq_lut) {
252 return;
253 }
254
255 if (!psde->is_rt_pipe) {
256 qos_lut = psde->pipe_sblk->creq_lut_nrt;
257 } else {
258 fmt = sde_get_sde_format_ext(
259 fb->pixel_format,
260 fb->modifier,
261 drm_format_num_planes(fb->pixel_format));
262 total_fl = _sde_plane_calc_fill_level(plane, fmt,
263 psde->pipe_cfg.src_rect.w);
264
265 if (SDE_FORMAT_IS_LINEAR(fmt))
266 qos_lut = _sde_plane_get_qos_lut_linear(total_fl);
267 else
268 qos_lut = _sde_plane_get_qos_lut_macrotile(total_fl);
269 }
270
271 psde->pipe_qos_cfg.creq_lut = qos_lut;
272
273 trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0,
274 (fmt) ? fmt->base.pixel_format : 0,
275 psde->is_rt_pipe, total_fl, qos_lut,
276 (fmt) ? SDE_FORMAT_IS_LINEAR(fmt) : 0);
277
278 SDE_DEBUG("plane%u: pnum:%d fmt:%x rt:%d fl:%u lut:0x%x\n",
279 plane->base.id,
280 psde->pipe - SSPP_VIG0,
281 (fmt) ? fmt->base.pixel_format : 0,
282 psde->is_rt_pipe, total_fl, qos_lut);
283
284 psde->pipe_hw->ops.setup_creq_lut(psde->pipe_hw, &psde->pipe_qos_cfg);
285}
286
287/**
288 * _sde_plane_set_panic_lut - set danger/safe LUT of the given plane
289 * @plane: Pointer to drm plane
290 * @fb: Pointer to framebuffer associated with the given plane
291 */
292static void _sde_plane_set_danger_lut(struct drm_plane *plane,
293 struct drm_framebuffer *fb)
294{
295 struct sde_plane *psde;
296 const struct sde_format *fmt = NULL;
297 u32 danger_lut, safe_lut;
298
299 if (!plane || !fb) {
300 SDE_ERROR("invalid arguments\n");
301 return;
302 }
303
304 psde = to_sde_plane(plane);
305
306 if (!psde->pipe_hw || !psde->pipe_sblk) {
307 SDE_ERROR("invalid arguments\n");
308 return;
309 } else if (!psde->pipe_hw->ops.setup_danger_safe_lut) {
310 return;
311 }
312
313 if (!psde->is_rt_pipe) {
314 danger_lut = psde->pipe_sblk->danger_lut_nrt;
315 safe_lut = psde->pipe_sblk->safe_lut_nrt;
316 } else {
317 fmt = sde_get_sde_format_ext(
318 fb->pixel_format,
319 fb->modifier,
320 drm_format_num_planes(fb->pixel_format));
321
322 if (SDE_FORMAT_IS_LINEAR(fmt)) {
323 danger_lut = psde->pipe_sblk->danger_lut_linear;
324 safe_lut = psde->pipe_sblk->safe_lut_linear;
325 } else {
326 danger_lut = psde->pipe_sblk->danger_lut_tile;
327 safe_lut = psde->pipe_sblk->safe_lut_tile;
328 }
329 }
330
331 psde->pipe_qos_cfg.danger_lut = danger_lut;
332 psde->pipe_qos_cfg.safe_lut = safe_lut;
333
334 trace_sde_perf_set_danger_luts(psde->pipe - SSPP_VIG0,
335 (fmt) ? fmt->base.pixel_format : 0,
336 (fmt) ? fmt->fetch_mode : 0,
337 psde->pipe_qos_cfg.danger_lut,
338 psde->pipe_qos_cfg.safe_lut);
339
340 SDE_DEBUG("plane%u: pnum:%d fmt:%x mode:%d luts[0x%x, 0x%x]\n",
341 plane->base.id,
342 psde->pipe - SSPP_VIG0,
343 fmt ? fmt->base.pixel_format : 0,
344 fmt ? fmt->fetch_mode : -1,
345 psde->pipe_qos_cfg.danger_lut,
346 psde->pipe_qos_cfg.safe_lut);
347
348 psde->pipe_hw->ops.setup_danger_safe_lut(psde->pipe_hw,
349 &psde->pipe_qos_cfg);
350}
351
352/**
353 * _sde_plane_set_qos_ctrl - set QoS control of the given plane
354 * @plane: Pointer to drm plane
355 * @enable: true to enable QoS control
356 * @flags: QoS control mode (enum sde_plane_qos)
357 */
358static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
359 bool enable, u32 flags)
360{
361 struct sde_plane *psde;
362
363 if (!plane) {
364 SDE_ERROR("invalid arguments\n");
365 return;
366 }
367
368 psde = to_sde_plane(plane);
369
370 if (!psde->pipe_hw || !psde->pipe_sblk) {
371 SDE_ERROR("invalid arguments\n");
372 return;
373 } else if (!psde->pipe_hw->ops.setup_qos_ctrl) {
374 return;
375 }
376
377 if (flags & SDE_PLANE_QOS_VBLANK_CTRL) {
378 psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank;
379 psde->pipe_qos_cfg.danger_vblank =
380 psde->pipe_sblk->danger_vblank;
381 psde->pipe_qos_cfg.vblank_en = enable;
382 }
383
384 if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) {
385 /* this feature overrules previous VBLANK_CTRL */
386 psde->pipe_qos_cfg.vblank_en = false;
387 psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */
388 }
389
390 if (flags & SDE_PLANE_QOS_PANIC_CTRL)
391 psde->pipe_qos_cfg.danger_safe_en = enable;
392
393 if (!psde->is_rt_pipe) {
394 psde->pipe_qos_cfg.vblank_en = false;
395 psde->pipe_qos_cfg.danger_safe_en = false;
396 }
397
398 SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x]\n",
399 plane->base.id,
400 psde->pipe - SSPP_VIG0,
401 psde->pipe_qos_cfg.danger_safe_en,
402 psde->pipe_qos_cfg.vblank_en,
403 psde->pipe_qos_cfg.creq_vblank,
404 psde->pipe_qos_cfg.danger_vblank);
405
406 psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw,
407 &psde->pipe_qos_cfg);
408}
409
Clarence Ipcae1bb62016-07-07 12:07:13 -0400410/* helper to update a state's input fence pointer from the property */
411static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -0400412 struct sde_plane_state *pstate, uint64_t fd)
413{
414 if (!plane || !pstate)
415 return;
416
417 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400418 if (pstate->input_fence)
419 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400420
421 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400422 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400423
Dhaval Patel47302cf2016-08-18 15:04:28 -0700424 SDE_DEBUG("0x%llX\n", fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400425}
426
Clarence Ipcae1bb62016-07-07 12:07:13 -0400427int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -0400428{
Clarence Ipcae1bb62016-07-07 12:07:13 -0400429 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400430 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400431 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400432 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400433
434 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700435 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400436 } else if (!plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700437 SDE_ERROR("invalid plane state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -0400438 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400439 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400440 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400441 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400442
Clarence Ipcae1bb62016-07-07 12:07:13 -0400443 if (input_fence) {
444 ret = sde_sync_wait(input_fence, wait_ms);
445 switch (ret) {
446 case 0:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700447 SDE_DEBUG("%s signaled\n", psde->pipe_name);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400448 break;
449 case -ETIME:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700450 SDE_ERROR("timeout on %s, %ums\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400451 psde->pipe_name, wait_ms);
452 psde->is_error = true;
453 break;
454 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700455 SDE_ERROR("error on %s, %d\n",
Clarence Ipcae1bb62016-07-07 12:07:13 -0400456 psde->pipe_name, ret);
457 psde->is_error = true;
458 break;
459 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400460 } else {
461 ret = 0;
462 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400463 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400464 return ret;
465}
466
Clarence Ipe78efb72016-06-24 18:35:21 -0400467static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400468 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400469 struct sde_hw_pipe_cfg *pipe_cfg,
470 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400471{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400472 struct sde_plane *psde;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400473 int ret, i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400474
Clarence Ipae4e60c2016-06-26 22:44:04 -0400475 if (!plane || !pstate || !pipe_cfg || !fb)
476 return;
477
478 psde = to_sde_plane(plane);
479
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400480 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
481 if (ret) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700482 SDE_ERROR("failed to get format layout, error: %d\n", ret);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400483 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400484 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400485
486 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
487 BIT(SDE_DRM_DEINTERLACE))
488 for (i = 0; i < SDE_MAX_PLANES; ++i)
489 pipe_cfg->layout.plane_pitch[i] <<= 1;
490
491 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
492 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400493}
494
Clarence Ipcb410d42016-06-26 22:52:33 -0400495static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400496 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
497 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400498 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400499 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
500{
501}
502
Clarence Ipcb410d42016-06-26 22:52:33 -0400503/**
504 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
505 * @psde: Pointer to SDE plane object
506 * @src: Source size
507 * @dst: Destination size
508 * @phase_steps: Pointer to output array for phase steps
509 * @filter: Pointer to output array for filter type
510 * @fmt: Pointer to format definition
511 * @chroma_subsampling: Subsampling amount for chroma channel
512 *
513 * Returns: 0 on success
514 */
515static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400516 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400517 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400518 uint32_t chroma_subsampling)
519{
Clarence Ipcb410d42016-06-26 22:52:33 -0400520 if (!psde || !phase_steps || !filter || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700521 SDE_ERROR("invalid arguments\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400522 return -EINVAL;
523 }
524
Clarence Ip4c1d9772016-06-26 09:35:38 -0400525 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400526 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400527 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400528 phase_steps[SDE_SSPP_COMP_1_2] =
529 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
530 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
531 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400532
533 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400534 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400535 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400536 (src <= dst) ? SDE_SCALE_FILTER_BIL :
537 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400538
Clarence Ipdbde9832016-06-26 09:48:36 -0400539 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400540 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400541 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
542 } else {
543 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
544 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400545 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400546 }
547 } else {
548 /* disable scaler */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700549 SDE_DEBUG("disable scaler\n");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400550 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
551 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
552 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400553 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400554 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400555}
556
Clarence Ipcb410d42016-06-26 22:52:33 -0400557/**
558 * _sde_plane_setup_pixel_ext - determine default pixel extension values
559 * @psde: Pointer to SDE plane object
560 * @src: Source size
561 * @dst: Destination size
562 * @decimated_src: Source size after decimation, if any
563 * @phase_steps: Pointer to output array for phase steps
564 * @out_src: Output array for pixel extension values
565 * @out_edge1: Output array for pixel extension first edge
566 * @out_edge2: Output array for pixel extension second edge
567 * @filter: Pointer to array for filter type
568 * @fmt: Pointer to format definition
569 * @chroma_subsampling: Subsampling amount for chroma channel
570 * @post_compare: Whether to chroma subsampled source size for comparisions
571 */
572static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573 uint32_t src, uint32_t dst, uint32_t decimated_src,
574 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400575 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400576 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400577 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400578{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400579 int64_t edge1, edge2, caf;
580 uint32_t src_work;
581 int i, tmp;
582
Clarence Ipcb410d42016-06-26 22:52:33 -0400583 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400584 out_edge2 && filter && fmt) {
585 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400586 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400587 caf = PHASE_STEP_UNIT_SCALE;
588 else
589 caf = 0;
590
591 for (i = 0; i < SDE_MAX_PLANES; i++) {
592 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400593 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400594 src_work /= chroma_subsampling;
595 if (post_compare)
596 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400597 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400598 /* unity */
599 edge1 = 0;
600 edge2 = 0;
601 } else if (dst >= src) {
602 /* upscale */
603 edge1 = (1 << PHASE_RESIDUAL);
604 edge1 -= caf;
605 edge2 = (1 << PHASE_RESIDUAL);
606 edge2 += (dst - 1) * *(phase_steps + i);
607 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
608 edge2 += caf;
609 edge2 = -(edge2);
610 } else {
611 /* downscale */
612 edge1 = 0;
613 edge2 = (dst - 1) * *(phase_steps + i);
614 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
615 edge2 += *(phase_steps + i);
616 edge2 = -(edge2);
617 }
618
619 /* only enable CAF for luma plane */
620 caf = 0;
621
622 /* populate output arrays */
623 *(out_src + i) = src_work;
624
625 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400626 if (edge1 >= 0) {
627 tmp = (uint32_t)edge1;
628 tmp >>= PHASE_STEP_SHIFT;
629 *(out_edge1 + i) = -tmp;
630 } else {
631 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400632 *(out_edge1 + i) =
633 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
634 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400635 }
636 if (edge2 >= 0) {
637 tmp = (uint32_t)edge2;
638 tmp >>= PHASE_STEP_SHIFT;
639 *(out_edge2 + i) = -tmp;
640 } else {
641 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400642 *(out_edge2 + i) =
643 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
644 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400645 }
646 }
647 }
648}
649
Clarence Ip5e2a9222016-06-26 22:38:24 -0400650/**
651 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
652 * sub-structure
653 * @blob_ptr: Pointer to start of incoming blob data
654 * @blob_size: Size of incoming blob data, in bytes
655 * @sub_ptr: Pointer to start of desired sub-structure
656 * @sub_size: Required size of sub-structure, in bytes
657 */
658static int _sde_plane_verify_blob(void *blob_ptr,
659 size_t blob_size,
660 void *sub_ptr,
661 size_t sub_size)
662{
663 /*
664 * Use the blob size provided by drm to check if there are enough
665 * bytes from the start of versioned sub-structures to the end of
666 * blob data:
667 *
668 * e.g.,
669 * blob_ptr --> struct blob_data {
670 * uint32_t version;
671 * sub_ptr --> struct blob_data_v1 v1;
672 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
673 * blob_ptr + blob_size --> };
674 *
675 * It's important to check the actual number of bytes from the start
676 * of the sub-structure to the end of the blob data, and not just rely
677 * on something like,
678 *
679 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
680 *
681 * This is because the start of the sub-structure can vary based on
682 * how the compiler pads the overall structure.
683 */
684 if (blob_ptr && sub_ptr)
685 /* return zero if end of blob >= end of sub-struct */
686 return ((unsigned char *)blob_ptr + blob_size) <
687 ((unsigned char *)sub_ptr + sub_size);
688 return -EINVAL;
689}
690
Clarence Ipe78efb72016-06-24 18:35:21 -0400691static void _sde_plane_setup_csc(struct sde_plane *psde,
692 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400693 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400694{
695 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
696 {
Clarence Ip373f8592016-05-26 00:58:42 -0400697 /* S15.16 format */
698 0x00012A00, 0x00000000, 0x00019880,
699 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
700 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400701 },
Clarence Ip373f8592016-05-26 00:58:42 -0400702 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400703 { 0xfff0, 0xff80, 0xff80,},
704 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400705 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400706 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400707 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400708 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400709 static const struct sde_csc_cfg sde_csc_NOP = {
710 {
Clarence Ip373f8592016-05-26 00:58:42 -0400711 /* identity matrix, S15.16 format */
712 0x10000, 0x00000, 0x00000,
713 0x00000, 0x10000, 0x00000,
714 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400715 },
Clarence Ip373f8592016-05-26 00:58:42 -0400716 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400717 { 0x0, 0x0, 0x0,},
718 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400719 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400720 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
721 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
722 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400723 struct sde_drm_csc *csc = NULL;
724 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400725 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400726
Clarence Ipaa0faf42016-05-30 12:07:48 -0400727 if (!psde || !pstate || !fmt) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700728 SDE_ERROR("invalid arguments\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -0400729 return;
730 }
731 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400732 return;
733
Clarence Ip5e2a9222016-06-26 22:38:24 -0400734 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400735 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400736 csc = msm_property_get_blob(&psde->property_info,
737 pstate->property_blobs,
738 &csc_size,
739 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400740 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400741 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400742 memcpy(&psde->csc_cfg,
743 &sde_csc_NOP,
744 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400745 switch (csc->version) {
746 case SDE_DRM_CSC_V1:
747 if (!_sde_plane_verify_blob(csc,
748 csc_size,
749 &csc->v1,
750 sizeof(struct sde_drm_csc_v1))) {
751 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400752 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400753 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400754 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400755 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400756 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400757 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400758 csc->v1.post_bias[i];
759 }
760 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400761 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400762 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400763 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400764 csc->v1.post_clamp[i];
765 }
Clarence Ipb493d762016-07-19 18:49:10 -0400766 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400767 }
768 break;
769 default:
770 break;
771 }
Clarence Ipb493d762016-07-19 18:49:10 -0400772 if (!psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700773 SDE_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400774 }
775
Clarence Ipcae1bb62016-07-07 12:07:13 -0400776 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400777 if (psde->csc_ptr)
Dhaval Patel47302cf2016-08-18 15:04:28 -0700778 SDE_DEBUG("user blob override for csc\n");
Clarence Ipb493d762016-07-19 18:49:10 -0400779 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400780 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400781}
782
Clarence Ipcb410d42016-06-26 22:52:33 -0400783static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400784 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400785 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700786{
Clarence Ipcb410d42016-06-26 22:52:33 -0400787 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400788 struct sde_drm_scaler *sc_u = NULL;
789 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400790 size_t sc_u_size = 0;
791 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
792 uint32_t tmp;
793 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400794
Clarence Ipcb410d42016-06-26 22:52:33 -0400795 if (!psde || !fmt)
796 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400797
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400798 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400799 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400800
Clarence Ip5e2a9222016-06-26 22:38:24 -0400801 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400802 if (pstate)
803 sc_u = msm_property_get_blob(&psde->property_info,
804 pstate->property_blobs,
805 &sc_u_size,
806 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400807 if (sc_u) {
808 switch (sc_u->version) {
809 case SDE_DRM_SCALER_V1:
810 if (!_sde_plane_verify_blob(sc_u,
811 sc_u_size,
812 &sc_u->v1,
813 sizeof(*sc_u1)))
814 sc_u1 = &sc_u->v1;
815 break;
816 default:
Dhaval Patel47302cf2016-08-18 15:04:28 -0700817 SDE_DEBUG("unrecognized scaler blob v%lld\n",
818 sc_u->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400819 break;
820 }
821 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400822
Clarence Ip04ec67d2016-05-26 01:16:15 -0400823 /* decimation */
824 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
825 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
826 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400827 } else {
828 psde->pipe_cfg.horz_decimation = 0;
829 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400830 }
831
832 /* don't chroma subsample if decimating */
833 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400834 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400835 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400836 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400837
Clarence Ip5e2a9222016-06-26 22:38:24 -0400838 /* update scaler */
839 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
840 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Dhaval Patel47302cf2016-08-18 15:04:28 -0700841 SDE_DEBUG("SCALER3 blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400842 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400843 _sde_plane_setup_scaler3(psde,
844 psde->pipe_cfg.src_rect.w,
845 psde->pipe_cfg.src_rect.h,
846 psde->pipe_cfg.dst_rect.w,
847 psde->pipe_cfg.dst_rect.h,
848 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400849 chroma_subsmpl_h, chroma_subsmpl_v);
850 } else {
851 /* always calculate basic scaler config */
852 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
853 /* populate from user space */
854 for (i = 0; i < SDE_MAX_PLANES; i++) {
855 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
856 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
857 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
858 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400859
Clarence Ip5e2a9222016-06-26 22:38:24 -0400860 pe->horz_filter[i] = sc_u1->horz_filter[i];
861 pe->vert_filter[i] = sc_u1->vert_filter[i];
862 }
863 } else {
864 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400865 _sde_plane_setup_scaler2(psde,
866 psde->pipe_cfg.src_rect.w,
867 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400868 pe->phase_step_x,
869 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400870 _sde_plane_setup_scaler2(psde,
871 psde->pipe_cfg.src_rect.h,
872 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400873 pe->phase_step_y,
874 pe->vert_filter, fmt, chroma_subsmpl_v);
875 }
876 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400877
Clarence Ip5e2a9222016-06-26 22:38:24 -0400878 /* update pixel extensions */
879 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
880 /* populate from user space */
Dhaval Patel47302cf2016-08-18 15:04:28 -0700881 SDE_DEBUG("pixel ext blob detected\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400882 for (i = 0; i < SDE_MAX_PLANES; i++) {
883 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
884 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
885 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
886 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
887 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
888 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
889 pe->roi_w[i] = sc_u1->lr.roi[i];
890
891 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
892 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
893 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
894 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
895 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
896 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
897 pe->roi_h[i] = sc_u1->tb.roi[i];
898 }
899 } else {
900 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400901 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400902 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400903 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400904 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400905 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
906 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400907 pe->phase_step_x,
908 pe->roi_w,
909 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400910 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400911 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400912
Clarence Ipcb410d42016-06-26 22:52:33 -0400913 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400914 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400915 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
916 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400917 pe->phase_step_y,
918 pe->roi_h,
919 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400920 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400921 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400922
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400923 for (i = 0; i < SDE_MAX_PLANES; i++) {
924 if (pe->num_ext_pxls_left[i] >= 0)
925 pe->left_rpt[i] =
926 pe->num_ext_pxls_left[i];
927 else
928 pe->left_ftch[i] =
929 pe->num_ext_pxls_left[i];
930
931 if (pe->num_ext_pxls_right[i] >= 0)
932 pe->right_rpt[i] =
933 pe->num_ext_pxls_right[i];
934 else
935 pe->right_ftch[i] =
936 pe->num_ext_pxls_right[i];
937
938 if (pe->num_ext_pxls_top[i] >= 0)
939 pe->top_rpt[i] =
940 pe->num_ext_pxls_top[i];
941 else
942 pe->top_ftch[i] =
943 pe->num_ext_pxls_top[i];
944
945 if (pe->num_ext_pxls_btm[i] >= 0)
946 pe->btm_rpt[i] =
947 pe->num_ext_pxls_btm[i];
948 else
949 pe->btm_ftch[i] =
950 pe->num_ext_pxls_btm[i];
951 }
952 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400953}
954
Clarence Ipcae1bb62016-07-07 12:07:13 -0400955/**
956 * _sde_plane_color_fill - enables color fill on plane
957 * @plane: Pointer to DRM plane object
958 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
959 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
960 * Returns: 0 on success
961 */
962static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -0400963 uint32_t color, uint32_t alpha)
964{
965 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400966 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400967
968 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700969 SDE_ERROR("invalid plane\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400970 return -EINVAL;
971 }
972
973 psde = to_sde_plane(plane);
974 if (!psde->pipe_hw) {
Dhaval Patel47302cf2016-08-18 15:04:28 -0700975 SDE_ERROR("invalid plane h/w pointer\n");
Clarence Ipcb410d42016-06-26 22:52:33 -0400976 return -EINVAL;
977 }
978
Clarence Ipcae1bb62016-07-07 12:07:13 -0400979 DBG("");
980
Clarence Ipcb410d42016-06-26 22:52:33 -0400981 /*
982 * select fill format to match user property expectation,
983 * h/w only supports RGB variants
984 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400985 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -0400986
987 /* update sspp */
988 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
989 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
990 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
991
992 /* override scaler/decimation if solid fill */
993 psde->pipe_cfg.src_rect.x = 0;
994 psde->pipe_cfg.src_rect.y = 0;
995 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
996 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
997
998 _sde_plane_setup_scaler(psde, fmt, 0);
999
1000 if (psde->pipe_hw->ops.setup_format)
1001 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
1002 fmt, SDE_SSPP_SOLID_FILL);
1003
1004 if (psde->pipe_hw->ops.setup_rects)
1005 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1006 &psde->pipe_cfg, &psde->pixel_ext);
1007 }
1008
1009 return 0;
1010}
1011
1012static int _sde_plane_mode_set(struct drm_plane *plane,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001013 struct drm_plane_state *state)
Clarence Ipcb410d42016-06-26 22:52:33 -04001014{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001015 uint32_t nplanes, src_flags;
Clarence Ipcb410d42016-06-26 22:52:33 -04001016 struct sde_plane *psde;
1017 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001018 const struct sde_format *fmt;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001019 struct drm_crtc *crtc;
1020 struct drm_framebuffer *fb;
1021 struct sde_rect src, dst;
1022 bool q16_data = true;
Clarence Ipcb410d42016-06-26 22:52:33 -04001023
1024 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001025 SDE_ERROR("invalid plane/state\n");
Clarence Ipcb410d42016-06-26 22:52:33 -04001026 return -EINVAL;
1027 }
1028
1029 psde = to_sde_plane(plane);
1030 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -04001031
Dhaval Patel47302cf2016-08-18 15:04:28 -07001032 crtc = state->crtc;
1033 fb = state->fb;
1034 if (!crtc || !fb) {
1035 SDE_ERROR("invalid crtc/fb\n");
1036 return -EINVAL;
1037 }
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001038 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001039 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -04001040
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001041 psde->is_rt_pipe = _sde_plane_is_rt_pipe(plane, crtc);
1042
1043 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1044
Dhaval Patel47302cf2016-08-18 15:04:28 -07001045 POPULATE_RECT(&src, state->src_x, state->src_y,
1046 state->src_w, state->src_h, q16_data);
1047 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y,
1048 state->crtc_w, state->crtc_h, !q16_data);
Clarence Ipcb410d42016-06-26 22:52:33 -04001049
Dhaval Patel47302cf2016-08-18 15:04:28 -07001050 SDE_DEBUG("%s:FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001051 psde->pipe_name,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001052 fb->base.id, src.x, src.y, src.w, src.h,
1053 crtc->base.id, dst.x, dst.y, dst.w, dst.h,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001054 drm_get_format_name(fmt->base.pixel_format),
1055 SDE_FORMAT_IS_UBWC(fmt));
Clarence Ipcb410d42016-06-26 22:52:33 -04001056
1057 /* update format configuration */
1058 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
1059 src_flags = 0;
1060
Clarence Ipcb410d42016-06-26 22:52:33 -04001061 /* flags */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001062 SDE_DEBUG("flags 0x%llX, rotation 0x%llX\n",
Clarence Ipcb410d42016-06-26 22:52:33 -04001063 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
1064 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
1065 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1066 BIT(DRM_REFLECT_X))
1067 src_flags |= SDE_SSPP_FLIP_LR;
1068 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
1069 BIT(DRM_REFLECT_Y))
1070 src_flags |= SDE_SSPP_FLIP_UD;
1071 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
1072 BIT(SDE_DRM_DEINTERLACE)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001073 src.h /= 2;
1074 src.y = DIV_ROUND_UP(src.y, 2);
1075 src.y &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -04001076 }
1077
Dhaval Patel47302cf2016-08-18 15:04:28 -07001078 psde->pipe_cfg.src_rect = src;
1079 psde->pipe_cfg.dst_rect = dst;
Clarence Ipcb410d42016-06-26 22:52:33 -04001080
Clarence Ipcb410d42016-06-26 22:52:33 -04001081 /* check for color fill */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001082 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001083 PLANE_PROP_COLOR_FILL);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001084 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1085 /* skip remaining processing on color fill */
1086 return 0;
Clarence Ipcb410d42016-06-26 22:52:33 -04001087
1088 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
1089
1090 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001091
Clarence Ip4c1d9772016-06-26 09:35:38 -04001092 if (psde->pipe_hw->ops.setup_format)
1093 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -04001094 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001095 if (psde->pipe_hw->ops.setup_rects)
1096 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
1097 &psde->pipe_cfg, &psde->pixel_ext);
1098
Clarence Ipe78efb72016-06-24 18:35:21 -04001099 /* update sharpening */
1100 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
1101 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
1102 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
1103 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
1104
1105 if (psde->pipe_hw->ops.setup_sharpening)
1106 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
1107 &psde->sharp_cfg);
1108
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001109 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -04001110 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -04001111 _sde_plane_setup_csc(psde, pstate, fmt);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001112 else
1113 psde->csc_ptr = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001114
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001115 _sde_plane_set_qos_lut(plane, fb);
1116 _sde_plane_set_danger_lut(plane, fb);
1117
1118 if (plane->type != DRM_PLANE_TYPE_CURSOR)
1119 _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL);
1120
Clarence Ip5e2a9222016-06-26 22:38:24 -04001121 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001122}
1123
1124static int sde_plane_prepare_fb(struct drm_plane *plane,
1125 const struct drm_plane_state *new_state)
1126{
1127 struct drm_framebuffer *fb = new_state->fb;
1128 struct sde_plane *psde = to_sde_plane(plane);
1129
1130 if (!new_state->fb)
1131 return 0;
1132
Dhaval Patel47302cf2016-08-18 15:04:28 -07001133 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001134 return msm_framebuffer_prepare(fb, psde->mmu_id);
1135}
1136
1137static void sde_plane_cleanup_fb(struct drm_plane *plane,
1138 const struct drm_plane_state *old_state)
1139{
1140 struct drm_framebuffer *fb = old_state->fb;
1141 struct sde_plane *psde = to_sde_plane(plane);
1142
1143 if (!fb)
1144 return;
1145
Dhaval Patel47302cf2016-08-18 15:04:28 -07001146 SDE_DEBUG("%s: FB[%u]\n", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001147 msm_framebuffer_cleanup(fb, psde->mmu_id);
1148}
1149
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001150static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
1151 struct drm_plane_state *state,
1152 struct drm_plane_state *old_state)
1153{
1154 struct sde_plane_state *pstate = to_sde_plane_state(state);
1155
Dhaval Patel47302cf2016-08-18 15:04:28 -07001156 /* no need to check it again */
1157 if (pstate->mode_changed)
1158 return;
1159
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001160 if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001161 SDE_DEBUG("%s: pipe enabling/disabling full modeset required\n",
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001162 psde->pipe_name);
1163 pstate->mode_changed = true;
1164 } else if (to_sde_plane_state(old_state)->pending) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001165 SDE_DEBUG("%s: still pending\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001166 pstate->mode_changed = true;
1167 } else if (state->src_w != old_state->src_w ||
Dhaval Patel47302cf2016-08-18 15:04:28 -07001168 state->src_h != old_state->src_h ||
1169 state->src_x != old_state->src_x ||
1170 state->src_y != old_state->src_y) {
1171 SDE_DEBUG("%s: src rect updated\n", psde->pipe_name);
1172 pstate->mode_changed = true;
1173 } else if (state->crtc_w != old_state->crtc_w ||
1174 state->crtc_h != old_state->crtc_h ||
1175 state->crtc_x != old_state->crtc_x ||
1176 state->crtc_y != old_state->crtc_y) {
1177 SDE_DEBUG("%s: crtc rect updated\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001178 pstate->mode_changed = true;
1179 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001180 SDE_DEBUG("%s: format change!\n", psde->pipe_name);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001181 pstate->mode_changed = true;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001182 } else {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001183 uint64_t *new_mods = state->fb->modifier;
1184 uint64_t *old_mods = old_state->fb->modifier;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001185 uint32_t *new_pitches = state->fb->pitches;
1186 uint32_t *old_pitches = old_state->fb->pitches;
1187 uint32_t *new_offset = state->fb->offsets;
1188 uint32_t *old_offset = old_state->fb->offsets;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001189 int i;
1190
1191 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
1192 if (new_mods[i] != old_mods[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001193 SDE_DEBUG("%s: format modifiers change\"\
1194 plane:%d new_mode:%llu old_mode:%llu\n",
1195 psde->pipe_name, i, new_mods[i],
1196 old_mods[i]);
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001197 pstate->mode_changed = true;
1198 break;
1199 }
1200 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001201 for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
1202 if (new_pitches[i] != old_pitches[i]) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001203 SDE_DEBUG("%s: pitches change plane:%d\"\
1204 old_pitches:%u new_pitches:%u\n",
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001205 psde->pipe_name, i, old_pitches[i],
1206 new_pitches[i]);
1207 pstate->mode_changed = true;
1208 break;
1209 }
1210 }
Dhaval Patel47302cf2016-08-18 15:04:28 -07001211 for (i = 0; i < ARRAY_SIZE(state->fb->offsets); i++) {
1212 if (new_offset[i] != old_offset[i]) {
1213 SDE_DEBUG("%s: offset change plane:%d\"\
1214 old_offset:%u new_offset:%u\n",
1215 psde->pipe_name, i, old_offset[i],
1216 new_offset[i]);
1217 pstate->mode_changed = true;
1218 break;
1219 }
1220 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -04001221 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001222}
1223
Dhaval Patel47302cf2016-08-18 15:04:28 -07001224static bool __get_scale_data(struct sde_plane *psde,
1225 struct sde_plane_state *pstate, struct sde_drm_scaler *sc_u,
1226 size_t *sc_u_size)
1227{
1228 bool valid_flag = false;
1229
1230 sc_u = msm_property_get_blob(&psde->property_info,
1231 pstate->property_blobs,
1232 sc_u_size,
1233 PLANE_PROP_SCALER);
1234 if (sc_u) {
1235 switch (sc_u->version) {
1236 case SDE_DRM_SCALER_V1:
1237 if (!_sde_plane_verify_blob(sc_u, *sc_u_size,
1238 &sc_u->v1, sizeof(struct sde_drm_scaler_v1)))
1239 valid_flag = true;
1240 break;
1241 default:
1242 SDE_DEBUG("unrecognized scaler blob v%lld\n",
1243 sc_u->version);
1244 break;
1245 }
1246 }
1247
1248 return valid_flag;
1249}
1250
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001251static int sde_plane_atomic_check(struct drm_plane *plane,
1252 struct drm_plane_state *state)
1253{
Dhaval Patel47302cf2016-08-18 15:04:28 -07001254 int ret = 0, valid_scale_data;
Clarence Ipdbde9832016-06-26 09:48:36 -04001255 struct sde_plane *psde;
1256 struct sde_plane_state *pstate;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001257 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -04001258 size_t sc_u_size = 0;
1259 struct sde_drm_scaler *sc_u = NULL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001260 struct sde_rect src, dst;
Clarence Ipdbde9832016-06-26 09:48:36 -04001261 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001262 uint32_t max_upscale, max_downscale, min_src_size, max_linewidth;
1263 bool q16_data = true;
Clarence Ipdbde9832016-06-26 09:48:36 -04001264
1265 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001266 SDE_ERROR("invalid plane/state\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001267 ret = -EINVAL;
1268 goto exit;
1269 }
1270
1271 psde = to_sde_plane(plane);
1272 pstate = to_sde_plane_state(state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001273
1274 if (!psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001275 SDE_ERROR("invalid plane catalog\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001276 ret = -EINVAL;
1277 goto exit;
1278 }
1279
Dhaval Patel47302cf2016-08-18 15:04:28 -07001280 valid_scale_data = __get_scale_data(psde, pstate, sc_u, &sc_u_size);
1281 deci_w = valid_scale_data && sc_u ? sc_u->v1.horz_decimate : 0;
1282 deci_h = valid_scale_data && sc_u ? sc_u->v1.vert_decimate : 0;
Clarence Ipdbde9832016-06-26 09:48:36 -04001283
1284 /* src values are in Q16 fixed point, convert to integer */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001285 POPULATE_RECT(&src, state->src_x, state->src_y, state->src_w,
1286 state->src_h, q16_data);
1287 POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w,
1288 state->crtc_h, !q16_data);
Clarence Ipdbde9832016-06-26 09:48:36 -04001289
Dhaval Patel47302cf2016-08-18 15:04:28 -07001290 src_deci_w = DECIMATED_DIMENSION(src.w, deci_w);
1291 src_deci_h = DECIMATED_DIMENSION(src.h, deci_h);
Clarence Ipdbde9832016-06-26 09:48:36 -04001292
Dhaval Patel47302cf2016-08-18 15:04:28 -07001293 max_upscale = psde->pipe_sblk->maxupscale;
1294 max_downscale = psde->pipe_sblk->maxdwnscale;
1295 max_linewidth = psde->pipe_sblk->maxlinewidth;
Clarence Ipdbde9832016-06-26 09:48:36 -04001296
Dhaval Patel47302cf2016-08-18 15:04:28 -07001297 SDE_DEBUG("%s: check (%d -> %d)\n", psde->pipe_name,
1298 sde_plane_enabled(plane->state), sde_plane_enabled(state));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001299
Dhaval Patel47302cf2016-08-18 15:04:28 -07001300 if (!sde_plane_enabled(state))
1301 goto modeset_update;
Clarence Ipdbde9832016-06-26 09:48:36 -04001302
Dhaval Patel47302cf2016-08-18 15:04:28 -07001303 fmt = to_sde_format(msm_framebuffer_format(state->fb));
1304
1305 min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1;
1306
1307 if (SDE_FORMAT_IS_YUV(fmt) &&
1308 (!(psde->features & SDE_SSPP_SCALER) ||
1309 !(psde->features & BIT(SDE_SSPP_CSC)))) {
1310 SDE_ERROR("plane doesn't have scaler/csc capability for yuv\n");
1311 ret = -EINVAL;
1312
1313 /* check src bounds */
1314 } else if (state->fb->width > MAX_IMG_WIDTH ||
1315 state->fb->height > MAX_IMG_HEIGHT ||
1316 src.w < min_src_size || src.h < min_src_size ||
1317 CHECK_LAYER_BOUNDS(src.x, src.w, state->fb->width) ||
1318 CHECK_LAYER_BOUNDS(src.y, src.h, state->fb->height)) {
1319 SDE_ERROR("invalid source (%u, %u) -> (%u, %u)\n",
1320 src.x, src.y, src.w, src.h);
1321 ret = -E2BIG;
1322
1323 /* valid yuv image */
1324 } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) ||
1325 (src.w & 0x1) || (src.h & 0x1))) {
1326 SDE_ERROR("invalid yuv source (%u, %u) -> (%u, %u)\n",
1327 src.x, src.y, src.w, src.h);
1328 ret = -EINVAL;
1329
1330 /* min dst support */
1331 } else if (dst.w < 0x1 || dst.h < 0x1) {
1332 SDE_ERROR("invalid dest rect (%u, %u) -> (%u, %u)\n",
1333 dst.x, dst.y, dst.w, dst.h);
1334 ret = -EINVAL;
1335
1336 /* decimation validation */
1337 } else if (deci_w || deci_h) {
1338 if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1339 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1340 SDE_ERROR("too much decimation requested\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001341 ret = -EINVAL;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001342 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
1343 SDE_ERROR("decimation requires linear fetch\n");
Clarence Ipdbde9832016-06-26 09:48:36 -04001344 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001345 }
1346
Dhaval Patel47302cf2016-08-18 15:04:28 -07001347 } else if (!(psde->features & SDE_SSPP_SCALER) &&
1348 ((src.w != dst.w) || (src.h != dst.h))) {
1349 SDE_ERROR("pipe doesn't support scaling %ux%u->%ux%u\n",
1350 src.w, src.h, dst.w, dst.h);
1351 ret = -EINVAL;
1352
1353 /* check decimated source width */
1354 } else if (src_deci_w > max_linewidth) {
1355 SDE_ERROR("invalid source width:%u, deci wid:%u, line wid:%u\n",
1356 src.w, src_deci_w, max_linewidth);
1357 ret = -E2BIG;
1358
1359 /* check max scaler capability */
1360 } else if (((src_deci_w * max_upscale) < dst.w) ||
1361 ((src_deci_h * max_upscale) < dst.h) ||
1362 ((dst.w * max_downscale) < src_deci_w) ||
1363 ((dst.h * max_downscale) < src_deci_h)) {
1364 SDE_ERROR("too much scaling requested %ux%u -> %ux%u\n",
1365 src_deci_w, src_deci_h, dst.w, dst.h);
1366 ret = -E2BIG;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001367 }
1368
Dhaval Patel47302cf2016-08-18 15:04:28 -07001369modeset_update:
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001370 if (!ret)
Dhaval Patel47302cf2016-08-18 15:04:28 -07001371 _sde_plane_atomic_check_mode_changed(psde, state, plane->state);
Clarence Ipdbde9832016-06-26 09:48:36 -04001372exit:
1373 return ret;
1374}
1375
Clarence Ipcae1bb62016-07-07 12:07:13 -04001376/**
1377 * sde_plane_flush - final plane operations before commit flush
1378 * @plane: Pointer to drm plane structure
1379 */
1380void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001381{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001382 struct sde_plane *psde;
1383
1384 if (!plane)
1385 return;
1386
1387 psde = to_sde_plane(plane);
1388
1389 /*
1390 * These updates have to be done immediately before the plane flush
1391 * timing, and may not be moved to the atomic_update/mode_set functions.
1392 */
1393 if (psde->is_error)
1394 /* force white frame with 0% alpha pipe output on error */
1395 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1396 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1397 /* force 100% alpha */
1398 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1399 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1400 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1401
1402 /* flag h/w flush complete */
1403 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001404 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001405}
1406
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001407static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001408 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001409{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001410 struct sde_plane *sde_plane;
1411 struct drm_plane_state *state;
1412 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001413
Clarence Ip5e2a9222016-06-26 22:38:24 -04001414 if (!plane || !plane->state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001415 SDE_ERROR("invalid plane/state\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001416 return;
1417 }
1418
1419 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001420 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001421 state = plane->state;
1422 pstate = to_sde_plane_state(state);
1423
Dhaval Patel47302cf2016-08-18 15:04:28 -07001424 SDE_DEBUG("%s: update\n", sde_plane->pipe_name);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001425
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001426 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001427 pstate->pending = true;
1428 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001429 int ret;
1430
Clarence Ip5e2a9222016-06-26 22:38:24 -04001431 pstate->pending = true;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001432 ret = _sde_plane_mode_set(plane, state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001433 /* atomic_check should have ensured that this doesn't fail */
1434 WARN_ON(ret < 0);
1435 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001436 _sde_plane_set_scanout(plane, pstate,
1437 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001438 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001439}
1440
Dhaval Patel47302cf2016-08-18 15:04:28 -07001441
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001442/* helper to install properties which are common to planes and crtcs */
Dhaval Patel47302cf2016-08-18 15:04:28 -07001443static void _sde_plane_install_properties(struct drm_plane *plane,
1444 u32 max_blendstages)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001445{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001446 static const struct drm_prop_enum_list e_blend_op[] = {
1447 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1448 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1449 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1450 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1451 };
1452 static const struct drm_prop_enum_list e_src_config[] = {
1453 {SDE_DRM_DEINTERLACE, "deinterlace"}
1454 };
Clarence Ipea3d6262016-07-15 16:20:11 -04001455 const struct sde_format_extended *format_list;
Dhaval Patel4e574842016-08-23 15:11:37 -07001456 struct sde_kms_info *info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001457 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001458
Clarence Ipaa0faf42016-05-30 12:07:48 -04001459 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001460 SDE_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001461 return;
1462 }
1463
Dhaval Patel47302cf2016-08-18 15:04:28 -07001464 msm_property_install_range(&psde->property_info, "zpos", 0x0, 0,
1465 max_blendstages, STAGE_BASE, PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001466
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001467 msm_property_install_range(&psde->property_info, "alpha",
Dhaval Patel47302cf2016-08-18 15:04:28 -07001468 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001469
Dhaval Patel47302cf2016-08-18 15:04:28 -07001470 /* linux default file descriptor range on each process */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001471 msm_property_install_range(&psde->property_info, "input_fence",
Dhaval Patel4e574842016-08-23 15:11:37 -07001472 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001473
1474 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001475 msm_property_install_rotation(&psde->property_info,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001476 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y), PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001477
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001478 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Dhaval Patel47302cf2016-08-18 15:04:28 -07001479 e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001480
Dhaval Patel47302cf2016-08-18 15:04:28 -07001481 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
1482 e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG);
1483
1484 if (psde->pipe_hw->ops.setup_solidfill)
1485 msm_property_install_range(&psde->property_info, "color_fill",
1486 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL);
1487
Clarence Ip4c1d9772016-06-26 09:35:38 -04001488 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001489 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001490 PLANE_PROP_SCALER);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001491
1492 if (psde->features & BIT(SDE_SSPP_CSC))
Clarence Ipaa0faf42016-05-30 12:07:48 -04001493 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001494 PLANE_PROP_CSC);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001495
Dhaval Patel4e574842016-08-23 15:11:37 -07001496 info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL);
1497 if (!info)
1498 return;
1499
1500 msm_property_install_blob(&psde->property_info, "capabilities",
1501 DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO);
1502 sde_kms_info_reset(info);
1503
Clarence Ipea3d6262016-07-15 16:20:11 -04001504 format_list = psde->pipe_sblk->format_list;
1505 if (format_list) {
Clarence Ipea3d6262016-07-15 16:20:11 -04001506 sde_kms_info_start(info, "pixel_formats");
1507 while (format_list->fourcc_format) {
1508 sde_kms_info_append_format(info,
1509 format_list->fourcc_format,
1510 format_list->modifier);
1511 ++format_list;
1512 }
1513 sde_kms_info_stop(info);
Clarence Ipea3d6262016-07-15 16:20:11 -04001514 }
Dhaval Patel4e574842016-08-23 15:11:37 -07001515
1516 sde_kms_info_add_keyint(info, "max_linewidth",
1517 psde->pipe_sblk->maxlinewidth);
1518 sde_kms_info_add_keyint(info, "max_upscale",
1519 psde->pipe_sblk->maxupscale);
1520 sde_kms_info_add_keyint(info, "max_downscale",
1521 psde->pipe_sblk->maxdwnscale);
1522 sde_kms_info_add_keyint(info, "max_horizontal_deci",
1523 psde->pipe_sblk->maxhdeciexp);
1524 sde_kms_info_add_keyint(info, "max_vertical_deci",
1525 psde->pipe_sblk->maxvdeciexp);
1526 msm_property_set_blob(&psde->property_info, &psde->blob_info,
1527 info->data, info->len, PLANE_PROP_INFO);
1528
1529 kfree(info);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001530}
1531
1532static int sde_plane_atomic_set_property(struct drm_plane *plane,
1533 struct drm_plane_state *state, struct drm_property *property,
1534 uint64_t val)
1535{
Clarence Ip730e7192016-06-26 22:45:09 -04001536 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001537 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001538 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001539
Clarence Ipaa0faf42016-05-30 12:07:48 -04001540 DBG("");
1541
1542 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001543 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001544 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001545 SDE_ERROR("invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001546 } else {
1547 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001548 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001549 ret = msm_property_atomic_set(&psde->property_info,
1550 pstate->property_values, pstate->property_blobs,
1551 property, val);
1552 if (!ret) {
1553 idx = msm_property_index(&psde->property_info,
1554 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001555 if (idx == PLANE_PROP_INPUT_FENCE)
1556 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001557 }
1558 }
1559
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001560 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001561}
1562
1563static int sde_plane_set_property(struct drm_plane *plane,
1564 struct drm_property *property, uint64_t val)
1565{
Clarence Ip4ce59322016-06-26 22:27:51 -04001566 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001567
Clarence Ipae4e60c2016-06-26 22:44:04 -04001568 return sde_plane_atomic_set_property(plane,
1569 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001570}
1571
1572static int sde_plane_atomic_get_property(struct drm_plane *plane,
1573 const struct drm_plane_state *state,
1574 struct drm_property *property, uint64_t *val)
1575{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001576 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001577 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001578 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001579
Clarence Ipaa0faf42016-05-30 12:07:48 -04001580 DBG("");
1581
1582 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001583 SDE_ERROR("invalid plane\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001584 } else if (!state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001585 SDE_ERROR("invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001586 } else {
1587 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001588 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001589 ret = msm_property_atomic_get(&psde->property_info,
1590 pstate->property_values, pstate->property_blobs,
1591 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001592 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001593
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001594 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001595}
1596
1597static void sde_plane_destroy(struct drm_plane *plane)
1598{
Clarence Ip4ce59322016-06-26 22:27:51 -04001599 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001600
Clarence Ip4ce59322016-06-26 22:27:51 -04001601 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001602
Clarence Ip4ce59322016-06-26 22:27:51 -04001603 if (plane) {
1604 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001605
Alan Kwong1a00e4d2016-07-18 09:42:30 -04001606 _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL);
1607
Clarence Ip4ce59322016-06-26 22:27:51 -04001608 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001609
Dhaval Patel4e574842016-08-23 15:11:37 -07001610 if (psde->blob_info)
1611 drm_property_unreference_blob(psde->blob_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001612 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001613 mutex_destroy(&psde->lock);
1614
Clarence Ip4ce59322016-06-26 22:27:51 -04001615 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001616
Clarence Ip4ce59322016-06-26 22:27:51 -04001617 /* this will destroy the states as well */
1618 drm_plane_cleanup(plane);
1619
Clarence Ip4c1d9772016-06-26 09:35:38 -04001620 if (psde->pipe_hw)
1621 sde_hw_sspp_destroy(psde->pipe_hw);
1622
Clarence Ip4ce59322016-06-26 22:27:51 -04001623 kfree(psde);
1624 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001625}
1626
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001627static void sde_plane_destroy_state(struct drm_plane *plane,
1628 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001629{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001630 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001631 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001632
Clarence Ipae4e60c2016-06-26 22:44:04 -04001633 if (!plane || !state) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001634 SDE_ERROR("invalid plane/state\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001635 return;
1636 }
1637
Clarence Ipaa0faf42016-05-30 12:07:48 -04001638 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001639 pstate = to_sde_plane_state(state);
1640
1641 DBG("");
1642
Clarence Ipe78efb72016-06-24 18:35:21 -04001643 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001644 if (state->fb)
1645 drm_framebuffer_unreference(state->fb);
1646
Clarence Ipae4e60c2016-06-26 22:44:04 -04001647 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001648 if (pstate->input_fence)
1649 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001650
Clarence Ipaa0faf42016-05-30 12:07:48 -04001651 /* destroy value helper */
1652 msm_property_destroy_state(&psde->property_info, pstate,
1653 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001654}
1655
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001656static struct drm_plane_state *
1657sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001658{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001659 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001660 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001661 struct sde_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001662
Clarence Ip730e7192016-06-26 22:45:09 -04001663 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001664 return NULL;
1665
Clarence Ip730e7192016-06-26 22:45:09 -04001666 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001667 psde = to_sde_plane(plane);
1668 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001669 if (!pstate)
1670 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001671
Clarence Ipaa0faf42016-05-30 12:07:48 -04001672 DBG("");
1673
1674 /* duplicate value helper */
1675 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1676 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001677
Clarence Ip730e7192016-06-26 22:45:09 -04001678 /* add ref count for frame buffer */
1679 if (pstate->base.fb)
1680 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001681
Clarence Ip730e7192016-06-26 22:45:09 -04001682 /* add ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001683 if (pstate->input_fence) {
1684 pstate->input_fence = 0;
1685 _sde_plane_set_input_fence(plane, pstate, pstate->
1686 property_values[PLANE_PROP_INPUT_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001687 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001688
Clarence Ip730e7192016-06-26 22:45:09 -04001689 pstate->mode_changed = false;
1690 pstate->pending = false;
1691
1692 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001693}
1694
1695static void sde_plane_reset(struct drm_plane *plane)
1696{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001697 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001698 struct sde_plane_state *pstate;
1699
Clarence Ipae4e60c2016-06-26 22:44:04 -04001700 if (!plane) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001701 SDE_ERROR("invalid plane\n");
Clarence Ipae4e60c2016-06-26 22:44:04 -04001702 return;
1703 }
1704
Clarence Ip730e7192016-06-26 22:45:09 -04001705 psde = to_sde_plane(plane);
Dhaval Patel47302cf2016-08-18 15:04:28 -07001706 SDE_DEBUG("%s\n", psde->pipe_name);
Clarence Ip730e7192016-06-26 22:45:09 -04001707
Clarence Ipae4e60c2016-06-26 22:44:04 -04001708 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001709 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001710 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001711 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001712 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001713
Clarence Ipaa0faf42016-05-30 12:07:48 -04001714 pstate = msm_property_alloc_state(&psde->property_info);
1715 if (!pstate)
1716 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001717
Clarence Ipaa0faf42016-05-30 12:07:48 -04001718 /* reset value helper */
1719 msm_property_reset_state(&psde->property_info, pstate,
1720 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001721
1722 pstate->base.plane = plane;
1723
1724 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001725}
1726
1727static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001728 .update_plane = drm_atomic_helper_update_plane,
1729 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001730 .destroy = sde_plane_destroy,
1731 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001732 .atomic_set_property = sde_plane_atomic_set_property,
1733 .atomic_get_property = sde_plane_atomic_get_property,
1734 .reset = sde_plane_reset,
1735 .atomic_duplicate_state = sde_plane_duplicate_state,
1736 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001737};
1738
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001739static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1740 .prepare_fb = sde_plane_prepare_fb,
1741 .cleanup_fb = sde_plane_cleanup_fb,
1742 .atomic_check = sde_plane_atomic_check,
1743 .atomic_update = sde_plane_atomic_update,
1744};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001745
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001746enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001747{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001748 struct sde_plane *sde_plane = to_sde_plane(plane);
1749
1750 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001751}
1752
Clarence Ip4ce59322016-06-26 22:27:51 -04001753static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1754{
1755 const struct sde_sspp_sub_blks *sblk = 0;
1756 const struct sde_sspp_cfg *cfg = 0;
1757
1758 if (psde && psde->pipe_hw)
1759 cfg = psde->pipe_hw->cap;
1760 if (cfg)
1761 sblk = cfg->sblk;
1762
1763 if (kms && sblk) {
1764 /* create overall sub-directory for the pipe */
1765 psde->debugfs_root =
1766 debugfs_create_dir(psde->pipe_name,
1767 sde_debugfs_get_root(kms));
1768 if (psde->debugfs_root) {
1769 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001770 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001771 psde->debugfs_root, &psde->features);
1772
1773 /* add register dump support */
1774 sde_debugfs_setup_regset32(&psde->debugfs_src,
1775 sblk->src_blk.base + cfg->base,
1776 sblk->src_blk.len,
1777 kms->mmio);
1778 sde_debugfs_create_regset32("src_blk", 0444,
1779 psde->debugfs_root, &psde->debugfs_src);
1780
1781 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1782 sblk->scaler_blk.base + cfg->base,
1783 sblk->scaler_blk.len,
1784 kms->mmio);
1785 sde_debugfs_create_regset32("scaler_blk", 0444,
1786 psde->debugfs_root,
1787 &psde->debugfs_scaler);
1788
1789 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1790 sblk->csc_blk.base + cfg->base,
1791 sblk->csc_blk.len,
1792 kms->mmio);
1793 sde_debugfs_create_regset32("csc_blk", 0444,
1794 psde->debugfs_root, &psde->debugfs_csc);
1795 }
1796 }
1797}
1798
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001799/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001800struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001801 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001802{
1803 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001804 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001805 struct msm_drm_private *priv;
1806 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001807 enum drm_plane_type type;
Dhaval Patel47302cf2016-08-18 15:04:28 -07001808 int ret = -EINVAL, max_blendstages = 255;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001809
1810 if (!dev) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001811 SDE_ERROR("[%u]device is NULL\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001812 goto exit;
1813 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001814
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001815 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001816 if (!priv) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001817 SDE_ERROR("[%u]private data is NULL\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001818 goto exit;
1819 }
1820
1821 if (!priv->kms) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001822 SDE_ERROR("[%u]invalid KMS reference\n", pipe);
Ben Chan78647cd2016-06-26 22:02:47 -04001823 goto exit;
1824 }
1825 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001826
Clarence Ip4c1d9772016-06-26 09:35:38 -04001827 if (!kms->catalog) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001828 SDE_ERROR("[%u]invalid catalog reference\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001829 goto exit;
1830 }
1831
Clarence Ip4ce59322016-06-26 22:27:51 -04001832 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001833 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1834 if (!psde) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001835 SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001836 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001837 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001838 }
1839
Clarence Ip4c1d9772016-06-26 09:35:38 -04001840 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001841 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001842 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04001843 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001844
Clarence Ip4c1d9772016-06-26 09:35:38 -04001845 /* initialize underlying h/w driver */
1846 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1847 if (IS_ERR(psde->pipe_hw)) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001848 SDE_ERROR("[%u]SSPP init failed\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001849 ret = PTR_ERR(psde->pipe_hw);
1850 goto clean_plane;
1851 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001852 SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001853 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001854 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001855
1856 /* cache features mask for later */
1857 psde->features = psde->pipe_hw->cap->features;
1858 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04001859 if (!psde->pipe_sblk) {
1860 SDE_ERROR("invalid sblk on pipe %d\n", pipe);
1861 goto clean_sspp;
1862 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001863
Dhaval Patel47302cf2016-08-18 15:04:28 -07001864 if (kms->catalog && kms->catalog->mixer_count && kms->catalog->mixer)
1865 max_blendstages = kms->catalog->mixer[0].sblk->maxblendstages;
1866
Clarence Ip4c1d9772016-06-26 09:35:38 -04001867 /* add plane to DRM framework */
Clarence Ipea3d6262016-07-15 16:20:11 -04001868 psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
1869 psde->formats,
1870 0,
1871 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001872
Clarence Ip4c1d9772016-06-26 09:35:38 -04001873 if (!psde->nformats) {
Dhaval Patel47302cf2016-08-18 15:04:28 -07001874 SDE_ERROR("[%u]no valid formats for plane\n", pipe);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001875 goto clean_sspp;
1876 }
1877
1878 if (psde->features & BIT(SDE_SSPP_CURSOR))
1879 type = DRM_PLANE_TYPE_CURSOR;
1880 else if (primary_plane)
1881 type = DRM_PLANE_TYPE_PRIMARY;
1882 else
1883 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001884 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1885 psde->formats, psde->nformats,
1886 type);
1887 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001888 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001889
Clarence Ip4c1d9772016-06-26 09:35:38 -04001890 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001891 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001892
Clarence Ipaa0faf42016-05-30 12:07:48 -04001893 msm_property_init(&psde->property_info, &plane->base, dev,
1894 priv->plane_property, psde->property_data,
1895 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
1896 sizeof(struct sde_plane_state));
1897
Dhaval Patel47302cf2016-08-18 15:04:28 -07001898 _sde_plane_install_properties(plane, max_blendstages);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001899
Clarence Ip4ce59322016-06-26 22:27:51 -04001900 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001901 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001902
Clarence Ip730e7192016-06-26 22:45:09 -04001903 mutex_init(&psde->lock);
1904
Clarence Ip4ce59322016-06-26 22:27:51 -04001905 _sde_plane_init_debugfs(psde, kms);
1906
Dhaval Patel47302cf2016-08-18 15:04:28 -07001907 DRM_INFO("[%u]successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001908 return plane;
1909
Clarence Ip4c1d9772016-06-26 09:35:38 -04001910clean_sspp:
1911 if (psde && psde->pipe_hw)
1912 sde_hw_sspp_destroy(psde->pipe_hw);
1913clean_plane:
1914 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001915exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001916 return ERR_PTR(ret);
1917}