• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022 MediaTek Inc.
4  * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
5  */
6 
7 #include <linux/math64.h>
8 #include <media/v4l2-common.h>
9 #include <media/videobuf2-v4l2.h>
10 #include <media/videobuf2-dma-contig.h>
11 #include "mtk-mdp3-core.h"
12 #include "mtk-mdp3-regs.h"
13 #include "mtk-mdp3-m2m.h"
14 
15 /*
16  * All 10-bit related formats are not added in the basic format list,
17  * please add the corresponding format settings before use.
18  */
19 static const struct mdp_format mdp_formats[] = {
20 	{
21 		.pixelformat	= V4L2_PIX_FMT_GREY,
22 		.mdp_color	= MDP_COLOR_GREY,
23 		.depth		= { 8 },
24 		.row_depth	= { 8 },
25 		.num_planes	= 1,
26 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
27 	}, {
28 		.pixelformat	= V4L2_PIX_FMT_RGB565X,
29 		.mdp_color	= MDP_COLOR_BGR565,
30 		.depth		= { 16 },
31 		.row_depth	= { 16 },
32 		.num_planes	= 1,
33 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
34 	}, {
35 		.pixelformat	= V4L2_PIX_FMT_RGB565,
36 		.mdp_color	= MDP_COLOR_RGB565,
37 		.depth		= { 16 },
38 		.row_depth	= { 16 },
39 		.num_planes	= 1,
40 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
41 	}, {
42 		.pixelformat	= V4L2_PIX_FMT_RGB24,
43 		.mdp_color	= MDP_COLOR_RGB888,
44 		.depth		= { 24 },
45 		.row_depth	= { 24 },
46 		.num_planes	= 1,
47 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
48 	}, {
49 		.pixelformat	= V4L2_PIX_FMT_BGR24,
50 		.mdp_color	= MDP_COLOR_BGR888,
51 		.depth		= { 24 },
52 		.row_depth	= { 24 },
53 		.num_planes	= 1,
54 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
55 	}, {
56 		.pixelformat	= V4L2_PIX_FMT_ABGR32,
57 		.mdp_color	= MDP_COLOR_BGRA8888,
58 		.depth		= { 32 },
59 		.row_depth	= { 32 },
60 		.num_planes	= 1,
61 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
62 	}, {
63 		.pixelformat	= V4L2_PIX_FMT_ARGB32,
64 		.mdp_color	= MDP_COLOR_ARGB8888,
65 		.depth		= { 32 },
66 		.row_depth	= { 32 },
67 		.num_planes	= 1,
68 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
69 	}, {
70 		.pixelformat	= V4L2_PIX_FMT_UYVY,
71 		.mdp_color	= MDP_COLOR_UYVY,
72 		.depth		= { 16 },
73 		.row_depth	= { 16 },
74 		.num_planes	= 1,
75 		.walign		= 1,
76 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
77 	}, {
78 		.pixelformat	= V4L2_PIX_FMT_VYUY,
79 		.mdp_color	= MDP_COLOR_VYUY,
80 		.depth		= { 16 },
81 		.row_depth	= { 16 },
82 		.num_planes	= 1,
83 		.walign		= 1,
84 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
85 	}, {
86 		.pixelformat	= V4L2_PIX_FMT_YUYV,
87 		.mdp_color	= MDP_COLOR_YUYV,
88 		.depth		= { 16 },
89 		.row_depth	= { 16 },
90 		.num_planes	= 1,
91 		.walign		= 1,
92 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
93 	}, {
94 		.pixelformat	= V4L2_PIX_FMT_YVYU,
95 		.mdp_color	= MDP_COLOR_YVYU,
96 		.depth		= { 16 },
97 		.row_depth	= { 16 },
98 		.num_planes	= 1,
99 		.walign		= 1,
100 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
101 	}, {
102 		.pixelformat	= V4L2_PIX_FMT_YUV420,
103 		.mdp_color	= MDP_COLOR_I420,
104 		.depth		= { 12 },
105 		.row_depth	= { 8 },
106 		.num_planes	= 1,
107 		.walign		= 1,
108 		.halign		= 1,
109 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
110 	}, {
111 		.pixelformat	= V4L2_PIX_FMT_YVU420,
112 		.mdp_color	= MDP_COLOR_YV12,
113 		.depth		= { 12 },
114 		.row_depth	= { 8 },
115 		.num_planes	= 1,
116 		.walign		= 1,
117 		.halign		= 1,
118 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
119 	}, {
120 		.pixelformat	= V4L2_PIX_FMT_NV12,
121 		.mdp_color	= MDP_COLOR_NV12,
122 		.depth		= { 12 },
123 		.row_depth	= { 8 },
124 		.num_planes	= 1,
125 		.walign		= 1,
126 		.halign		= 1,
127 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
128 	}, {
129 		.pixelformat	= V4L2_PIX_FMT_NV21,
130 		.mdp_color	= MDP_COLOR_NV21,
131 		.depth		= { 12 },
132 		.row_depth	= { 8 },
133 		.num_planes	= 1,
134 		.walign		= 1,
135 		.halign		= 1,
136 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
137 	}, {
138 		.pixelformat	= V4L2_PIX_FMT_NV16,
139 		.mdp_color	= MDP_COLOR_NV16,
140 		.depth		= { 16 },
141 		.row_depth	= { 8 },
142 		.num_planes	= 1,
143 		.walign		= 1,
144 		.flags		= MDP_FMT_FLAG_OUTPUT,
145 	}, {
146 		.pixelformat	= V4L2_PIX_FMT_NV61,
147 		.mdp_color	= MDP_COLOR_NV61,
148 		.depth		= { 16 },
149 		.row_depth	= { 8 },
150 		.num_planes	= 1,
151 		.walign		= 1,
152 		.flags		= MDP_FMT_FLAG_OUTPUT,
153 	}, {
154 		.pixelformat	= V4L2_PIX_FMT_NV24,
155 		.mdp_color	= MDP_COLOR_NV24,
156 		.depth		= { 24 },
157 		.row_depth	= { 8 },
158 		.num_planes	= 1,
159 		.flags		= MDP_FMT_FLAG_OUTPUT,
160 	}, {
161 		.pixelformat	= V4L2_PIX_FMT_NV42,
162 		.mdp_color	= MDP_COLOR_NV42,
163 		.depth		= { 24 },
164 		.row_depth	= { 8 },
165 		.num_planes	= 1,
166 		.flags		= MDP_FMT_FLAG_OUTPUT,
167 	}, {
168 		.pixelformat	= V4L2_PIX_FMT_MT21C,
169 		.mdp_color	= MDP_COLOR_420_BLK_UFO,
170 		.depth		= { 8, 4 },
171 		.row_depth	= { 8, 8 },
172 		.num_planes	= 2,
173 		.walign		= 4,
174 		.halign		= 5,
175 		.flags		= MDP_FMT_FLAG_OUTPUT,
176 	}, {
177 		.pixelformat	= V4L2_PIX_FMT_MM21,
178 		.mdp_color	= MDP_COLOR_420_BLK,
179 		.depth		= { 8, 4 },
180 		.row_depth	= { 8, 8 },
181 		.num_planes	= 2,
182 		.walign		= 4,
183 		.halign		= 5,
184 		.flags		= MDP_FMT_FLAG_OUTPUT,
185 	}, {
186 		.pixelformat	= V4L2_PIX_FMT_NV12M,
187 		.mdp_color	= MDP_COLOR_NV12,
188 		.depth		= { 8, 4 },
189 		.row_depth	= { 8, 8 },
190 		.num_planes	= 2,
191 		.walign		= 1,
192 		.halign		= 1,
193 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
194 	}, {
195 		.pixelformat	= V4L2_PIX_FMT_NV21M,
196 		.mdp_color	= MDP_COLOR_NV21,
197 		.depth		= { 8, 4 },
198 		.row_depth	= { 8, 8 },
199 		.num_planes	= 2,
200 		.walign		= 1,
201 		.halign		= 1,
202 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
203 	}, {
204 		.pixelformat	= V4L2_PIX_FMT_NV16M,
205 		.mdp_color	= MDP_COLOR_NV16,
206 		.depth		= { 8, 8 },
207 		.row_depth	= { 8, 8 },
208 		.num_planes	= 2,
209 		.walign		= 1,
210 		.flags		= MDP_FMT_FLAG_OUTPUT,
211 	}, {
212 		.pixelformat	= V4L2_PIX_FMT_NV61M,
213 		.mdp_color	= MDP_COLOR_NV61,
214 		.depth		= { 8, 8 },
215 		.row_depth	= { 8, 8 },
216 		.num_planes	= 2,
217 		.walign		= 1,
218 		.flags		= MDP_FMT_FLAG_OUTPUT,
219 	}, {
220 		.pixelformat	= V4L2_PIX_FMT_YUV420M,
221 		.mdp_color	= MDP_COLOR_I420,
222 		.depth		= { 8, 2, 2 },
223 		.row_depth	= { 8, 4, 4 },
224 		.num_planes	= 3,
225 		.walign		= 1,
226 		.halign		= 1,
227 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
228 	}, {
229 		.pixelformat	= V4L2_PIX_FMT_YVU420M,
230 		.mdp_color	= MDP_COLOR_YV12,
231 		.depth		= { 8, 2, 2 },
232 		.row_depth	= { 8, 4, 4 },
233 		.num_planes	= 3,
234 		.walign		= 1,
235 		.halign		= 1,
236 		.flags		= MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
237 	}
238 };
239 
240 static const struct mdp_limit mdp_def_limit = {
241 	.out_limit = {
242 		.wmin	= 16,
243 		.hmin	= 16,
244 		.wmax	= 8176,
245 		.hmax	= 8176,
246 	},
247 	.cap_limit = {
248 		.wmin	= 2,
249 		.hmin	= 2,
250 		.wmax	= 8176,
251 		.hmax	= 8176,
252 	},
253 	.h_scale_up_max = 32,
254 	.v_scale_up_max = 32,
255 	.h_scale_down_max = 20,
256 	.v_scale_down_max = 128,
257 };
258 
mdp_find_fmt(u32 pixelformat,u32 type)259 static const struct mdp_format *mdp_find_fmt(u32 pixelformat, u32 type)
260 {
261 	u32 i, flag;
262 
263 	flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
264 					MDP_FMT_FLAG_CAPTURE;
265 	for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
266 		if (!(mdp_formats[i].flags & flag))
267 			continue;
268 		if (mdp_formats[i].pixelformat == pixelformat)
269 			return &mdp_formats[i];
270 	}
271 	return NULL;
272 }
273 
mdp_find_fmt_by_index(u32 index,u32 type)274 static const struct mdp_format *mdp_find_fmt_by_index(u32 index, u32 type)
275 {
276 	u32 i, flag, num = 0;
277 
278 	flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
279 					MDP_FMT_FLAG_CAPTURE;
280 	for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
281 		if (!(mdp_formats[i].flags & flag))
282 			continue;
283 		if (index == num)
284 			return &mdp_formats[i];
285 		num++;
286 	}
287 	return NULL;
288 }
289 
mdp_map_ycbcr_prof_mplane(struct v4l2_format * f,u32 mdp_color)290 enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f,
291 						 u32 mdp_color)
292 {
293 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
294 
295 	if (MDP_COLOR_IS_RGB(mdp_color))
296 		return MDP_YCBCR_PROFILE_FULL_BT601;
297 
298 	switch (pix_mp->colorspace) {
299 	case V4L2_COLORSPACE_JPEG:
300 		return MDP_YCBCR_PROFILE_JPEG;
301 	case V4L2_COLORSPACE_REC709:
302 	case V4L2_COLORSPACE_DCI_P3:
303 		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
304 			return MDP_YCBCR_PROFILE_FULL_BT709;
305 		return MDP_YCBCR_PROFILE_BT709;
306 	case V4L2_COLORSPACE_BT2020:
307 		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
308 			return MDP_YCBCR_PROFILE_FULL_BT2020;
309 		return MDP_YCBCR_PROFILE_BT2020;
310 	default:
311 		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
312 			return MDP_YCBCR_PROFILE_FULL_BT601;
313 		return MDP_YCBCR_PROFILE_BT601;
314 	}
315 }
316 
mdp_bound_align_image(u32 * w,u32 * h,struct v4l2_frmsize_stepwise * s,unsigned int salign)317 static void mdp_bound_align_image(u32 *w, u32 *h,
318 				  struct v4l2_frmsize_stepwise *s,
319 				  unsigned int salign)
320 {
321 	unsigned int org_w, org_h;
322 
323 	org_w = *w;
324 	org_h = *h;
325 	v4l_bound_align_image(w, s->min_width, s->max_width, s->step_width,
326 			      h, s->min_height, s->max_height, s->step_height,
327 			      salign);
328 
329 	s->min_width = org_w;
330 	s->min_height = org_h;
331 	v4l2_apply_frmsize_constraints(w, h, s);
332 }
333 
mdp_clamp_align(s32 * x,int min,int max,unsigned int align)334 static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align)
335 {
336 	unsigned int mask;
337 
338 	if (min < 0 || max < 0)
339 		return -ERANGE;
340 
341 	/* Bits that must be zero to be aligned */
342 	mask = ~((1 << align) - 1);
343 
344 	min = 0 ? 0 : ((min + ~mask) & mask);
345 	max = max & mask;
346 	if ((unsigned int)min > (unsigned int)max)
347 		return -ERANGE;
348 
349 	/* Clamp to aligned min and max */
350 	*x = clamp(*x, min, max);
351 
352 	/* Round to nearest aligned value */
353 	if (align)
354 		*x = (*x + (1 << (align - 1))) & mask;
355 	return 0;
356 }
357 
mdp_enum_fmt_mplane(struct v4l2_fmtdesc * f)358 int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f)
359 {
360 	const struct mdp_format *fmt;
361 
362 	fmt = mdp_find_fmt_by_index(f->index, f->type);
363 	if (!fmt)
364 		return -EINVAL;
365 
366 	f->pixelformat = fmt->pixelformat;
367 	return 0;
368 }
369 
mdp_try_fmt_mplane(struct v4l2_format * f,struct mdp_frameparam * param,u32 ctx_id)370 const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
371 					    struct mdp_frameparam *param,
372 					    u32 ctx_id)
373 {
374 	struct device *dev = &param->ctx->mdp_dev->pdev->dev;
375 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
376 	const struct mdp_format *fmt;
377 	const struct mdp_pix_limit *pix_limit;
378 	struct v4l2_frmsize_stepwise s;
379 	u32 org_w, org_h;
380 	unsigned int i;
381 
382 	fmt = mdp_find_fmt(pix_mp->pixelformat, f->type);
383 	if (!fmt) {
384 		fmt = mdp_find_fmt_by_index(0, f->type);
385 		if (!fmt) {
386 			dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id,
387 				(pix_mp->pixelformat & 0xff),
388 				(pix_mp->pixelformat >>  8) & 0xff,
389 				(pix_mp->pixelformat >> 16) & 0xff,
390 				(pix_mp->pixelformat >> 24) & 0xff);
391 			return NULL;
392 		}
393 	}
394 
395 	pix_mp->field = V4L2_FIELD_NONE;
396 	pix_mp->flags = 0;
397 	pix_mp->pixelformat = fmt->pixelformat;
398 	if (V4L2_TYPE_IS_CAPTURE(f->type)) {
399 		pix_mp->colorspace = param->colorspace;
400 		pix_mp->xfer_func = param->xfer_func;
401 		pix_mp->ycbcr_enc = param->ycbcr_enc;
402 		pix_mp->quantization = param->quant;
403 	}
404 
405 	pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? &param->limit->out_limit :
406 						&param->limit->cap_limit;
407 	s.min_width = pix_limit->wmin;
408 	s.max_width = pix_limit->wmax;
409 	s.step_width = fmt->walign;
410 	s.min_height = pix_limit->hmin;
411 	s.max_height = pix_limit->hmax;
412 	s.step_height = fmt->halign;
413 	org_w = pix_mp->width;
414 	org_h = pix_mp->height;
415 
416 	mdp_bound_align_image(&pix_mp->width, &pix_mp->height, &s, fmt->salign);
417 	if (org_w != pix_mp->width || org_h != pix_mp->height)
418 		dev_dbg(dev, "%d: size change: %ux%u to %ux%u", ctx_id,
419 			org_w, org_h, pix_mp->width, pix_mp->height);
420 
421 	if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes)
422 		dev_dbg(dev, "%d num of planes change: %u to %u", ctx_id,
423 			pix_mp->num_planes, fmt->num_planes);
424 	pix_mp->num_planes = fmt->num_planes;
425 
426 	for (i = 0; i < pix_mp->num_planes; ++i) {
427 		u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) >> 3;
428 		u32 max_bpl = (pix_limit->wmax * fmt->row_depth[i]) >> 3;
429 		u32 bpl = pix_mp->plane_fmt[i].bytesperline;
430 		u32 min_si, max_si;
431 		u32 si = pix_mp->plane_fmt[i].sizeimage;
432 		u64 di;
433 
434 		bpl = clamp(bpl, min_bpl, max_bpl);
435 		pix_mp->plane_fmt[i].bytesperline = bpl;
436 
437 		di = (u64)bpl * pix_mp->height * fmt->depth[i];
438 		min_si = (u32)div_u64(di, fmt->row_depth[i]);
439 		di = (u64)bpl * s.max_height * fmt->depth[i];
440 		max_si = (u32)div_u64(di, fmt->row_depth[i]);
441 
442 		si = clamp(si, min_si, max_si);
443 		pix_mp->plane_fmt[i].sizeimage = si;
444 
445 		dev_dbg(dev, "%d: p%u, bpl:%u [%u, %u], sizeimage:%u [%u, %u]",
446 			ctx_id, i, bpl, min_bpl, max_bpl, si, min_si, max_si);
447 	}
448 
449 	return fmt;
450 }
451 
mdp_clamp_start(s32 * x,int min,int max,unsigned int align,u32 flags)452 static int mdp_clamp_start(s32 *x, int min, int max, unsigned int align,
453 			   u32 flags)
454 {
455 	if (flags & V4L2_SEL_FLAG_GE)
456 		max = *x;
457 	if (flags & V4L2_SEL_FLAG_LE)
458 		min = *x;
459 	return mdp_clamp_align(x, min, max, align);
460 }
461 
mdp_clamp_end(s32 * x,int min,int max,unsigned int align,u32 flags)462 static int mdp_clamp_end(s32 *x, int min, int max, unsigned int align,
463 			 u32 flags)
464 {
465 	if (flags & V4L2_SEL_FLAG_GE)
466 		min = *x;
467 	if (flags & V4L2_SEL_FLAG_LE)
468 		max = *x;
469 	return mdp_clamp_align(x, min, max, align);
470 }
471 
mdp_try_crop(struct mdp_m2m_ctx * ctx,struct v4l2_rect * r,const struct v4l2_selection * s,struct mdp_frame * frame)472 int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r,
473 		 const struct v4l2_selection *s, struct mdp_frame *frame)
474 {
475 	struct device *dev = &ctx->mdp_dev->pdev->dev;
476 	s32 left, top, right, bottom;
477 	u32 framew, frameh, walign, halign;
478 	int ret;
479 
480 	dev_dbg(dev, "%d target:%d, set:(%d,%d) %ux%u", ctx->id,
481 		s->target, s->r.left, s->r.top, s->r.width, s->r.height);
482 
483 	left = s->r.left;
484 	top = s->r.top;
485 	right = s->r.left + s->r.width;
486 	bottom = s->r.top + s->r.height;
487 	framew = frame->format.fmt.pix_mp.width;
488 	frameh = frame->format.fmt.pix_mp.height;
489 
490 	if (mdp_target_is_crop(s->target)) {
491 		walign = 1;
492 		halign = 1;
493 	} else {
494 		walign = frame->mdp_fmt->walign;
495 		halign = frame->mdp_fmt->halign;
496 	}
497 
498 	dev_dbg(dev, "%d align:%u,%u, bound:%ux%u", ctx->id,
499 		walign, halign, framew, frameh);
500 
501 	ret = mdp_clamp_start(&left, 0, right, walign, s->flags);
502 	if (ret)
503 		return ret;
504 	ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags);
505 	if (ret)
506 		return ret;
507 	ret = mdp_clamp_end(&right, left, framew, walign, s->flags);
508 	if (ret)
509 		return ret;
510 	ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags);
511 	if (ret)
512 		return ret;
513 
514 	r->left = left;
515 	r->top = top;
516 	r->width = right - left;
517 	r->height = bottom - top;
518 
519 	dev_dbg(dev, "%d crop:(%d,%d) %ux%u", ctx->id,
520 		r->left, r->top, r->width, r->height);
521 	return 0;
522 }
523 
mdp_check_scaling_ratio(const struct v4l2_rect * crop,const struct v4l2_rect * compose,s32 rotation,const struct mdp_limit * limit)524 int mdp_check_scaling_ratio(const struct v4l2_rect *crop,
525 			    const struct v4l2_rect *compose, s32 rotation,
526 	const struct mdp_limit *limit)
527 {
528 	u32 crop_w, crop_h, comp_w, comp_h;
529 
530 	crop_w = crop->width;
531 	crop_h = crop->height;
532 	if (90 == rotation || 270 == rotation) {
533 		comp_w = compose->height;
534 		comp_h = compose->width;
535 	} else {
536 		comp_w = compose->width;
537 		comp_h = compose->height;
538 	}
539 
540 	if ((crop_w / comp_w) > limit->h_scale_down_max ||
541 	    (crop_h / comp_h) > limit->v_scale_down_max ||
542 	    (comp_w / crop_w) > limit->h_scale_up_max ||
543 	    (comp_h / crop_h) > limit->v_scale_up_max)
544 		return -ERANGE;
545 	return 0;
546 }
547 
548 /* Stride that is accepted by MDP HW */
mdp_fmt_get_stride(const struct mdp_format * fmt,u32 bytesperline,unsigned int plane)549 static u32 mdp_fmt_get_stride(const struct mdp_format *fmt,
550 			      u32 bytesperline, unsigned int plane)
551 {
552 	enum mdp_color c = fmt->mdp_color;
553 	u32 stride;
554 
555 	stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c))
556 		/ fmt->row_depth[0];
557 	if (plane == 0)
558 		return stride;
559 	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
560 		if (MDP_COLOR_IS_BLOCK_MODE(c))
561 			stride = stride / 2;
562 		return stride;
563 	}
564 	return 0;
565 }
566 
567 /* Stride that is accepted by MDP HW of format with contiguous planes */
mdp_fmt_get_stride_contig(const struct mdp_format * fmt,u32 pix_stride,unsigned int plane)568 static u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt,
569 				     u32 pix_stride, unsigned int plane)
570 {
571 	enum mdp_color c = fmt->mdp_color;
572 	u32 stride = pix_stride;
573 
574 	if (plane == 0)
575 		return stride;
576 	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
577 		stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c);
578 		if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c))
579 			stride = stride * 2;
580 		return stride;
581 	}
582 	return 0;
583 }
584 
585 /* Plane size that is accepted by MDP HW */
mdp_fmt_get_plane_size(const struct mdp_format * fmt,u32 stride,u32 height,unsigned int plane)586 static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt,
587 				  u32 stride, u32 height, unsigned int plane)
588 {
589 	enum mdp_color c = fmt->mdp_color;
590 	u32 bytesperline;
591 
592 	bytesperline = (stride * fmt->row_depth[0])
593 		/ MDP_COLOR_BITS_PER_PIXEL(c);
594 	if (plane == 0)
595 		return bytesperline * height;
596 	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
597 		height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c);
598 		if (MDP_COLOR_IS_BLOCK_MODE(c))
599 			bytesperline = bytesperline * 2;
600 		return bytesperline * height;
601 	}
602 	return 0;
603 }
604 
mdp_prepare_buffer(struct img_image_buffer * b,struct mdp_frame * frame,struct vb2_buffer * vb)605 static void mdp_prepare_buffer(struct img_image_buffer *b,
606 			       struct mdp_frame *frame, struct vb2_buffer *vb)
607 {
608 	struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp;
609 	unsigned int i;
610 
611 	b->format.colorformat = frame->mdp_fmt->mdp_color;
612 	b->format.ycbcr_prof = frame->ycbcr_prof;
613 	for (i = 0; i < pix_mp->num_planes; ++i) {
614 		u32 stride = mdp_fmt_get_stride(frame->mdp_fmt,
615 			pix_mp->plane_fmt[i].bytesperline, i);
616 
617 		b->format.plane_fmt[i].stride = stride;
618 		b->format.plane_fmt[i].size =
619 			mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
620 					       pix_mp->height, i);
621 		b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i);
622 	}
623 	for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) {
624 		u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt,
625 			b->format.plane_fmt[0].stride, i);
626 
627 		b->format.plane_fmt[i].stride = stride;
628 		b->format.plane_fmt[i].size =
629 			mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
630 					       pix_mp->height, i);
631 		b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size;
632 	}
633 	b->usage = frame->usage;
634 }
635 
mdp_set_src_config(struct img_input * in,struct mdp_frame * frame,struct vb2_buffer * vb)636 void mdp_set_src_config(struct img_input *in,
637 			struct mdp_frame *frame, struct vb2_buffer *vb)
638 {
639 	in->buffer.format.width = frame->format.fmt.pix_mp.width;
640 	in->buffer.format.height = frame->format.fmt.pix_mp.height;
641 	mdp_prepare_buffer(&in->buffer, frame, vb);
642 }
643 
mdp_to_fixed(u32 * r,struct v4l2_fract * f)644 static u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f)
645 {
646 	u32 q;
647 
648 	if (f->denominator == 0) {
649 		*r = 0;
650 		return 0;
651 	}
652 
653 	q = f->numerator / f->denominator;
654 	*r = div_u64(((u64)f->numerator - q * f->denominator) <<
655 		     IMG_SUBPIXEL_SHIFT, f->denominator);
656 	return q;
657 }
658 
mdp_set_src_crop(struct img_crop * c,struct mdp_crop * crop)659 static void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop)
660 {
661 	c->left = crop->c.left
662 		+ mdp_to_fixed(&c->left_subpix, &crop->left_subpix);
663 	c->top = crop->c.top
664 		+ mdp_to_fixed(&c->top_subpix, &crop->top_subpix);
665 	c->width = crop->c.width
666 		+ mdp_to_fixed(&c->width_subpix, &crop->width_subpix);
667 	c->height = crop->c.height
668 		+ mdp_to_fixed(&c->height_subpix, &crop->height_subpix);
669 }
670 
mdp_set_orientation(struct img_output * out,s32 rotation,bool hflip,bool vflip)671 static void mdp_set_orientation(struct img_output *out,
672 				s32 rotation, bool hflip, bool vflip)
673 {
674 	u8 flip = 0;
675 
676 	if (hflip)
677 		flip ^= 1;
678 	if (vflip) {
679 		/*
680 		 * A vertical flip is equivalent to
681 		 * a 180-degree rotation with a horizontal flip
682 		 */
683 		rotation += 180;
684 		flip ^= 1;
685 	}
686 
687 	out->rotation = rotation % 360;
688 	if (flip != 0)
689 		out->flags |= IMG_CTRL_FLAG_HFLIP;
690 	else
691 		out->flags &= ~IMG_CTRL_FLAG_HFLIP;
692 }
693 
mdp_set_dst_config(struct img_output * out,struct mdp_frame * frame,struct vb2_buffer * vb)694 void mdp_set_dst_config(struct img_output *out,
695 			struct mdp_frame *frame, struct vb2_buffer *vb)
696 {
697 	out->buffer.format.width = frame->compose.width;
698 	out->buffer.format.height = frame->compose.height;
699 	mdp_prepare_buffer(&out->buffer, frame, vb);
700 	mdp_set_src_crop(&out->crop, &frame->crop);
701 	mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip);
702 }
703 
mdp_frameparam_init(struct mdp_frameparam * param)704 int mdp_frameparam_init(struct mdp_frameparam *param)
705 {
706 	struct mdp_frame *frame;
707 
708 	if (!param)
709 		return -EINVAL;
710 
711 	INIT_LIST_HEAD(&param->list);
712 	param->limit = &mdp_def_limit;
713 	param->type = MDP_STREAM_TYPE_BITBLT;
714 
715 	frame = &param->output;
716 	frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
717 	frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
718 	frame->ycbcr_prof =
719 		mdp_map_ycbcr_prof_mplane(&frame->format,
720 					  frame->mdp_fmt->mdp_color);
721 	frame->usage = MDP_BUFFER_USAGE_HW_READ;
722 
723 	param->num_captures = 1;
724 	frame = &param->captures[0];
725 	frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
726 	frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
727 	frame->ycbcr_prof =
728 		mdp_map_ycbcr_prof_mplane(&frame->format,
729 					  frame->mdp_fmt->mdp_color);
730 	frame->usage = MDP_BUFFER_USAGE_MDP;
731 	frame->crop.c.width = param->output.format.fmt.pix_mp.width;
732 	frame->crop.c.height = param->output.format.fmt.pix_mp.height;
733 	frame->compose.width = frame->format.fmt.pix_mp.width;
734 	frame->compose.height = frame->format.fmt.pix_mp.height;
735 
736 	return 0;
737 }
738