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