162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2022 MediaTek Inc. 462306a36Sopenharmony_ci * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/math64.h> 862306a36Sopenharmony_ci#include <media/v4l2-common.h> 962306a36Sopenharmony_ci#include <media/videobuf2-v4l2.h> 1062306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 1162306a36Sopenharmony_ci#include "mtk-mdp3-core.h" 1262306a36Sopenharmony_ci#include "mtk-mdp3-regs.h" 1362306a36Sopenharmony_ci#include "mtk-mdp3-m2m.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic const struct mdp_format *mdp_find_fmt(const struct mtk_mdp_driver_data *mdp_data, 1662306a36Sopenharmony_ci u32 pixelformat, u32 type) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci u32 i, flag; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT : 2162306a36Sopenharmony_ci MDP_FMT_FLAG_CAPTURE; 2262306a36Sopenharmony_ci for (i = 0; i < mdp_data->format_len; ++i) { 2362306a36Sopenharmony_ci if (!(mdp_data->format[i].flags & flag)) 2462306a36Sopenharmony_ci continue; 2562306a36Sopenharmony_ci if (mdp_data->format[i].pixelformat == pixelformat) 2662306a36Sopenharmony_ci return &mdp_data->format[i]; 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci return NULL; 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct mdp_format *mdp_find_fmt_by_index(const struct mtk_mdp_driver_data *mdp_data, 3262306a36Sopenharmony_ci u32 index, u32 type) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci u32 i, flag, num = 0; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT : 3762306a36Sopenharmony_ci MDP_FMT_FLAG_CAPTURE; 3862306a36Sopenharmony_ci for (i = 0; i < mdp_data->format_len; ++i) { 3962306a36Sopenharmony_ci if (!(mdp_data->format[i].flags & flag)) 4062306a36Sopenharmony_ci continue; 4162306a36Sopenharmony_ci if (index == num) 4262306a36Sopenharmony_ci return &mdp_data->format[i]; 4362306a36Sopenharmony_ci num++; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci return NULL; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cienum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f, 4962306a36Sopenharmony_ci u32 mdp_color) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (MDP_COLOR_IS_RGB(mdp_color)) 5462306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_FULL_BT601; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci switch (pix_mp->colorspace) { 5762306a36Sopenharmony_ci case V4L2_COLORSPACE_JPEG: 5862306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_JPEG; 5962306a36Sopenharmony_ci case V4L2_COLORSPACE_REC709: 6062306a36Sopenharmony_ci case V4L2_COLORSPACE_DCI_P3: 6162306a36Sopenharmony_ci if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) 6262306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_FULL_BT709; 6362306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_BT709; 6462306a36Sopenharmony_ci case V4L2_COLORSPACE_BT2020: 6562306a36Sopenharmony_ci if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) 6662306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_FULL_BT2020; 6762306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_BT2020; 6862306a36Sopenharmony_ci default: 6962306a36Sopenharmony_ci if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) 7062306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_FULL_BT601; 7162306a36Sopenharmony_ci return MDP_YCBCR_PROFILE_BT601; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void mdp_bound_align_image(u32 *w, u32 *h, 7662306a36Sopenharmony_ci struct v4l2_frmsize_stepwise *s, 7762306a36Sopenharmony_ci unsigned int salign) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned int org_w, org_h; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci org_w = *w; 8262306a36Sopenharmony_ci org_h = *h; 8362306a36Sopenharmony_ci v4l_bound_align_image(w, s->min_width, s->max_width, s->step_width, 8462306a36Sopenharmony_ci h, s->min_height, s->max_height, s->step_height, 8562306a36Sopenharmony_ci salign); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci s->min_width = org_w; 8862306a36Sopenharmony_ci s->min_height = org_h; 8962306a36Sopenharmony_ci v4l2_apply_frmsize_constraints(w, h, s); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int mdp_clamp_align(s32 *x, int min, int max, unsigned int align) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci unsigned int mask; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (min < 0 || max < 0) 9762306a36Sopenharmony_ci return -ERANGE; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Bits that must be zero to be aligned */ 10062306a36Sopenharmony_ci mask = ~((1 << align) - 1); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci min = 0 ? 0 : ((min + ~mask) & mask); 10362306a36Sopenharmony_ci max = max & mask; 10462306a36Sopenharmony_ci if ((unsigned int)min > (unsigned int)max) 10562306a36Sopenharmony_ci return -ERANGE; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Clamp to aligned min and max */ 10862306a36Sopenharmony_ci *x = clamp(*x, min, max); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Round to nearest aligned value */ 11162306a36Sopenharmony_ci if (align) 11262306a36Sopenharmony_ci *x = (*x + (1 << (align - 1))) & mask; 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint mdp_enum_fmt_mplane(struct mdp_dev *mdp, struct v4l2_fmtdesc *f) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci const struct mdp_format *fmt; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci fmt = mdp_find_fmt_by_index(mdp->mdp_data, f->index, f->type); 12162306a36Sopenharmony_ci if (!fmt) 12262306a36Sopenharmony_ci return -EINVAL; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci f->pixelformat = fmt->pixelformat; 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciconst struct mdp_format *mdp_try_fmt_mplane(struct mdp_dev *mdp, 12962306a36Sopenharmony_ci struct v4l2_format *f, 13062306a36Sopenharmony_ci struct mdp_frameparam *param, 13162306a36Sopenharmony_ci u32 ctx_id) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct device *dev = ¶m->ctx->mdp_dev->pdev->dev; 13462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 13562306a36Sopenharmony_ci const struct mdp_format *fmt; 13662306a36Sopenharmony_ci const struct mdp_pix_limit *pix_limit; 13762306a36Sopenharmony_ci struct v4l2_frmsize_stepwise s; 13862306a36Sopenharmony_ci u32 org_w, org_h; 13962306a36Sopenharmony_ci unsigned int i; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci fmt = mdp_find_fmt(mdp->mdp_data, pix_mp->pixelformat, f->type); 14262306a36Sopenharmony_ci if (!fmt) { 14362306a36Sopenharmony_ci fmt = mdp_find_fmt_by_index(mdp->mdp_data, 0, f->type); 14462306a36Sopenharmony_ci if (!fmt) { 14562306a36Sopenharmony_ci dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id, 14662306a36Sopenharmony_ci (pix_mp->pixelformat & 0xff), 14762306a36Sopenharmony_ci (pix_mp->pixelformat >> 8) & 0xff, 14862306a36Sopenharmony_ci (pix_mp->pixelformat >> 16) & 0xff, 14962306a36Sopenharmony_ci (pix_mp->pixelformat >> 24) & 0xff); 15062306a36Sopenharmony_ci return NULL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci pix_mp->field = V4L2_FIELD_NONE; 15562306a36Sopenharmony_ci pix_mp->flags = 0; 15662306a36Sopenharmony_ci pix_mp->pixelformat = fmt->pixelformat; 15762306a36Sopenharmony_ci if (V4L2_TYPE_IS_CAPTURE(f->type)) { 15862306a36Sopenharmony_ci pix_mp->colorspace = param->colorspace; 15962306a36Sopenharmony_ci pix_mp->xfer_func = param->xfer_func; 16062306a36Sopenharmony_ci pix_mp->ycbcr_enc = param->ycbcr_enc; 16162306a36Sopenharmony_ci pix_mp->quantization = param->quant; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? ¶m->limit->out_limit : 16562306a36Sopenharmony_ci ¶m->limit->cap_limit; 16662306a36Sopenharmony_ci s.min_width = pix_limit->wmin; 16762306a36Sopenharmony_ci s.max_width = pix_limit->wmax; 16862306a36Sopenharmony_ci s.step_width = fmt->walign; 16962306a36Sopenharmony_ci s.min_height = pix_limit->hmin; 17062306a36Sopenharmony_ci s.max_height = pix_limit->hmax; 17162306a36Sopenharmony_ci s.step_height = fmt->halign; 17262306a36Sopenharmony_ci org_w = pix_mp->width; 17362306a36Sopenharmony_ci org_h = pix_mp->height; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci mdp_bound_align_image(&pix_mp->width, &pix_mp->height, &s, fmt->salign); 17662306a36Sopenharmony_ci if (org_w != pix_mp->width || org_h != pix_mp->height) 17762306a36Sopenharmony_ci dev_dbg(dev, "%d: size change: %ux%u to %ux%u", ctx_id, 17862306a36Sopenharmony_ci org_w, org_h, pix_mp->width, pix_mp->height); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes) 18162306a36Sopenharmony_ci dev_dbg(dev, "%d num of planes change: %u to %u", ctx_id, 18262306a36Sopenharmony_ci pix_mp->num_planes, fmt->num_planes); 18362306a36Sopenharmony_ci pix_mp->num_planes = fmt->num_planes; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci for (i = 0; i < pix_mp->num_planes; ++i) { 18662306a36Sopenharmony_ci u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) >> 3; 18762306a36Sopenharmony_ci u32 max_bpl = (pix_limit->wmax * fmt->row_depth[i]) >> 3; 18862306a36Sopenharmony_ci u32 bpl = pix_mp->plane_fmt[i].bytesperline; 18962306a36Sopenharmony_ci u32 min_si, max_si; 19062306a36Sopenharmony_ci u32 si = pix_mp->plane_fmt[i].sizeimage; 19162306a36Sopenharmony_ci u64 di; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci bpl = clamp(bpl, min_bpl, max_bpl); 19462306a36Sopenharmony_ci pix_mp->plane_fmt[i].bytesperline = bpl; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci di = (u64)bpl * pix_mp->height * fmt->depth[i]; 19762306a36Sopenharmony_ci min_si = (u32)div_u64(di, fmt->row_depth[i]); 19862306a36Sopenharmony_ci di = (u64)bpl * s.max_height * fmt->depth[i]; 19962306a36Sopenharmony_ci max_si = (u32)div_u64(di, fmt->row_depth[i]); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci si = clamp(si, min_si, max_si); 20262306a36Sopenharmony_ci pix_mp->plane_fmt[i].sizeimage = si; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci dev_dbg(dev, "%d: p%u, bpl:%u [%u, %u], sizeimage:%u [%u, %u]", 20562306a36Sopenharmony_ci ctx_id, i, bpl, min_bpl, max_bpl, si, min_si, max_si); 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return fmt; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int mdp_clamp_start(s32 *x, int min, int max, unsigned int align, 21262306a36Sopenharmony_ci u32 flags) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci if (flags & V4L2_SEL_FLAG_GE) 21562306a36Sopenharmony_ci max = *x; 21662306a36Sopenharmony_ci if (flags & V4L2_SEL_FLAG_LE) 21762306a36Sopenharmony_ci min = *x; 21862306a36Sopenharmony_ci return mdp_clamp_align(x, min, max, align); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int mdp_clamp_end(s32 *x, int min, int max, unsigned int align, 22262306a36Sopenharmony_ci u32 flags) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci if (flags & V4L2_SEL_FLAG_GE) 22562306a36Sopenharmony_ci min = *x; 22662306a36Sopenharmony_ci if (flags & V4L2_SEL_FLAG_LE) 22762306a36Sopenharmony_ci max = *x; 22862306a36Sopenharmony_ci return mdp_clamp_align(x, min, max, align); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciint mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r, 23262306a36Sopenharmony_ci const struct v4l2_selection *s, struct mdp_frame *frame) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct device *dev = &ctx->mdp_dev->pdev->dev; 23562306a36Sopenharmony_ci s32 left, top, right, bottom; 23662306a36Sopenharmony_ci u32 framew, frameh, walign, halign; 23762306a36Sopenharmony_ci int ret; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci dev_dbg(dev, "%d target:%d, set:(%d,%d) %ux%u", ctx->id, 24062306a36Sopenharmony_ci s->target, s->r.left, s->r.top, s->r.width, s->r.height); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci left = s->r.left; 24362306a36Sopenharmony_ci top = s->r.top; 24462306a36Sopenharmony_ci right = s->r.left + s->r.width; 24562306a36Sopenharmony_ci bottom = s->r.top + s->r.height; 24662306a36Sopenharmony_ci framew = frame->format.fmt.pix_mp.width; 24762306a36Sopenharmony_ci frameh = frame->format.fmt.pix_mp.height; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (mdp_target_is_crop(s->target)) { 25062306a36Sopenharmony_ci walign = 1; 25162306a36Sopenharmony_ci halign = 1; 25262306a36Sopenharmony_ci } else { 25362306a36Sopenharmony_ci walign = frame->mdp_fmt->walign; 25462306a36Sopenharmony_ci halign = frame->mdp_fmt->halign; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dev_dbg(dev, "%d align:%u,%u, bound:%ux%u", ctx->id, 25862306a36Sopenharmony_ci walign, halign, framew, frameh); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci ret = mdp_clamp_start(&left, 0, right, walign, s->flags); 26162306a36Sopenharmony_ci if (ret) 26262306a36Sopenharmony_ci return ret; 26362306a36Sopenharmony_ci ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags); 26462306a36Sopenharmony_ci if (ret) 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci ret = mdp_clamp_end(&right, left, framew, walign, s->flags); 26762306a36Sopenharmony_ci if (ret) 26862306a36Sopenharmony_ci return ret; 26962306a36Sopenharmony_ci ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags); 27062306a36Sopenharmony_ci if (ret) 27162306a36Sopenharmony_ci return ret; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci r->left = left; 27462306a36Sopenharmony_ci r->top = top; 27562306a36Sopenharmony_ci r->width = right - left; 27662306a36Sopenharmony_ci r->height = bottom - top; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci dev_dbg(dev, "%d crop:(%d,%d) %ux%u", ctx->id, 27962306a36Sopenharmony_ci r->left, r->top, r->width, r->height); 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ciint mdp_check_scaling_ratio(const struct v4l2_rect *crop, 28462306a36Sopenharmony_ci const struct v4l2_rect *compose, s32 rotation, 28562306a36Sopenharmony_ci const struct mdp_limit *limit) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci u32 crop_w, crop_h, comp_w, comp_h; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci crop_w = crop->width; 29062306a36Sopenharmony_ci crop_h = crop->height; 29162306a36Sopenharmony_ci if (90 == rotation || 270 == rotation) { 29262306a36Sopenharmony_ci comp_w = compose->height; 29362306a36Sopenharmony_ci comp_h = compose->width; 29462306a36Sopenharmony_ci } else { 29562306a36Sopenharmony_ci comp_w = compose->width; 29662306a36Sopenharmony_ci comp_h = compose->height; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if ((crop_w / comp_w) > limit->h_scale_down_max || 30062306a36Sopenharmony_ci (crop_h / comp_h) > limit->v_scale_down_max || 30162306a36Sopenharmony_ci (comp_w / crop_w) > limit->h_scale_up_max || 30262306a36Sopenharmony_ci (comp_h / crop_h) > limit->v_scale_up_max) 30362306a36Sopenharmony_ci return -ERANGE; 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/* Stride that is accepted by MDP HW */ 30862306a36Sopenharmony_cistatic u32 mdp_fmt_get_stride(const struct mdp_format *fmt, 30962306a36Sopenharmony_ci u32 bytesperline, unsigned int plane) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci enum mdp_color c = fmt->mdp_color; 31262306a36Sopenharmony_ci u32 stride; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c)) 31562306a36Sopenharmony_ci / fmt->row_depth[0]; 31662306a36Sopenharmony_ci if (plane == 0) 31762306a36Sopenharmony_ci return stride; 31862306a36Sopenharmony_ci if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { 31962306a36Sopenharmony_ci if (MDP_COLOR_IS_BLOCK_MODE(c)) 32062306a36Sopenharmony_ci stride = stride / 2; 32162306a36Sopenharmony_ci return stride; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/* Stride that is accepted by MDP HW of format with contiguous planes */ 32762306a36Sopenharmony_cistatic u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt, 32862306a36Sopenharmony_ci u32 pix_stride, unsigned int plane) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci enum mdp_color c = fmt->mdp_color; 33162306a36Sopenharmony_ci u32 stride = pix_stride; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if (plane == 0) 33462306a36Sopenharmony_ci return stride; 33562306a36Sopenharmony_ci if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { 33662306a36Sopenharmony_ci stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c); 33762306a36Sopenharmony_ci if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c)) 33862306a36Sopenharmony_ci stride = stride * 2; 33962306a36Sopenharmony_ci return stride; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/* Plane size that is accepted by MDP HW */ 34562306a36Sopenharmony_cistatic u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt, 34662306a36Sopenharmony_ci u32 stride, u32 height, unsigned int plane) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci enum mdp_color c = fmt->mdp_color; 34962306a36Sopenharmony_ci u32 bytesperline; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci bytesperline = (stride * fmt->row_depth[0]) 35262306a36Sopenharmony_ci / MDP_COLOR_BITS_PER_PIXEL(c); 35362306a36Sopenharmony_ci if (plane == 0) 35462306a36Sopenharmony_ci return bytesperline * height; 35562306a36Sopenharmony_ci if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { 35662306a36Sopenharmony_ci height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c); 35762306a36Sopenharmony_ci if (MDP_COLOR_IS_BLOCK_MODE(c)) 35862306a36Sopenharmony_ci bytesperline = bytesperline * 2; 35962306a36Sopenharmony_ci return bytesperline * height; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void mdp_prepare_buffer(struct img_image_buffer *b, 36562306a36Sopenharmony_ci struct mdp_frame *frame, struct vb2_buffer *vb) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp; 36862306a36Sopenharmony_ci unsigned int i; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci b->format.colorformat = frame->mdp_fmt->mdp_color; 37162306a36Sopenharmony_ci b->format.ycbcr_prof = frame->ycbcr_prof; 37262306a36Sopenharmony_ci for (i = 0; i < pix_mp->num_planes; ++i) { 37362306a36Sopenharmony_ci u32 stride = mdp_fmt_get_stride(frame->mdp_fmt, 37462306a36Sopenharmony_ci pix_mp->plane_fmt[i].bytesperline, i); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci b->format.plane_fmt[i].stride = stride; 37762306a36Sopenharmony_ci b->format.plane_fmt[i].size = 37862306a36Sopenharmony_ci mdp_fmt_get_plane_size(frame->mdp_fmt, stride, 37962306a36Sopenharmony_ci pix_mp->height, i); 38062306a36Sopenharmony_ci b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) { 38362306a36Sopenharmony_ci u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt, 38462306a36Sopenharmony_ci b->format.plane_fmt[0].stride, i); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci b->format.plane_fmt[i].stride = stride; 38762306a36Sopenharmony_ci b->format.plane_fmt[i].size = 38862306a36Sopenharmony_ci mdp_fmt_get_plane_size(frame->mdp_fmt, stride, 38962306a36Sopenharmony_ci pix_mp->height, i); 39062306a36Sopenharmony_ci b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci b->usage = frame->usage; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_civoid mdp_set_src_config(struct img_input *in, 39662306a36Sopenharmony_ci struct mdp_frame *frame, struct vb2_buffer *vb) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci in->buffer.format.width = frame->format.fmt.pix_mp.width; 39962306a36Sopenharmony_ci in->buffer.format.height = frame->format.fmt.pix_mp.height; 40062306a36Sopenharmony_ci mdp_prepare_buffer(&in->buffer, frame, vb); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci u32 q; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (f->denominator == 0) { 40862306a36Sopenharmony_ci *r = 0; 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci q = f->numerator / f->denominator; 41362306a36Sopenharmony_ci *r = div_u64(((u64)f->numerator - q * f->denominator) << 41462306a36Sopenharmony_ci IMG_SUBPIXEL_SHIFT, f->denominator); 41562306a36Sopenharmony_ci return q; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci c->left = crop->c.left 42162306a36Sopenharmony_ci + mdp_to_fixed(&c->left_subpix, &crop->left_subpix); 42262306a36Sopenharmony_ci c->top = crop->c.top 42362306a36Sopenharmony_ci + mdp_to_fixed(&c->top_subpix, &crop->top_subpix); 42462306a36Sopenharmony_ci c->width = crop->c.width 42562306a36Sopenharmony_ci + mdp_to_fixed(&c->width_subpix, &crop->width_subpix); 42662306a36Sopenharmony_ci c->height = crop->c.height 42762306a36Sopenharmony_ci + mdp_to_fixed(&c->height_subpix, &crop->height_subpix); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic void mdp_set_orientation(struct img_output *out, 43162306a36Sopenharmony_ci s32 rotation, bool hflip, bool vflip) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci u8 flip = 0; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (hflip) 43662306a36Sopenharmony_ci flip ^= 1; 43762306a36Sopenharmony_ci if (vflip) { 43862306a36Sopenharmony_ci /* 43962306a36Sopenharmony_ci * A vertical flip is equivalent to 44062306a36Sopenharmony_ci * a 180-degree rotation with a horizontal flip 44162306a36Sopenharmony_ci */ 44262306a36Sopenharmony_ci rotation += 180; 44362306a36Sopenharmony_ci flip ^= 1; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci out->rotation = rotation % 360; 44762306a36Sopenharmony_ci if (flip != 0) 44862306a36Sopenharmony_ci out->flags |= IMG_CTRL_FLAG_HFLIP; 44962306a36Sopenharmony_ci else 45062306a36Sopenharmony_ci out->flags &= ~IMG_CTRL_FLAG_HFLIP; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_civoid mdp_set_dst_config(struct img_output *out, 45462306a36Sopenharmony_ci struct mdp_frame *frame, struct vb2_buffer *vb) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci out->buffer.format.width = frame->compose.width; 45762306a36Sopenharmony_ci out->buffer.format.height = frame->compose.height; 45862306a36Sopenharmony_ci mdp_prepare_buffer(&out->buffer, frame, vb); 45962306a36Sopenharmony_ci mdp_set_src_crop(&out->crop, &frame->crop); 46062306a36Sopenharmony_ci mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ciint mdp_frameparam_init(struct mdp_dev *mdp, struct mdp_frameparam *param) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct mdp_frame *frame; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!param) 46862306a36Sopenharmony_ci return -EINVAL; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci INIT_LIST_HEAD(¶m->list); 47162306a36Sopenharmony_ci param->limit = mdp->mdp_data->def_limit; 47262306a36Sopenharmony_ci param->type = MDP_STREAM_TYPE_BITBLT; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci frame = ¶m->output; 47562306a36Sopenharmony_ci frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 47662306a36Sopenharmony_ci frame->mdp_fmt = mdp_try_fmt_mplane(mdp, &frame->format, param, 0); 47762306a36Sopenharmony_ci frame->ycbcr_prof = 47862306a36Sopenharmony_ci mdp_map_ycbcr_prof_mplane(&frame->format, 47962306a36Sopenharmony_ci frame->mdp_fmt->mdp_color); 48062306a36Sopenharmony_ci frame->usage = MDP_BUFFER_USAGE_HW_READ; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci param->num_captures = 1; 48362306a36Sopenharmony_ci frame = ¶m->captures[0]; 48462306a36Sopenharmony_ci frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 48562306a36Sopenharmony_ci frame->mdp_fmt = mdp_try_fmt_mplane(mdp, &frame->format, param, 0); 48662306a36Sopenharmony_ci frame->ycbcr_prof = 48762306a36Sopenharmony_ci mdp_map_ycbcr_prof_mplane(&frame->format, 48862306a36Sopenharmony_ci frame->mdp_fmt->mdp_color); 48962306a36Sopenharmony_ci frame->usage = MDP_BUFFER_USAGE_MDP; 49062306a36Sopenharmony_ci frame->crop.c.width = param->output.format.fmt.pix_mp.width; 49162306a36Sopenharmony_ci frame->crop.c.height = param->output.format.fmt.pix_mp.height; 49262306a36Sopenharmony_ci frame->compose.width = frame->format.fmt.pix_mp.width; 49362306a36Sopenharmony_ci frame->compose.height = frame->format.fmt.pix_mp.height; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return 0; 49662306a36Sopenharmony_ci} 497