void gsc_hw_set_out_image_format(struct gsc_ctx *ctx) { struct gsc_dev *dev = ctx->gsc_dev; struct gsc_frame *frame = &ctx->d_frame; u32 i, depth = 0; u32 cfg; cfg = readl(dev->regs + GSC_OUT_CON); cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK | GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK | GSC_OUT_CHROM_STRIDE_SEL_MASK | GSC_OUT_RB_SWAP_MASK); writel(cfg, dev->regs + GSC_OUT_CON); if (is_rgb(frame->fmt->pixelformat)) { gsc_hw_set_out_image_rgb(ctx); return; } if (ctx->out_path != GSC_DMA) { cfg |= GSC_OUT_YUV444; goto end_set; } for (i = 0; i < frame->fmt->num_planes; i++) depth += frame->fmt->depth[i]; switch (frame->fmt->nr_comp) { case 1: cfg |= GSC_OUT_YUV422_1P; if (frame->fmt->yorder == GSC_LSB_Y) cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y; else cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C; if (frame->fmt->corder == GSC_CBCR) cfg |= GSC_OUT_CHROMA_ORDER_CBCR; else cfg |= GSC_OUT_CHROMA_ORDER_CRCB; break; case 2: if (depth == 12) cfg |= GSC_OUT_YUV420_2P; else cfg |= GSC_OUT_YUV422_2P; if (frame->fmt->corder == GSC_CBCR) cfg |= GSC_OUT_CHROMA_ORDER_CBCR; else cfg |= GSC_OUT_CHROMA_ORDER_CRCB; break; case 3: cfg |= GSC_OUT_YUV420_3P; break; }; if (is_AYV12(frame->fmt->pixelformat)) { cfg |= GSC_OUT_CHROM_STRIDE_SEPAR; gsc_hw_set_out_chrom_stride(ctx); } end_set: writel(cfg, dev->regs + GSC_OUT_CON); }
void gsc_hw_set_in_image_format(struct gsc_ctx *ctx) { struct gsc_dev *dev = ctx->gsc_dev; struct gsc_frame *frame = &ctx->s_frame; u32 i, depth = 0; u32 cfg; cfg = readl(dev->regs + GSC_IN_CON); cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK | GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK | GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE | GSC_IN_CHROM_STRIDE_SEL_MASK); writel(cfg, dev->regs + GSC_IN_CON); if (is_rgb(frame->fmt->pixelformat)) { gsc_hw_set_in_image_rgb(ctx); return; } for (i = 0; i < frame->fmt->num_planes; i++) depth += frame->fmt->depth[i]; switch (frame->fmt->nr_comp) { case 1: cfg |= GSC_IN_YUV422_1P; if (frame->fmt->yorder == GSC_LSB_Y) cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y; else cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C; if (frame->fmt->corder == GSC_CBCR && !rt_is_flag(GSC_REORDER)) cfg |= GSC_IN_CHROMA_ORDER_CBCR; else cfg |= GSC_IN_CHROMA_ORDER_CRCB; break; case 2: if (depth == 12) cfg |= GSC_IN_YUV420_2P; else cfg |= GSC_IN_YUV422_2P; if (frame->fmt->corder == GSC_CBCR && !rt_is_flag(GSC_REORDER)) cfg |= GSC_IN_CHROMA_ORDER_CBCR; else cfg |= GSC_IN_CHROMA_ORDER_CRCB; break; case 3: if (depth == 12) cfg |= GSC_IN_YUV420_3P; else cfg |= GSC_IN_YUV422_3P; break; }; if (is_AYV12(frame->fmt->pixelformat)) gsc_hw_set_in_chrom_stride(ctx); if (is_tiled(frame->fmt)) cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE; writel(cfg, dev->regs + GSC_IN_CON); }
void gsc_hw_set_global_alpha(struct gsc_ctx *ctx) { struct gsc_dev *dev = ctx->gsc_dev; struct gsc_frame *frame = &ctx->d_frame; u32 cfg; cfg = readl(dev->regs + GSC_OUT_CON); cfg &= ~GSC_OUT_GLOBAL_ALPHA_MASK; if (!is_rgb(frame->fmt->pixelformat)) { gsc_dbg("Not a RGB format"); return; } cfg |= GSC_OUT_GLOBAL_ALPHA(ctx->gsc_ctrls.global_alpha->val); writel(cfg, dev->regs + GSC_OUT_CON); }
void validate_state(const GraphBuilder::state &state) { if (!state.width || !state.height) throw error::ZeroImageSize{ "image dimensions must be non-zero" }; if (is_greyscale(state)) { if (state.subsample_w || state.subsample_h) throw error::GreyscaleSubsampling{ "cannot subsample greyscale image" }; if (state.colorspace.matrix == zimg::colorspace::MatrixCoefficients::MATRIX_RGB) throw error::ColorFamilyMismatch{ "GREY color family cannot be RGB" }; } if (is_rgb(state)) { if (state.subsample_w || state.subsample_h) throw zimg::error::UnsupportedSubsampling{ "subsampled RGB image not supported" }; if (state.colorspace.matrix != zimg::colorspace::MatrixCoefficients::MATRIX_UNSPECIFIED && state.colorspace.matrix != zimg::colorspace::MatrixCoefficients::MATRIX_RGB) throw error::ColorFamilyMismatch{ "RGB color family cannot be YUV" }; } if (is_yuv(state)) { if (state.colorspace.matrix == zimg::colorspace::MatrixCoefficients::MATRIX_RGB) throw error::ColorFamilyMismatch{ "YUV color family cannot be RGB" }; } if (state.subsample_h > 1 && state.parity != GraphBuilder::FieldParity::FIELD_PROGRESSIVE) throw error::UnsupportedSubsampling{ "vertical subsampling greater than 2x is not supported" }; if (state.subsample_w > 2 || state.subsample_h > 2) throw error::UnsupportedSubsampling{ "subsampling greater than 4x is not supported" }; if (state.width % (1 << state.subsample_w) || state.height % (1 << state.subsample_h)) throw error::ImageNotDivislbe{ "image dimensions must be divisible by subsampling factor" }; if (state.depth > pixel_depth(state.type)) throw error::BitDepthOverflow{ "bit depth exceeds limits of type" }; if (!state.fullrange && state.depth < 8) throw error::BitDepthOverflow{ "bit depth must be at least 8 for limited range" }; }
int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr) { struct gsc_frame *f; struct gsc_dev *gsc = ctx->gsc_dev; struct gsc_variant *variant = gsc->variant; u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h; u32 min_w, min_h, max_w, max_h; if (cr->c.top < 0 || cr->c.left < 0) { pr_err("doesn't support negative values for top & left\n"); return -EINVAL; } pr_debug("user put w: %d, h: %d", cr->c.width, cr->c.height); if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) f = &ctx->d_frame; else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) f = &ctx->s_frame; else return -EINVAL; max_w = f->f_width; max_h = f->f_height; tmp_w = cr->c.width; tmp_h = cr->c.height; if (V4L2_TYPE_IS_OUTPUT(cr->type)) { if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) || is_rgb(f->fmt->color)) min_w = 32; else min_w = 64; if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 3) || is_yuv420(f->fmt->color)) min_h = 32; else min_h = 16; } else { if (is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) mod_x = ffs(variant->pix_align->target_w) - 1; if (is_yuv420(f->fmt->color)) mod_y = ffs(variant->pix_align->target_h) - 1; if (ctx->gsc_ctrls.rotate->val == 90 || ctx->gsc_ctrls.rotate->val == 270) { max_w = f->f_height; max_h = f->f_width; min_w = variant->pix_min->target_rot_en_w; min_h = variant->pix_min->target_rot_en_h; tmp_w = cr->c.height; tmp_h = cr->c.width; } else { min_w = variant->pix_min->target_rot_dis_w; min_h = variant->pix_min->target_rot_dis_h; } } pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d", mod_x, mod_y, min_w, min_h); pr_debug("tmp_w : %d, tmp_h : %d", tmp_w, tmp_h); v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, &tmp_h, min_h, max_h, mod_y, 0); if (!V4L2_TYPE_IS_OUTPUT(cr->type) && (ctx->gsc_ctrls.rotate->val == 90 || ctx->gsc_ctrls.rotate->val == 270)) gsc_check_crop_change(tmp_h, tmp_w, &cr->c.width, &cr->c.height); else gsc_check_crop_change(tmp_w, tmp_h, &cr->c.width, &cr->c.height); /* adjust left/top if cropping rectangle is out of bounds */ /* Need to add code to algin left value with 2's multiple */ if (cr->c.left + tmp_w > max_w) cr->c.left = max_w - tmp_w; if (cr->c.top + tmp_h > max_h) cr->c.top = max_h - tmp_h; if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) && cr->c.left & 1) cr->c.left -= 1; pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h); return 0; }
int shveu_setup( SHVEU *veu, const struct ren_vid_surface *src_surface, const struct ren_vid_surface *dst_surface, shveu_rotation_t filter_control) { float scale_x, scale_y; uint32_t temp; uint32_t Y, C; const struct veu_format_info *src_info; const struct veu_format_info *dst_info; struct ren_vid_surface local_src; struct ren_vid_surface local_dst; struct ren_vid_surface *src = &local_src; struct ren_vid_surface *dst = &local_dst; void *base_addr; if (!veu || !src_surface || !dst_surface) { debug_info("ERR: Invalid input - need src and dest"); return -1; } src_info = fmt_info(src_surface->format); dst_info = fmt_info(dst_surface->format); dbg(__func__, __LINE__, "src_user", src_surface); dbg(__func__, __LINE__, "dst_user", dst_surface); /* scale factors */ scale_x = (float)dst_surface->w / src_surface->w; scale_y = (float)dst_surface->h / src_surface->h; if (!format_supported(src_surface->format) || !format_supported(dst_surface->format)) { debug_info("ERR: Invalid surface format!"); return -1; } /* Scaling limits */ if (veu_is_veu2h(veu)) { if ((scale_x > 8.0) || (scale_y > 8.0)) { debug_info("ERR: Outside scaling limits!"); return -1; } } else { if ((scale_x > 16.0) || (scale_y > 16.0)) { debug_info("ERR: Outside scaling limits!"); return -1; } } if ((scale_x < 1.0/16.0) || (scale_y < 1.0/16.0)) { debug_info("ERR: Outside scaling limits!"); return -1; } /* source - use a buffer the hardware can access */ if (get_hw_surface(veu->uiomux, veu->uiores, src, src_surface) < 0) { debug_info("ERR: src is not accessible by hardware"); return -1; } copy_surface(src, src_surface); /* destination - use a buffer the hardware can access */ if (get_hw_surface(veu->uiomux, veu->uiores, dst, dst_surface) < 0) { debug_info("ERR: dest is not accessible by hardware"); return -1; } uiomux_lock (veu->uiomux, veu->uiores); base_addr = veu->uio_mmio.iomem; /* Keep track of the requested surfaces */ veu->src_user = *src_surface; veu->dst_user = *dst_surface; /* Keep track of the actual surfaces used */ veu->src_hw = local_src; veu->dst_hw = local_dst; /* Software reset */ if (read_reg(base_addr, VESTR) & 0x1) write_reg(base_addr, 0, VESTR); while (read_reg(base_addr, VESTR) & 1) ; /* Clear VEU end interrupt flag */ write_reg(base_addr, 0, VEVTR); /* VEU Module reset */ write_reg(base_addr, 0x100, VBSRR); /* default to not using bundle mode */ write_reg(base_addr, 0, VBSSR); /* source */ Y = uiomux_all_virt_to_phys(src->py); C = uiomux_all_virt_to_phys(src->pc); write_reg(base_addr, Y, VSAYR); write_reg(base_addr, C, VSACR); write_reg(base_addr, (src->h << 16) | src->w, VESSR); write_reg(base_addr, size_y(src->format, src->pitch), VESWR); /* destination */ Y = uiomux_all_virt_to_phys(dst->py); C = uiomux_all_virt_to_phys(dst->pc); if (filter_control & 0xFF) { if ((filter_control & 0xFF) == 0x10) { /* Horizontal Mirror (A) */ Y += size_y(dst->format, src->w); C += size_y(dst->format, src->w); } else if ((filter_control & 0xFF) == 0x20) { /* Vertical Mirror (B) */ Y += size_y(dst->format, (src->h-1) * dst->pitch); C += size_c(dst->format, (src->h-2) * dst->pitch); } else if ((filter_control & 0xFF) == 0x30) { /* Rotate 180 (C) */ Y += size_y(dst->format, src->w); C += size_y(dst->format, src->w); Y += size_y(dst->format, src->h * dst->pitch); C += size_c(dst->format, src->h * dst->pitch); } else if ((filter_control & 0xFF) == 1) { /* Rotate 90 (D) */ Y += size_y(dst->format, src->h-16); C += size_y(dst->format, src->h-16); } else if ((filter_control & 0xFF) == 2) { /* Rotate 270 (E) */ Y += size_y(dst->format, (src->w-16) * dst->pitch); C += size_c(dst->format, (src->w-16) * dst->pitch); } else if ((filter_control & 0xFF) == 0x11) { /* Rotate 90 & Mirror Horizontal (F) */ /* Nothing to do */ } else if ((filter_control & 0xFF) == 0x21) { /* Rotate 90 & Mirror Vertical (G) */ Y += size_y(dst->format, src->h-16); C += size_y(dst->format, src->h-16); Y += size_y(dst->format, (src->w-16) * dst->pitch); C += size_c(dst->format, (src->w-16) * dst->pitch); } } write_reg(base_addr, Y, VDAYR); write_reg(base_addr, C, VDACR); write_reg(base_addr, size_y(dst->format, dst->pitch), VEDWR); /* byte/word swapping */ temp = 0; #ifdef __LITTLE_ENDIAN__ temp |= src_info->vswpr; temp |= dst_info->vswpr << 4; #endif write_reg(base_addr, temp, VSWPR); /* transform control */ temp = src_info->vtrcr_src; temp |= dst_info->vtrcr_dst; if (is_rgb(src_surface->format)) temp |= VTRCR_RY_SRC_RGB; if (different_colorspace(src_surface->format, dst_surface->format)) temp |= VTRCR_TE_BIT_SET; if (veu->bt709) temp |= VTRCR_BT709; if (veu->full_range) temp |= VTRCR_FULL_COLOR_CONV; write_reg(base_addr, temp, VTRCR); if (veu_is_veu2h(veu)) { /* color conversion matrix */ write_reg(base_addr, 0x0cc5, VMCR00); write_reg(base_addr, 0x0950, VMCR01); write_reg(base_addr, 0x0000, VMCR02); write_reg(base_addr, 0x397f, VMCR10); write_reg(base_addr, 0x0950, VMCR11); write_reg(base_addr, 0x3cdd, VMCR12); write_reg(base_addr, 0x0000, VMCR20); write_reg(base_addr, 0x0950, VMCR21); write_reg(base_addr, 0x1023, VMCR22); write_reg(base_addr, 0x00800010, VCOFFR); } /* Clipping */ write_reg(base_addr, 0, VRFSR); set_clip(base_addr, 0, dst->w); set_clip(base_addr, 1, dst->h); /* Scaling */ write_reg(base_addr, 0, VRFCR); if (!(filter_control & 0x3)) { /* Not a rotate operation */ set_scale(veu, base_addr, 0, src->w, dst->w, 0); set_scale(veu, base_addr, 1, src->h, dst->h, 0); } /* Filter control - directly pass user arg to register */ write_reg(base_addr, filter_control, VFMCR); return 0; fail: uiomux_unlock(veu->uiomux, veu->uiores); return -1; }