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