blob: e20161c0bb90bd2e9e0057fed25099eaadc4611d [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;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -040046 uint32_t formats[64];
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 Ipea3d6262016-07-15 16:20:11 -040065 struct drm_property_blob *blob_sde_info;
Clarence Ip730e7192016-06-26 22:45:09 -040066
Clarence Ip4ce59322016-06-26 22:27:51 -040067 /* debugfs related stuff */
68 struct dentry *debugfs_root;
69 struct sde_debugfs_regset32 debugfs_src;
70 struct sde_debugfs_regset32 debugfs_scaler;
71 struct sde_debugfs_regset32 debugfs_csc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070072};
73#define to_sde_plane(x) container_of(x, struct sde_plane, base)
74
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040075static bool sde_plane_enabled(struct drm_plane_state *state)
76{
Clarence Ipdbde9832016-06-26 09:48:36 -040077 return state && state->fb && state->crtc;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -040078}
79
Clarence Ipcae1bb62016-07-07 12:07:13 -040080/* helper to update a state's input fence pointer from the property */
81static void _sde_plane_set_input_fence(struct drm_plane *plane,
Clarence Ipae4e60c2016-06-26 22:44:04 -040082 struct sde_plane_state *pstate, uint64_t fd)
83{
84 if (!plane || !pstate)
85 return;
86
87 /* clear previous reference */
Clarence Ipcae1bb62016-07-07 12:07:13 -040088 if (pstate->input_fence)
89 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -040090
91 /* get fence pointer for later */
Clarence Ipcae1bb62016-07-07 12:07:13 -040092 pstate->input_fence = sde_sync_get(fd);
Clarence Ipae4e60c2016-06-26 22:44:04 -040093
94 DBG("0x%llX", fd);
95}
96
Clarence Ipcae1bb62016-07-07 12:07:13 -040097int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms)
Clarence Ipae4e60c2016-06-26 22:44:04 -040098{
Clarence Ipcae1bb62016-07-07 12:07:13 -040099 struct sde_plane *psde;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400100 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400101 void *input_fence;
Clarence Ipcb410d42016-06-26 22:52:33 -0400102 int ret = -EINVAL;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400103
104 if (!plane) {
105 DRM_ERROR("Invalid plane\n");
106 } else if (!plane->state) {
107 DRM_ERROR("Invalid plane state\n");
108 } else {
Clarence Ipcae1bb62016-07-07 12:07:13 -0400109 psde = to_sde_plane(plane);
Clarence Ipae4e60c2016-06-26 22:44:04 -0400110 pstate = to_sde_plane_state(plane->state);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400111 input_fence = pstate->input_fence;
Clarence Ipae4e60c2016-06-26 22:44:04 -0400112
Clarence Ipcae1bb62016-07-07 12:07:13 -0400113 if (input_fence) {
114 ret = sde_sync_wait(input_fence, wait_ms);
115 switch (ret) {
116 case 0:
117 DBG("%s signaled", psde->pipe_name);
118 break;
119 case -ETIME:
120 DRM_ERROR("timeout on %s, %ums\n",
121 psde->pipe_name, wait_ms);
122 psde->is_error = true;
123 break;
124 default:
125 DRM_ERROR("error on %s, %d\n",
126 psde->pipe_name, ret);
127 psde->is_error = true;
128 break;
129 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400130 } else {
131 ret = 0;
132 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400133 }
Clarence Ipae4e60c2016-06-26 22:44:04 -0400134 return ret;
135}
136
Clarence Ipe78efb72016-06-24 18:35:21 -0400137static void _sde_plane_set_scanout(struct drm_plane *plane,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400138 struct sde_plane_state *pstate,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400139 struct sde_hw_pipe_cfg *pipe_cfg,
140 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400141{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400142 struct sde_plane *psde;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400143 int ret, i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400144
Clarence Ipae4e60c2016-06-26 22:44:04 -0400145 if (!plane || !pstate || !pipe_cfg || !fb)
146 return;
147
148 psde = to_sde_plane(plane);
149
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400150 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
151 if (ret) {
152 DRM_ERROR("failed to get format layout, error: %d\n", ret);
153 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400154 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400155
156 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
157 BIT(SDE_DRM_DEINTERLACE))
158 for (i = 0; i < SDE_MAX_PLANES; ++i)
159 pipe_cfg->layout.plane_pitch[i] <<= 1;
160
161 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
162 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400163}
164
Clarence Ipcb410d42016-06-26 22:52:33 -0400165static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400166 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
167 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400168 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400169 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
170{
171}
172
Clarence Ipcb410d42016-06-26 22:52:33 -0400173/**
174 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
175 * @psde: Pointer to SDE plane object
176 * @src: Source size
177 * @dst: Destination size
178 * @phase_steps: Pointer to output array for phase steps
179 * @filter: Pointer to output array for filter type
180 * @fmt: Pointer to format definition
181 * @chroma_subsampling: Subsampling amount for chroma channel
182 *
183 * Returns: 0 on success
184 */
185static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400186 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400187 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400188 uint32_t chroma_subsampling)
189{
Clarence Ipcb410d42016-06-26 22:52:33 -0400190 if (!psde || !phase_steps || !filter || !fmt) {
191 DRM_ERROR("Invalid arguments\n");
192 return -EINVAL;
193 }
194
Clarence Ip4c1d9772016-06-26 09:35:38 -0400195 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400196 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400197 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400198 phase_steps[SDE_SSPP_COMP_1_2] =
199 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
200 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
201 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400202
203 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400204 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400205 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400206 (src <= dst) ? SDE_SCALE_FILTER_BIL :
207 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400208
Clarence Ipdbde9832016-06-26 09:48:36 -0400209 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400210 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400211 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
212 } else {
213 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
214 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400215 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400216 }
217 } else {
218 /* disable scaler */
Clarence Ipcb410d42016-06-26 22:52:33 -0400219 DBG("Disable scaler");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400220 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
221 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
222 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400223 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400224 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400225}
226
Clarence Ipcb410d42016-06-26 22:52:33 -0400227/**
228 * _sde_plane_setup_pixel_ext - determine default pixel extension values
229 * @psde: Pointer to SDE plane object
230 * @src: Source size
231 * @dst: Destination size
232 * @decimated_src: Source size after decimation, if any
233 * @phase_steps: Pointer to output array for phase steps
234 * @out_src: Output array for pixel extension values
235 * @out_edge1: Output array for pixel extension first edge
236 * @out_edge2: Output array for pixel extension second edge
237 * @filter: Pointer to array for filter type
238 * @fmt: Pointer to format definition
239 * @chroma_subsampling: Subsampling amount for chroma channel
240 * @post_compare: Whether to chroma subsampled source size for comparisions
241 */
242static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400243 uint32_t src, uint32_t dst, uint32_t decimated_src,
244 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400245 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400246 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400247 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400248{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400249 int64_t edge1, edge2, caf;
250 uint32_t src_work;
251 int i, tmp;
252
Clarence Ipcb410d42016-06-26 22:52:33 -0400253 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400254 out_edge2 && filter && fmt) {
255 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400256 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400257 caf = PHASE_STEP_UNIT_SCALE;
258 else
259 caf = 0;
260
261 for (i = 0; i < SDE_MAX_PLANES; i++) {
262 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400263 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400264 src_work /= chroma_subsampling;
265 if (post_compare)
266 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400267 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400268 /* unity */
269 edge1 = 0;
270 edge2 = 0;
271 } else if (dst >= src) {
272 /* upscale */
273 edge1 = (1 << PHASE_RESIDUAL);
274 edge1 -= caf;
275 edge2 = (1 << PHASE_RESIDUAL);
276 edge2 += (dst - 1) * *(phase_steps + i);
277 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
278 edge2 += caf;
279 edge2 = -(edge2);
280 } else {
281 /* downscale */
282 edge1 = 0;
283 edge2 = (dst - 1) * *(phase_steps + i);
284 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
285 edge2 += *(phase_steps + i);
286 edge2 = -(edge2);
287 }
288
289 /* only enable CAF for luma plane */
290 caf = 0;
291
292 /* populate output arrays */
293 *(out_src + i) = src_work;
294
295 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400296 if (edge1 >= 0) {
297 tmp = (uint32_t)edge1;
298 tmp >>= PHASE_STEP_SHIFT;
299 *(out_edge1 + i) = -tmp;
300 } else {
301 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400302 *(out_edge1 + i) =
303 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
304 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400305 }
306 if (edge2 >= 0) {
307 tmp = (uint32_t)edge2;
308 tmp >>= PHASE_STEP_SHIFT;
309 *(out_edge2 + i) = -tmp;
310 } else {
311 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400312 *(out_edge2 + i) =
313 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
314 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400315 }
316 }
317 }
318}
319
Clarence Ip5e2a9222016-06-26 22:38:24 -0400320/**
321 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
322 * sub-structure
323 * @blob_ptr: Pointer to start of incoming blob data
324 * @blob_size: Size of incoming blob data, in bytes
325 * @sub_ptr: Pointer to start of desired sub-structure
326 * @sub_size: Required size of sub-structure, in bytes
327 */
328static int _sde_plane_verify_blob(void *blob_ptr,
329 size_t blob_size,
330 void *sub_ptr,
331 size_t sub_size)
332{
333 /*
334 * Use the blob size provided by drm to check if there are enough
335 * bytes from the start of versioned sub-structures to the end of
336 * blob data:
337 *
338 * e.g.,
339 * blob_ptr --> struct blob_data {
340 * uint32_t version;
341 * sub_ptr --> struct blob_data_v1 v1;
342 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
343 * blob_ptr + blob_size --> };
344 *
345 * It's important to check the actual number of bytes from the start
346 * of the sub-structure to the end of the blob data, and not just rely
347 * on something like,
348 *
349 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
350 *
351 * This is because the start of the sub-structure can vary based on
352 * how the compiler pads the overall structure.
353 */
354 if (blob_ptr && sub_ptr)
355 /* return zero if end of blob >= end of sub-struct */
356 return ((unsigned char *)blob_ptr + blob_size) <
357 ((unsigned char *)sub_ptr + sub_size);
358 return -EINVAL;
359}
360
Clarence Ipe78efb72016-06-24 18:35:21 -0400361static void _sde_plane_setup_csc(struct sde_plane *psde,
362 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400363 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400364{
365 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
366 {
Clarence Ip373f8592016-05-26 00:58:42 -0400367 /* S15.16 format */
368 0x00012A00, 0x00000000, 0x00019880,
369 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
370 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400371 },
Clarence Ip373f8592016-05-26 00:58:42 -0400372 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400373 { 0xfff0, 0xff80, 0xff80,},
374 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400375 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400376 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400377 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400378 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400379 static const struct sde_csc_cfg sde_csc_NOP = {
380 {
Clarence Ip373f8592016-05-26 00:58:42 -0400381 /* identity matrix, S15.16 format */
382 0x10000, 0x00000, 0x00000,
383 0x00000, 0x10000, 0x00000,
384 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400385 },
Clarence Ip373f8592016-05-26 00:58:42 -0400386 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400387 { 0x0, 0x0, 0x0,},
388 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400389 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400390 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
391 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
392 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400393 struct sde_drm_csc *csc = NULL;
394 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400395 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400396
Clarence Ipaa0faf42016-05-30 12:07:48 -0400397 if (!psde || !pstate || !fmt) {
398 DRM_ERROR("Invalid arguments\n");
399 return;
400 }
401 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400402 return;
403
Clarence Ip5e2a9222016-06-26 22:38:24 -0400404 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400405 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400406 csc = msm_property_get_blob(&psde->property_info,
407 pstate->property_blobs,
408 &csc_size,
409 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400410 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400411 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400412 memcpy(&psde->csc_cfg,
413 &sde_csc_NOP,
414 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400415 switch (csc->version) {
416 case SDE_DRM_CSC_V1:
417 if (!_sde_plane_verify_blob(csc,
418 csc_size,
419 &csc->v1,
420 sizeof(struct sde_drm_csc_v1))) {
421 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400422 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400423 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400424 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400425 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400426 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400427 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400428 csc->v1.post_bias[i];
429 }
430 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400431 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400432 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400433 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400434 csc->v1.post_clamp[i];
435 }
Clarence Ipb493d762016-07-19 18:49:10 -0400436 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400437 }
438 break;
439 default:
440 break;
441 }
Clarence Ipb493d762016-07-19 18:49:10 -0400442 if (!psde->csc_ptr)
443 DRM_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400444 }
445
Clarence Ipcae1bb62016-07-07 12:07:13 -0400446 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400447 if (psde->csc_ptr)
448 DBG("user blob override for csc");
Clarence Ipb493d762016-07-19 18:49:10 -0400449 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400450 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400451}
452
Clarence Ipcb410d42016-06-26 22:52:33 -0400453static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400454 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400455 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700456{
Clarence Ipcb410d42016-06-26 22:52:33 -0400457 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400458 struct sde_drm_scaler *sc_u = NULL;
459 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400460 size_t sc_u_size = 0;
461 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
462 uint32_t tmp;
463 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400464
Clarence Ipcb410d42016-06-26 22:52:33 -0400465 if (!psde || !fmt)
466 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400467
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400468 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400469 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400470
Clarence Ip5e2a9222016-06-26 22:38:24 -0400471 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400472 if (pstate)
473 sc_u = msm_property_get_blob(&psde->property_info,
474 pstate->property_blobs,
475 &sc_u_size,
476 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400477 if (sc_u) {
478 switch (sc_u->version) {
479 case SDE_DRM_SCALER_V1:
480 if (!_sde_plane_verify_blob(sc_u,
481 sc_u_size,
482 &sc_u->v1,
483 sizeof(*sc_u1)))
484 sc_u1 = &sc_u->v1;
485 break;
486 default:
487 DBG("Unrecognized scaler blob v%lld", sc_u->version);
488 break;
489 }
490 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400491
Clarence Ip04ec67d2016-05-26 01:16:15 -0400492 /* decimation */
493 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
494 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
495 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400496 } else {
497 psde->pipe_cfg.horz_decimation = 0;
498 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400499 }
500
501 /* don't chroma subsample if decimating */
502 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400503 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400504 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400505 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400506
Clarence Ip5e2a9222016-06-26 22:38:24 -0400507 /* update scaler */
508 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
509 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Clarence Ipcb410d42016-06-26 22:52:33 -0400510 DBG("SCALER3 blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400511 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400512 _sde_plane_setup_scaler3(psde,
513 psde->pipe_cfg.src_rect.w,
514 psde->pipe_cfg.src_rect.h,
515 psde->pipe_cfg.dst_rect.w,
516 psde->pipe_cfg.dst_rect.h,
517 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400518 chroma_subsmpl_h, chroma_subsmpl_v);
519 } else {
520 /* always calculate basic scaler config */
521 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
522 /* populate from user space */
523 for (i = 0; i < SDE_MAX_PLANES; i++) {
524 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
525 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
526 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
527 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400528
Clarence Ip5e2a9222016-06-26 22:38:24 -0400529 pe->horz_filter[i] = sc_u1->horz_filter[i];
530 pe->vert_filter[i] = sc_u1->vert_filter[i];
531 }
532 } else {
533 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400534 _sde_plane_setup_scaler2(psde,
535 psde->pipe_cfg.src_rect.w,
536 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400537 pe->phase_step_x,
538 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400539 _sde_plane_setup_scaler2(psde,
540 psde->pipe_cfg.src_rect.h,
541 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400542 pe->phase_step_y,
543 pe->vert_filter, fmt, chroma_subsmpl_v);
544 }
545 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400546
Clarence Ip5e2a9222016-06-26 22:38:24 -0400547 /* update pixel extensions */
548 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
549 /* populate from user space */
Clarence Ipcb410d42016-06-26 22:52:33 -0400550 DBG("PIXEXT blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400551 for (i = 0; i < SDE_MAX_PLANES; i++) {
552 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
553 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
554 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
555 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
556 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
557 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
558 pe->roi_w[i] = sc_u1->lr.roi[i];
559
560 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
561 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
562 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
563 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
564 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
565 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
566 pe->roi_h[i] = sc_u1->tb.roi[i];
567 }
568 } else {
569 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400570 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400571 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400572 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400573 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400574 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
575 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400576 pe->phase_step_x,
577 pe->roi_w,
578 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400579 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400580 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400581
Clarence Ipcb410d42016-06-26 22:52:33 -0400582 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400583 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400584 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
585 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400586 pe->phase_step_y,
587 pe->roi_h,
588 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400589 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400590 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400591
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400592 for (i = 0; i < SDE_MAX_PLANES; i++) {
593 if (pe->num_ext_pxls_left[i] >= 0)
594 pe->left_rpt[i] =
595 pe->num_ext_pxls_left[i];
596 else
597 pe->left_ftch[i] =
598 pe->num_ext_pxls_left[i];
599
600 if (pe->num_ext_pxls_right[i] >= 0)
601 pe->right_rpt[i] =
602 pe->num_ext_pxls_right[i];
603 else
604 pe->right_ftch[i] =
605 pe->num_ext_pxls_right[i];
606
607 if (pe->num_ext_pxls_top[i] >= 0)
608 pe->top_rpt[i] =
609 pe->num_ext_pxls_top[i];
610 else
611 pe->top_ftch[i] =
612 pe->num_ext_pxls_top[i];
613
614 if (pe->num_ext_pxls_btm[i] >= 0)
615 pe->btm_rpt[i] =
616 pe->num_ext_pxls_btm[i];
617 else
618 pe->btm_ftch[i] =
619 pe->num_ext_pxls_btm[i];
620 }
621 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400622}
623
Clarence Ipcae1bb62016-07-07 12:07:13 -0400624/**
625 * _sde_plane_color_fill - enables color fill on plane
626 * @plane: Pointer to DRM plane object
627 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
628 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
629 * Returns: 0 on success
630 */
631static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -0400632 uint32_t color, uint32_t alpha)
633{
634 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400635 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400636
637 if (!plane) {
638 DRM_ERROR("Invalid plane\n");
639 return -EINVAL;
640 }
641
642 psde = to_sde_plane(plane);
643 if (!psde->pipe_hw) {
644 DRM_ERROR("Invalid plane h/w pointer\n");
645 return -EINVAL;
646 }
647
Clarence Ipcae1bb62016-07-07 12:07:13 -0400648 DBG("");
649
Clarence Ipcb410d42016-06-26 22:52:33 -0400650 /*
651 * select fill format to match user property expectation,
652 * h/w only supports RGB variants
653 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400654 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -0400655
656 /* update sspp */
657 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
658 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
659 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
660
661 /* override scaler/decimation if solid fill */
662 psde->pipe_cfg.src_rect.x = 0;
663 psde->pipe_cfg.src_rect.y = 0;
664 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
665 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
666
667 _sde_plane_setup_scaler(psde, fmt, 0);
668
669 if (psde->pipe_hw->ops.setup_format)
670 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
671 fmt, SDE_SSPP_SOLID_FILL);
672
673 if (psde->pipe_hw->ops.setup_rects)
674 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
675 &psde->pipe_cfg, &psde->pixel_ext);
676 }
677
678 return 0;
679}
680
681static int _sde_plane_mode_set(struct drm_plane *plane,
682 struct drm_crtc *crtc, struct drm_framebuffer *fb,
683 int crtc_x, int crtc_y,
684 unsigned int crtc_w, unsigned int crtc_h,
685 uint32_t src_x, uint32_t src_y,
686 uint32_t src_w, uint32_t src_h)
687{
688 struct sde_plane *psde;
689 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400690 uint32_t nplanes;
Clarence Ipcb410d42016-06-26 22:52:33 -0400691 uint32_t src_flags;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400692 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400693
694 DBG("");
695
696 if (!plane || !plane->state) {
697 DRM_ERROR("Invalid plane/state\n");
698 return -EINVAL;
699 }
700 if (!crtc || !fb) {
701 DRM_ERROR("Invalid crtc/fb\n");
702 return -EINVAL;
703 }
704
705 psde = to_sde_plane(plane);
706 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -0400707
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400708 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400709 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -0400710
711 /* src values are in Q16 fixed point, convert to integer */
712 src_x = src_x >> 16;
713 src_y = src_y >> 16;
714 src_w = src_w >> 16;
715 src_h = src_h >> 16;
716
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400717 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d",
718 psde->pipe_name,
Clarence Ipcb410d42016-06-26 22:52:33 -0400719 fb->base.id, src_x, src_y, src_w, src_h,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400720 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h,
721 drm_get_format_name(fmt->base.pixel_format),
722 SDE_FORMAT_IS_UBWC(fmt));
Clarence Ipcb410d42016-06-26 22:52:33 -0400723
724 /* update format configuration */
725 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
726 src_flags = 0;
727
Clarence Ipcb410d42016-06-26 22:52:33 -0400728 /* flags */
729 DBG("Flags 0x%llX, rotation 0x%llX",
730 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
731 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
732 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
733 BIT(DRM_REFLECT_X))
734 src_flags |= SDE_SSPP_FLIP_LR;
735 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
736 BIT(DRM_REFLECT_Y))
737 src_flags |= SDE_SSPP_FLIP_UD;
738 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
739 BIT(SDE_DRM_DEINTERLACE)) {
740 src_h /= 2;
741 src_y = DIV_ROUND_UP(src_y, 2);
742 src_y &= ~0x1;
743 }
744
745 psde->pipe_cfg.src_rect.x = src_x;
746 psde->pipe_cfg.src_rect.y = src_y;
747 psde->pipe_cfg.src_rect.w = src_w;
748 psde->pipe_cfg.src_rect.h = src_h;
749
750 psde->pipe_cfg.dst_rect.x = crtc_x;
751 psde->pipe_cfg.dst_rect.y = crtc_y;
752 psde->pipe_cfg.dst_rect.w = crtc_w;
753 psde->pipe_cfg.dst_rect.h = crtc_h;
754
Clarence Ipcb410d42016-06-26 22:52:33 -0400755 /* check for color fill */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400756 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400757 PLANE_PROP_COLOR_FILL);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400758 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
759 /* skip remaining processing on color fill */
760 return 0;
Clarence Ipcb410d42016-06-26 22:52:33 -0400761
762 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
763
764 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400765
Clarence Ip4c1d9772016-06-26 09:35:38 -0400766 if (psde->pipe_hw->ops.setup_format)
767 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -0400768 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400769 if (psde->pipe_hw->ops.setup_rects)
770 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
771 &psde->pipe_cfg, &psde->pixel_ext);
772
Clarence Ipe78efb72016-06-24 18:35:21 -0400773 /* update sharpening */
774 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
775 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
776 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
777 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
778
779 if (psde->pipe_hw->ops.setup_sharpening)
780 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
781 &psde->sharp_cfg);
782
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400783 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -0400784 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -0400785 _sde_plane_setup_csc(psde, pstate, fmt);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400786 else
787 psde->csc_ptr = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400788
Clarence Ip5e2a9222016-06-26 22:38:24 -0400789 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400790}
791
792static int sde_plane_prepare_fb(struct drm_plane *plane,
793 const struct drm_plane_state *new_state)
794{
795 struct drm_framebuffer *fb = new_state->fb;
796 struct sde_plane *psde = to_sde_plane(plane);
797
798 if (!new_state->fb)
799 return 0;
800
Clarence Ipae4e60c2016-06-26 22:44:04 -0400801 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400802 return msm_framebuffer_prepare(fb, psde->mmu_id);
803}
804
805static void sde_plane_cleanup_fb(struct drm_plane *plane,
806 const struct drm_plane_state *old_state)
807{
808 struct drm_framebuffer *fb = old_state->fb;
809 struct sde_plane *psde = to_sde_plane(plane);
810
811 if (!fb)
812 return;
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 msm_framebuffer_cleanup(fb, psde->mmu_id);
816}
817
Clarence Ipdbde9832016-06-26 09:48:36 -0400818static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
819 struct sde_plane_state *pstate,
820 struct drm_framebuffer *fb)
821{
822 return 0;
823}
824
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400825static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
826 struct drm_plane_state *state,
827 struct drm_plane_state *old_state)
828{
829 struct sde_plane_state *pstate = to_sde_plane_state(state);
830
831 if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
832 DBG("%s: pipe enabling/disabling full modeset required",
833 psde->pipe_name);
834 pstate->mode_changed = true;
835 } else if (to_sde_plane_state(old_state)->pending) {
836 DBG("%s: still pending", psde->pipe_name);
837 pstate->mode_changed = true;
838 } else if (state->src_w != old_state->src_w ||
839 state->src_h != old_state->src_h) {
840 DBG("%s: src_w change", psde->pipe_name);
841 pstate->mode_changed = true;
842 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
843 DBG("%s: format change!", psde->pipe_name);
844 pstate->mode_changed = true;
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -0400845 }
846
847 if (!pstate->mode_changed) {
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400848 uint64_t *new_mods = state->fb->modifier;
849 uint64_t *old_mods = old_state->fb->modifier;
850 int i;
851
852 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
853 if (new_mods[i] != old_mods[i]) {
854 DBG("%s: format modifiers change",
855 psde->pipe_name);
856 pstate->mode_changed = true;
857 break;
858 }
859 }
860 }
Lloyd Atkinson3ab9ef72016-07-14 17:42:41 -0400861
862 if (!pstate->mode_changed) {
863 uint32_t *new_pitches = state->fb->pitches;
864 uint32_t *old_pitches = old_state->fb->pitches;
865 int i;
866
867 for (i = 0; i < ARRAY_SIZE(state->fb->pitches); i++) {
868 if (new_pitches[i] != old_pitches[i]) {
869 DBG("%s: pitches change plane %d: %u, %u",
870 psde->pipe_name, i, old_pitches[i],
871 new_pitches[i]);
872 pstate->mode_changed = true;
873 break;
874 }
875 }
876 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400877}
878
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400879static int sde_plane_atomic_check(struct drm_plane *plane,
880 struct drm_plane_state *state)
881{
Clarence Ipdbde9832016-06-26 09:48:36 -0400882 struct sde_plane *psde;
883 struct sde_plane_state *pstate;
884 struct drm_plane_state *old_state;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400885 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -0400886 size_t sc_u_size = 0;
887 struct sde_drm_scaler *sc_u = NULL;
888 int ret = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400889
Clarence Ipdbde9832016-06-26 09:48:36 -0400890 uint32_t src_x, src_y;
891 uint32_t src_w, src_h;
892 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
893 uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
894 uint32_t upscale_max, downscale_max;
895
896 DBG();
897
898 if (!plane || !state) {
899 DRM_ERROR("Invalid plane/state\n");
900 ret = -EINVAL;
901 goto exit;
902 }
903
904 psde = to_sde_plane(plane);
905 pstate = to_sde_plane_state(state);
906 old_state = plane->state;
907
908 if (!psde->pipe_sblk) {
909 DRM_ERROR("Invalid plane catalog\n");
910 ret = -EINVAL;
911 goto exit;
912 }
913
914 /* get decimation config from user space */
915 deci_w = 0;
916 deci_h = 0;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400917 sc_u = msm_property_get_blob(&psde->property_info,
918 pstate->property_blobs,
919 &sc_u_size,
920 PLANE_PROP_SCALER);
Clarence Ipdbde9832016-06-26 09:48:36 -0400921 if (sc_u) {
922 switch (sc_u->version) {
923 case SDE_DRM_SCALER_V1:
924 if (!_sde_plane_verify_blob(sc_u,
925 sc_u_size,
926 &sc_u->v1,
927 sizeof(struct sde_drm_scaler_v1))) {
928 deci_w = sc_u->v1.horz_decimate;
929 deci_h = sc_u->v1.vert_decimate;
930 }
931 break;
932 default:
933 DBG("Unrecognized scaler blob v%lld", sc_u->version);
934 break;
935 }
936 }
937
938 /* src values are in Q16 fixed point, convert to integer */
939 src_x = state->src_x >> 16;
940 src_y = state->src_y >> 16;
941 src_w = state->src_w >> 16;
942 src_h = state->src_h >> 16;
943
944 src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
945 src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
946
947 src_max_x = 0xFFFF;
948 src_max_y = 0xFFFF;
949 src_max_w = 0x3FFF;
950 src_max_h = 0x3FFF;
951 upscale_max = psde->pipe_sblk->maxupscale;
952 downscale_max = psde->pipe_sblk->maxdwnscale;
953
954 /*
955 * Including checks from mdss
956 * - mdss_mdp_overlay_req_check()
957 */
Clarence Ip4ce59322016-06-26 22:27:51 -0400958 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400959 sde_plane_enabled(old_state), sde_plane_enabled(state));
960
961 if (sde_plane_enabled(state)) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400962 /* determine SDE format definition. State's fb is valid here. */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400963 fmt = to_sde_format(msm_framebuffer_format(state->fb));
Clarence Ipdbde9832016-06-26 09:48:36 -0400964
965 /* don't check for other errors after first failure */
966 if (SDE_FORMAT_IS_YUV(fmt) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400967 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400968 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400969 DRM_ERROR("Pipe doesn't support YUV\n");
Clarence Ipdbde9832016-06-26 09:48:36 -0400970 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400971
Clarence Ipdbde9832016-06-26 09:48:36 -0400972 /* verify source size/region */
973 } else if (!src_w || !src_h ||
974 (src_w > src_max_w) || (src_h > src_max_h) ||
975 (src_x > src_max_x) || (src_y > src_max_y) ||
976 (src_x + src_w > src_max_x) ||
977 (src_y + src_h > src_max_y)) {
978 DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
979 src_x, src_y, src_x + src_w,
980 src_y + src_h);
981 ret = -EINVAL;
982
983 /* require even source for YUV */
984 } else if (SDE_FORMAT_IS_YUV(fmt) &&
985 ((src_x & 0x1) || (src_y & 0x1) ||
986 (src_w & 0x1) || (src_h & 0x1))) {
987 DRM_ERROR("Invalid odd src res/pos for YUV\n");
988 ret = -EINVAL;
989
990 /* verify scaler requirements */
991 } else if (!(psde->features & SDE_SSPP_SCALER) &&
992 ((src_w != state->crtc_w) ||
993 (src_h != state->crtc_h))) {
994 DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
995 src_w, src_h, state->crtc_w,
996 state->crtc_h);
997 ret = -EINVAL;
998
999 /* check decimated source width */
1000 } else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
1001 DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
1002 src_w, src_deci_w,
1003 psde->pipe_sblk->maxlinewidth);
1004 ret = -EINVAL;
1005
1006 /* check max scaler capability */
1007 } else if (((src_deci_w * upscale_max) < state->crtc_w) ||
1008 ((src_deci_h * upscale_max) < state->crtc_h) ||
1009 ((state->crtc_w * downscale_max) < src_deci_w) ||
1010 ((state->crtc_h * downscale_max) < src_deci_h)) {
1011 DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
1012 src_deci_w, src_deci_h,
1013 state->crtc_w, state->crtc_h);
1014 ret = -EINVAL;
1015
1016 /* check frame buffer */
1017 } else if (_sde_plane_atomic_check_fb(
1018 psde, pstate, state->fb)) {
1019 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001020 }
1021
Clarence Ipdbde9832016-06-26 09:48:36 -04001022 /* check decimation (and bwc/fetch mode) */
1023 if (!ret && (deci_w || deci_h)) {
1024 if (SDE_FORMAT_IS_UBWC(fmt)) {
1025 DRM_ERROR("No decimation with BWC\n");
1026 ret = -EINVAL;
1027 } else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1028 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1029 DRM_ERROR("Too much decimation requested\n");
1030 ret = -EINVAL;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001031 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
Clarence Ipdbde9832016-06-26 09:48:36 -04001032 DRM_ERROR("Decimation requires linear fetch\n");
1033 ret = -EINVAL;
1034 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001035 }
1036 }
1037
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001038 if (!ret)
1039 _sde_plane_atomic_check_mode_changed(psde, state, old_state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001040
Clarence Ipdbde9832016-06-26 09:48:36 -04001041exit:
1042 return ret;
1043}
1044
Clarence Ipcae1bb62016-07-07 12:07:13 -04001045/**
1046 * sde_plane_flush - final plane operations before commit flush
1047 * @plane: Pointer to drm plane structure
1048 */
1049void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001050{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001051 struct sde_plane *psde;
1052
1053 if (!plane)
1054 return;
1055
1056 psde = to_sde_plane(plane);
1057
1058 /*
1059 * These updates have to be done immediately before the plane flush
1060 * timing, and may not be moved to the atomic_update/mode_set functions.
1061 */
1062 if (psde->is_error)
1063 /* force white frame with 0% alpha pipe output on error */
1064 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1065 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1066 /* force 100% alpha */
1067 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1068 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1069 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1070
1071 /* flag h/w flush complete */
1072 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001073 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001074}
1075
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001076static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001077 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001078{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001079 struct sde_plane *sde_plane;
1080 struct drm_plane_state *state;
1081 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001082
Clarence Ip5e2a9222016-06-26 22:38:24 -04001083 if (!plane || !plane->state) {
1084 DRM_ERROR("Invalid plane/state\n");
1085 return;
1086 }
1087
1088 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001089 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001090 state = plane->state;
1091 pstate = to_sde_plane_state(state);
1092
Clarence Ipae4e60c2016-06-26 22:44:04 -04001093 DBG("%s: update", sde_plane->pipe_name);
1094
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001095 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001096 pstate->pending = true;
1097 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001098 int ret;
1099
Clarence Ip5e2a9222016-06-26 22:38:24 -04001100 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -04001101 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001102 state->crtc, state->fb,
1103 state->crtc_x, state->crtc_y,
1104 state->crtc_w, state->crtc_h,
1105 state->src_x, state->src_y,
1106 state->src_w, state->src_h);
1107 /* atomic_check should have ensured that this doesn't fail */
1108 WARN_ON(ret < 0);
1109 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001110 _sde_plane_set_scanout(plane, pstate,
1111 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001112 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001113}
1114
1115/* helper to install properties which are common to planes and crtcs */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001116static void _sde_plane_install_properties(struct drm_plane *plane)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001117{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001118 static const struct drm_prop_enum_list e_blend_op[] = {
1119 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1120 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1121 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1122 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1123 };
1124 static const struct drm_prop_enum_list e_src_config[] = {
1125 {SDE_DRM_DEINTERLACE, "deinterlace"}
1126 };
Clarence Ipea3d6262016-07-15 16:20:11 -04001127 const struct sde_format_extended *format_list;
1128 static struct sde_kms_info sde_info;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001129 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001130
Clarence Ip4ce59322016-06-26 22:27:51 -04001131 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001132
Clarence Ipaa0faf42016-05-30 12:07:48 -04001133 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
1134 DRM_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001135 return;
1136 }
1137
1138 /* range properties */
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001139 msm_property_install_range(&psde->property_info, "zpos", 0x0, 0, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001140 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1141 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1142 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001143
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001144 msm_property_install_range(&psde->property_info, "alpha",
1145 0x0, 0, 255, 255, PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001146
Clarence Ipcb410d42016-06-26 22:52:33 -04001147 if (psde->pipe_hw->ops.setup_solidfill)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001148 msm_property_install_range(&psde->property_info, "color_fill",
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001149 0, 0, 0xFFFFFFFF, 0,
Clarence Ipcb410d42016-06-26 22:52:33 -04001150 PLANE_PROP_COLOR_FILL);
1151
Clarence Ipcae1bb62016-07-07 12:07:13 -04001152 msm_property_install_range(&psde->property_info, "input_fence",
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001153 0x0, 0, ~0, ~0,
Clarence Ipcae1bb62016-07-07 12:07:13 -04001154 PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001155
1156 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001157 msm_property_install_rotation(&psde->property_info,
1158 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y),
1159 PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001160
Clarence Ip04ec67d2016-05-26 01:16:15 -04001161 /* enum/bitmask properties */
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001162 msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001163 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001164 PLANE_PROP_BLEND_OP);
Lloyd Atkinson38ad8c92016-07-06 10:39:32 -04001165 msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001166 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001167 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001168
Clarence Ipe78efb72016-06-24 18:35:21 -04001169 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001170 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001171 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001172 PLANE_PROP_SCALER);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001173 if (psde->features & BIT(SDE_SSPP_CSC)) {
1174 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001175 PLANE_PROP_CSC);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001176 }
Clarence Ipea3d6262016-07-15 16:20:11 -04001177 format_list = psde->pipe_sblk->format_list;
1178 if (format_list) {
1179 /* assume single thread */
1180 struct sde_kms_info *info = &sde_info;
1181
1182 msm_property_install_blob(&psde->property_info, "sde_info",
1183 DRM_MODE_PROP_IMMUTABLE,
1184 PLANE_PROP_SDE_INFO);
1185 sde_kms_info_reset(info);
1186 sde_kms_info_start(info, "pixel_formats");
1187 while (format_list->fourcc_format) {
1188 sde_kms_info_append_format(info,
1189 format_list->fourcc_format,
1190 format_list->modifier);
1191 ++format_list;
1192 }
1193 sde_kms_info_stop(info);
1194 msm_property_set_blob(&psde->property_info,
1195 &psde->blob_sde_info,
1196 SDE_KMS_INFO_DATA(info),
1197 SDE_KMS_INFO_DATALEN(info),
1198 PLANE_PROP_SDE_INFO);
1199 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001200}
1201
1202static int sde_plane_atomic_set_property(struct drm_plane *plane,
1203 struct drm_plane_state *state, struct drm_property *property,
1204 uint64_t val)
1205{
Clarence Ip730e7192016-06-26 22:45:09 -04001206 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001207 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001208 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001209
Clarence Ipaa0faf42016-05-30 12:07:48 -04001210 DBG("");
1211
1212 if (!plane) {
1213 DRM_ERROR("Invalid plane\n");
1214 } else if (!state) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001215 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001216 } else {
1217 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001218 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001219 ret = msm_property_atomic_set(&psde->property_info,
1220 pstate->property_values, pstate->property_blobs,
1221 property, val);
1222 if (!ret) {
1223 idx = msm_property_index(&psde->property_info,
1224 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001225 if (idx == PLANE_PROP_INPUT_FENCE)
1226 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001227 }
1228 }
1229
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001230 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001231}
1232
1233static int sde_plane_set_property(struct drm_plane *plane,
1234 struct drm_property *property, uint64_t val)
1235{
Clarence Ip4ce59322016-06-26 22:27:51 -04001236 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001237
Clarence Ipae4e60c2016-06-26 22:44:04 -04001238 return sde_plane_atomic_set_property(plane,
1239 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001240}
1241
1242static int sde_plane_atomic_get_property(struct drm_plane *plane,
1243 const struct drm_plane_state *state,
1244 struct drm_property *property, uint64_t *val)
1245{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001246 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001247 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001248 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001249
Clarence Ipaa0faf42016-05-30 12:07:48 -04001250 DBG("");
1251
1252 if (!plane) {
1253 DRM_ERROR("Invalid plane\n");
1254 } else if (!state) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001255 DRM_ERROR("Invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001256 } else {
1257 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001258 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001259 ret = msm_property_atomic_get(&psde->property_info,
1260 pstate->property_values, pstate->property_blobs,
1261 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001262 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001263
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001264 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001265}
1266
1267static void sde_plane_destroy(struct drm_plane *plane)
1268{
Clarence Ip4ce59322016-06-26 22:27:51 -04001269 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001270
Clarence Ip4ce59322016-06-26 22:27:51 -04001271 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001272
Clarence Ip4ce59322016-06-26 22:27:51 -04001273 if (plane) {
1274 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001275
Clarence Ip4ce59322016-06-26 22:27:51 -04001276 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001277
Clarence Ipea3d6262016-07-15 16:20:11 -04001278 if (psde->blob_sde_info)
1279 drm_property_unreference_blob(psde->blob_sde_info);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001280 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001281 mutex_destroy(&psde->lock);
1282
Clarence Ip4ce59322016-06-26 22:27:51 -04001283 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001284
Clarence Ip4ce59322016-06-26 22:27:51 -04001285 /* this will destroy the states as well */
1286 drm_plane_cleanup(plane);
1287
Clarence Ip4c1d9772016-06-26 09:35:38 -04001288 if (psde->pipe_hw)
1289 sde_hw_sspp_destroy(psde->pipe_hw);
1290
Clarence Ip4ce59322016-06-26 22:27:51 -04001291 kfree(psde);
1292 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001293}
1294
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001295static void sde_plane_destroy_state(struct drm_plane *plane,
1296 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001297{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001298 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001299 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001300
Clarence Ipae4e60c2016-06-26 22:44:04 -04001301 if (!plane || !state) {
1302 DRM_ERROR("Invalid plane/state\n");
1303 return;
1304 }
1305
Clarence Ipaa0faf42016-05-30 12:07:48 -04001306 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001307 pstate = to_sde_plane_state(state);
1308
1309 DBG("");
1310
Clarence Ipe78efb72016-06-24 18:35:21 -04001311 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001312 if (state->fb)
1313 drm_framebuffer_unreference(state->fb);
1314
Clarence Ipae4e60c2016-06-26 22:44:04 -04001315 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001316 if (pstate->input_fence)
1317 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001318
Clarence Ipaa0faf42016-05-30 12:07:48 -04001319 /* destroy value helper */
1320 msm_property_destroy_state(&psde->property_info, pstate,
1321 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001322}
1323
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001324static struct drm_plane_state *
1325sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001326{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001327 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001328 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001329 struct sde_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001330
Clarence Ip730e7192016-06-26 22:45:09 -04001331 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001332 return NULL;
1333
Clarence Ip730e7192016-06-26 22:45:09 -04001334 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001335 psde = to_sde_plane(plane);
1336 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001337 if (!pstate)
1338 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001339
Clarence Ipaa0faf42016-05-30 12:07:48 -04001340 DBG("");
1341
1342 /* duplicate value helper */
1343 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1344 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001345
Clarence Ip730e7192016-06-26 22:45:09 -04001346 /* add ref count for frame buffer */
1347 if (pstate->base.fb)
1348 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001349
Clarence Ip730e7192016-06-26 22:45:09 -04001350 /* add ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001351 if (pstate->input_fence) {
1352 pstate->input_fence = 0;
1353 _sde_plane_set_input_fence(plane, pstate, pstate->
1354 property_values[PLANE_PROP_INPUT_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001355 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001356
Clarence Ip730e7192016-06-26 22:45:09 -04001357 pstate->mode_changed = false;
1358 pstate->pending = false;
1359
1360 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001361}
1362
1363static void sde_plane_reset(struct drm_plane *plane)
1364{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001365 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001366 struct sde_plane_state *pstate;
1367
Clarence Ipae4e60c2016-06-26 22:44:04 -04001368 if (!plane) {
1369 DRM_ERROR("Invalid plane\n");
1370 return;
1371 }
1372
Clarence Ip730e7192016-06-26 22:45:09 -04001373 psde = to_sde_plane(plane);
1374 DBG("%s", psde->pipe_name);
1375
Clarence Ipae4e60c2016-06-26 22:44:04 -04001376 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001377 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001378 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001379 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001380 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001381
Clarence Ipaa0faf42016-05-30 12:07:48 -04001382 pstate = msm_property_alloc_state(&psde->property_info);
1383 if (!pstate)
1384 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001385
Clarence Ipaa0faf42016-05-30 12:07:48 -04001386 /* reset value helper */
1387 msm_property_reset_state(&psde->property_info, pstate,
1388 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001389
1390 pstate->base.plane = plane;
1391
1392 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001393}
1394
1395static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001396 .update_plane = drm_atomic_helper_update_plane,
1397 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001398 .destroy = sde_plane_destroy,
1399 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001400 .atomic_set_property = sde_plane_atomic_set_property,
1401 .atomic_get_property = sde_plane_atomic_get_property,
1402 .reset = sde_plane_reset,
1403 .atomic_duplicate_state = sde_plane_duplicate_state,
1404 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001405};
1406
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001407static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1408 .prepare_fb = sde_plane_prepare_fb,
1409 .cleanup_fb = sde_plane_cleanup_fb,
1410 .atomic_check = sde_plane_atomic_check,
1411 .atomic_update = sde_plane_atomic_update,
1412};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001413
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001414enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001415{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001416 struct sde_plane *sde_plane = to_sde_plane(plane);
1417
1418 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001419}
1420
Clarence Ip4ce59322016-06-26 22:27:51 -04001421static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1422{
1423 const struct sde_sspp_sub_blks *sblk = 0;
1424 const struct sde_sspp_cfg *cfg = 0;
1425
1426 if (psde && psde->pipe_hw)
1427 cfg = psde->pipe_hw->cap;
1428 if (cfg)
1429 sblk = cfg->sblk;
1430
1431 if (kms && sblk) {
1432 /* create overall sub-directory for the pipe */
1433 psde->debugfs_root =
1434 debugfs_create_dir(psde->pipe_name,
1435 sde_debugfs_get_root(kms));
1436 if (psde->debugfs_root) {
1437 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001438 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001439 psde->debugfs_root, &psde->features);
1440
1441 /* add register dump support */
1442 sde_debugfs_setup_regset32(&psde->debugfs_src,
1443 sblk->src_blk.base + cfg->base,
1444 sblk->src_blk.len,
1445 kms->mmio);
1446 sde_debugfs_create_regset32("src_blk", 0444,
1447 psde->debugfs_root, &psde->debugfs_src);
1448
1449 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1450 sblk->scaler_blk.base + cfg->base,
1451 sblk->scaler_blk.len,
1452 kms->mmio);
1453 sde_debugfs_create_regset32("scaler_blk", 0444,
1454 psde->debugfs_root,
1455 &psde->debugfs_scaler);
1456
1457 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1458 sblk->csc_blk.base + cfg->base,
1459 sblk->csc_blk.len,
1460 kms->mmio);
1461 sde_debugfs_create_regset32("csc_blk", 0444,
1462 psde->debugfs_root, &psde->debugfs_csc);
1463 }
1464 }
1465}
1466
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001467/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001468struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001469 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001470{
1471 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001472 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001473 struct msm_drm_private *priv;
1474 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001475 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001476 int ret = -EINVAL;
1477
1478 if (!dev) {
1479 DRM_ERROR("[%u]Device is NULL\n", pipe);
1480 goto exit;
1481 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001482
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001483 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001484 if (!priv) {
1485 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1486 goto exit;
1487 }
1488
1489 if (!priv->kms) {
1490 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1491 goto exit;
1492 }
1493 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001494
Clarence Ip4c1d9772016-06-26 09:35:38 -04001495 if (!kms->catalog) {
1496 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1497 goto exit;
1498 }
1499
Clarence Ip4ce59322016-06-26 22:27:51 -04001500 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001501 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1502 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001503 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001504 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001505 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001506 }
1507
Clarence Ip4c1d9772016-06-26 09:35:38 -04001508 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001509 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001510 psde->pipe = pipe;
Alan Kwong112a84f2016-05-24 20:49:21 -04001511 psde->mmu_id = kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001512
Clarence Ip4c1d9772016-06-26 09:35:38 -04001513 /* initialize underlying h/w driver */
1514 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1515 if (IS_ERR(psde->pipe_hw)) {
1516 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1517 ret = PTR_ERR(psde->pipe_hw);
1518 goto clean_plane;
1519 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1520 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1521 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001522 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001523
1524 /* cache features mask for later */
1525 psde->features = psde->pipe_hw->cap->features;
1526 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
Clarence Ipea3d6262016-07-15 16:20:11 -04001527 if (!psde->pipe_sblk) {
1528 SDE_ERROR("invalid sblk on pipe %d\n", pipe);
1529 goto clean_sspp;
1530 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001531
1532 /* add plane to DRM framework */
Clarence Ipea3d6262016-07-15 16:20:11 -04001533 psde->nformats = sde_populate_formats(psde->pipe_sblk->format_list,
1534 psde->formats,
1535 0,
1536 ARRAY_SIZE(psde->formats));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001537
Clarence Ip4c1d9772016-06-26 09:35:38 -04001538 if (!psde->nformats) {
1539 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1540 goto clean_sspp;
1541 }
1542
1543 if (psde->features & BIT(SDE_SSPP_CURSOR))
1544 type = DRM_PLANE_TYPE_CURSOR;
1545 else if (primary_plane)
1546 type = DRM_PLANE_TYPE_PRIMARY;
1547 else
1548 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001549 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1550 psde->formats, psde->nformats,
1551 type);
1552 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001553 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001554
Clarence Ip4c1d9772016-06-26 09:35:38 -04001555 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001556 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001557
Clarence Ipaa0faf42016-05-30 12:07:48 -04001558 msm_property_init(&psde->property_info, &plane->base, dev,
1559 priv->plane_property, psde->property_data,
1560 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
1561 sizeof(struct sde_plane_state));
1562
1563 _sde_plane_install_properties(plane);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001564
Clarence Ip4ce59322016-06-26 22:27:51 -04001565 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001566 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001567
Clarence Ip730e7192016-06-26 22:45:09 -04001568 mutex_init(&psde->lock);
1569
Clarence Ip4ce59322016-06-26 22:27:51 -04001570 _sde_plane_init_debugfs(psde, kms);
1571
Clarence Ip4c1d9772016-06-26 09:35:38 -04001572 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001573 return plane;
1574
Clarence Ip4c1d9772016-06-26 09:35:38 -04001575clean_sspp:
1576 if (psde && psde->pipe_hw)
1577 sde_hw_sspp_destroy(psde->pipe_hw);
1578clean_plane:
1579 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001580exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001581 return ERR_PTR(ret);
1582}