Пример #1
0
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);
}
Пример #2
0
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);
}
Пример #3
0
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);
}
Пример #4
0
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" };
}
Пример #5
0
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;
}
Пример #6
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;
}