blob: a7c38bf0f142574e55f4932a04d31423a9bd1b97 [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 */
Clarence Ip4ce59322016-06-26 22:27:51 -040012#include <linux/debugfs.h>
Clarence Ip5e2a9222016-06-26 22:38:24 -040013#include <uapi/drm/sde_drm.h>
Clarence Ipaa0faf42016-05-30 12:07:48 -040014
15#include "msm_prop.h"
16
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070017#include "sde_kms.h"
Clarence Ipae4e60c2016-06-26 22:44:04 -040018#include "sde_fence.h"
Clarence Ipc475b082016-06-26 09:27:23 -040019#include "sde_formats.h"
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040020#include "sde_hw_sspp.h"
21
22#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci))
23#define PHASE_STEP_SHIFT 21
24#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT))
25#define PHASE_RESIDUAL 15
26
Clarence Ipe78efb72016-06-24 18:35:21 -040027#define SHARP_STRENGTH_DEFAULT 32
28#define SHARP_EDGE_THR_DEFAULT 112
29#define SHARP_SMOOTH_THR_DEFAULT 8
30#define SHARP_NOISE_THR_DEFAULT 2
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040031
Clarence Ip5e2a9222016-06-26 22:38:24 -040032#define SDE_NAME_SIZE 12
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070033
Clarence Ipcae1bb62016-07-07 12:07:13 -040034#define SDE_PLANE_COLOR_FILL_FLAG BIT(31)
35
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070036struct sde_plane {
37 struct drm_plane base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040038
39 int mmu_id;
40
Clarence Ip730e7192016-06-26 22:45:09 -040041 struct mutex lock;
42
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040043 enum sde_sspp pipe;
44 uint32_t features; /* capabilities from catalog */
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070045 uint32_t nformats;
46 uint32_t formats[32];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040047
48 struct sde_hw_pipe *pipe_hw;
49 struct sde_hw_pipe_cfg pipe_cfg;
50 struct sde_hw_pixel_ext pixel_ext;
Clarence Ipe78efb72016-06-24 18:35:21 -040051 struct sde_hw_sharp_cfg sharp_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -040052 struct sde_hw_scaler3_cfg scaler3_cfg;
Clarence Ipcae1bb62016-07-07 12:07:13 -040053 uint32_t color_fill;
54 bool is_error;
Clarence Ip4ce59322016-06-26 22:27:51 -040055
Clarence Ip373f8592016-05-26 00:58:42 -040056 struct sde_csc_cfg csc_cfg;
57 struct sde_csc_cfg *csc_ptr;
58
Clarence Ip4c1d9772016-06-26 09:35:38 -040059 const struct sde_sspp_sub_blks *pipe_sblk;
60
Clarence Ip5e2a9222016-06-26 22:38:24 -040061 char pipe_name[SDE_NAME_SIZE];
Clarence Ip4ce59322016-06-26 22:27:51 -040062
Clarence Ipaa0faf42016-05-30 12:07:48 -040063 struct msm_property_info property_info;
64 struct msm_property_data property_data[PLANE_PROP_COUNT];
Clarence Ip730e7192016-06-26 22:45:09 -040065
Clarence Ip4ce59322016-06-26 22:27:51 -040066 /* debugfs related stuff */
67 struct dentry *debugfs_root;
68 struct sde_debugfs_regset32 debugfs_src;
69 struct sde_debugfs_regset32 debugfs_scaler;
70 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070071};
72#define to_sde_plane(x) container_of(x, struct sde_plane, base)
73
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040074static bool sde_plane_enabled(struct drm_plane_state *state)
75{
Clarence Ipdbde9832016-06-26 09:48:36 -040076 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040077}
78
Clarence Ipcae1bb62016-07-07 12:07:13 -040079/* helper to update a state's input fence pointer from the property */
80static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -040081 struct sde_plane_state *pstate, uint64_t fd)
82{
83 if (!plane || !pstate)
84 return;
85
86 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -040087 if (pstate->input_fence)
88 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -040089
90 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -040091 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -040092
93 DBG("0x%llX", fd);
94}
95
Clarence Ipcae1bb62016-07-07 12:07:13 -040096int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -040097{
Clarence Ipcae1bb62016-07-07 12:07:13 -040098 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -040099 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400100 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400101 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400102
103 if (!plane) {
104 DRM_ERROR("Invalid plane\n");
105 } else if (!plane->state) {
106 DRM_ERROR("Invalid plane state\n");
107 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400108 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400109 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400110 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400111
Clarence Ipcae1bb62016-07-07 12:07:13 -0400112 if (input_fence) {
113 ret = sde_sync_wait(input_fence, wait_ms);
114 switch (ret) {
115 case 0:
116 DBG("%s signaled", psde->pipe_name);
117 break;
118 case -ETIME:
119 DRM_ERROR("timeout on %s, %ums\n",
120 psde->pipe_name, wait_ms);
121 psde->is_error = true;
122 break;
123 default:
124 DRM_ERROR("error on %s, %d\n",
125 psde->pipe_name, ret);
126 psde->is_error = true;
127 break;
128 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400129 } else {
130 ret = 0;
131 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400132 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400133 return ret;
134}
135
Clarence Ipe78efb72016-06-24 18:35:21 -0400136static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400137 struct sde_plane_state *pstate,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400138 struct sde_hw_pipe_cfg *pipe_cfg, struct drm_framebuffer *fb)
139{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400140 struct sde_plane *psde;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400141 unsigned int shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400142 int i;
143
Clarence Ipae4e60c2016-06-26 22:44:04 -0400144 if (!plane || !pstate || !pipe_cfg || !fb)
145 return;
146
147 psde = to_sde_plane(plane);
148
149 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400150 /* stride */
Clarence Ip4c1d9772016-06-26 09:35:38 -0400151 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
Clarence Ip5e2a9222016-06-26 22:38:24 -0400152 BIT(SDE_DRM_DEINTERLACE))
153 shift = 1;
154 else
155 shift = 0;
156
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400157 i = min_t(int, ARRAY_SIZE(fb->pitches), SDE_MAX_PLANES);
158 while (i) {
159 --i;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400160 pipe_cfg->src.ystride[i] = fb->pitches[i] << shift;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400161 }
162
163 /* address */
164 for (i = 0; i < ARRAY_SIZE(pipe_cfg->addr.plane); ++i)
165 pipe_cfg->addr.plane[i] = msm_framebuffer_iova(fb,
166 psde->mmu_id, i);
167
168 /* hw driver */
169 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
170 }
171}
172
Clarence Ipcb410d42016-06-26 22:52:33 -0400173static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400174 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
175 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400176 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400177 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
178{
179}
180
Clarence Ipcb410d42016-06-26 22:52:33 -0400181/**
182 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
183 * @psde: Pointer to SDE plane object
184 * @src: Source size
185 * @dst: Destination size
186 * @phase_steps: Pointer to output array for phase steps
187 * @filter: Pointer to output array for filter type
188 * @fmt: Pointer to format definition
189 * @chroma_subsampling: Subsampling amount for chroma channel
190 *
191 * Returns: 0 on success
192 */
193static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400194 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400195 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400196 uint32_t chroma_subsampling)
197{
Clarence Ipcb410d42016-06-26 22:52:33 -0400198 if (!psde || !phase_steps || !filter || !fmt) {
199 DRM_ERROR("Invalid arguments\n");
200 return -EINVAL;
201 }
202
Clarence Ip4c1d9772016-06-26 09:35:38 -0400203 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400204 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400205 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400206 phase_steps[SDE_SSPP_COMP_1_2] =
207 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
208 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
209 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400210
211 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400212 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400213 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400214 (src <= dst) ? SDE_SCALE_FILTER_BIL :
215 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400216
Clarence Ipdbde9832016-06-26 09:48:36 -0400217 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400218 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400219 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
220 } else {
221 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
222 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400223 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400224 }
225 } else {
226 /* disable scaler */
Clarence Ipcb410d42016-06-26 22:52:33 -0400227 DBG("Disable scaler");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400228 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
229 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
230 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400231 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400232 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400233}
234
Clarence Ipcb410d42016-06-26 22:52:33 -0400235/**
236 * _sde_plane_setup_pixel_ext - determine default pixel extension values
237 * @psde: Pointer to SDE plane object
238 * @src: Source size
239 * @dst: Destination size
240 * @decimated_src: Source size after decimation, if any
241 * @phase_steps: Pointer to output array for phase steps
242 * @out_src: Output array for pixel extension values
243 * @out_edge1: Output array for pixel extension first edge
244 * @out_edge2: Output array for pixel extension second edge
245 * @filter: Pointer to array for filter type
246 * @fmt: Pointer to format definition
247 * @chroma_subsampling: Subsampling amount for chroma channel
248 * @post_compare: Whether to chroma subsampled source size for comparisions
249 */
250static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400251 uint32_t src, uint32_t dst, uint32_t decimated_src,
252 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400253 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400254 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400255 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400256{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400257 int64_t edge1, edge2, caf;
258 uint32_t src_work;
259 int i, tmp;
260
Clarence Ipcb410d42016-06-26 22:52:33 -0400261 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400262 out_edge2 && filter && fmt) {
263 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400264 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400265 caf = PHASE_STEP_UNIT_SCALE;
266 else
267 caf = 0;
268
269 for (i = 0; i < SDE_MAX_PLANES; i++) {
270 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400271 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400272 src_work /= chroma_subsampling;
273 if (post_compare)
274 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400275 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400276 /* unity */
277 edge1 = 0;
278 edge2 = 0;
279 } else if (dst >= src) {
280 /* upscale */
281 edge1 = (1 << PHASE_RESIDUAL);
282 edge1 -= caf;
283 edge2 = (1 << PHASE_RESIDUAL);
284 edge2 += (dst - 1) * *(phase_steps + i);
285 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
286 edge2 += caf;
287 edge2 = -(edge2);
288 } else {
289 /* downscale */
290 edge1 = 0;
291 edge2 = (dst - 1) * *(phase_steps + i);
292 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
293 edge2 += *(phase_steps + i);
294 edge2 = -(edge2);
295 }
296
297 /* only enable CAF for luma plane */
298 caf = 0;
299
300 /* populate output arrays */
301 *(out_src + i) = src_work;
302
303 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400304 if (edge1 >= 0) {
305 tmp = (uint32_t)edge1;
306 tmp >>= PHASE_STEP_SHIFT;
307 *(out_edge1 + i) = -tmp;
308 } else {
309 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400310 *(out_edge1 + i) =
311 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
312 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400313 }
314 if (edge2 >= 0) {
315 tmp = (uint32_t)edge2;
316 tmp >>= PHASE_STEP_SHIFT;
317 *(out_edge2 + i) = -tmp;
318 } else {
319 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400320 *(out_edge2 + i) =
321 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
322 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400323 }
324 }
325 }
326}
327
Clarence Ip5e2a9222016-06-26 22:38:24 -0400328/**
329 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
330 * sub-structure
331 * @blob_ptr: Pointer to start of incoming blob data
332 * @blob_size: Size of incoming blob data, in bytes
333 * @sub_ptr: Pointer to start of desired sub-structure
334 * @sub_size: Required size of sub-structure, in bytes
335 */
336static int _sde_plane_verify_blob(void *blob_ptr,
337 size_t blob_size,
338 void *sub_ptr,
339 size_t sub_size)
340{
341 /*
342 * Use the blob size provided by drm to check if there are enough
343 * bytes from the start of versioned sub-structures to the end of
344 * blob data:
345 *
346 * e.g.,
347 * blob_ptr --> struct blob_data {
348 * uint32_t version;
349 * sub_ptr --> struct blob_data_v1 v1;
350 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
351 * blob_ptr + blob_size --> };
352 *
353 * It's important to check the actual number of bytes from the start
354 * of the sub-structure to the end of the blob data, and not just rely
355 * on something like,
356 *
357 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
358 *
359 * This is because the start of the sub-structure can vary based on
360 * how the compiler pads the overall structure.
361 */
362 if (blob_ptr && sub_ptr)
363 /* return zero if end of blob >= end of sub-struct */
364 return ((unsigned char *)blob_ptr + blob_size) <
365 ((unsigned char *)sub_ptr + sub_size);
366 return -EINVAL;
367}
368
Clarence Ipe78efb72016-06-24 18:35:21 -0400369static void _sde_plane_setup_csc(struct sde_plane *psde,
370 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400371 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400372{
373 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
374 {
Clarence Ip373f8592016-05-26 00:58:42 -0400375 /* S15.16 format */
376 0x00012A00, 0x00000000, 0x00019880,
377 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
378 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400379 },
Clarence Ip373f8592016-05-26 00:58:42 -0400380 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400381 { 0xfff0, 0xff80, 0xff80,},
382 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400383 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400384 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400385 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400386 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400387 static const struct sde_csc_cfg sde_csc_NOP = {
388 {
Clarence Ip373f8592016-05-26 00:58:42 -0400389 /* identity matrix, S15.16 format */
390 0x10000, 0x00000, 0x00000,
391 0x00000, 0x10000, 0x00000,
392 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400393 },
Clarence Ip373f8592016-05-26 00:58:42 -0400394 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400395 { 0x0, 0x0, 0x0,},
396 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400397 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400398 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
399 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
400 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400401 struct sde_drm_csc *csc = NULL;
402 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400403 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400404
Clarence Ipaa0faf42016-05-30 12:07:48 -0400405 if (!psde || !pstate || !fmt) {
406 DRM_ERROR("Invalid arguments\n");
407 return;
408 }
409 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400410 return;
411
Clarence Ip5e2a9222016-06-26 22:38:24 -0400412 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400413 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400414 csc = msm_property_get_blob(&psde->property_info,
415 pstate->property_blobs,
416 &csc_size,
417 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400418 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400419 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400420 memcpy(&psde->csc_cfg,
421 &sde_csc_NOP,
422 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400423 switch (csc->version) {
424 case SDE_DRM_CSC_V1:
425 if (!_sde_plane_verify_blob(csc,
426 csc_size,
427 &csc->v1,
428 sizeof(struct sde_drm_csc_v1))) {
429 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400430 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400431 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400432 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400433 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400434 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400435 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400436 csc->v1.post_bias[i];
437 }
438 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400439 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400440 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400441 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400442 csc->v1.post_clamp[i];
443 }
Clarence Ipb493d762016-07-19 18:49:10 -0400444 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400445 }
446 break;
447 default:
448 break;
449 }
Clarence Ipb493d762016-07-19 18:49:10 -0400450 if (!psde->csc_ptr)
451 DRM_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400452 }
453
Clarence Ipcae1bb62016-07-07 12:07:13 -0400454 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400455 if (psde->csc_ptr)
456 DBG("user blob override for csc");
Clarence Ipb493d762016-07-19 18:49:10 -0400457 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400458 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400459}
460
Clarence Ipcb410d42016-06-26 22:52:33 -0400461static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400462 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400463 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700464{
Clarence Ipcb410d42016-06-26 22:52:33 -0400465 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400466 struct sde_drm_scaler *sc_u = NULL;
467 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400468 size_t sc_u_size = 0;
469 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
470 uint32_t tmp;
471 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400472
Clarence Ipcb410d42016-06-26 22:52:33 -0400473 if (!psde || !fmt)
474 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400475
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400476 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400477 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400478
Clarence Ip5e2a9222016-06-26 22:38:24 -0400479 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400480 if (pstate)
481 sc_u = msm_property_get_blob(&psde->property_info,
482 pstate->property_blobs,
483 &sc_u_size,
484 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400485 if (sc_u) {
486 switch (sc_u->version) {
487 case SDE_DRM_SCALER_V1:
488 if (!_sde_plane_verify_blob(sc_u,
489 sc_u_size,
490 &sc_u->v1,
491 sizeof(*sc_u1)))
492 sc_u1 = &sc_u->v1;
493 break;
494 default:
495 DBG("Unrecognized scaler blob v%lld", sc_u->version);
496 break;
497 }
498 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400499
Clarence Ip04ec67d2016-05-26 01:16:15 -0400500 /* decimation */
501 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
502 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
503 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400504 } else {
505 psde->pipe_cfg.horz_decimation = 0;
506 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400507 }
508
509 /* don't chroma subsample if decimating */
510 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400511 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400512 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400513 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400514
Clarence Ip5e2a9222016-06-26 22:38:24 -0400515 /* update scaler */
516 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
517 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Clarence Ipcb410d42016-06-26 22:52:33 -0400518 DBG("SCALER3 blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400519 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400520 _sde_plane_setup_scaler3(psde,
521 psde->pipe_cfg.src_rect.w,
522 psde->pipe_cfg.src_rect.h,
523 psde->pipe_cfg.dst_rect.w,
524 psde->pipe_cfg.dst_rect.h,
525 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400526 chroma_subsmpl_h, chroma_subsmpl_v);
527 } else {
528 /* always calculate basic scaler config */
529 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
530 /* populate from user space */
531 for (i = 0; i < SDE_MAX_PLANES; i++) {
532 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
533 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
534 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
535 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400536
Clarence Ip5e2a9222016-06-26 22:38:24 -0400537 pe->horz_filter[i] = sc_u1->horz_filter[i];
538 pe->vert_filter[i] = sc_u1->vert_filter[i];
539 }
540 } else {
541 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400542 _sde_plane_setup_scaler2(psde,
543 psde->pipe_cfg.src_rect.w,
544 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400545 pe->phase_step_x,
546 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400547 _sde_plane_setup_scaler2(psde,
548 psde->pipe_cfg.src_rect.h,
549 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400550 pe->phase_step_y,
551 pe->vert_filter, fmt, chroma_subsmpl_v);
552 }
553 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400554
Clarence Ip5e2a9222016-06-26 22:38:24 -0400555 /* update pixel extensions */
556 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
557 /* populate from user space */
Clarence Ipcb410d42016-06-26 22:52:33 -0400558 DBG("PIXEXT blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400559 for (i = 0; i < SDE_MAX_PLANES; i++) {
560 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
561 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
562 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
563 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
564 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
565 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
566 pe->roi_w[i] = sc_u1->lr.roi[i];
567
568 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
569 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
570 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
571 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
572 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
573 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
574 pe->roi_h[i] = sc_u1->tb.roi[i];
575 }
576 } else {
577 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400578 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400579 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400580 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400581 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400582 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
583 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400584 pe->phase_step_x,
585 pe->roi_w,
586 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400587 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400588 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400589
Clarence Ipcb410d42016-06-26 22:52:33 -0400590 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400591 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400592 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
593 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400594 pe->phase_step_y,
595 pe->roi_h,
596 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400597 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400598 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400599
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400600 for (i = 0; i < SDE_MAX_PLANES; i++) {
601 if (pe->num_ext_pxls_left[i] >= 0)
602 pe->left_rpt[i] =
603 pe->num_ext_pxls_left[i];
604 else
605 pe->left_ftch[i] =
606 pe->num_ext_pxls_left[i];
607
608 if (pe->num_ext_pxls_right[i] >= 0)
609 pe->right_rpt[i] =
610 pe->num_ext_pxls_right[i];
611 else
612 pe->right_ftch[i] =
613 pe->num_ext_pxls_right[i];
614
615 if (pe->num_ext_pxls_top[i] >= 0)
616 pe->top_rpt[i] =
617 pe->num_ext_pxls_top[i];
618 else
619 pe->top_ftch[i] =
620 pe->num_ext_pxls_top[i];
621
622 if (pe->num_ext_pxls_btm[i] >= 0)
623 pe->btm_rpt[i] =
624 pe->num_ext_pxls_btm[i];
625 else
626 pe->btm_ftch[i] =
627 pe->num_ext_pxls_btm[i];
628 }
629 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400630}
631
Clarence Ipcae1bb62016-07-07 12:07:13 -0400632/**
633 * _sde_plane_color_fill - enables color fill on plane
634 * @plane: Pointer to DRM plane object
635 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
636 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
637 * Returns: 0 on success
638 */
639static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -0400640 uint32_t color, uint32_t alpha)
641{
642 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400643 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400644
645 if (!plane) {
646 DRM_ERROR("Invalid plane\n");
647 return -EINVAL;
648 }
649
650 psde = to_sde_plane(plane);
651 if (!psde->pipe_hw) {
652 DRM_ERROR("Invalid plane h/w pointer\n");
653 return -EINVAL;
654 }
655
Clarence Ipcae1bb62016-07-07 12:07:13 -0400656 DBG("");
657
Clarence Ipcb410d42016-06-26 22:52:33 -0400658 /*
659 * select fill format to match user property expectation,
660 * h/w only supports RGB variants
661 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400662 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -0400663
664 /* update sspp */
665 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
666 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
667 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
668
669 /* override scaler/decimation if solid fill */
670 psde->pipe_cfg.src_rect.x = 0;
671 psde->pipe_cfg.src_rect.y = 0;
672 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
673 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
674
675 _sde_plane_setup_scaler(psde, fmt, 0);
676
677 if (psde->pipe_hw->ops.setup_format)
678 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
679 fmt, SDE_SSPP_SOLID_FILL);
680
681 if (psde->pipe_hw->ops.setup_rects)
682 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
683 &psde->pipe_cfg, &psde->pixel_ext);
684 }
685
686 return 0;
687}
688
689static int _sde_plane_mode_set(struct drm_plane *plane,
690 struct drm_crtc *crtc, struct drm_framebuffer *fb,
691 int crtc_x, int crtc_y,
692 unsigned int crtc_w, unsigned int crtc_h,
693 uint32_t src_x, uint32_t src_y,
694 uint32_t src_w, uint32_t src_h)
695{
696 struct sde_plane *psde;
697 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400698 uint32_t nplanes;
Clarence Ipcb410d42016-06-26 22:52:33 -0400699 uint32_t src_flags;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400700 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400701
702 DBG("");
703
704 if (!plane || !plane->state) {
705 DRM_ERROR("Invalid plane/state\n");
706 return -EINVAL;
707 }
708 if (!crtc || !fb) {
709 DRM_ERROR("Invalid crtc/fb\n");
710 return -EINVAL;
711 }
712
713 psde = to_sde_plane(plane);
714 pstate = to_sde_plane_state(plane->state);
715 nplanes = drm_format_num_planes(fb->pixel_format);
716
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400717 fmt = to_sde_format(msm_framebuffer_format(fb));
Clarence Ipcb410d42016-06-26 22:52:33 -0400718
719 /* src values are in Q16 fixed point, convert to integer */
720 src_x = src_x >> 16;
721 src_y = src_y >> 16;
722 src_w = src_w >> 16;
723 src_h = src_h >> 16;
724
725 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", psde->pipe_name,
726 fb->base.id, src_x, src_y, src_w, src_h,
727 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
728
729 /* update format configuration */
730 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
731 src_flags = 0;
732
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400733 psde->pipe_cfg.src.format = fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400734 psde->pipe_cfg.src.width = fb->width;
735 psde->pipe_cfg.src.height = fb->height;
736 psde->pipe_cfg.src.num_planes = nplanes;
737
738 /* flags */
739 DBG("Flags 0x%llX, rotation 0x%llX",
740 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
741 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
742 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
743 BIT(DRM_REFLECT_X))
744 src_flags |= SDE_SSPP_FLIP_LR;
745 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
746 BIT(DRM_REFLECT_Y))
747 src_flags |= SDE_SSPP_FLIP_UD;
748 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
749 BIT(SDE_DRM_DEINTERLACE)) {
750 src_h /= 2;
751 src_y = DIV_ROUND_UP(src_y, 2);
752 src_y &= ~0x1;
753 }
754
755 psde->pipe_cfg.src_rect.x = src_x;
756 psde->pipe_cfg.src_rect.y = src_y;
757 psde->pipe_cfg.src_rect.w = src_w;
758 psde->pipe_cfg.src_rect.h = src_h;
759
760 psde->pipe_cfg.dst_rect.x = crtc_x;
761 psde->pipe_cfg.dst_rect.y = crtc_y;
762 psde->pipe_cfg.dst_rect.w = crtc_w;
763 psde->pipe_cfg.dst_rect.h = crtc_h;
764
765 /* get sde pixel format definition */
766 fmt = psde->pipe_cfg.src.format;
767
768 /* check for color fill */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400769 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400770 PLANE_PROP_COLOR_FILL);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400771 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
772 /* skip remaining processing on color fill */
773 return 0;
Clarence Ipcb410d42016-06-26 22:52:33 -0400774
775 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
776
777 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400778
Clarence Ip4c1d9772016-06-26 09:35:38 -0400779 if (psde->pipe_hw->ops.setup_format)
780 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -0400781 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400782 if (psde->pipe_hw->ops.setup_rects)
783 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
784 &psde->pipe_cfg, &psde->pixel_ext);
785
Clarence Ipe78efb72016-06-24 18:35:21 -0400786 /* update sharpening */
787 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
788 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
789 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
790 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
791
792 if (psde->pipe_hw->ops.setup_sharpening)
793 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
794 &psde->sharp_cfg);
795
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400796 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -0400797 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -0400798 _sde_plane_setup_csc(psde, pstate, fmt);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400799 else
800 psde->csc_ptr = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400801
Clarence Ip5e2a9222016-06-26 22:38:24 -0400802 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400803}
804
805static int sde_plane_prepare_fb(struct drm_plane *plane,
806 const struct drm_plane_state *new_state)
807{
808 struct drm_framebuffer *fb = new_state->fb;
809 struct sde_plane *psde = to_sde_plane(plane);
810
811 if (!new_state->fb)
812 return 0;
813
Clarence Ipae4e60c2016-06-26 22:44:04 -0400814 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400815 return msm_framebuffer_prepare(fb, psde->mmu_id);
816}
817
818static void sde_plane_cleanup_fb(struct drm_plane *plane,
819 const struct drm_plane_state *old_state)
820{
821 struct drm_framebuffer *fb = old_state->fb;
822 struct sde_plane *psde = to_sde_plane(plane);
823
824 if (!fb)
825 return;
826
Clarence Ipae4e60c2016-06-26 22:44:04 -0400827 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400828 msm_framebuffer_cleanup(fb, psde->mmu_id);
829}
830
Clarence Ipdbde9832016-06-26 09:48:36 -0400831static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
832 struct sde_plane_state *pstate,
833 struct drm_framebuffer *fb)
834{
835 return 0;
836}
837
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400838static int sde_plane_atomic_check(struct drm_plane *plane,
839 struct drm_plane_state *state)
840{
Clarence Ipdbde9832016-06-26 09:48:36 -0400841 struct sde_plane *psde;
842 struct sde_plane_state *pstate;
843 struct drm_plane_state *old_state;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400844 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -0400845 size_t sc_u_size = 0;
846 struct sde_drm_scaler *sc_u = NULL;
847 int ret = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400848
Clarence Ipdbde9832016-06-26 09:48:36 -0400849 uint32_t src_x, src_y;
850 uint32_t src_w, src_h;
851 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
852 uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
853 uint32_t upscale_max, downscale_max;
854
855 DBG();
856
857 if (!plane || !state) {
858 DRM_ERROR("Invalid plane/state\n");
859 ret = -EINVAL;
860 goto exit;
861 }
862
863 psde = to_sde_plane(plane);
864 pstate = to_sde_plane_state(state);
865 old_state = plane->state;
866
867 if (!psde->pipe_sblk) {
868 DRM_ERROR("Invalid plane catalog\n");
869 ret = -EINVAL;
870 goto exit;
871 }
872
873 /* get decimation config from user space */
874 deci_w = 0;
875 deci_h = 0;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400876 sc_u = msm_property_get_blob(&psde->property_info,
877 pstate->property_blobs,
878 &sc_u_size,
879 PLANE_PROP_SCALER);
Clarence Ipdbde9832016-06-26 09:48:36 -0400880 if (sc_u) {
881 switch (sc_u->version) {
882 case SDE_DRM_SCALER_V1:
883 if (!_sde_plane_verify_blob(sc_u,
884 sc_u_size,
885 &sc_u->v1,
886 sizeof(struct sde_drm_scaler_v1))) {
887 deci_w = sc_u->v1.horz_decimate;
888 deci_h = sc_u->v1.vert_decimate;
889 }
890 break;
891 default:
892 DBG("Unrecognized scaler blob v%lld", sc_u->version);
893 break;
894 }
895 }
896
897 /* src values are in Q16 fixed point, convert to integer */
898 src_x = state->src_x >> 16;
899 src_y = state->src_y >> 16;
900 src_w = state->src_w >> 16;
901 src_h = state->src_h >> 16;
902
903 src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
904 src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
905
906 src_max_x = 0xFFFF;
907 src_max_y = 0xFFFF;
908 src_max_w = 0x3FFF;
909 src_max_h = 0x3FFF;
910 upscale_max = psde->pipe_sblk->maxupscale;
911 downscale_max = psde->pipe_sblk->maxdwnscale;
912
913 /*
914 * Including checks from mdss
915 * - mdss_mdp_overlay_req_check()
916 */
Clarence Ip4ce59322016-06-26 22:27:51 -0400917 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400918 sde_plane_enabled(old_state), sde_plane_enabled(state));
919
920 if (sde_plane_enabled(state)) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400921 /* determine SDE format definition. State's fb is valid here. */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400922 fmt = to_sde_format(msm_framebuffer_format(state->fb));
Clarence Ipdbde9832016-06-26 09:48:36 -0400923
924 /* don't check for other errors after first failure */
925 if (SDE_FORMAT_IS_YUV(fmt) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400926 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400927 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400928 DRM_ERROR("Pipe doesn't support YUV\n");
Clarence Ipdbde9832016-06-26 09:48:36 -0400929 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400930
Clarence Ipdbde9832016-06-26 09:48:36 -0400931 /* verify source size/region */
932 } else if (!src_w || !src_h ||
933 (src_w > src_max_w) || (src_h > src_max_h) ||
934 (src_x > src_max_x) || (src_y > src_max_y) ||
935 (src_x + src_w > src_max_x) ||
936 (src_y + src_h > src_max_y)) {
937 DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
938 src_x, src_y, src_x + src_w,
939 src_y + src_h);
940 ret = -EINVAL;
941
942 /* require even source for YUV */
943 } else if (SDE_FORMAT_IS_YUV(fmt) &&
944 ((src_x & 0x1) || (src_y & 0x1) ||
945 (src_w & 0x1) || (src_h & 0x1))) {
946 DRM_ERROR("Invalid odd src res/pos for YUV\n");
947 ret = -EINVAL;
948
949 /* verify scaler requirements */
950 } else if (!(psde->features & SDE_SSPP_SCALER) &&
951 ((src_w != state->crtc_w) ||
952 (src_h != state->crtc_h))) {
953 DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
954 src_w, src_h, state->crtc_w,
955 state->crtc_h);
956 ret = -EINVAL;
957
958 /* check decimated source width */
959 } else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
960 DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
961 src_w, src_deci_w,
962 psde->pipe_sblk->maxlinewidth);
963 ret = -EINVAL;
964
965 /* check max scaler capability */
966 } else if (((src_deci_w * upscale_max) < state->crtc_w) ||
967 ((src_deci_h * upscale_max) < state->crtc_h) ||
968 ((state->crtc_w * downscale_max) < src_deci_w) ||
969 ((state->crtc_h * downscale_max) < src_deci_h)) {
970 DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
971 src_deci_w, src_deci_h,
972 state->crtc_w, state->crtc_h);
973 ret = -EINVAL;
974
975 /* check frame buffer */
976 } else if (_sde_plane_atomic_check_fb(
977 psde, pstate, state->fb)) {
978 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400979 }
980
Clarence Ipdbde9832016-06-26 09:48:36 -0400981 /* check decimation (and bwc/fetch mode) */
982 if (!ret && (deci_w || deci_h)) {
983 if (SDE_FORMAT_IS_UBWC(fmt)) {
984 DRM_ERROR("No decimation with BWC\n");
985 ret = -EINVAL;
986 } else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
987 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
988 DRM_ERROR("Too much decimation requested\n");
989 ret = -EINVAL;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400990 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400991 DRM_ERROR("Decimation requires linear fetch\n");
992 ret = -EINVAL;
993 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400994 }
995 }
996
Clarence Ipdbde9832016-06-26 09:48:36 -0400997 if (!ret) {
998 if (sde_plane_enabled(state) &&
999 sde_plane_enabled(old_state)) {
1000 bool full_modeset = false;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001001
Clarence Ipdbde9832016-06-26 09:48:36 -04001002 if (state->fb->pixel_format !=
1003 old_state->fb->pixel_format) {
1004 DBG("%s: format change!", psde->pipe_name);
1005 full_modeset = true;
1006 }
1007 if (state->src_w != old_state->src_w ||
1008 state->src_h != old_state->src_h) {
1009 DBG("%s: src_w change!", psde->pipe_name);
1010 full_modeset = true;
1011 }
1012 if (to_sde_plane_state(old_state)->pending) {
1013 DBG("%s: still pending!", psde->pipe_name);
1014 full_modeset = true;
1015 }
Lloyd Atkinson66358902016-03-23 11:58:23 -04001016 if (full_modeset)
Clarence Ipdbde9832016-06-26 09:48:36 -04001017 to_sde_plane_state(state)->mode_changed = true;
Lloyd Atkinson66358902016-03-23 11:58:23 -04001018
Clarence Ipdbde9832016-06-26 09:48:36 -04001019 } else {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001020 to_sde_plane_state(state)->mode_changed = true;
1021 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001022 }
1023
Clarence Ipdbde9832016-06-26 09:48:36 -04001024exit:
1025 return ret;
1026}
1027
Clarence Ipcae1bb62016-07-07 12:07:13 -04001028/**
1029 * sde_plane_flush - final plane operations before commit flush
1030 * @plane: Pointer to drm plane structure
1031 */
1032void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001033{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001034 struct sde_plane *psde;
1035
1036 if (!plane)
1037 return;
1038
1039 psde = to_sde_plane(plane);
1040
1041 /*
1042 * These updates have to be done immediately before the plane flush
1043 * timing, and may not be moved to the atomic_update/mode_set functions.
1044 */
1045 if (psde->is_error)
1046 /* force white frame with 0% alpha pipe output on error */
1047 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1048 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1049 /* force 100% alpha */
1050 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1051 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1052 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1053
1054 /* flag h/w flush complete */
1055 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001056 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001057}
1058
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001059static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001060 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001061{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001062 struct sde_plane *sde_plane;
1063 struct drm_plane_state *state;
1064 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001065
Clarence Ip5e2a9222016-06-26 22:38:24 -04001066 if (!plane || !plane->state) {
1067 DRM_ERROR("Invalid plane/state\n");
1068 return;
1069 }
1070
1071 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001072 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001073 state = plane->state;
1074 pstate = to_sde_plane_state(state);
1075
Clarence Ipae4e60c2016-06-26 22:44:04 -04001076 DBG("%s: update", sde_plane->pipe_name);
1077
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001078 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001079 pstate->pending = true;
1080 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001081 int ret;
1082
Clarence Ip5e2a9222016-06-26 22:38:24 -04001083 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -04001084 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001085 state->crtc, state->fb,
1086 state->crtc_x, state->crtc_y,
1087 state->crtc_w, state->crtc_h,
1088 state->src_x, state->src_y,
1089 state->src_w, state->src_h);
1090 /* atomic_check should have ensured that this doesn't fail */
1091 WARN_ON(ret < 0);
1092 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001093 _sde_plane_set_scanout(plane, pstate,
1094 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001095 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001096}
1097
1098/* helper to install properties which are common to planes and crtcs */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001099static void _sde_plane_install_properties(struct drm_plane *plane)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001100{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001101 static const struct drm_prop_enum_list e_blend_op[] = {
1102 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1103 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1104 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1105 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1106 };
1107 static const struct drm_prop_enum_list e_src_config[] = {
1108 {SDE_DRM_DEINTERLACE, "deinterlace"}
1109 };
1110 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001111
Clarence Ip4ce59322016-06-26 22:27:51 -04001112 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001113
Clarence Ipaa0faf42016-05-30 12:07:48 -04001114 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
1115 DRM_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001116 return;
1117 }
1118
1119 /* range properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001120 msm_property_install_range(&psde->property_info, "zpos", 0, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001121 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1122 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1123 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001124
Clarence Ipaa0faf42016-05-30 12:07:48 -04001125 msm_property_install_range(&psde->property_info, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001126 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001127
Clarence Ipcb410d42016-06-26 22:52:33 -04001128 if (psde->pipe_hw->ops.setup_solidfill)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001129 msm_property_install_range(&psde->property_info, "color_fill",
Clarence Ipcb410d42016-06-26 22:52:33 -04001130 0, 0xFFFFFFFF, 0,
1131 PLANE_PROP_COLOR_FILL);
1132
Clarence Ipcae1bb62016-07-07 12:07:13 -04001133 msm_property_install_range(&psde->property_info, "input_fence",
1134 0, ~0, ~0,
1135 PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001136
1137 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001138 msm_property_install_rotation(&psde->property_info,
1139 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y),
1140 PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001141
Clarence Ip04ec67d2016-05-26 01:16:15 -04001142 /* enum/bitmask properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001143 msm_property_install_enum(&psde->property_info, "blend_op", 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001144 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001145 PLANE_PROP_BLEND_OP);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001146 msm_property_install_enum(&psde->property_info, "src_config", 1,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001147 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001148 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001149
Clarence Ipe78efb72016-06-24 18:35:21 -04001150 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001151 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001152 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001153 PLANE_PROP_SCALER);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001154 if (psde->features & BIT(SDE_SSPP_CSC)) {
1155 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001156 PLANE_PROP_CSC);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001157 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001158}
1159
1160static int sde_plane_atomic_set_property(struct drm_plane *plane,
1161 struct drm_plane_state *state, struct drm_property *property,
1162 uint64_t val)
1163{
Clarence Ip730e7192016-06-26 22:45:09 -04001164 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001165 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001166 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001167
Clarence Ipaa0faf42016-05-30 12:07:48 -04001168 DBG("");
1169
1170 if (!plane) {
1171 DRM_ERROR("Invalid plane\n");
1172 } else if (!state) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001173 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001174 } else {
1175 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001176 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001177 ret = msm_property_atomic_set(&psde->property_info,
1178 pstate->property_values, pstate->property_blobs,
1179 property, val);
1180 if (!ret) {
1181 idx = msm_property_index(&psde->property_info,
1182 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001183 if (idx == PLANE_PROP_INPUT_FENCE)
1184 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001185 }
1186 }
1187
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001188 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001189}
1190
1191static int sde_plane_set_property(struct drm_plane *plane,
1192 struct drm_property *property, uint64_t val)
1193{
Clarence Ip4ce59322016-06-26 22:27:51 -04001194 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001195
Clarence Ipae4e60c2016-06-26 22:44:04 -04001196 return sde_plane_atomic_set_property(plane,
1197 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001198}
1199
1200static int sde_plane_atomic_get_property(struct drm_plane *plane,
1201 const struct drm_plane_state *state,
1202 struct drm_property *property, uint64_t *val)
1203{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001204 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001205 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001206 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001207
Clarence Ipaa0faf42016-05-30 12:07:48 -04001208 DBG("");
1209
1210 if (!plane) {
1211 DRM_ERROR("Invalid plane\n");
1212 } else if (!state) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001213 DRM_ERROR("Invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001214 } else {
1215 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001216 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001217 ret = msm_property_atomic_get(&psde->property_info,
1218 pstate->property_values, pstate->property_blobs,
1219 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001220 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001221
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001222 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001223}
1224
1225static void sde_plane_destroy(struct drm_plane *plane)
1226{
Clarence Ip4ce59322016-06-26 22:27:51 -04001227 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001228
Clarence Ip4ce59322016-06-26 22:27:51 -04001229 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001230
Clarence Ip4ce59322016-06-26 22:27:51 -04001231 if (plane) {
1232 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001233
Clarence Ip4ce59322016-06-26 22:27:51 -04001234 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001235
Clarence Ipaa0faf42016-05-30 12:07:48 -04001236 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001237 mutex_destroy(&psde->lock);
1238
Clarence Ip4ce59322016-06-26 22:27:51 -04001239 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001240
Clarence Ip4ce59322016-06-26 22:27:51 -04001241 /* this will destroy the states as well */
1242 drm_plane_cleanup(plane);
1243
Clarence Ip4c1d9772016-06-26 09:35:38 -04001244 if (psde->pipe_hw)
1245 sde_hw_sspp_destroy(psde->pipe_hw);
1246
Clarence Ip4ce59322016-06-26 22:27:51 -04001247 kfree(psde);
1248 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001249}
1250
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001251static void sde_plane_destroy_state(struct drm_plane *plane,
1252 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001253{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001254 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001255 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001256
Clarence Ipae4e60c2016-06-26 22:44:04 -04001257 if (!plane || !state) {
1258 DRM_ERROR("Invalid plane/state\n");
1259 return;
1260 }
1261
Clarence Ipaa0faf42016-05-30 12:07:48 -04001262 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001263 pstate = to_sde_plane_state(state);
1264
1265 DBG("");
1266
Clarence Ipe78efb72016-06-24 18:35:21 -04001267 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001268 if (state->fb)
1269 drm_framebuffer_unreference(state->fb);
1270
Clarence Ipae4e60c2016-06-26 22:44:04 -04001271 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001272 if (pstate->input_fence)
1273 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001274
Clarence Ipaa0faf42016-05-30 12:07:48 -04001275 /* destroy value helper */
1276 msm_property_destroy_state(&psde->property_info, pstate,
1277 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001278}
1279
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001280static struct drm_plane_state *
1281sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001282{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001283 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001284 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001285 struct sde_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001286
Clarence Ip730e7192016-06-26 22:45:09 -04001287 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001288 return NULL;
1289
Clarence Ip730e7192016-06-26 22:45:09 -04001290 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001291 psde = to_sde_plane(plane);
1292 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001293 if (!pstate)
1294 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001295
Clarence Ipaa0faf42016-05-30 12:07:48 -04001296 DBG("");
1297
1298 /* duplicate value helper */
1299 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1300 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001301
Clarence Ip730e7192016-06-26 22:45:09 -04001302 /* add ref count for frame buffer */
1303 if (pstate->base.fb)
1304 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001305
Clarence Ip730e7192016-06-26 22:45:09 -04001306 /* add ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001307 if (pstate->input_fence) {
1308 pstate->input_fence = 0;
1309 _sde_plane_set_input_fence(plane, pstate, pstate->
1310 property_values[PLANE_PROP_INPUT_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001311 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001312
Clarence Ip730e7192016-06-26 22:45:09 -04001313 pstate->mode_changed = false;
1314 pstate->pending = false;
1315
1316 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001317}
1318
1319static void sde_plane_reset(struct drm_plane *plane)
1320{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001321 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001322 struct sde_plane_state *pstate;
1323
Clarence Ipae4e60c2016-06-26 22:44:04 -04001324 if (!plane) {
1325 DRM_ERROR("Invalid plane\n");
1326 return;
1327 }
1328
Clarence Ip730e7192016-06-26 22:45:09 -04001329 psde = to_sde_plane(plane);
1330 DBG("%s", psde->pipe_name);
1331
Clarence Ipae4e60c2016-06-26 22:44:04 -04001332 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001333 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001334 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001335 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001336 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001337
Clarence Ipaa0faf42016-05-30 12:07:48 -04001338 pstate = msm_property_alloc_state(&psde->property_info);
1339 if (!pstate)
1340 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001341
Clarence Ipaa0faf42016-05-30 12:07:48 -04001342 /* reset value helper */
1343 msm_property_reset_state(&psde->property_info, pstate,
1344 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001345
1346 pstate->base.plane = plane;
1347
1348 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001349}
1350
1351static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001352 .update_plane = drm_atomic_helper_update_plane,
1353 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001354 .destroy = sde_plane_destroy,
1355 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001356 .atomic_set_property = sde_plane_atomic_set_property,
1357 .atomic_get_property = sde_plane_atomic_get_property,
1358 .reset = sde_plane_reset,
1359 .atomic_duplicate_state = sde_plane_duplicate_state,
1360 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001361};
1362
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001363static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1364 .prepare_fb = sde_plane_prepare_fb,
1365 .cleanup_fb = sde_plane_cleanup_fb,
1366 .atomic_check = sde_plane_atomic_check,
1367 .atomic_update = sde_plane_atomic_update,
1368};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001369
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001370enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001371{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001372 struct sde_plane *sde_plane = to_sde_plane(plane);
1373
1374 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001375}
1376
Clarence Ip4ce59322016-06-26 22:27:51 -04001377static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1378{
1379 const struct sde_sspp_sub_blks *sblk = 0;
1380 const struct sde_sspp_cfg *cfg = 0;
1381
1382 if (psde && psde->pipe_hw)
1383 cfg = psde->pipe_hw->cap;
1384 if (cfg)
1385 sblk = cfg->sblk;
1386
1387 if (kms && sblk) {
1388 /* create overall sub-directory for the pipe */
1389 psde->debugfs_root =
1390 debugfs_create_dir(psde->pipe_name,
1391 sde_debugfs_get_root(kms));
1392 if (psde->debugfs_root) {
1393 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001394 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001395 psde->debugfs_root, &psde->features);
1396
1397 /* add register dump support */
1398 sde_debugfs_setup_regset32(&psde->debugfs_src,
1399 sblk->src_blk.base + cfg->base,
1400 sblk->src_blk.len,
1401 kms->mmio);
1402 sde_debugfs_create_regset32("src_blk", 0444,
1403 psde->debugfs_root, &psde->debugfs_src);
1404
1405 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1406 sblk->scaler_blk.base + cfg->base,
1407 sblk->scaler_blk.len,
1408 kms->mmio);
1409 sde_debugfs_create_regset32("scaler_blk", 0444,
1410 psde->debugfs_root,
1411 &psde->debugfs_scaler);
1412
1413 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1414 sblk->csc_blk.base + cfg->base,
1415 sblk->csc_blk.len,
1416 kms->mmio);
1417 sde_debugfs_create_regset32("csc_blk", 0444,
1418 psde->debugfs_root, &psde->debugfs_csc);
1419 }
1420 }
1421}
1422
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001423/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001424struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001425 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001426{
1427 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001428 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001429 struct msm_drm_private *priv;
1430 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001431 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001432 int ret = -EINVAL;
1433
1434 if (!dev) {
1435 DRM_ERROR("[%u]Device is NULL\n", pipe);
1436 goto exit;
1437 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001438
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001439 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001440 if (!priv) {
1441 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1442 goto exit;
1443 }
1444
1445 if (!priv->kms) {
1446 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1447 goto exit;
1448 }
1449 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001450
Clarence Ip4c1d9772016-06-26 09:35:38 -04001451 if (!kms->catalog) {
1452 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1453 goto exit;
1454 }
1455
Clarence Ip4ce59322016-06-26 22:27:51 -04001456 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001457 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1458 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001459 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001460 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001461 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001462 }
1463
Clarence Ip4c1d9772016-06-26 09:35:38 -04001464 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001465 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001466 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001467 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001468
Clarence Ip4c1d9772016-06-26 09:35:38 -04001469 /* initialize underlying h/w driver */
1470 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1471 if (IS_ERR(psde->pipe_hw)) {
1472 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1473 ret = PTR_ERR(psde->pipe_hw);
1474 goto clean_plane;
1475 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1476 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1477 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001478 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001479
1480 /* cache features mask for later */
1481 psde->features = psde->pipe_hw->cap->features;
1482 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1483
1484 /* add plane to DRM framework */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001485 psde->nformats = sde_populate_formats(psde->formats,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001486 ARRAY_SIZE(psde->formats),
1487 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001488 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001489
Clarence Ip4c1d9772016-06-26 09:35:38 -04001490 if (!psde->nformats) {
1491 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1492 goto clean_sspp;
1493 }
1494
1495 if (psde->features & BIT(SDE_SSPP_CURSOR))
1496 type = DRM_PLANE_TYPE_CURSOR;
1497 else if (primary_plane)
1498 type = DRM_PLANE_TYPE_PRIMARY;
1499 else
1500 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001501 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1502 psde->formats, psde->nformats,
1503 type);
1504 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001505 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001506
Clarence Ip4c1d9772016-06-26 09:35:38 -04001507 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001508 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001509
Clarence Ipaa0faf42016-05-30 12:07:48 -04001510 msm_property_init(&psde->property_info, &plane->base, dev,
1511 priv->plane_property, psde->property_data,
1512 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
1513 sizeof(struct sde_plane_state));
1514
1515 _sde_plane_install_properties(plane);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001516
Clarence Ip4ce59322016-06-26 22:27:51 -04001517 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001518 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001519
Clarence Ip730e7192016-06-26 22:45:09 -04001520 mutex_init(&psde->lock);
1521
Clarence Ip4ce59322016-06-26 22:27:51 -04001522 _sde_plane_init_debugfs(psde, kms);
1523
Clarence Ip4c1d9772016-06-26 09:35:38 -04001524 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001525 return plane;
1526
Clarence Ip4c1d9772016-06-26 09:35:38 -04001527clean_sspp:
1528 if (psde && psde->pipe_hw)
1529 sde_hw_sspp_destroy(psde->pipe_hw);
1530clean_plane:
1531 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001532exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001533 return ERR_PTR(ret);
1534}