blob: 0f8a8e13c76d5f7598de881a9e73173242825c72 [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 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,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400138 struct sde_hw_pipe_cfg *pipe_cfg,
139 struct drm_framebuffer *fb)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400140{
Clarence Ipae4e60c2016-06-26 22:44:04 -0400141 struct sde_plane *psde;
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400142 int ret, i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400143
Clarence Ipae4e60c2016-06-26 22:44:04 -0400144 if (!plane || !pstate || !pipe_cfg || !fb)
145 return;
146
147 psde = to_sde_plane(plane);
148
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400149 ret = sde_format_populate_layout(psde->mmu_id, fb, &pipe_cfg->layout);
150 if (ret) {
151 DRM_ERROR("failed to get format layout, error: %d\n", ret);
152 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400153 }
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400154
155 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
156 BIT(SDE_DRM_DEINTERLACE))
157 for (i = 0; i < SDE_MAX_PLANES; ++i)
158 pipe_cfg->layout.plane_pitch[i] <<= 1;
159
160 if (psde->pipe_hw && psde->pipe_hw->ops.setup_sourceaddress)
161 psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400162}
163
Clarence Ipcb410d42016-06-26 22:52:33 -0400164static void _sde_plane_setup_scaler3(struct sde_plane *psde,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400165 uint32_t src_w, uint32_t src_h, uint32_t dst_w, uint32_t dst_h,
166 struct sde_hw_scaler3_cfg *scale_cfg,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400167 const struct sde_format *fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400168 uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v)
169{
170}
171
Clarence Ipcb410d42016-06-26 22:52:33 -0400172/**
173 * _sde_plane_setup_scaler2(): Determine default scaler phase steps/filter type
174 * @psde: Pointer to SDE plane object
175 * @src: Source size
176 * @dst: Destination size
177 * @phase_steps: Pointer to output array for phase steps
178 * @filter: Pointer to output array for filter type
179 * @fmt: Pointer to format definition
180 * @chroma_subsampling: Subsampling amount for chroma channel
181 *
182 * Returns: 0 on success
183 */
184static int _sde_plane_setup_scaler2(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400185 uint32_t src, uint32_t dst, uint32_t *phase_steps,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400186 enum sde_hw_filter *filter, const struct sde_format *fmt,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400187 uint32_t chroma_subsampling)
188{
Clarence Ipcb410d42016-06-26 22:52:33 -0400189 if (!psde || !phase_steps || !filter || !fmt) {
190 DRM_ERROR("Invalid arguments\n");
191 return -EINVAL;
192 }
193
Clarence Ip4c1d9772016-06-26 09:35:38 -0400194 /* calculate phase steps, leave init phase as zero */
Clarence Ipe78efb72016-06-24 18:35:21 -0400195 phase_steps[SDE_SSPP_COMP_0] =
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400196 mult_frac(1 << PHASE_STEP_SHIFT, src, dst);
Clarence Ipe78efb72016-06-24 18:35:21 -0400197 phase_steps[SDE_SSPP_COMP_1_2] =
198 phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling;
199 phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2];
200 phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400201
202 /* calculate scaler config, if necessary */
Clarence Ipdbde9832016-06-26 09:48:36 -0400203 if (SDE_FORMAT_IS_YUV(fmt) || src != dst) {
Clarence Ipe78efb72016-06-24 18:35:21 -0400204 filter[SDE_SSPP_COMP_3] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400205 (src <= dst) ? SDE_SCALE_FILTER_BIL :
206 SDE_SCALE_FILTER_PCMN;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400207
Clarence Ipdbde9832016-06-26 09:48:36 -0400208 if (SDE_FORMAT_IS_YUV(fmt)) {
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400209 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA;
Clarence Ipe78efb72016-06-24 18:35:21 -0400210 filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3];
211 } else {
212 filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3];
213 filter[SDE_SSPP_COMP_1_2] =
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400214 SDE_SCALE_FILTER_NEAREST;
Clarence Ipe78efb72016-06-24 18:35:21 -0400215 }
216 } else {
217 /* disable scaler */
Clarence Ipcb410d42016-06-26 22:52:33 -0400218 DBG("Disable scaler");
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400219 filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX;
220 filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX;
221 filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400222 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400223 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400224}
225
Clarence Ipcb410d42016-06-26 22:52:33 -0400226/**
227 * _sde_plane_setup_pixel_ext - determine default pixel extension values
228 * @psde: Pointer to SDE plane object
229 * @src: Source size
230 * @dst: Destination size
231 * @decimated_src: Source size after decimation, if any
232 * @phase_steps: Pointer to output array for phase steps
233 * @out_src: Output array for pixel extension values
234 * @out_edge1: Output array for pixel extension first edge
235 * @out_edge2: Output array for pixel extension second edge
236 * @filter: Pointer to array for filter type
237 * @fmt: Pointer to format definition
238 * @chroma_subsampling: Subsampling amount for chroma channel
239 * @post_compare: Whether to chroma subsampled source size for comparisions
240 */
241static void _sde_plane_setup_pixel_ext(struct sde_plane *psde,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400242 uint32_t src, uint32_t dst, uint32_t decimated_src,
243 uint32_t *phase_steps, uint32_t *out_src, int *out_edge1,
Clarence Ipe78efb72016-06-24 18:35:21 -0400244 int *out_edge2, enum sde_hw_filter *filter,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400245 const struct sde_format *fmt, uint32_t chroma_subsampling,
Clarence Ipe78efb72016-06-24 18:35:21 -0400246 bool post_compare)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400247{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400248 int64_t edge1, edge2, caf;
249 uint32_t src_work;
250 int i, tmp;
251
Clarence Ipcb410d42016-06-26 22:52:33 -0400252 if (psde && phase_steps && out_src && out_edge1 &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400253 out_edge2 && filter && fmt) {
254 /* handle CAF for YUV formats */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400255 if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400256 caf = PHASE_STEP_UNIT_SCALE;
257 else
258 caf = 0;
259
260 for (i = 0; i < SDE_MAX_PLANES; i++) {
261 src_work = decimated_src;
Clarence Ipe78efb72016-06-24 18:35:21 -0400262 if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400263 src_work /= chroma_subsampling;
264 if (post_compare)
265 src = src_work;
Clarence Ipdbde9832016-06-26 09:48:36 -0400266 if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400267 /* unity */
268 edge1 = 0;
269 edge2 = 0;
270 } else if (dst >= src) {
271 /* upscale */
272 edge1 = (1 << PHASE_RESIDUAL);
273 edge1 -= caf;
274 edge2 = (1 << PHASE_RESIDUAL);
275 edge2 += (dst - 1) * *(phase_steps + i);
276 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
277 edge2 += caf;
278 edge2 = -(edge2);
279 } else {
280 /* downscale */
281 edge1 = 0;
282 edge2 = (dst - 1) * *(phase_steps + i);
283 edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE;
284 edge2 += *(phase_steps + i);
285 edge2 = -(edge2);
286 }
287
288 /* only enable CAF for luma plane */
289 caf = 0;
290
291 /* populate output arrays */
292 *(out_src + i) = src_work;
293
294 /* edge updates taken from __pxl_extn_helper */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400295 if (edge1 >= 0) {
296 tmp = (uint32_t)edge1;
297 tmp >>= PHASE_STEP_SHIFT;
298 *(out_edge1 + i) = -tmp;
299 } else {
300 tmp = (uint32_t)(-edge1);
Clarence Ipe78efb72016-06-24 18:35:21 -0400301 *(out_edge1 + i) =
302 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
303 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400304 }
305 if (edge2 >= 0) {
306 tmp = (uint32_t)edge2;
307 tmp >>= PHASE_STEP_SHIFT;
308 *(out_edge2 + i) = -tmp;
309 } else {
310 tmp = (uint32_t)(-edge2);
Clarence Ipe78efb72016-06-24 18:35:21 -0400311 *(out_edge2 + i) =
312 (tmp + PHASE_STEP_UNIT_SCALE - 1) >>
313 PHASE_STEP_SHIFT;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400314 }
315 }
316 }
317}
318
Clarence Ip5e2a9222016-06-26 22:38:24 -0400319/**
320 * _sde_plane_verify_blob - verify incoming blob is big enough to contain
321 * sub-structure
322 * @blob_ptr: Pointer to start of incoming blob data
323 * @blob_size: Size of incoming blob data, in bytes
324 * @sub_ptr: Pointer to start of desired sub-structure
325 * @sub_size: Required size of sub-structure, in bytes
326 */
327static int _sde_plane_verify_blob(void *blob_ptr,
328 size_t blob_size,
329 void *sub_ptr,
330 size_t sub_size)
331{
332 /*
333 * Use the blob size provided by drm to check if there are enough
334 * bytes from the start of versioned sub-structures to the end of
335 * blob data:
336 *
337 * e.g.,
338 * blob_ptr --> struct blob_data {
339 * uint32_t version;
340 * sub_ptr --> struct blob_data_v1 v1;
341 * sub_ptr + sub_size --> struct blob_stuff more_stuff;
342 * blob_ptr + blob_size --> };
343 *
344 * It's important to check the actual number of bytes from the start
345 * of the sub-structure to the end of the blob data, and not just rely
346 * on something like,
347 *
348 * sizeof(blob) - sizeof(blob->version) >= sizeof(sub-struct)
349 *
350 * This is because the start of the sub-structure can vary based on
351 * how the compiler pads the overall structure.
352 */
353 if (blob_ptr && sub_ptr)
354 /* return zero if end of blob >= end of sub-struct */
355 return ((unsigned char *)blob_ptr + blob_size) <
356 ((unsigned char *)sub_ptr + sub_size);
357 return -EINVAL;
358}
359
Clarence Ipe78efb72016-06-24 18:35:21 -0400360static void _sde_plane_setup_csc(struct sde_plane *psde,
361 struct sde_plane_state *pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400362 const struct sde_format *fmt)
Clarence Ipe78efb72016-06-24 18:35:21 -0400363{
364 static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = {
365 {
Clarence Ip373f8592016-05-26 00:58:42 -0400366 /* S15.16 format */
367 0x00012A00, 0x00000000, 0x00019880,
368 0x00012A00, 0xFFFF9B80, 0xFFFF3000,
369 0x00012A00, 0x00020480, 0x00000000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400370 },
Clarence Ip373f8592016-05-26 00:58:42 -0400371 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400372 { 0xfff0, 0xff80, 0xff80,},
373 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400374 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400375 { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400376 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,},
Clarence Ipe78efb72016-06-24 18:35:21 -0400377 };
Clarence Ipe78efb72016-06-24 18:35:21 -0400378 static const struct sde_csc_cfg sde_csc_NOP = {
379 {
Clarence Ip373f8592016-05-26 00:58:42 -0400380 /* identity matrix, S15.16 format */
381 0x10000, 0x00000, 0x00000,
382 0x00000, 0x10000, 0x00000,
383 0x00000, 0x00000, 0x10000,
Clarence Ipe78efb72016-06-24 18:35:21 -0400384 },
Clarence Ip373f8592016-05-26 00:58:42 -0400385 /* signed bias */
Clarence Ipe78efb72016-06-24 18:35:21 -0400386 { 0x0, 0x0, 0x0,},
387 { 0x0, 0x0, 0x0,},
Clarence Ip373f8592016-05-26 00:58:42 -0400388 /* unsigned clamp */
Clarence Ipe78efb72016-06-24 18:35:21 -0400389 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
390 { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
391 };
Clarence Ip5e2a9222016-06-26 22:38:24 -0400392 struct sde_drm_csc *csc = NULL;
393 size_t csc_size = 0;
Clarence Ipb493d762016-07-19 18:49:10 -0400394 int i;
Clarence Ipe78efb72016-06-24 18:35:21 -0400395
Clarence Ipaa0faf42016-05-30 12:07:48 -0400396 if (!psde || !pstate || !fmt) {
397 DRM_ERROR("Invalid arguments\n");
398 return;
399 }
400 if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_csc)
Clarence Ipe78efb72016-06-24 18:35:21 -0400401 return;
402
Clarence Ip5e2a9222016-06-26 22:38:24 -0400403 /* check for user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400404 psde->csc_ptr = NULL;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400405 csc = msm_property_get_blob(&psde->property_info,
406 pstate->property_blobs,
407 &csc_size,
408 PLANE_PROP_CSC);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400409 if (csc) {
Clarence Ip5e2a9222016-06-26 22:38:24 -0400410 /* user space override */
Clarence Ipb493d762016-07-19 18:49:10 -0400411 memcpy(&psde->csc_cfg,
412 &sde_csc_NOP,
413 sizeof(struct sde_csc_cfg));
Clarence Ip5e2a9222016-06-26 22:38:24 -0400414 switch (csc->version) {
415 case SDE_DRM_CSC_V1:
416 if (!_sde_plane_verify_blob(csc,
417 csc_size,
418 &csc->v1,
419 sizeof(struct sde_drm_csc_v1))) {
420 for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i)
Clarence Ipb493d762016-07-19 18:49:10 -0400421 psde->csc_cfg.csc_mv[i] =
Clarence Ip373f8592016-05-26 00:58:42 -0400422 csc->v1.ctm_coeff[i] >> 16;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400423 for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400424 psde->csc_cfg.csc_pre_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400425 csc->v1.pre_bias[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400426 psde->csc_cfg.csc_post_bv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400427 csc->v1.post_bias[i];
428 }
429 for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) {
Clarence Ipb493d762016-07-19 18:49:10 -0400430 psde->csc_cfg.csc_pre_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400431 csc->v1.pre_clamp[i];
Clarence Ipb493d762016-07-19 18:49:10 -0400432 psde->csc_cfg.csc_post_lv[i] =
Clarence Ip5e2a9222016-06-26 22:38:24 -0400433 csc->v1.post_clamp[i];
434 }
Clarence Ipb493d762016-07-19 18:49:10 -0400435 psde->csc_ptr = &psde->csc_cfg;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400436 }
437 break;
438 default:
439 break;
440 }
Clarence Ipb493d762016-07-19 18:49:10 -0400441 if (!psde->csc_ptr)
442 DRM_ERROR("invalid csc blob, v%lld\n", csc->version);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400443 }
444
Clarence Ipcae1bb62016-07-07 12:07:13 -0400445 /* revert to kernel default if override not available */
Clarence Ipb493d762016-07-19 18:49:10 -0400446 if (psde->csc_ptr)
447 DBG("user blob override for csc");
Clarence Ipb493d762016-07-19 18:49:10 -0400448 else if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ip373f8592016-05-26 00:58:42 -0400449 psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L;
Clarence Ipe78efb72016-06-24 18:35:21 -0400450}
451
Clarence Ipcb410d42016-06-26 22:52:33 -0400452static void _sde_plane_setup_scaler(struct sde_plane *psde,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400453 const struct sde_format *fmt,
Clarence Ipcb410d42016-06-26 22:52:33 -0400454 struct sde_plane_state *pstate)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700455{
Clarence Ipcb410d42016-06-26 22:52:33 -0400456 struct sde_hw_pixel_ext *pe = NULL;
Clarence Ip5e2a9222016-06-26 22:38:24 -0400457 struct sde_drm_scaler *sc_u = NULL;
458 struct sde_drm_scaler_v1 *sc_u1 = NULL;
Clarence Ipcb410d42016-06-26 22:52:33 -0400459 size_t sc_u_size = 0;
460 uint32_t chroma_subsmpl_h, chroma_subsmpl_v;
461 uint32_t tmp;
462 int i;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400463
Clarence Ipcb410d42016-06-26 22:52:33 -0400464 if (!psde || !fmt)
465 return;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400466
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400467 pe = &(psde->pixel_ext);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400468 memset(pe, 0, sizeof(struct sde_hw_pixel_ext));
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400469
Clarence Ip5e2a9222016-06-26 22:38:24 -0400470 /* get scaler config from user space */
Clarence Ipc3ffec12016-07-18 19:07:24 -0400471 if (pstate)
472 sc_u = msm_property_get_blob(&psde->property_info,
473 pstate->property_blobs,
474 &sc_u_size,
475 PLANE_PROP_SCALER);
Clarence Ip5e2a9222016-06-26 22:38:24 -0400476 if (sc_u) {
477 switch (sc_u->version) {
478 case SDE_DRM_SCALER_V1:
479 if (!_sde_plane_verify_blob(sc_u,
480 sc_u_size,
481 &sc_u->v1,
482 sizeof(*sc_u1)))
483 sc_u1 = &sc_u->v1;
484 break;
485 default:
486 DBG("Unrecognized scaler blob v%lld", sc_u->version);
487 break;
488 }
489 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400490
Clarence Ip04ec67d2016-05-26 01:16:15 -0400491 /* decimation */
492 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_DECIMATE)) {
493 psde->pipe_cfg.horz_decimation = sc_u1->horz_decimate;
494 psde->pipe_cfg.vert_decimation = sc_u1->vert_decimate;
Clarence Ipcb410d42016-06-26 22:52:33 -0400495 } else {
496 psde->pipe_cfg.horz_decimation = 0;
497 psde->pipe_cfg.vert_decimation = 0;
Clarence Ip04ec67d2016-05-26 01:16:15 -0400498 }
499
500 /* don't chroma subsample if decimating */
501 chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400502 drm_format_horz_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400503 chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 :
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400504 drm_format_vert_chroma_subsampling(fmt->base.pixel_format);
Clarence Ip04ec67d2016-05-26 01:16:15 -0400505
Clarence Ip5e2a9222016-06-26 22:38:24 -0400506 /* update scaler */
507 if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) {
508 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_3))
Clarence Ipcb410d42016-06-26 22:52:33 -0400509 DBG("SCALER3 blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400510 else
Clarence Ipcb410d42016-06-26 22:52:33 -0400511 _sde_plane_setup_scaler3(psde,
512 psde->pipe_cfg.src_rect.w,
513 psde->pipe_cfg.src_rect.h,
514 psde->pipe_cfg.dst_rect.w,
515 psde->pipe_cfg.dst_rect.h,
516 &psde->scaler3_cfg, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400517 chroma_subsmpl_h, chroma_subsmpl_v);
518 } else {
519 /* always calculate basic scaler config */
520 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_SCALER_2)) {
521 /* populate from user space */
522 for (i = 0; i < SDE_MAX_PLANES; i++) {
523 pe->init_phase_x[i] = sc_u1->init_phase_x[i];
524 pe->phase_step_x[i] = sc_u1->phase_step_x[i];
525 pe->init_phase_y[i] = sc_u1->init_phase_y[i];
526 pe->phase_step_y[i] = sc_u1->phase_step_y[i];
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400527
Clarence Ip5e2a9222016-06-26 22:38:24 -0400528 pe->horz_filter[i] = sc_u1->horz_filter[i];
529 pe->vert_filter[i] = sc_u1->vert_filter[i];
530 }
531 } else {
532 /* calculate phase steps */
Clarence Ipcb410d42016-06-26 22:52:33 -0400533 _sde_plane_setup_scaler2(psde,
534 psde->pipe_cfg.src_rect.w,
535 psde->pipe_cfg.dst_rect.w,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400536 pe->phase_step_x,
537 pe->horz_filter, fmt, chroma_subsmpl_h);
Clarence Ipcb410d42016-06-26 22:52:33 -0400538 _sde_plane_setup_scaler2(psde,
539 psde->pipe_cfg.src_rect.h,
540 psde->pipe_cfg.dst_rect.h,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400541 pe->phase_step_y,
542 pe->vert_filter, fmt, chroma_subsmpl_v);
543 }
544 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400545
Clarence Ip5e2a9222016-06-26 22:38:24 -0400546 /* update pixel extensions */
547 if (sc_u1 && (sc_u1->enable & SDE_DRM_SCALER_PIX_EXT)) {
548 /* populate from user space */
Clarence Ipcb410d42016-06-26 22:52:33 -0400549 DBG("PIXEXT blob detected");
Clarence Ip5e2a9222016-06-26 22:38:24 -0400550 for (i = 0; i < SDE_MAX_PLANES; i++) {
551 pe->num_ext_pxls_left[i] = sc_u1->lr.num_pxls_start[i];
552 pe->num_ext_pxls_right[i] = sc_u1->lr.num_pxls_end[i];
553 pe->left_ftch[i] = sc_u1->lr.ftch_start[i];
554 pe->right_ftch[i] = sc_u1->lr.ftch_end[i];
555 pe->left_rpt[i] = sc_u1->lr.rpt_start[i];
556 pe->right_rpt[i] = sc_u1->lr.rpt_end[i];
557 pe->roi_w[i] = sc_u1->lr.roi[i];
558
559 pe->num_ext_pxls_top[i] = sc_u1->tb.num_pxls_start[i];
560 pe->num_ext_pxls_btm[i] = sc_u1->tb.num_pxls_end[i];
561 pe->top_ftch[i] = sc_u1->tb.ftch_start[i];
562 pe->btm_ftch[i] = sc_u1->tb.ftch_end[i];
563 pe->top_rpt[i] = sc_u1->tb.rpt_start[i];
564 pe->btm_rpt[i] = sc_u1->tb.rpt_end[i];
565 pe->roi_h[i] = sc_u1->tb.roi[i];
566 }
567 } else {
568 /* calculate left/right/top/bottom pixel extensions */
Clarence Ipcb410d42016-06-26 22:52:33 -0400569 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400570 psde->pipe_cfg.horz_decimation);
Clarence Ipdbde9832016-06-26 09:48:36 -0400571 if (SDE_FORMAT_IS_YUV(fmt))
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400572 tmp &= ~0x1;
Clarence Ipcb410d42016-06-26 22:52:33 -0400573 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w,
574 psde->pipe_cfg.dst_rect.w, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400575 pe->phase_step_x,
576 pe->roi_w,
577 pe->num_ext_pxls_left,
Clarence Ipe78efb72016-06-24 18:35:21 -0400578 pe->num_ext_pxls_right, pe->horz_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400579 chroma_subsmpl_h, 0);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400580
Clarence Ipcb410d42016-06-26 22:52:33 -0400581 tmp = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400582 psde->pipe_cfg.vert_decimation);
Clarence Ipcb410d42016-06-26 22:52:33 -0400583 _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h,
584 psde->pipe_cfg.dst_rect.h, tmp,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400585 pe->phase_step_y,
586 pe->roi_h,
587 pe->num_ext_pxls_top,
Clarence Ipe78efb72016-06-24 18:35:21 -0400588 pe->num_ext_pxls_btm, pe->vert_filter, fmt,
Clarence Ip5e2a9222016-06-26 22:38:24 -0400589 chroma_subsmpl_v, 1);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400590
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400591 for (i = 0; i < SDE_MAX_PLANES; i++) {
592 if (pe->num_ext_pxls_left[i] >= 0)
593 pe->left_rpt[i] =
594 pe->num_ext_pxls_left[i];
595 else
596 pe->left_ftch[i] =
597 pe->num_ext_pxls_left[i];
598
599 if (pe->num_ext_pxls_right[i] >= 0)
600 pe->right_rpt[i] =
601 pe->num_ext_pxls_right[i];
602 else
603 pe->right_ftch[i] =
604 pe->num_ext_pxls_right[i];
605
606 if (pe->num_ext_pxls_top[i] >= 0)
607 pe->top_rpt[i] =
608 pe->num_ext_pxls_top[i];
609 else
610 pe->top_ftch[i] =
611 pe->num_ext_pxls_top[i];
612
613 if (pe->num_ext_pxls_btm[i] >= 0)
614 pe->btm_rpt[i] =
615 pe->num_ext_pxls_btm[i];
616 else
617 pe->btm_ftch[i] =
618 pe->num_ext_pxls_btm[i];
619 }
620 }
Clarence Ipcb410d42016-06-26 22:52:33 -0400621}
622
Clarence Ipcae1bb62016-07-07 12:07:13 -0400623/**
624 * _sde_plane_color_fill - enables color fill on plane
625 * @plane: Pointer to DRM plane object
626 * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red
627 * @alpha: 8-bit fill alpha value, 255 selects 100% alpha
628 * Returns: 0 on success
629 */
630static int _sde_plane_color_fill(struct drm_plane *plane,
Clarence Ipcb410d42016-06-26 22:52:33 -0400631 uint32_t color, uint32_t alpha)
632{
633 struct sde_plane *psde;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400634 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400635
636 if (!plane) {
637 DRM_ERROR("Invalid plane\n");
638 return -EINVAL;
639 }
640
641 psde = to_sde_plane(plane);
642 if (!psde->pipe_hw) {
643 DRM_ERROR("Invalid plane h/w pointer\n");
644 return -EINVAL;
645 }
646
Clarence Ipcae1bb62016-07-07 12:07:13 -0400647 DBG("");
648
Clarence Ipcb410d42016-06-26 22:52:33 -0400649 /*
650 * select fill format to match user property expectation,
651 * h/w only supports RGB variants
652 */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400653 fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888);
Clarence Ipcb410d42016-06-26 22:52:33 -0400654
655 /* update sspp */
656 if (fmt && psde->pipe_hw->ops.setup_solidfill) {
657 psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw,
658 (color & 0xFFFFFF) | ((alpha & 0xFF) << 24));
659
660 /* override scaler/decimation if solid fill */
661 psde->pipe_cfg.src_rect.x = 0;
662 psde->pipe_cfg.src_rect.y = 0;
663 psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
664 psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
665
666 _sde_plane_setup_scaler(psde, fmt, 0);
667
668 if (psde->pipe_hw->ops.setup_format)
669 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
670 fmt, SDE_SSPP_SOLID_FILL);
671
672 if (psde->pipe_hw->ops.setup_rects)
673 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
674 &psde->pipe_cfg, &psde->pixel_ext);
675 }
676
677 return 0;
678}
679
680static int _sde_plane_mode_set(struct drm_plane *plane,
681 struct drm_crtc *crtc, struct drm_framebuffer *fb,
682 int crtc_x, int crtc_y,
683 unsigned int crtc_w, unsigned int crtc_h,
684 uint32_t src_x, uint32_t src_y,
685 uint32_t src_w, uint32_t src_h)
686{
687 struct sde_plane *psde;
688 struct sde_plane_state *pstate;
Clarence Ipcae1bb62016-07-07 12:07:13 -0400689 uint32_t nplanes;
Clarence Ipcb410d42016-06-26 22:52:33 -0400690 uint32_t src_flags;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400691 const struct sde_format *fmt;
Clarence Ipcb410d42016-06-26 22:52:33 -0400692
693 DBG("");
694
695 if (!plane || !plane->state) {
696 DRM_ERROR("Invalid plane/state\n");
697 return -EINVAL;
698 }
699 if (!crtc || !fb) {
700 DRM_ERROR("Invalid crtc/fb\n");
701 return -EINVAL;
702 }
703
704 psde = to_sde_plane(plane);
705 pstate = to_sde_plane_state(plane->state);
Clarence Ipcb410d42016-06-26 22:52:33 -0400706
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400707 fmt = to_sde_format(msm_framebuffer_format(fb));
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400708 nplanes = fmt->num_planes;
Clarence Ipcb410d42016-06-26 22:52:33 -0400709
710 /* src values are in Q16 fixed point, convert to integer */
711 src_x = src_x >> 16;
712 src_y = src_y >> 16;
713 src_w = src_w >> 16;
714 src_h = src_h >> 16;
715
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400716 DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u, %s ubwc %d",
717 psde->pipe_name,
Clarence Ipcb410d42016-06-26 22:52:33 -0400718 fb->base.id, src_x, src_y, src_w, src_h,
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400719 crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h,
720 drm_get_format_name(fmt->base.pixel_format),
721 SDE_FORMAT_IS_UBWC(fmt));
Clarence Ipcb410d42016-06-26 22:52:33 -0400722
723 /* update format configuration */
724 memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
725 src_flags = 0;
726
Clarence Ipcb410d42016-06-26 22:52:33 -0400727 /* flags */
728 DBG("Flags 0x%llX, rotation 0x%llX",
729 sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG),
730 sde_plane_get_property(pstate, PLANE_PROP_ROTATION));
731 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
732 BIT(DRM_REFLECT_X))
733 src_flags |= SDE_SSPP_FLIP_LR;
734 if (sde_plane_get_property(pstate, PLANE_PROP_ROTATION) &
735 BIT(DRM_REFLECT_Y))
736 src_flags |= SDE_SSPP_FLIP_UD;
737 if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) &
738 BIT(SDE_DRM_DEINTERLACE)) {
739 src_h /= 2;
740 src_y = DIV_ROUND_UP(src_y, 2);
741 src_y &= ~0x1;
742 }
743
744 psde->pipe_cfg.src_rect.x = src_x;
745 psde->pipe_cfg.src_rect.y = src_y;
746 psde->pipe_cfg.src_rect.w = src_w;
747 psde->pipe_cfg.src_rect.h = src_h;
748
749 psde->pipe_cfg.dst_rect.x = crtc_x;
750 psde->pipe_cfg.dst_rect.y = crtc_y;
751 psde->pipe_cfg.dst_rect.w = crtc_w;
752 psde->pipe_cfg.dst_rect.h = crtc_h;
753
Clarence Ipcb410d42016-06-26 22:52:33 -0400754 /* check for color fill */
Clarence Ipcae1bb62016-07-07 12:07:13 -0400755 psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400756 PLANE_PROP_COLOR_FILL);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400757 if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
758 /* skip remaining processing on color fill */
759 return 0;
Clarence Ipcb410d42016-06-26 22:52:33 -0400760
761 _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb);
762
763 _sde_plane_setup_scaler(psde, fmt, pstate);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400764
Clarence Ip4c1d9772016-06-26 09:35:38 -0400765 if (psde->pipe_hw->ops.setup_format)
766 psde->pipe_hw->ops.setup_format(psde->pipe_hw,
Clarence Ipcb410d42016-06-26 22:52:33 -0400767 fmt, src_flags);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400768 if (psde->pipe_hw->ops.setup_rects)
769 psde->pipe_hw->ops.setup_rects(psde->pipe_hw,
770 &psde->pipe_cfg, &psde->pixel_ext);
771
Clarence Ipe78efb72016-06-24 18:35:21 -0400772 /* update sharpening */
773 psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT;
774 psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT;
775 psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT;
776 psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT;
777
778 if (psde->pipe_hw->ops.setup_sharpening)
779 psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw,
780 &psde->sharp_cfg);
781
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400782 /* update csc */
Clarence Ipdbde9832016-06-26 09:48:36 -0400783 if (SDE_FORMAT_IS_YUV(fmt))
Clarence Ipe78efb72016-06-24 18:35:21 -0400784 _sde_plane_setup_csc(psde, pstate, fmt);
Clarence Ipcae1bb62016-07-07 12:07:13 -0400785 else
786 psde->csc_ptr = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400787
Clarence Ip5e2a9222016-06-26 22:38:24 -0400788 return 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400789}
790
791static int sde_plane_prepare_fb(struct drm_plane *plane,
792 const struct drm_plane_state *new_state)
793{
794 struct drm_framebuffer *fb = new_state->fb;
795 struct sde_plane *psde = to_sde_plane(plane);
796
797 if (!new_state->fb)
798 return 0;
799
Clarence Ipae4e60c2016-06-26 22:44:04 -0400800 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400801 return msm_framebuffer_prepare(fb, psde->mmu_id);
802}
803
804static void sde_plane_cleanup_fb(struct drm_plane *plane,
805 const struct drm_plane_state *old_state)
806{
807 struct drm_framebuffer *fb = old_state->fb;
808 struct sde_plane *psde = to_sde_plane(plane);
809
810 if (!fb)
811 return;
812
Clarence Ipae4e60c2016-06-26 22:44:04 -0400813 DBG("%s: FB[%u]", psde->pipe_name, fb->base.id);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400814 msm_framebuffer_cleanup(fb, psde->mmu_id);
815}
816
Clarence Ipdbde9832016-06-26 09:48:36 -0400817static int _sde_plane_atomic_check_fb(struct sde_plane *psde,
818 struct sde_plane_state *pstate,
819 struct drm_framebuffer *fb)
820{
821 return 0;
822}
823
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -0400824static void _sde_plane_atomic_check_mode_changed(struct sde_plane *psde,
825 struct drm_plane_state *state,
826 struct drm_plane_state *old_state)
827{
828 struct sde_plane_state *pstate = to_sde_plane_state(state);
829
830 if (!(sde_plane_enabled(state) && sde_plane_enabled(old_state))) {
831 DBG("%s: pipe enabling/disabling full modeset required",
832 psde->pipe_name);
833 pstate->mode_changed = true;
834 } else if (to_sde_plane_state(old_state)->pending) {
835 DBG("%s: still pending", psde->pipe_name);
836 pstate->mode_changed = true;
837 } else if (state->src_w != old_state->src_w ||
838 state->src_h != old_state->src_h) {
839 DBG("%s: src_w change", psde->pipe_name);
840 pstate->mode_changed = true;
841 } else if (state->fb->pixel_format != old_state->fb->pixel_format) {
842 DBG("%s: format change!", psde->pipe_name);
843 pstate->mode_changed = true;
844 } else {
845 uint64_t *new_mods = state->fb->modifier;
846 uint64_t *old_mods = old_state->fb->modifier;
847 int i;
848
849 for (i = 0; i < ARRAY_SIZE(state->fb->modifier); i++) {
850 if (new_mods[i] != old_mods[i]) {
851 DBG("%s: format modifiers change",
852 psde->pipe_name);
853 pstate->mode_changed = true;
854 break;
855 }
856 }
857 }
858}
859
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400860static int sde_plane_atomic_check(struct drm_plane *plane,
861 struct drm_plane_state *state)
862{
Clarence Ipdbde9832016-06-26 09:48:36 -0400863 struct sde_plane *psde;
864 struct sde_plane_state *pstate;
865 struct drm_plane_state *old_state;
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400866 const struct sde_format *fmt;
Clarence Ipdbde9832016-06-26 09:48:36 -0400867 size_t sc_u_size = 0;
868 struct sde_drm_scaler *sc_u = NULL;
869 int ret = 0;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400870
Clarence Ipdbde9832016-06-26 09:48:36 -0400871 uint32_t src_x, src_y;
872 uint32_t src_w, src_h;
873 uint32_t deci_w, deci_h, src_deci_w, src_deci_h;
874 uint32_t src_max_x, src_max_y, src_max_w, src_max_h;
875 uint32_t upscale_max, downscale_max;
876
877 DBG();
878
879 if (!plane || !state) {
880 DRM_ERROR("Invalid plane/state\n");
881 ret = -EINVAL;
882 goto exit;
883 }
884
885 psde = to_sde_plane(plane);
886 pstate = to_sde_plane_state(state);
887 old_state = plane->state;
888
889 if (!psde->pipe_sblk) {
890 DRM_ERROR("Invalid plane catalog\n");
891 ret = -EINVAL;
892 goto exit;
893 }
894
895 /* get decimation config from user space */
896 deci_w = 0;
897 deci_h = 0;
Clarence Ipaa0faf42016-05-30 12:07:48 -0400898 sc_u = msm_property_get_blob(&psde->property_info,
899 pstate->property_blobs,
900 &sc_u_size,
901 PLANE_PROP_SCALER);
Clarence Ipdbde9832016-06-26 09:48:36 -0400902 if (sc_u) {
903 switch (sc_u->version) {
904 case SDE_DRM_SCALER_V1:
905 if (!_sde_plane_verify_blob(sc_u,
906 sc_u_size,
907 &sc_u->v1,
908 sizeof(struct sde_drm_scaler_v1))) {
909 deci_w = sc_u->v1.horz_decimate;
910 deci_h = sc_u->v1.vert_decimate;
911 }
912 break;
913 default:
914 DBG("Unrecognized scaler blob v%lld", sc_u->version);
915 break;
916 }
917 }
918
919 /* src values are in Q16 fixed point, convert to integer */
920 src_x = state->src_x >> 16;
921 src_y = state->src_y >> 16;
922 src_w = state->src_w >> 16;
923 src_h = state->src_h >> 16;
924
925 src_deci_w = DECIMATED_DIMENSION(src_w, deci_w);
926 src_deci_h = DECIMATED_DIMENSION(src_h, deci_h);
927
928 src_max_x = 0xFFFF;
929 src_max_y = 0xFFFF;
930 src_max_w = 0x3FFF;
931 src_max_h = 0x3FFF;
932 upscale_max = psde->pipe_sblk->maxupscale;
933 downscale_max = psde->pipe_sblk->maxdwnscale;
934
935 /*
936 * Including checks from mdss
937 * - mdss_mdp_overlay_req_check()
938 */
Clarence Ip4ce59322016-06-26 22:27:51 -0400939 DBG("%s: check (%d -> %d)", psde->pipe_name,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400940 sde_plane_enabled(old_state), sde_plane_enabled(state));
941
942 if (sde_plane_enabled(state)) {
Clarence Ipdbde9832016-06-26 09:48:36 -0400943 /* determine SDE format definition. State's fb is valid here. */
Lloyd Atkinson9a673492016-07-05 11:41:57 -0400944 fmt = to_sde_format(msm_framebuffer_format(state->fb));
Clarence Ipdbde9832016-06-26 09:48:36 -0400945
946 /* don't check for other errors after first failure */
947 if (SDE_FORMAT_IS_YUV(fmt) &&
Clarence Ipe78efb72016-06-24 18:35:21 -0400948 (!(psde->features & SDE_SSPP_SCALER) ||
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400949 !(psde->features & BIT(SDE_SSPP_CSC)))) {
Lloyd Atkinsond49de562016-05-30 13:23:48 -0400950 DRM_ERROR("Pipe doesn't support YUV\n");
Clarence Ipdbde9832016-06-26 09:48:36 -0400951 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -0400952
Clarence Ipdbde9832016-06-26 09:48:36 -0400953 /* verify source size/region */
954 } else if (!src_w || !src_h ||
955 (src_w > src_max_w) || (src_h > src_max_h) ||
956 (src_x > src_max_x) || (src_y > src_max_y) ||
957 (src_x + src_w > src_max_x) ||
958 (src_y + src_h > src_max_y)) {
959 DRM_ERROR("Invalid source (%u, %u) -> (%u, %u)\n",
960 src_x, src_y, src_x + src_w,
961 src_y + src_h);
962 ret = -EINVAL;
963
964 /* require even source for YUV */
965 } else if (SDE_FORMAT_IS_YUV(fmt) &&
966 ((src_x & 0x1) || (src_y & 0x1) ||
967 (src_w & 0x1) || (src_h & 0x1))) {
968 DRM_ERROR("Invalid odd src res/pos for YUV\n");
969 ret = -EINVAL;
970
971 /* verify scaler requirements */
972 } else if (!(psde->features & SDE_SSPP_SCALER) &&
973 ((src_w != state->crtc_w) ||
974 (src_h != state->crtc_h))) {
975 DRM_ERROR("Pipe doesn't support scaling %ux%u->%ux%u\n",
976 src_w, src_h, state->crtc_w,
977 state->crtc_h);
978 ret = -EINVAL;
979
980 /* check decimated source width */
981 } else if (src_deci_w > psde->pipe_sblk->maxlinewidth) {
982 DRM_ERROR("Invalid source [W:%u, Wd:%u] > %u\n",
983 src_w, src_deci_w,
984 psde->pipe_sblk->maxlinewidth);
985 ret = -EINVAL;
986
987 /* check max scaler capability */
988 } else if (((src_deci_w * upscale_max) < state->crtc_w) ||
989 ((src_deci_h * upscale_max) < state->crtc_h) ||
990 ((state->crtc_w * downscale_max) < src_deci_w) ||
991 ((state->crtc_h * downscale_max) < src_deci_h)) {
992 DRM_ERROR("Too much scaling requested %ux%u -> %ux%u\n",
993 src_deci_w, src_deci_h,
994 state->crtc_w, state->crtc_h);
995 ret = -EINVAL;
996
997 /* check frame buffer */
998 } else if (_sde_plane_atomic_check_fb(
999 psde, pstate, state->fb)) {
1000 ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001001 }
1002
Clarence Ipdbde9832016-06-26 09:48:36 -04001003 /* check decimation (and bwc/fetch mode) */
1004 if (!ret && (deci_w || deci_h)) {
1005 if (SDE_FORMAT_IS_UBWC(fmt)) {
1006 DRM_ERROR("No decimation with BWC\n");
1007 ret = -EINVAL;
1008 } else if ((deci_w > psde->pipe_sblk->maxhdeciexp) ||
1009 (deci_h > psde->pipe_sblk->maxvdeciexp)) {
1010 DRM_ERROR("Too much decimation requested\n");
1011 ret = -EINVAL;
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001012 } else if (fmt->fetch_mode != SDE_FETCH_LINEAR) {
Clarence Ipdbde9832016-06-26 09:48:36 -04001013 DRM_ERROR("Decimation requires linear fetch\n");
1014 ret = -EINVAL;
1015 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001016 }
1017 }
1018
Lloyd Atkinsonfa2489c2016-05-25 15:16:03 -04001019 if (!ret)
1020 _sde_plane_atomic_check_mode_changed(psde, state, old_state);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001021
Clarence Ipdbde9832016-06-26 09:48:36 -04001022exit:
1023 return ret;
1024}
1025
Clarence Ipcae1bb62016-07-07 12:07:13 -04001026/**
1027 * sde_plane_flush - final plane operations before commit flush
1028 * @plane: Pointer to drm plane structure
1029 */
1030void sde_plane_flush(struct drm_plane *plane)
Clarence Ipdbde9832016-06-26 09:48:36 -04001031{
Clarence Ipcae1bb62016-07-07 12:07:13 -04001032 struct sde_plane *psde;
1033
1034 if (!plane)
1035 return;
1036
1037 psde = to_sde_plane(plane);
1038
1039 /*
1040 * These updates have to be done immediately before the plane flush
1041 * timing, and may not be moved to the atomic_update/mode_set functions.
1042 */
1043 if (psde->is_error)
1044 /* force white frame with 0% alpha pipe output on error */
1045 _sde_plane_color_fill(plane, 0xFFFFFF, 0x0);
1046 else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG)
1047 /* force 100% alpha */
1048 _sde_plane_color_fill(plane, psde->color_fill, 0xFF);
1049 else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc)
1050 psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr);
1051
1052 /* flag h/w flush complete */
1053 if (plane->state)
Clarence Ipdbde9832016-06-26 09:48:36 -04001054 to_sde_plane_state(plane->state)->pending = false;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001055}
1056
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001057static void sde_plane_atomic_update(struct drm_plane *plane,
Clarence Ipe78efb72016-06-24 18:35:21 -04001058 struct drm_plane_state *old_state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001059{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001060 struct sde_plane *sde_plane;
1061 struct drm_plane_state *state;
1062 struct sde_plane_state *pstate;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001063
Clarence Ip5e2a9222016-06-26 22:38:24 -04001064 if (!plane || !plane->state) {
1065 DRM_ERROR("Invalid plane/state\n");
1066 return;
1067 }
1068
1069 sde_plane = to_sde_plane(plane);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001070 sde_plane->is_error = false;
Clarence Ip5e2a9222016-06-26 22:38:24 -04001071 state = plane->state;
1072 pstate = to_sde_plane_state(state);
1073
Clarence Ipae4e60c2016-06-26 22:44:04 -04001074 DBG("%s: update", sde_plane->pipe_name);
1075
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001076 if (!sde_plane_enabled(state)) {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001077 pstate->pending = true;
1078 } else if (pstate->mode_changed) {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001079 int ret;
1080
Clarence Ip5e2a9222016-06-26 22:38:24 -04001081 pstate->pending = true;
Clarence Ipe78efb72016-06-24 18:35:21 -04001082 ret = _sde_plane_mode_set(plane,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001083 state->crtc, state->fb,
1084 state->crtc_x, state->crtc_y,
1085 state->crtc_w, state->crtc_h,
1086 state->src_x, state->src_y,
1087 state->src_w, state->src_h);
1088 /* atomic_check should have ensured that this doesn't fail */
1089 WARN_ON(ret < 0);
1090 } else {
Clarence Ip5e2a9222016-06-26 22:38:24 -04001091 _sde_plane_set_scanout(plane, pstate,
1092 &sde_plane->pipe_cfg, state->fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001093 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001094}
1095
1096/* helper to install properties which are common to planes and crtcs */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001097static void _sde_plane_install_properties(struct drm_plane *plane)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001098{
Clarence Ip5e2a9222016-06-26 22:38:24 -04001099 static const struct drm_prop_enum_list e_blend_op[] = {
1100 {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"},
1101 {SDE_DRM_BLEND_OP_OPAQUE, "opaque"},
1102 {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"},
1103 {SDE_DRM_BLEND_OP_COVERAGE, "coverage"}
1104 };
1105 static const struct drm_prop_enum_list e_src_config[] = {
1106 {SDE_DRM_DEINTERLACE, "deinterlace"}
1107 };
1108 struct sde_plane *psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001109
Clarence Ip4ce59322016-06-26 22:27:51 -04001110 DBG("");
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001111
Clarence Ipaa0faf42016-05-30 12:07:48 -04001112 if (!plane || !psde || !psde->pipe_hw || !psde->pipe_sblk) {
1113 DRM_ERROR("Invalid argument(s)\n");
Clarence Ip5e2a9222016-06-26 22:38:24 -04001114 return;
1115 }
1116
1117 /* range properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001118 msm_property_install_range(&psde->property_info, "zpos", 0, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001119 plane->type == DRM_PLANE_TYPE_PRIMARY ?
1120 STAGE_BASE : STAGE0 + drm_plane_index(plane),
1121 PLANE_PROP_ZPOS);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001122
Clarence Ipaa0faf42016-05-30 12:07:48 -04001123 msm_property_install_range(&psde->property_info, "alpha", 0, 255, 255,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001124 PLANE_PROP_ALPHA);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001125
Clarence Ipcb410d42016-06-26 22:52:33 -04001126 if (psde->pipe_hw->ops.setup_solidfill)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001127 msm_property_install_range(&psde->property_info, "color_fill",
Clarence Ipcb410d42016-06-26 22:52:33 -04001128 0, 0xFFFFFFFF, 0,
1129 PLANE_PROP_COLOR_FILL);
1130
Clarence Ipcae1bb62016-07-07 12:07:13 -04001131 msm_property_install_range(&psde->property_info, "input_fence",
1132 0, ~0, ~0,
1133 PLANE_PROP_INPUT_FENCE);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001134
1135 /* standard properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001136 msm_property_install_rotation(&psde->property_info,
1137 BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y),
1138 PLANE_PROP_ROTATION);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001139
Clarence Ip04ec67d2016-05-26 01:16:15 -04001140 /* enum/bitmask properties */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001141 msm_property_install_enum(&psde->property_info, "blend_op", 0,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001142 e_blend_op, ARRAY_SIZE(e_blend_op),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001143 PLANE_PROP_BLEND_OP);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001144 msm_property_install_enum(&psde->property_info, "src_config", 1,
Clarence Ip5e2a9222016-06-26 22:38:24 -04001145 e_src_config, ARRAY_SIZE(e_src_config),
Clarence Ipae4e60c2016-06-26 22:44:04 -04001146 PLANE_PROP_SRC_CONFIG);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001147
Clarence Ipe78efb72016-06-24 18:35:21 -04001148 /* blob properties */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001149 if (psde->features & SDE_SSPP_SCALER)
Clarence Ipaa0faf42016-05-30 12:07:48 -04001150 msm_property_install_blob(&psde->property_info, "scaler", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001151 PLANE_PROP_SCALER);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001152 if (psde->features & BIT(SDE_SSPP_CSC)) {
1153 msm_property_install_blob(&psde->property_info, "csc", 0,
Clarence Ipae4e60c2016-06-26 22:44:04 -04001154 PLANE_PROP_CSC);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001155 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001156}
1157
1158static int sde_plane_atomic_set_property(struct drm_plane *plane,
1159 struct drm_plane_state *state, struct drm_property *property,
1160 uint64_t val)
1161{
Clarence Ip730e7192016-06-26 22:45:09 -04001162 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001163 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001164 int idx, ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001165
Clarence Ipaa0faf42016-05-30 12:07:48 -04001166 DBG("");
1167
1168 if (!plane) {
1169 DRM_ERROR("Invalid plane\n");
1170 } else if (!state) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001171 DRM_ERROR("Invalid state\n");
Clarence Ip730e7192016-06-26 22:45:09 -04001172 } else {
1173 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001174 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001175 ret = msm_property_atomic_set(&psde->property_info,
1176 pstate->property_values, pstate->property_blobs,
1177 property, val);
1178 if (!ret) {
1179 idx = msm_property_index(&psde->property_info,
1180 property);
Clarence Ipcae1bb62016-07-07 12:07:13 -04001181 if (idx == PLANE_PROP_INPUT_FENCE)
1182 _sde_plane_set_input_fence(plane, pstate, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001183 }
1184 }
1185
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001186 return ret;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001187}
1188
1189static int sde_plane_set_property(struct drm_plane *plane,
1190 struct drm_property *property, uint64_t val)
1191{
Clarence Ip4ce59322016-06-26 22:27:51 -04001192 DBG("");
Clarence Ip4c1d9772016-06-26 09:35:38 -04001193
Clarence Ipae4e60c2016-06-26 22:44:04 -04001194 return sde_plane_atomic_set_property(plane,
1195 plane->state, property, val);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001196}
1197
1198static int sde_plane_atomic_get_property(struct drm_plane *plane,
1199 const struct drm_plane_state *state,
1200 struct drm_property *property, uint64_t *val)
1201{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001202 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001203 struct sde_plane_state *pstate;
Clarence Ipaa0faf42016-05-30 12:07:48 -04001204 int ret = -EINVAL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001205
Clarence Ipaa0faf42016-05-30 12:07:48 -04001206 DBG("");
1207
1208 if (!plane) {
1209 DRM_ERROR("Invalid plane\n");
1210 } else if (!state) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001211 DRM_ERROR("Invalid state\n");
Clarence Ipaa0faf42016-05-30 12:07:48 -04001212 } else {
1213 psde = to_sde_plane(plane);
Clarence Ip4c1d9772016-06-26 09:35:38 -04001214 pstate = to_sde_plane_state(state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001215 ret = msm_property_atomic_get(&psde->property_info,
1216 pstate->property_values, pstate->property_blobs,
1217 property, val);
Clarence Ipe78efb72016-06-24 18:35:21 -04001218 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001219
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001220 return ret;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001221}
1222
1223static void sde_plane_destroy(struct drm_plane *plane)
1224{
Clarence Ip4ce59322016-06-26 22:27:51 -04001225 struct sde_plane *psde;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001226
Clarence Ip4ce59322016-06-26 22:27:51 -04001227 DBG("");
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001228
Clarence Ip4ce59322016-06-26 22:27:51 -04001229 if (plane) {
1230 psde = to_sde_plane(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001231
Clarence Ip4ce59322016-06-26 22:27:51 -04001232 debugfs_remove_recursive(psde->debugfs_root);
Clarence Ipe78efb72016-06-24 18:35:21 -04001233
Clarence Ipaa0faf42016-05-30 12:07:48 -04001234 msm_property_destroy(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001235 mutex_destroy(&psde->lock);
1236
Clarence Ip4ce59322016-06-26 22:27:51 -04001237 drm_plane_helper_disable(plane);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001238
Clarence Ip4ce59322016-06-26 22:27:51 -04001239 /* this will destroy the states as well */
1240 drm_plane_cleanup(plane);
1241
Clarence Ip4c1d9772016-06-26 09:35:38 -04001242 if (psde->pipe_hw)
1243 sde_hw_sspp_destroy(psde->pipe_hw);
1244
Clarence Ip4ce59322016-06-26 22:27:51 -04001245 kfree(psde);
1246 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001247}
1248
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001249static void sde_plane_destroy_state(struct drm_plane *plane,
1250 struct drm_plane_state *state)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001251{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001252 struct sde_plane *psde;
Clarence Ipe78efb72016-06-24 18:35:21 -04001253 struct sde_plane_state *pstate;
Clarence Ipe78efb72016-06-24 18:35:21 -04001254
Clarence Ipae4e60c2016-06-26 22:44:04 -04001255 if (!plane || !state) {
1256 DRM_ERROR("Invalid plane/state\n");
1257 return;
1258 }
1259
Clarence Ipaa0faf42016-05-30 12:07:48 -04001260 psde = to_sde_plane(plane);
Clarence Ip730e7192016-06-26 22:45:09 -04001261 pstate = to_sde_plane_state(state);
1262
1263 DBG("");
1264
Clarence Ipe78efb72016-06-24 18:35:21 -04001265 /* remove ref count for frame buffers */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001266 if (state->fb)
1267 drm_framebuffer_unreference(state->fb);
1268
Clarence Ipae4e60c2016-06-26 22:44:04 -04001269 /* remove ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001270 if (pstate->input_fence)
1271 sde_sync_put(pstate->input_fence);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001272
Clarence Ipaa0faf42016-05-30 12:07:48 -04001273 /* destroy value helper */
1274 msm_property_destroy_state(&psde->property_info, pstate,
1275 pstate->property_values, pstate->property_blobs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001276}
1277
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001278static struct drm_plane_state *
1279sde_plane_duplicate_state(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001280{
Clarence Ipaa0faf42016-05-30 12:07:48 -04001281 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001282 struct sde_plane_state *pstate;
Clarence Ip730e7192016-06-26 22:45:09 -04001283 struct sde_plane_state *old_state;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001284
Clarence Ip730e7192016-06-26 22:45:09 -04001285 if (!plane || !plane->state)
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001286 return NULL;
1287
Clarence Ip730e7192016-06-26 22:45:09 -04001288 old_state = to_sde_plane_state(plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001289 psde = to_sde_plane(plane);
1290 pstate = msm_property_alloc_state(&psde->property_info);
Clarence Ip730e7192016-06-26 22:45:09 -04001291 if (!pstate)
1292 return NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001293
Clarence Ipaa0faf42016-05-30 12:07:48 -04001294 DBG("");
1295
1296 /* duplicate value helper */
1297 msm_property_duplicate_state(&psde->property_info, old_state, pstate,
1298 pstate->property_values, pstate->property_blobs);
Clarence Ipae4e60c2016-06-26 22:44:04 -04001299
Clarence Ip730e7192016-06-26 22:45:09 -04001300 /* add ref count for frame buffer */
1301 if (pstate->base.fb)
1302 drm_framebuffer_reference(pstate->base.fb);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001303
Clarence Ip730e7192016-06-26 22:45:09 -04001304 /* add ref count for fence */
Clarence Ipcae1bb62016-07-07 12:07:13 -04001305 if (pstate->input_fence) {
1306 pstate->input_fence = 0;
1307 _sde_plane_set_input_fence(plane, pstate, pstate->
1308 property_values[PLANE_PROP_INPUT_FENCE]);
Clarence Ipe78efb72016-06-24 18:35:21 -04001309 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001310
Clarence Ip730e7192016-06-26 22:45:09 -04001311 pstate->mode_changed = false;
1312 pstate->pending = false;
1313
1314 return &pstate->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001315}
1316
1317static void sde_plane_reset(struct drm_plane *plane)
1318{
Clarence Ipae4e60c2016-06-26 22:44:04 -04001319 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001320 struct sde_plane_state *pstate;
1321
Clarence Ipae4e60c2016-06-26 22:44:04 -04001322 if (!plane) {
1323 DRM_ERROR("Invalid plane\n");
1324 return;
1325 }
1326
Clarence Ip730e7192016-06-26 22:45:09 -04001327 psde = to_sde_plane(plane);
1328 DBG("%s", psde->pipe_name);
1329
Clarence Ipae4e60c2016-06-26 22:44:04 -04001330 /* remove previous state, if present */
Clarence Ipaa0faf42016-05-30 12:07:48 -04001331 if (plane->state) {
Clarence Ipae4e60c2016-06-26 22:44:04 -04001332 sde_plane_destroy_state(plane, plane->state);
Clarence Ipaa0faf42016-05-30 12:07:48 -04001333 plane->state = 0;
Clarence Ipae4e60c2016-06-26 22:44:04 -04001334 }
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001335
Clarence Ipaa0faf42016-05-30 12:07:48 -04001336 pstate = msm_property_alloc_state(&psde->property_info);
1337 if (!pstate)
1338 return;
Clarence Ip730e7192016-06-26 22:45:09 -04001339
Clarence Ipaa0faf42016-05-30 12:07:48 -04001340 /* reset value helper */
1341 msm_property_reset_state(&psde->property_info, pstate,
1342 pstate->property_values, pstate->property_blobs);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001343
1344 pstate->base.plane = plane;
1345
1346 plane->state = &pstate->base;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001347}
1348
1349static const struct drm_plane_funcs sde_plane_funcs = {
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001350 .update_plane = drm_atomic_helper_update_plane,
1351 .disable_plane = drm_atomic_helper_disable_plane,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001352 .destroy = sde_plane_destroy,
1353 .set_property = sde_plane_set_property,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001354 .atomic_set_property = sde_plane_atomic_set_property,
1355 .atomic_get_property = sde_plane_atomic_get_property,
1356 .reset = sde_plane_reset,
1357 .atomic_duplicate_state = sde_plane_duplicate_state,
1358 .atomic_destroy_state = sde_plane_destroy_state,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001359};
1360
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001361static const struct drm_plane_helper_funcs sde_plane_helper_funcs = {
1362 .prepare_fb = sde_plane_prepare_fb,
1363 .cleanup_fb = sde_plane_cleanup_fb,
1364 .atomic_check = sde_plane_atomic_check,
1365 .atomic_update = sde_plane_atomic_update,
1366};
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001367
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001368enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001369{
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001370 struct sde_plane *sde_plane = to_sde_plane(plane);
1371
1372 return sde_plane->pipe;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001373}
1374
Clarence Ip4ce59322016-06-26 22:27:51 -04001375static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
1376{
1377 const struct sde_sspp_sub_blks *sblk = 0;
1378 const struct sde_sspp_cfg *cfg = 0;
1379
1380 if (psde && psde->pipe_hw)
1381 cfg = psde->pipe_hw->cap;
1382 if (cfg)
1383 sblk = cfg->sblk;
1384
1385 if (kms && sblk) {
1386 /* create overall sub-directory for the pipe */
1387 psde->debugfs_root =
1388 debugfs_create_dir(psde->pipe_name,
1389 sde_debugfs_get_root(kms));
1390 if (psde->debugfs_root) {
1391 /* don't error check these */
Clarence Ip4c1d9772016-06-26 09:35:38 -04001392 debugfs_create_x32("features", 0644,
Clarence Ip4ce59322016-06-26 22:27:51 -04001393 psde->debugfs_root, &psde->features);
1394
1395 /* add register dump support */
1396 sde_debugfs_setup_regset32(&psde->debugfs_src,
1397 sblk->src_blk.base + cfg->base,
1398 sblk->src_blk.len,
1399 kms->mmio);
1400 sde_debugfs_create_regset32("src_blk", 0444,
1401 psde->debugfs_root, &psde->debugfs_src);
1402
1403 sde_debugfs_setup_regset32(&psde->debugfs_scaler,
1404 sblk->scaler_blk.base + cfg->base,
1405 sblk->scaler_blk.len,
1406 kms->mmio);
1407 sde_debugfs_create_regset32("scaler_blk", 0444,
1408 psde->debugfs_root,
1409 &psde->debugfs_scaler);
1410
1411 sde_debugfs_setup_regset32(&psde->debugfs_csc,
1412 sblk->csc_blk.base + cfg->base,
1413 sblk->csc_blk.len,
1414 kms->mmio);
1415 sde_debugfs_create_regset32("csc_blk", 0444,
1416 psde->debugfs_root, &psde->debugfs_csc);
1417 }
1418 }
1419}
1420
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001421/* initialize plane */
Clarence Ipe78efb72016-06-24 18:35:21 -04001422struct drm_plane *sde_plane_init(struct drm_device *dev,
Clarence Ip4c1d9772016-06-26 09:35:38 -04001423 uint32_t pipe, bool primary_plane)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001424{
1425 struct drm_plane *plane = NULL;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001426 struct sde_plane *psde;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001427 struct msm_drm_private *priv;
1428 struct sde_kms *kms;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001429 enum drm_plane_type type;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001430 int ret = -EINVAL;
1431
1432 if (!dev) {
1433 DRM_ERROR("[%u]Device is NULL\n", pipe);
1434 goto exit;
1435 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001436
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001437 priv = dev->dev_private;
Ben Chan78647cd2016-06-26 22:02:47 -04001438 if (!priv) {
1439 DRM_ERROR("[%u]Private data is NULL\n", pipe);
1440 goto exit;
1441 }
1442
1443 if (!priv->kms) {
1444 DRM_ERROR("[%u]Invalid KMS reference\n", pipe);
1445 goto exit;
1446 }
1447 kms = to_sde_kms(priv->kms);
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001448
Clarence Ip4c1d9772016-06-26 09:35:38 -04001449 if (!kms->catalog) {
1450 DRM_ERROR("[%u]Invalid catalog reference\n", pipe);
1451 goto exit;
1452 }
1453
Clarence Ip4ce59322016-06-26 22:27:51 -04001454 /* create and zero local structure */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001455 psde = kzalloc(sizeof(*psde), GFP_KERNEL);
1456 if (!psde) {
Clarence Ip4c1d9772016-06-26 09:35:38 -04001457 DRM_ERROR("[%u]Failed to allocate local plane struct\n", pipe);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001458 ret = -ENOMEM;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001459 goto exit;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001460 }
1461
Clarence Ip4c1d9772016-06-26 09:35:38 -04001462 /* cache local stuff for later */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001463 plane = &psde->base;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001464 psde->pipe = pipe;
Clarence Ip4c1d9772016-06-26 09:35:38 -04001465 psde->mmu_id = kms->mmu_id;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001466
Clarence Ip4c1d9772016-06-26 09:35:38 -04001467 /* initialize underlying h/w driver */
1468 psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog);
1469 if (IS_ERR(psde->pipe_hw)) {
1470 DRM_ERROR("[%u]SSPP init failed\n", pipe);
1471 ret = PTR_ERR(psde->pipe_hw);
1472 goto clean_plane;
1473 } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) {
1474 DRM_ERROR("[%u]SSPP init returned invalid cfg\n", pipe);
1475 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001476 }
Clarence Ip4c1d9772016-06-26 09:35:38 -04001477
1478 /* cache features mask for later */
1479 psde->features = psde->pipe_hw->cap->features;
1480 psde->pipe_sblk = psde->pipe_hw->cap->sblk;
1481
1482 /* add plane to DRM framework */
Lloyd Atkinson9a673492016-07-05 11:41:57 -04001483 psde->nformats = sde_populate_formats(psde->formats,
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001484 ARRAY_SIZE(psde->formats),
1485 !(psde->features & BIT(SDE_SSPP_CSC)) ||
Clarence Ipe78efb72016-06-24 18:35:21 -04001486 !(psde->features & SDE_SSPP_SCALER));
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001487
Clarence Ip4c1d9772016-06-26 09:35:38 -04001488 if (!psde->nformats) {
1489 DRM_ERROR("[%u]No valid formats for plane\n", pipe);
1490 goto clean_sspp;
1491 }
1492
1493 if (psde->features & BIT(SDE_SSPP_CURSOR))
1494 type = DRM_PLANE_TYPE_CURSOR;
1495 else if (primary_plane)
1496 type = DRM_PLANE_TYPE_PRIMARY;
1497 else
1498 type = DRM_PLANE_TYPE_OVERLAY;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001499 ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs,
1500 psde->formats, psde->nformats,
1501 type);
1502 if (ret)
Clarence Ip4c1d9772016-06-26 09:35:38 -04001503 goto clean_sspp;
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001504
Clarence Ip4c1d9772016-06-26 09:35:38 -04001505 /* success! finalize initialization */
Abhijit Kulkarni3e3e0d22016-06-24 17:56:13 -04001506 drm_plane_helper_add(plane, &sde_plane_helper_funcs);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001507
Clarence Ipaa0faf42016-05-30 12:07:48 -04001508 msm_property_init(&psde->property_info, &plane->base, dev,
1509 priv->plane_property, psde->property_data,
1510 PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT,
1511 sizeof(struct sde_plane_state));
1512
1513 _sde_plane_install_properties(plane);
Clarence Ip5e2a9222016-06-26 22:38:24 -04001514
Clarence Ip4ce59322016-06-26 22:27:51 -04001515 /* save user friendly pipe name for later */
Clarence Ip5e2a9222016-06-26 22:38:24 -04001516 snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id);
Clarence Ip4ce59322016-06-26 22:27:51 -04001517
Clarence Ip730e7192016-06-26 22:45:09 -04001518 mutex_init(&psde->lock);
1519
Clarence Ip4ce59322016-06-26 22:27:51 -04001520 _sde_plane_init_debugfs(psde, kms);
1521
Clarence Ip4c1d9772016-06-26 09:35:38 -04001522 DRM_INFO("[%u]Successfully created %s\n", pipe, psde->pipe_name);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001523 return plane;
1524
Clarence Ip4c1d9772016-06-26 09:35:38 -04001525clean_sspp:
1526 if (psde && psde->pipe_hw)
1527 sde_hw_sspp_destroy(psde->pipe_hw);
1528clean_plane:
1529 kfree(psde);
Ben Chan78647cd2016-06-26 22:02:47 -04001530exit:
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001531 return ERR_PTR(ret);
1532}