161890ccaSMoudy Ho // SPDX-License-Identifier: GPL-2.0-only
261890ccaSMoudy Ho /*
361890ccaSMoudy Ho  * Copyright (c) 2022 MediaTek Inc.
461890ccaSMoudy Ho  * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
561890ccaSMoudy Ho  */
661890ccaSMoudy Ho 
741687207SMoudy Ho #include <linux/math64.h>
861890ccaSMoudy Ho #include <media/v4l2-common.h>
961890ccaSMoudy Ho #include <media/videobuf2-v4l2.h>
1061890ccaSMoudy Ho #include <media/videobuf2-dma-contig.h>
1161890ccaSMoudy Ho #include "mtk-mdp3-core.h"
1261890ccaSMoudy Ho #include "mtk-mdp3-regs.h"
1361890ccaSMoudy Ho #include "mtk-mdp3-m2m.h"
1461890ccaSMoudy Ho 
mdp_find_fmt(const struct mtk_mdp_driver_data * mdp_data,u32 pixelformat,u32 type)156b8910e3SMoudy Ho static const struct mdp_format *mdp_find_fmt(const struct mtk_mdp_driver_data *mdp_data,
166b8910e3SMoudy Ho 					     u32 pixelformat, u32 type)
1761890ccaSMoudy Ho {
1861890ccaSMoudy Ho 	u32 i, flag;
1961890ccaSMoudy Ho 
2061890ccaSMoudy Ho 	flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
2161890ccaSMoudy Ho 					MDP_FMT_FLAG_CAPTURE;
226b8910e3SMoudy Ho 	for (i = 0; i < mdp_data->format_len; ++i) {
236b8910e3SMoudy Ho 		if (!(mdp_data->format[i].flags & flag))
2461890ccaSMoudy Ho 			continue;
256b8910e3SMoudy Ho 		if (mdp_data->format[i].pixelformat == pixelformat)
266b8910e3SMoudy Ho 			return &mdp_data->format[i];
2761890ccaSMoudy Ho 	}
2861890ccaSMoudy Ho 	return NULL;
2961890ccaSMoudy Ho }
3061890ccaSMoudy Ho 
mdp_find_fmt_by_index(const struct mtk_mdp_driver_data * mdp_data,u32 index,u32 type)316b8910e3SMoudy Ho static const struct mdp_format *mdp_find_fmt_by_index(const struct mtk_mdp_driver_data *mdp_data,
326b8910e3SMoudy Ho 						      u32 index, u32 type)
3361890ccaSMoudy Ho {
3461890ccaSMoudy Ho 	u32 i, flag, num = 0;
3561890ccaSMoudy Ho 
3661890ccaSMoudy Ho 	flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
3761890ccaSMoudy Ho 					MDP_FMT_FLAG_CAPTURE;
386b8910e3SMoudy Ho 	for (i = 0; i < mdp_data->format_len; ++i) {
396b8910e3SMoudy Ho 		if (!(mdp_data->format[i].flags & flag))
4061890ccaSMoudy Ho 			continue;
4161890ccaSMoudy Ho 		if (index == num)
426b8910e3SMoudy Ho 			return &mdp_data->format[i];
4361890ccaSMoudy Ho 		num++;
4461890ccaSMoudy Ho 	}
4561890ccaSMoudy Ho 	return NULL;
4661890ccaSMoudy Ho }
4761890ccaSMoudy Ho 
mdp_map_ycbcr_prof_mplane(struct v4l2_format * f,u32 mdp_color)4861890ccaSMoudy Ho enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f,
4961890ccaSMoudy Ho 						 u32 mdp_color)
5061890ccaSMoudy Ho {
5161890ccaSMoudy Ho 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
5261890ccaSMoudy Ho 
5361890ccaSMoudy Ho 	if (MDP_COLOR_IS_RGB(mdp_color))
5461890ccaSMoudy Ho 		return MDP_YCBCR_PROFILE_FULL_BT601;
5561890ccaSMoudy Ho 
5661890ccaSMoudy Ho 	switch (pix_mp->colorspace) {
5761890ccaSMoudy Ho 	case V4L2_COLORSPACE_JPEG:
5861890ccaSMoudy Ho 		return MDP_YCBCR_PROFILE_JPEG;
5961890ccaSMoudy Ho 	case V4L2_COLORSPACE_REC709:
6061890ccaSMoudy Ho 	case V4L2_COLORSPACE_DCI_P3:
6161890ccaSMoudy Ho 		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
6261890ccaSMoudy Ho 			return MDP_YCBCR_PROFILE_FULL_BT709;
6361890ccaSMoudy Ho 		return MDP_YCBCR_PROFILE_BT709;
6461890ccaSMoudy Ho 	case V4L2_COLORSPACE_BT2020:
6561890ccaSMoudy Ho 		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
6661890ccaSMoudy Ho 			return MDP_YCBCR_PROFILE_FULL_BT2020;
6761890ccaSMoudy Ho 		return MDP_YCBCR_PROFILE_BT2020;
6861890ccaSMoudy Ho 	default:
6961890ccaSMoudy Ho 		if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
7061890ccaSMoudy Ho 			return MDP_YCBCR_PROFILE_FULL_BT601;
7161890ccaSMoudy Ho 		return MDP_YCBCR_PROFILE_BT601;
7261890ccaSMoudy Ho 	}
7361890ccaSMoudy Ho }
7461890ccaSMoudy Ho 
mdp_bound_align_image(u32 * w,u32 * h,struct v4l2_frmsize_stepwise * s,unsigned int salign)7561890ccaSMoudy Ho static void mdp_bound_align_image(u32 *w, u32 *h,
7661890ccaSMoudy Ho 				  struct v4l2_frmsize_stepwise *s,
7761890ccaSMoudy Ho 				  unsigned int salign)
7861890ccaSMoudy Ho {
7961890ccaSMoudy Ho 	unsigned int org_w, org_h;
8061890ccaSMoudy Ho 
8161890ccaSMoudy Ho 	org_w = *w;
8261890ccaSMoudy Ho 	org_h = *h;
8361890ccaSMoudy Ho 	v4l_bound_align_image(w, s->min_width, s->max_width, s->step_width,
8461890ccaSMoudy Ho 			      h, s->min_height, s->max_height, s->step_height,
8561890ccaSMoudy Ho 			      salign);
8661890ccaSMoudy Ho 
8761890ccaSMoudy Ho 	s->min_width = org_w;
8861890ccaSMoudy Ho 	s->min_height = org_h;
8961890ccaSMoudy Ho 	v4l2_apply_frmsize_constraints(w, h, s);
9061890ccaSMoudy Ho }
9161890ccaSMoudy Ho 
mdp_clamp_align(s32 * x,int min,int max,unsigned int align)9261890ccaSMoudy Ho static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align)
9361890ccaSMoudy Ho {
9461890ccaSMoudy Ho 	unsigned int mask;
9561890ccaSMoudy Ho 
9661890ccaSMoudy Ho 	if (min < 0 || max < 0)
9761890ccaSMoudy Ho 		return -ERANGE;
9861890ccaSMoudy Ho 
9961890ccaSMoudy Ho 	/* Bits that must be zero to be aligned */
10061890ccaSMoudy Ho 	mask = ~((1 << align) - 1);
10161890ccaSMoudy Ho 
10261890ccaSMoudy Ho 	min = 0 ? 0 : ((min + ~mask) & mask);
10361890ccaSMoudy Ho 	max = max & mask;
10461890ccaSMoudy Ho 	if ((unsigned int)min > (unsigned int)max)
10561890ccaSMoudy Ho 		return -ERANGE;
10661890ccaSMoudy Ho 
10761890ccaSMoudy Ho 	/* Clamp to aligned min and max */
10861890ccaSMoudy Ho 	*x = clamp(*x, min, max);
10961890ccaSMoudy Ho 
11061890ccaSMoudy Ho 	/* Round to nearest aligned value */
11161890ccaSMoudy Ho 	if (align)
11261890ccaSMoudy Ho 		*x = (*x + (1 << (align - 1))) & mask;
11361890ccaSMoudy Ho 	return 0;
11461890ccaSMoudy Ho }
11561890ccaSMoudy Ho 
mdp_enum_fmt_mplane(struct mdp_dev * mdp,struct v4l2_fmtdesc * f)1166b8910e3SMoudy Ho int mdp_enum_fmt_mplane(struct mdp_dev *mdp, struct v4l2_fmtdesc *f)
11761890ccaSMoudy Ho {
11861890ccaSMoudy Ho 	const struct mdp_format *fmt;
11961890ccaSMoudy Ho 
1206b8910e3SMoudy Ho 	fmt = mdp_find_fmt_by_index(mdp->mdp_data, f->index, f->type);
12161890ccaSMoudy Ho 	if (!fmt)
12261890ccaSMoudy Ho 		return -EINVAL;
12361890ccaSMoudy Ho 
12461890ccaSMoudy Ho 	f->pixelformat = fmt->pixelformat;
12561890ccaSMoudy Ho 	return 0;
12661890ccaSMoudy Ho }
12761890ccaSMoudy Ho 
mdp_try_fmt_mplane(struct mdp_dev * mdp,struct v4l2_format * f,struct mdp_frameparam * param,u32 ctx_id)1286b8910e3SMoudy Ho const struct mdp_format *mdp_try_fmt_mplane(struct mdp_dev *mdp,
1296b8910e3SMoudy Ho 					    struct v4l2_format *f,
13061890ccaSMoudy Ho 					    struct mdp_frameparam *param,
13161890ccaSMoudy Ho 					    u32 ctx_id)
13261890ccaSMoudy Ho {
13361890ccaSMoudy Ho 	struct device *dev = &param->ctx->mdp_dev->pdev->dev;
13461890ccaSMoudy Ho 	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
13561890ccaSMoudy Ho 	const struct mdp_format *fmt;
13661890ccaSMoudy Ho 	const struct mdp_pix_limit *pix_limit;
13761890ccaSMoudy Ho 	struct v4l2_frmsize_stepwise s;
13861890ccaSMoudy Ho 	u32 org_w, org_h;
13961890ccaSMoudy Ho 	unsigned int i;
14061890ccaSMoudy Ho 
1416b8910e3SMoudy Ho 	fmt = mdp_find_fmt(mdp->mdp_data, pix_mp->pixelformat, f->type);
14261890ccaSMoudy Ho 	if (!fmt) {
1436b8910e3SMoudy Ho 		fmt = mdp_find_fmt_by_index(mdp->mdp_data, 0, f->type);
14461890ccaSMoudy Ho 		if (!fmt) {
14561890ccaSMoudy Ho 			dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id,
14661890ccaSMoudy Ho 				(pix_mp->pixelformat & 0xff),
14761890ccaSMoudy Ho 				(pix_mp->pixelformat >>  8) & 0xff,
14861890ccaSMoudy Ho 				(pix_mp->pixelformat >> 16) & 0xff,
14961890ccaSMoudy Ho 				(pix_mp->pixelformat >> 24) & 0xff);
15061890ccaSMoudy Ho 			return NULL;
15161890ccaSMoudy Ho 		}
15261890ccaSMoudy Ho 	}
15361890ccaSMoudy Ho 
15461890ccaSMoudy Ho 	pix_mp->field = V4L2_FIELD_NONE;
15561890ccaSMoudy Ho 	pix_mp->flags = 0;
15661890ccaSMoudy Ho 	pix_mp->pixelformat = fmt->pixelformat;
15761890ccaSMoudy Ho 	if (V4L2_TYPE_IS_CAPTURE(f->type)) {
15861890ccaSMoudy Ho 		pix_mp->colorspace = param->colorspace;
15961890ccaSMoudy Ho 		pix_mp->xfer_func = param->xfer_func;
16061890ccaSMoudy Ho 		pix_mp->ycbcr_enc = param->ycbcr_enc;
16161890ccaSMoudy Ho 		pix_mp->quantization = param->quant;
16261890ccaSMoudy Ho 	}
16361890ccaSMoudy Ho 
16461890ccaSMoudy Ho 	pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? &param->limit->out_limit :
16561890ccaSMoudy Ho 						&param->limit->cap_limit;
16661890ccaSMoudy Ho 	s.min_width = pix_limit->wmin;
16761890ccaSMoudy Ho 	s.max_width = pix_limit->wmax;
16861890ccaSMoudy Ho 	s.step_width = fmt->walign;
16961890ccaSMoudy Ho 	s.min_height = pix_limit->hmin;
17061890ccaSMoudy Ho 	s.max_height = pix_limit->hmax;
17161890ccaSMoudy Ho 	s.step_height = fmt->halign;
17261890ccaSMoudy Ho 	org_w = pix_mp->width;
17361890ccaSMoudy Ho 	org_h = pix_mp->height;
17461890ccaSMoudy Ho 
17561890ccaSMoudy Ho 	mdp_bound_align_image(&pix_mp->width, &pix_mp->height, &s, fmt->salign);
17661890ccaSMoudy Ho 	if (org_w != pix_mp->width || org_h != pix_mp->height)
17761890ccaSMoudy Ho 		dev_dbg(dev, "%d: size change: %ux%u to %ux%u", ctx_id,
17861890ccaSMoudy Ho 			org_w, org_h, pix_mp->width, pix_mp->height);
17961890ccaSMoudy Ho 
18061890ccaSMoudy Ho 	if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes)
18161890ccaSMoudy Ho 		dev_dbg(dev, "%d num of planes change: %u to %u", ctx_id,
18261890ccaSMoudy Ho 			pix_mp->num_planes, fmt->num_planes);
18361890ccaSMoudy Ho 	pix_mp->num_planes = fmt->num_planes;
18461890ccaSMoudy Ho 
18561890ccaSMoudy Ho 	for (i = 0; i < pix_mp->num_planes; ++i) {
18661890ccaSMoudy Ho 		u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) >> 3;
18761890ccaSMoudy Ho 		u32 max_bpl = (pix_limit->wmax * fmt->row_depth[i]) >> 3;
18861890ccaSMoudy Ho 		u32 bpl = pix_mp->plane_fmt[i].bytesperline;
18961890ccaSMoudy Ho 		u32 min_si, max_si;
19061890ccaSMoudy Ho 		u32 si = pix_mp->plane_fmt[i].sizeimage;
19141687207SMoudy Ho 		u64 di;
19261890ccaSMoudy Ho 
19361890ccaSMoudy Ho 		bpl = clamp(bpl, min_bpl, max_bpl);
19461890ccaSMoudy Ho 		pix_mp->plane_fmt[i].bytesperline = bpl;
19561890ccaSMoudy Ho 
19641687207SMoudy Ho 		di = (u64)bpl * pix_mp->height * fmt->depth[i];
19741687207SMoudy Ho 		min_si = (u32)div_u64(di, fmt->row_depth[i]);
19841687207SMoudy Ho 		di = (u64)bpl * s.max_height * fmt->depth[i];
19941687207SMoudy Ho 		max_si = (u32)div_u64(di, fmt->row_depth[i]);
20061890ccaSMoudy Ho 
20161890ccaSMoudy Ho 		si = clamp(si, min_si, max_si);
20261890ccaSMoudy Ho 		pix_mp->plane_fmt[i].sizeimage = si;
20361890ccaSMoudy Ho 
20461890ccaSMoudy Ho 		dev_dbg(dev, "%d: p%u, bpl:%u [%u, %u], sizeimage:%u [%u, %u]",
20561890ccaSMoudy Ho 			ctx_id, i, bpl, min_bpl, max_bpl, si, min_si, max_si);
20661890ccaSMoudy Ho 	}
20761890ccaSMoudy Ho 
20861890ccaSMoudy Ho 	return fmt;
20961890ccaSMoudy Ho }
21061890ccaSMoudy Ho 
mdp_clamp_start(s32 * x,int min,int max,unsigned int align,u32 flags)21161890ccaSMoudy Ho static int mdp_clamp_start(s32 *x, int min, int max, unsigned int align,
21261890ccaSMoudy Ho 			   u32 flags)
21361890ccaSMoudy Ho {
21461890ccaSMoudy Ho 	if (flags & V4L2_SEL_FLAG_GE)
21561890ccaSMoudy Ho 		max = *x;
21661890ccaSMoudy Ho 	if (flags & V4L2_SEL_FLAG_LE)
21761890ccaSMoudy Ho 		min = *x;
21861890ccaSMoudy Ho 	return mdp_clamp_align(x, min, max, align);
21961890ccaSMoudy Ho }
22061890ccaSMoudy Ho 
mdp_clamp_end(s32 * x,int min,int max,unsigned int align,u32 flags)22161890ccaSMoudy Ho static int mdp_clamp_end(s32 *x, int min, int max, unsigned int align,
22261890ccaSMoudy Ho 			 u32 flags)
22361890ccaSMoudy Ho {
22461890ccaSMoudy Ho 	if (flags & V4L2_SEL_FLAG_GE)
22561890ccaSMoudy Ho 		min = *x;
22661890ccaSMoudy Ho 	if (flags & V4L2_SEL_FLAG_LE)
22761890ccaSMoudy Ho 		max = *x;
22861890ccaSMoudy Ho 	return mdp_clamp_align(x, min, max, align);
22961890ccaSMoudy Ho }
23061890ccaSMoudy Ho 
mdp_try_crop(struct mdp_m2m_ctx * ctx,struct v4l2_rect * r,const struct v4l2_selection * s,struct mdp_frame * frame)23161890ccaSMoudy Ho int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r,
23261890ccaSMoudy Ho 		 const struct v4l2_selection *s, struct mdp_frame *frame)
23361890ccaSMoudy Ho {
23461890ccaSMoudy Ho 	struct device *dev = &ctx->mdp_dev->pdev->dev;
23561890ccaSMoudy Ho 	s32 left, top, right, bottom;
23661890ccaSMoudy Ho 	u32 framew, frameh, walign, halign;
23761890ccaSMoudy Ho 	int ret;
23861890ccaSMoudy Ho 
23961890ccaSMoudy Ho 	dev_dbg(dev, "%d target:%d, set:(%d,%d) %ux%u", ctx->id,
24061890ccaSMoudy Ho 		s->target, s->r.left, s->r.top, s->r.width, s->r.height);
24161890ccaSMoudy Ho 
24261890ccaSMoudy Ho 	left = s->r.left;
24361890ccaSMoudy Ho 	top = s->r.top;
24461890ccaSMoudy Ho 	right = s->r.left + s->r.width;
24561890ccaSMoudy Ho 	bottom = s->r.top + s->r.height;
24661890ccaSMoudy Ho 	framew = frame->format.fmt.pix_mp.width;
24761890ccaSMoudy Ho 	frameh = frame->format.fmt.pix_mp.height;
24861890ccaSMoudy Ho 
24961890ccaSMoudy Ho 	if (mdp_target_is_crop(s->target)) {
25061890ccaSMoudy Ho 		walign = 1;
25161890ccaSMoudy Ho 		halign = 1;
25261890ccaSMoudy Ho 	} else {
25361890ccaSMoudy Ho 		walign = frame->mdp_fmt->walign;
25461890ccaSMoudy Ho 		halign = frame->mdp_fmt->halign;
25561890ccaSMoudy Ho 	}
25661890ccaSMoudy Ho 
25761890ccaSMoudy Ho 	dev_dbg(dev, "%d align:%u,%u, bound:%ux%u", ctx->id,
25861890ccaSMoudy Ho 		walign, halign, framew, frameh);
25961890ccaSMoudy Ho 
26061890ccaSMoudy Ho 	ret = mdp_clamp_start(&left, 0, right, walign, s->flags);
26161890ccaSMoudy Ho 	if (ret)
26261890ccaSMoudy Ho 		return ret;
26361890ccaSMoudy Ho 	ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags);
26461890ccaSMoudy Ho 	if (ret)
26561890ccaSMoudy Ho 		return ret;
26661890ccaSMoudy Ho 	ret = mdp_clamp_end(&right, left, framew, walign, s->flags);
26761890ccaSMoudy Ho 	if (ret)
26861890ccaSMoudy Ho 		return ret;
26961890ccaSMoudy Ho 	ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags);
27061890ccaSMoudy Ho 	if (ret)
27161890ccaSMoudy Ho 		return ret;
27261890ccaSMoudy Ho 
27361890ccaSMoudy Ho 	r->left = left;
27461890ccaSMoudy Ho 	r->top = top;
27561890ccaSMoudy Ho 	r->width = right - left;
27661890ccaSMoudy Ho 	r->height = bottom - top;
27761890ccaSMoudy Ho 
27861890ccaSMoudy Ho 	dev_dbg(dev, "%d crop:(%d,%d) %ux%u", ctx->id,
27961890ccaSMoudy Ho 		r->left, r->top, r->width, r->height);
28061890ccaSMoudy Ho 	return 0;
28161890ccaSMoudy Ho }
28261890ccaSMoudy Ho 
mdp_check_scaling_ratio(const struct v4l2_rect * crop,const struct v4l2_rect * compose,s32 rotation,const struct mdp_limit * limit)28361890ccaSMoudy Ho int mdp_check_scaling_ratio(const struct v4l2_rect *crop,
28461890ccaSMoudy Ho 			    const struct v4l2_rect *compose, s32 rotation,
28561890ccaSMoudy Ho 	const struct mdp_limit *limit)
28661890ccaSMoudy Ho {
28761890ccaSMoudy Ho 	u32 crop_w, crop_h, comp_w, comp_h;
28861890ccaSMoudy Ho 
28961890ccaSMoudy Ho 	crop_w = crop->width;
29061890ccaSMoudy Ho 	crop_h = crop->height;
29161890ccaSMoudy Ho 	if (90 == rotation || 270 == rotation) {
29261890ccaSMoudy Ho 		comp_w = compose->height;
29361890ccaSMoudy Ho 		comp_h = compose->width;
29461890ccaSMoudy Ho 	} else {
29561890ccaSMoudy Ho 		comp_w = compose->width;
29661890ccaSMoudy Ho 		comp_h = compose->height;
29761890ccaSMoudy Ho 	}
29861890ccaSMoudy Ho 
29961890ccaSMoudy Ho 	if ((crop_w / comp_w) > limit->h_scale_down_max ||
30061890ccaSMoudy Ho 	    (crop_h / comp_h) > limit->v_scale_down_max ||
30161890ccaSMoudy Ho 	    (comp_w / crop_w) > limit->h_scale_up_max ||
30261890ccaSMoudy Ho 	    (comp_h / crop_h) > limit->v_scale_up_max)
30361890ccaSMoudy Ho 		return -ERANGE;
30461890ccaSMoudy Ho 	return 0;
30561890ccaSMoudy Ho }
30661890ccaSMoudy Ho 
30761890ccaSMoudy Ho /* Stride that is accepted by MDP HW */
mdp_fmt_get_stride(const struct mdp_format * fmt,u32 bytesperline,unsigned int plane)30861890ccaSMoudy Ho static u32 mdp_fmt_get_stride(const struct mdp_format *fmt,
30961890ccaSMoudy Ho 			      u32 bytesperline, unsigned int plane)
31061890ccaSMoudy Ho {
31161890ccaSMoudy Ho 	enum mdp_color c = fmt->mdp_color;
31261890ccaSMoudy Ho 	u32 stride;
31361890ccaSMoudy Ho 
31461890ccaSMoudy Ho 	stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c))
31561890ccaSMoudy Ho 		/ fmt->row_depth[0];
31661890ccaSMoudy Ho 	if (plane == 0)
31761890ccaSMoudy Ho 		return stride;
31861890ccaSMoudy Ho 	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
31961890ccaSMoudy Ho 		if (MDP_COLOR_IS_BLOCK_MODE(c))
32061890ccaSMoudy Ho 			stride = stride / 2;
32161890ccaSMoudy Ho 		return stride;
32261890ccaSMoudy Ho 	}
32361890ccaSMoudy Ho 	return 0;
32461890ccaSMoudy Ho }
32561890ccaSMoudy Ho 
32661890ccaSMoudy Ho /* 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)32761890ccaSMoudy Ho static u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt,
32861890ccaSMoudy Ho 				     u32 pix_stride, unsigned int plane)
32961890ccaSMoudy Ho {
33061890ccaSMoudy Ho 	enum mdp_color c = fmt->mdp_color;
33161890ccaSMoudy Ho 	u32 stride = pix_stride;
33261890ccaSMoudy Ho 
33361890ccaSMoudy Ho 	if (plane == 0)
33461890ccaSMoudy Ho 		return stride;
33561890ccaSMoudy Ho 	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
33661890ccaSMoudy Ho 		stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c);
33761890ccaSMoudy Ho 		if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c))
33861890ccaSMoudy Ho 			stride = stride * 2;
33961890ccaSMoudy Ho 		return stride;
34061890ccaSMoudy Ho 	}
34161890ccaSMoudy Ho 	return 0;
34261890ccaSMoudy Ho }
34361890ccaSMoudy Ho 
34461890ccaSMoudy Ho /* 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)34561890ccaSMoudy Ho static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt,
34661890ccaSMoudy Ho 				  u32 stride, u32 height, unsigned int plane)
34761890ccaSMoudy Ho {
34861890ccaSMoudy Ho 	enum mdp_color c = fmt->mdp_color;
34961890ccaSMoudy Ho 	u32 bytesperline;
35061890ccaSMoudy Ho 
35161890ccaSMoudy Ho 	bytesperline = (stride * fmt->row_depth[0])
35261890ccaSMoudy Ho 		/ MDP_COLOR_BITS_PER_PIXEL(c);
35361890ccaSMoudy Ho 	if (plane == 0)
35461890ccaSMoudy Ho 		return bytesperline * height;
35561890ccaSMoudy Ho 	if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
35661890ccaSMoudy Ho 		height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c);
35761890ccaSMoudy Ho 		if (MDP_COLOR_IS_BLOCK_MODE(c))
35861890ccaSMoudy Ho 			bytesperline = bytesperline * 2;
35961890ccaSMoudy Ho 		return bytesperline * height;
36061890ccaSMoudy Ho 	}
36161890ccaSMoudy Ho 	return 0;
36261890ccaSMoudy Ho }
36361890ccaSMoudy Ho 
mdp_prepare_buffer(struct img_image_buffer * b,struct mdp_frame * frame,struct vb2_buffer * vb)36461890ccaSMoudy Ho static void mdp_prepare_buffer(struct img_image_buffer *b,
36561890ccaSMoudy Ho 			       struct mdp_frame *frame, struct vb2_buffer *vb)
36661890ccaSMoudy Ho {
36761890ccaSMoudy Ho 	struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp;
36861890ccaSMoudy Ho 	unsigned int i;
36961890ccaSMoudy Ho 
37061890ccaSMoudy Ho 	b->format.colorformat = frame->mdp_fmt->mdp_color;
37161890ccaSMoudy Ho 	b->format.ycbcr_prof = frame->ycbcr_prof;
37261890ccaSMoudy Ho 	for (i = 0; i < pix_mp->num_planes; ++i) {
37361890ccaSMoudy Ho 		u32 stride = mdp_fmt_get_stride(frame->mdp_fmt,
37461890ccaSMoudy Ho 			pix_mp->plane_fmt[i].bytesperline, i);
37561890ccaSMoudy Ho 
37661890ccaSMoudy Ho 		b->format.plane_fmt[i].stride = stride;
37761890ccaSMoudy Ho 		b->format.plane_fmt[i].size =
37861890ccaSMoudy Ho 			mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
37961890ccaSMoudy Ho 					       pix_mp->height, i);
38061890ccaSMoudy Ho 		b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i);
38161890ccaSMoudy Ho 	}
38261890ccaSMoudy Ho 	for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) {
38361890ccaSMoudy Ho 		u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt,
38461890ccaSMoudy Ho 			b->format.plane_fmt[0].stride, i);
38561890ccaSMoudy Ho 
38661890ccaSMoudy Ho 		b->format.plane_fmt[i].stride = stride;
38761890ccaSMoudy Ho 		b->format.plane_fmt[i].size =
38861890ccaSMoudy Ho 			mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
38961890ccaSMoudy Ho 					       pix_mp->height, i);
39061890ccaSMoudy Ho 		b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size;
39161890ccaSMoudy Ho 	}
39261890ccaSMoudy Ho 	b->usage = frame->usage;
39361890ccaSMoudy Ho }
39461890ccaSMoudy Ho 
mdp_set_src_config(struct img_input * in,struct mdp_frame * frame,struct vb2_buffer * vb)39561890ccaSMoudy Ho void mdp_set_src_config(struct img_input *in,
39661890ccaSMoudy Ho 			struct mdp_frame *frame, struct vb2_buffer *vb)
39761890ccaSMoudy Ho {
39861890ccaSMoudy Ho 	in->buffer.format.width = frame->format.fmt.pix_mp.width;
39961890ccaSMoudy Ho 	in->buffer.format.height = frame->format.fmt.pix_mp.height;
40061890ccaSMoudy Ho 	mdp_prepare_buffer(&in->buffer, frame, vb);
40161890ccaSMoudy Ho }
40261890ccaSMoudy Ho 
mdp_to_fixed(u32 * r,struct v4l2_fract * f)40361890ccaSMoudy Ho static u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f)
40461890ccaSMoudy Ho {
40561890ccaSMoudy Ho 	u32 q;
40661890ccaSMoudy Ho 
40761890ccaSMoudy Ho 	if (f->denominator == 0) {
40861890ccaSMoudy Ho 		*r = 0;
40961890ccaSMoudy Ho 		return 0;
41061890ccaSMoudy Ho 	}
41161890ccaSMoudy Ho 
41261890ccaSMoudy Ho 	q = f->numerator / f->denominator;
41361890ccaSMoudy Ho 	*r = div_u64(((u64)f->numerator - q * f->denominator) <<
41461890ccaSMoudy Ho 		     IMG_SUBPIXEL_SHIFT, f->denominator);
41561890ccaSMoudy Ho 	return q;
41661890ccaSMoudy Ho }
41761890ccaSMoudy Ho 
mdp_set_src_crop(struct img_crop * c,struct mdp_crop * crop)41861890ccaSMoudy Ho static void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop)
41961890ccaSMoudy Ho {
42061890ccaSMoudy Ho 	c->left = crop->c.left
42161890ccaSMoudy Ho 		+ mdp_to_fixed(&c->left_subpix, &crop->left_subpix);
42261890ccaSMoudy Ho 	c->top = crop->c.top
42361890ccaSMoudy Ho 		+ mdp_to_fixed(&c->top_subpix, &crop->top_subpix);
42461890ccaSMoudy Ho 	c->width = crop->c.width
42561890ccaSMoudy Ho 		+ mdp_to_fixed(&c->width_subpix, &crop->width_subpix);
42661890ccaSMoudy Ho 	c->height = crop->c.height
42761890ccaSMoudy Ho 		+ mdp_to_fixed(&c->height_subpix, &crop->height_subpix);
42861890ccaSMoudy Ho }
42961890ccaSMoudy Ho 
mdp_set_orientation(struct img_output * out,s32 rotation,bool hflip,bool vflip)43061890ccaSMoudy Ho static void mdp_set_orientation(struct img_output *out,
43161890ccaSMoudy Ho 				s32 rotation, bool hflip, bool vflip)
43261890ccaSMoudy Ho {
43361890ccaSMoudy Ho 	u8 flip = 0;
43461890ccaSMoudy Ho 
43561890ccaSMoudy Ho 	if (hflip)
43661890ccaSMoudy Ho 		flip ^= 1;
43761890ccaSMoudy Ho 	if (vflip) {
43861890ccaSMoudy Ho 		/*
43961890ccaSMoudy Ho 		 * A vertical flip is equivalent to
44061890ccaSMoudy Ho 		 * a 180-degree rotation with a horizontal flip
44161890ccaSMoudy Ho 		 */
44261890ccaSMoudy Ho 		rotation += 180;
44361890ccaSMoudy Ho 		flip ^= 1;
44461890ccaSMoudy Ho 	}
44561890ccaSMoudy Ho 
44661890ccaSMoudy Ho 	out->rotation = rotation % 360;
44761890ccaSMoudy Ho 	if (flip != 0)
44861890ccaSMoudy Ho 		out->flags |= IMG_CTRL_FLAG_HFLIP;
44961890ccaSMoudy Ho 	else
45061890ccaSMoudy Ho 		out->flags &= ~IMG_CTRL_FLAG_HFLIP;
45161890ccaSMoudy Ho }
45261890ccaSMoudy Ho 
mdp_set_dst_config(struct img_output * out,struct mdp_frame * frame,struct vb2_buffer * vb)45361890ccaSMoudy Ho void mdp_set_dst_config(struct img_output *out,
45461890ccaSMoudy Ho 			struct mdp_frame *frame, struct vb2_buffer *vb)
45561890ccaSMoudy Ho {
45661890ccaSMoudy Ho 	out->buffer.format.width = frame->compose.width;
45761890ccaSMoudy Ho 	out->buffer.format.height = frame->compose.height;
45861890ccaSMoudy Ho 	mdp_prepare_buffer(&out->buffer, frame, vb);
45961890ccaSMoudy Ho 	mdp_set_src_crop(&out->crop, &frame->crop);
46061890ccaSMoudy Ho 	mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip);
46161890ccaSMoudy Ho }
46261890ccaSMoudy Ho 
mdp_frameparam_init(struct mdp_dev * mdp,struct mdp_frameparam * param)4636b8910e3SMoudy Ho int mdp_frameparam_init(struct mdp_dev *mdp, struct mdp_frameparam *param)
46461890ccaSMoudy Ho {
46561890ccaSMoudy Ho 	struct mdp_frame *frame;
46661890ccaSMoudy Ho 
46761890ccaSMoudy Ho 	if (!param)
46861890ccaSMoudy Ho 		return -EINVAL;
46961890ccaSMoudy Ho 
47061890ccaSMoudy Ho 	INIT_LIST_HEAD(&param->list);
471*b35bf333SMoudy Ho 	param->limit = mdp->mdp_data->def_limit;
47261890ccaSMoudy Ho 	param->type = MDP_STREAM_TYPE_BITBLT;
47361890ccaSMoudy Ho 
47461890ccaSMoudy Ho 	frame = &param->output;
47561890ccaSMoudy Ho 	frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
4766b8910e3SMoudy Ho 	frame->mdp_fmt = mdp_try_fmt_mplane(mdp, &frame->format, param, 0);
47761890ccaSMoudy Ho 	frame->ycbcr_prof =
47861890ccaSMoudy Ho 		mdp_map_ycbcr_prof_mplane(&frame->format,
47961890ccaSMoudy Ho 					  frame->mdp_fmt->mdp_color);
48061890ccaSMoudy Ho 	frame->usage = MDP_BUFFER_USAGE_HW_READ;
48161890ccaSMoudy Ho 
48261890ccaSMoudy Ho 	param->num_captures = 1;
48361890ccaSMoudy Ho 	frame = &param->captures[0];
48461890ccaSMoudy Ho 	frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
4856b8910e3SMoudy Ho 	frame->mdp_fmt = mdp_try_fmt_mplane(mdp, &frame->format, param, 0);
48661890ccaSMoudy Ho 	frame->ycbcr_prof =
48761890ccaSMoudy Ho 		mdp_map_ycbcr_prof_mplane(&frame->format,
48861890ccaSMoudy Ho 					  frame->mdp_fmt->mdp_color);
48961890ccaSMoudy Ho 	frame->usage = MDP_BUFFER_USAGE_MDP;
49061890ccaSMoudy Ho 	frame->crop.c.width = param->output.format.fmt.pix_mp.width;
49161890ccaSMoudy Ho 	frame->crop.c.height = param->output.format.fmt.pix_mp.height;
49261890ccaSMoudy Ho 	frame->compose.width = frame->format.fmt.pix_mp.width;
49361890ccaSMoudy Ho 	frame->compose.height = frame->format.fmt.pix_mp.height;
49461890ccaSMoudy Ho 
49561890ccaSMoudy Ho 	return 0;
49661890ccaSMoudy Ho }
497