Re: [PATCH v2 2/5] [media] exynos-mscl: Add core functionality for the M-Scaler driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 08/19/2013 12:58 PM, Shaik Ameer Basha wrote:
> This patch adds the core functionality for the M-Scaler driver.

Some more comments below...

> 
> Signed-off-by: Shaik Ameer Basha <shaik.ameer@xxxxxxxxxxx>
> ---
>  drivers/media/platform/exynos-mscl/mscl-core.c | 1312 ++++++++++++++++++++++++
>  drivers/media/platform/exynos-mscl/mscl-core.h |  549 ++++++++++
>  2 files changed, 1861 insertions(+)
>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.c
>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.h
> 
> diff --git a/drivers/media/platform/exynos-mscl/mscl-core.c b/drivers/media/platform/exynos-mscl/mscl-core.c
> new file mode 100644
> index 0000000..4a3a851
> --- /dev/null
> +++ b/drivers/media/platform/exynos-mscl/mscl-core.c
> @@ -0,0 +1,1312 @@
> +/*
> + * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Samsung EXYNOS5 SoC series M-Scaler driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published
> + * by the Free Software Foundation, either version 2 of the License,
> + * or (at your option) any later version.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/pm_runtime.h>
> +
> +#ifdef CONFIG_EXYNOS_IOMMU
> +#include <asm/dma-iommu.h>
> +#endif
> +
> +#include "mscl-core.h"
> +
> +#define MSCL_CLOCK_GATE_NAME	"mscl"
> +
> +static const struct mscl_fmt mscl_formats[] = {
> +	{
> +		.name		= "YUV 4:2:0 non-contig. 2p, Y/CbCr",
> +		.pixelformat	= V4L2_PIX_FMT_NV12M,
> +		.depth		= { 8, 4 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 2,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV420_2P_Y_UV,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +
> +	}, {
> +		.name		= "YUV 4:2:0 contig. 2p, Y/CbCr",
> +		.pixelformat	= V4L2_PIX_FMT_NV12,
> +		.depth		= { 12 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV420_2P_Y_UV,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
> +		.pixelformat	= V4L2_PIX_FMT_NV12MT_16X16,
> +		.depth		= { 8, 4 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 2,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV420_2P_Y_UV,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC),
> +		.is_tiled	= true,
> +	}, {
> +		.name		= "YUV 4:2:2 contig. 2p, Y/CbCr",
> +		.pixelformat	= V4L2_PIX_FMT_NV16,
> +		.depth		= { 16 },
> +		.color		= MSCL_YUV422,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV422_2P_Y_UV,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:4:4 contig. 2p, Y/CbCr",
> +		.pixelformat	= V4L2_PIX_FMT_NV24,
> +		.depth		= { 24 },
> +		.color		= MSCL_YUV444,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV444_2P_Y_UV,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "RGB565",
> +		.pixelformat	= V4L2_PIX_FMT_RGB565X,
> +		.depth		= { 16 },
> +		.color		= MSCL_RGB,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mscl_color	= MSCL_RGB565,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "XRGB-1555, 16 bpp",
> +		.pixelformat	= V4L2_PIX_FMT_RGB555,
> +		.depth		= { 16 },
> +		.color		= MSCL_RGB,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mscl_color	= MSCL_ARGB1555,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "XRGB-8888, 32 bpp",
> +		.pixelformat	= V4L2_PIX_FMT_RGB32,
> +		.depth		= { 32 },
> +		.color		= MSCL_RGB,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mscl_color	= MSCL_ARGB8888,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:2 packed, YCrYCb",
> +		.pixelformat	= V4L2_PIX_FMT_YVYU,
> +		.depth		= { 16 },
> +		.color		= MSCL_YUV422,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,
> +		.mscl_color	= MSCL_YUV422_1P_YVYU,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:2 packed, YCbYCr",
> +		.pixelformat	= V4L2_PIX_FMT_YUYV,
> +		.depth		= { 16 },
> +		.color		= MSCL_YUV422,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,
> +		.mscl_color	= MSCL_YUV422_1P_YUYV,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:2 packed, CbYCrY",
> +		.pixelformat	= V4L2_PIX_FMT_UYVY,
> +		.depth		= { 16 },
> +		.color		= MSCL_YUV422,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,
> +		.mscl_color	= MSCL_YUV422_1P_UYVY,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "XRGB-4444, 16 bpp",
> +		.pixelformat	= V4L2_PIX_FMT_RGB444,
> +		.depth		= { 16 },
> +		.color		= MSCL_RGB,
> +		.num_planes	= 1,
> +		.num_comp	= 1,
> +		.mscl_color	= MSCL_ARGB4444,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 non-contig. 2p, Y/CrCb",
> +		.pixelformat	= V4L2_PIX_FMT_NV21M,
> +		.depth		= { 8, 4 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 2,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV420_2P_Y_VU,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 contig. 2p, Y/CrCb",
> +		.pixelformat	= V4L2_PIX_FMT_NV21,
> +		.depth		= { 12 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 1,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV420_2P_Y_VU,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:2 contig. 2p, Y/CrCb",
> +		.pixelformat	= V4L2_PIX_FMT_NV61,
> +		.depth		= { 16 },
> +		.color		= MSCL_YUV422,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 1,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV422_2P_Y_VU,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:4:4 contig. 2p, Y/CrCb",
> +		.pixelformat	= V4L2_PIX_FMT_NV42,
> +		.depth		= { 24 },
> +		.color		= MSCL_YUV444,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 1,
> +		.num_comp	= 2,
> +		.mscl_color	= MSCL_YUV444_2P_Y_VU,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 contig. 3p, YCbCr",
> +		.pixelformat	= V4L2_PIX_FMT_YUV420,
> +		.depth		= { 12 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 3,
> +		.mscl_color	= MSCL_YUV420_3P_Y_U_V,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 contig. 3p, YCrCb",
> +		.pixelformat	= V4L2_PIX_FMT_YVU420,
> +		.depth		= { 12 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 1,
> +		.num_comp	= 3,
> +		.mscl_color	= MSCL_YUV420_3P_Y_U_V,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
> +		.pixelformat	= V4L2_PIX_FMT_YUV420M,
> +		.depth		= { 8, 2, 2 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 3,
> +		.num_comp	= 3,
> +		.mscl_color	= MSCL_YUV420_3P_Y_U_V,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
> +		.pixelformat	= V4L2_PIX_FMT_YVU420M,
> +		.depth		= { 8, 2, 2 },
> +		.color		= MSCL_YUV420,
> +		.corder		= MSCL_CRCB,
> +		.num_planes	= 3,
> +		.num_comp	= 3,
> +		.mscl_color	= MSCL_YUV420_3P_Y_U_V,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	}, {
> +		.name		= "YUV 4:2:2 contig. 3p, Y/Cb/Cr",
> +		.pixelformat	= V4L2_PIX_FMT_YUV422P,
> +		.depth		= { 16 },
> +		.color		= MSCL_YUV422,
> +		.corder		= MSCL_CBCR,
> +		.num_planes	= 1,
> +		.num_comp	= 3,
> +		.mscl_color	= MSCL_YUV422_3P_Y_U_V,
> +		.mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +	},
> +
> +	/* [TBD] support pixel formats, corresponds to these mscl_color formats
> +	 * MSCL_L8A8, MSCL_RGBA8888, MSCL_L8 etc
> +	 */
> +};
> +
> +const struct mscl_fmt *mscl_get_format(int index)
> +{
> +	if (index >= ARRAY_SIZE(mscl_formats))
> +		return NULL;
> +
> +	return (struct mscl_fmt *)&mscl_formats[index];
> +}
> +
> +const struct mscl_fmt *mscl_find_fmt(u32 *pixelformat,
> +				u32 *mbus_code, u32 index)
> +{
> +	const struct mscl_fmt *fmt, *def_fmt = NULL;
> +	unsigned int i;
> +
> +	if (index >= ARRAY_SIZE(mscl_formats))
> +		return NULL;
> +
> +	for (i = 0; i < ARRAY_SIZE(mscl_formats); ++i) {
> +		fmt = mscl_get_format(i);
> +		if (pixelformat && fmt->pixelformat == *pixelformat)
> +			return fmt;
> +		if (mbus_code && fmt->mbus_code == *mbus_code)
> +			return fmt;
> +		if (index == i)
> +			def_fmt = fmt;
> +	}
> +
> +	return def_fmt;
> +}
> +
> +void mscl_set_frame_size(struct mscl_frame *frame, int width, int height)
> +{
> +	frame->f_width	= width;
> +	frame->f_height	= height;
> +	frame->crop.width = width;
> +	frame->crop.height = height;
> +	frame->crop.left = 0;
> +	frame->crop.top = 0;
> +}
> +
> +int mscl_enum_fmt_mplane(struct v4l2_fmtdesc *f)
> +{
> +	const struct mscl_fmt *fmt;
> +
> +	fmt = mscl_find_fmt(NULL, NULL, f->index);
> +	if (!fmt)
> +		return -EINVAL;
> +
> +	/* input supports all mscl_formats but all mscl_formats are not
> +	 * supported for output. don't return the unsupported formats for output
> +	 */
> +	if (!(V4L2_TYPE_IS_OUTPUT(f->type) &&
> +		(fmt->mscl_color_fmt_type & MSCL_FMT_SRC)))
> +		return -EINVAL;

Confusing layout. It's better to align it like this:

	if (!(V4L2_TYPE_IS_OUTPUT(f->type) &&
	    (fmt->mscl_color_fmt_type & MSCL_FMT_SRC)))
		return -EINVAL;

> +
> +	strlcpy(f->description, fmt->name, sizeof(f->description));
> +	f->pixelformat = fmt->pixelformat;
> +
> +	return 0;
> +}
> +
> +static u32 get_plane_info(struct mscl_frame *frm, u32 addr, u32 *index)
> +{
> +	if (frm->addr.y == addr) {
> +		*index = 0;
> +		return frm->addr.y;
> +	} else if (frm->addr.cb == addr) {
> +		*index = 1;
> +		return frm->addr.cb;
> +	} else if (frm->addr.cr == addr) {
> +		*index = 2;
> +		return frm->addr.cr;
> +	} else {
> +		pr_debug("Plane address is wrong");
> +		return -EINVAL;
> +	}

Since all the statement blocks above end with a 'return' the 'else' keyword.
isn't necessary.

So just do:

	if (frm->addr.y == addr) {
		*index = 0;
		return frm->addr.y;
	}
	if (frm->addr.cb == addr) {
		*index = 1;
		return frm->addr.cb;
	}
	if (frm->addr.cr == addr) {
		*index = 2;
		return frm->addr.cr;
	}
	pr_debug("Plane address is wrong");
	return -EINVAL;


> +}
> +
> +void mscl_set_prefbuf(struct mscl_dev *mscl, struct mscl_frame *frm)
> +{
> +	u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
> +	f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
> +
> +	f_chk_addr = frm->addr.y;
> +	f_chk_len = frm->payload[0];
> +	if (frm->fmt->num_planes == 2) {
> +		s_chk_addr = frm->addr.cb;
> +		s_chk_len = frm->payload[1];
> +	} else if (frm->fmt->num_planes == 3) {
> +		u32 low_addr, low_plane, mid_addr, mid_plane;
> +		u32 high_addr, high_plane;
> +		u32 t_min, t_max;
> +
> +		t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr);
> +		low_addr = get_plane_info(frm, t_min, &low_plane);
> +		t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
> +		high_addr = get_plane_info(frm, t_max, &high_plane);
> +
> +		mid_plane = 3 - (low_plane + high_plane);
> +		if (mid_plane == 0)
> +			mid_addr = frm->addr.y;
> +		else if (mid_plane == 1)
> +			mid_addr = frm->addr.cb;
> +		else if (mid_plane == 2)
> +			mid_addr = frm->addr.cr;
> +		else
> +			return;
> +
> +		f_chk_addr = low_addr;
> +		if (mid_addr + frm->payload[mid_plane] - low_addr >
> +		    high_addr + frm->payload[high_plane] - mid_addr) {
> +			f_chk_len = frm->payload[low_plane];
> +			s_chk_addr = mid_addr;
> +			s_chk_len = high_addr +
> +					frm->payload[high_plane] - mid_addr;
> +		} else {
> +			f_chk_len = mid_addr +
> +					frm->payload[mid_plane] - low_addr;
> +			s_chk_addr = high_addr;
> +			s_chk_len = frm->payload[high_plane];
> +		}
> +	}
> +	dev_dbg(&mscl->pdev->dev,
> +		"f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n",
> +		f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
> +}
> +
> +int mscl_try_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f)
> +{
> +	struct mscl_dev *mscl = ctx->mscl_dev;
> +	struct device *dev = &mscl->pdev->dev;
> +	struct mscl_variant *variant = mscl->variant;
> +	struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +	const struct mscl_fmt *fmt;
> +	u32 max_w, max_h, mod_w = 0, mod_h = 0;
> +	u32 min_w, min_h, tmp_w, tmp_h;
> +	int i;
> +	struct mscl_frm_limit *frm_limit;
> +
> +	dev_dbg(dev, "user put w: %d, h: %d",
> +			pix_mp->width, pix_mp->height);
> +
> +	fmt = mscl_find_fmt(&pix_mp->pixelformat, NULL, 0);
> +	if (!fmt) {
> +		dev_dbg(dev, "pixelformat format (0x%X) invalid\n",
> +						pix_mp->pixelformat);
> +		return -EINVAL;
> +	}
> +
> +	if (pix_mp->field == V4L2_FIELD_ANY)
> +		pix_mp->field = V4L2_FIELD_NONE;
> +	else if (pix_mp->field != V4L2_FIELD_NONE) {
> +		dev_dbg(dev, "Not supported field order(%d)\n", pix_mp->field);
> +		return -EINVAL;

Don't return an error, just always map field to FIELD_NONE.

> +	}
> +
> +	if (V4L2_TYPE_IS_OUTPUT(f->type))
> +		frm_limit = variant->pix_out;
> +	else
> +		frm_limit = variant->pix_in;
> +
> +	max_w = frm_limit->max_w;
> +	max_h = frm_limit->max_h;
> +	min_w = frm_limit->min_w;
> +	min_h = frm_limit->min_h;
> +
> +	/* Span has to be even number for YCbCr422-2p or YCbCr420 format */
> +	if (is_yuv422_2p(fmt) || is_yuv420(fmt))
> +		mod_w = 1;
> +
> +	dev_dbg(dev, "mod_w: %d, mod_h: %d, max_w: %d, max_h = %d",
> +			mod_w, mod_h, max_w, max_h);
> +
> +	/* To check if image size is modified to adjust parameter against
> +	   hardware abilities */
> +	tmp_w = pix_mp->width;
> +	tmp_h = pix_mp->height;
> +
> +	v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_w,
> +		&pix_mp->height, min_h, max_h, mod_h, 0);
> +	if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
> +		dev_info(dev,
> +			 "Image size has been modified from %dx%d to %dx%d",
> +			 tmp_w, tmp_h, pix_mp->width, pix_mp->height);
> +
> +	pix_mp->num_planes = fmt->num_planes;
> +
> +	/* nothing mentioned about the colorspace in m2m-scaler
> +	 * default value is set to V4L2_COLORSPACE_REC709
> +	 */
> +	pix_mp->colorspace = V4L2_COLORSPACE_REC709;
> +
> +	for (i = 0; i < pix_mp->num_planes; ++i) {
> +		int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
> +		pix_mp->plane_fmt[i].bytesperline = bpl;
> +		pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
> +
> +		dev_dbg(dev, "[%d]: bpl: %d, sizeimage: %d",
> +				i, bpl, pix_mp->plane_fmt[i].sizeimage);
> +	}
> +
> +	return 0;
> +}
> +
> +int mscl_g_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f)
> +{
> +	struct mscl_frame *frame;
> +	struct v4l2_pix_format_mplane *pix_mp;
> +	int i;
> +
> +	frame = ctx_get_frame(ctx, f->type);
> +	if (IS_ERR(frame))
> +		return PTR_ERR(frame);
> +
> +	pix_mp = &f->fmt.pix_mp;
> +
> +	pix_mp->width		= frame->f_width;
> +	pix_mp->height		= frame->f_height;
> +	pix_mp->field		= V4L2_FIELD_NONE;
> +	pix_mp->pixelformat	= frame->fmt->pixelformat;
> +	pix_mp->colorspace	= V4L2_COLORSPACE_REC709;
> +	pix_mp->num_planes	= frame->fmt->num_planes;
> +
> +	for (i = 0; i < pix_mp->num_planes; ++i) {
> +		pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
> +			frame->fmt->depth[i]) / 8;
> +		pix_mp->plane_fmt[i].sizeimage =
> +			 pix_mp->plane_fmt[i].bytesperline * frame->f_height;
> +	}
> +
> +	return 0;
> +}
> +
> +void mscl_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
> +{
> +	if (tmp_w != *w || tmp_h != *h) {
> +		pr_info("Cropped size has been modified from %dx%d to %dx%d",
> +							*w, *h, tmp_w, tmp_h);
> +		*w = tmp_w;
> +		*h = tmp_h;
> +	}
> +}
> +
> +int mscl_g_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr)
> +{
> +	struct mscl_frame *frame;
> +
> +	frame = ctx_get_frame(ctx, cr->type);
> +	if (IS_ERR(frame))
> +		return PTR_ERR(frame);
> +
> +	cr->c = frame->crop;
> +
> +	return 0;
> +}
> +
> +int mscl_try_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr)
> +{
> +	struct mscl_frame *f;
> +	const struct mscl_fmt *fmt;
> +	struct mscl_dev *mscl = ctx->mscl_dev;
> +	struct device *dev = &mscl->pdev->dev;
> +	struct mscl_variant *variant = mscl->variant;
> +	u32 mod_w = 0, mod_h = 0, tmp_w, tmp_h;
> +	u32 min_w, min_h, max_w, max_h;
> +	struct mscl_frm_limit *frm_limit;
> +
> +	if (cr->c.top < 0 || cr->c.left < 0) {
> +		dev_dbg(dev, "doesn't support negative values\n");
> +		return -EINVAL;
> +	}
> +	dev_dbg(dev, "user requested width: %d, height: %d",
> +					cr->c.width, cr->c.height);
> +
> +	f = ctx_get_frame(ctx, cr->type);
> +	if (IS_ERR(f))
> +		return PTR_ERR(f);
> +
> +	fmt = f->fmt;
> +	tmp_w = cr->c.width;
> +	tmp_h = cr->c.height;
> +
> +	if (V4L2_TYPE_IS_OUTPUT(cr->type))
> +		frm_limit = variant->pix_out;
> +	else
> +		frm_limit = variant->pix_in;
> +
> +	max_w = f->f_width;
> +	max_h = f->f_height;
> +	min_w = frm_limit->min_w;
> +	min_h = frm_limit->min_h;
> +
> +	if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
> +		if (is_yuv420(fmt)) {
> +			mod_w = ffs(variant->pix_align->dst_w_420) - 1;
> +			mod_h = ffs(variant->pix_align->dst_h_420) - 1;
> +		} else if (is_yuv422(fmt)) {
> +			mod_w = ffs(variant->pix_align->dst_w_422) - 1;
> +		}
> +	} else {
> +		if (is_yuv420(fmt)) {
> +			mod_w = ffs(variant->pix_align->src_w_420) - 1;
> +			mod_h = ffs(variant->pix_align->src_h_420) - 1;
> +		} else if (is_yuv422(fmt)) {
> +			mod_w = ffs(variant->pix_align->src_w_422) - 1;
> +		}
> +
> +		if (ctx->ctrls_mscl.rotate->val == 90 ||
> +		    ctx->ctrls_mscl.rotate->val == 270) {
> +			max_w = f->f_height;
> +			max_h = f->f_width;
> +			tmp_w = cr->c.height;
> +			tmp_h = cr->c.width;
> +		}
> +	}
> +
> +	dev_dbg(dev, "mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
> +					mod_w, mod_h, min_w, min_h);
> +	dev_dbg(dev, "tmp_w : %d, tmp_h : %d", tmp_w, tmp_h);
> +
> +	v4l_bound_align_image(&tmp_w, min_w, max_w, mod_w,
> +			      &tmp_h, min_h, max_h, mod_h, 0);
> +
> +	if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
> +		(ctx->ctrls_mscl.rotate->val == 90 ||
> +		 ctx->ctrls_mscl.rotate->val == 270))
> +		mscl_check_crop_change(tmp_h, tmp_w,
> +					&cr->c.width, &cr->c.height);
> +	else
> +		mscl_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_yuv422_1p(fmt) && (cr->c.left & 1))
> +		cr->c.left -= 1;
> +
> +	dev_dbg(dev, "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 mscl_check_scaler_ratio(struct mscl_variant *var, int sw, int sh, int dw,
> +			   int dh, int rot)
> +{
> +	if ((dw == 0) || (dh == 0))
> +		return -EINVAL;
> +
> +	if (rot == 90 || rot == 270)
> +		swap(dh, dw);
> +
> +	pr_debug("sw: %d, sh: %d, dw: %d, dh: %d\n", sw, sh, dw, dh);
> +
> +	if ((sw/dw) > var->scl_down_max || (sh/dh) > var->scl_down_max ||
> +	    (dw/sw) > var->scl_up_max   || (dh/sh) > var->scl_up_max)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +int mscl_set_scaler_info(struct mscl_ctx *ctx)
> +{
> +	struct mscl_scaler *sc = &ctx->scaler;
> +	struct mscl_frame *s_frame = &ctx->s_frame;
> +	struct mscl_frame *d_frame = &ctx->d_frame;
> +	struct mscl_variant *variant = ctx->mscl_dev->variant;
> +	struct device *dev = &ctx->mscl_dev->pdev->dev;
> +	int src_w, src_h, ret;
> +
> +	ret = mscl_check_scaler_ratio(variant,
> +				s_frame->crop.width, s_frame->crop.height,
> +				d_frame->crop.width, d_frame->crop.height,
> +				ctx->ctrls_mscl.rotate->val);
> +	if (ret) {
> +		dev_dbg(dev, "out of scaler range\n");
> +		return ret;
> +	}
> +
> +	if (ctx->ctrls_mscl.rotate->val == 90 ||
> +		ctx->ctrls_mscl.rotate->val == 270) {
> +		src_w = s_frame->crop.height;
> +		src_h = s_frame->crop.width;
> +	} else {
> +		src_w = s_frame->crop.width;
> +		src_h = s_frame->crop.height;
> +	}
> +
> +	sc->hratio = (src_w << 16) / d_frame->crop.width;
> +	sc->vratio = (src_h << 16) / d_frame->crop.height;
> +
> +	dev_dbg(dev, "scaler settings::\n"
> +		 "sx = %d, sy = %d, sw = %d, sh = %d\n"
> +		 "dx = %d, dy = %d, dw = %d, dh = %d\n"
> +		 "h-ratio : %d, v-ratio: %d\n",
> +		 s_frame->crop.left, s_frame->crop.top,
> +		 s_frame->crop.width, s_frame->crop.height,
> +		 d_frame->crop.left, d_frame->crop.top,
> +		 d_frame->crop.width, s_frame->crop.height,
> +		 sc->hratio, sc->vratio);
> +
> +	return 0;
> +}
> +
> +static int __mscl_s_ctrl(struct mscl_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +	struct mscl_dev *mscl = ctx->mscl_dev;
> +	struct mscl_variant *variant = mscl->variant;
> +	unsigned int flags = MSCL_DST_FMT | MSCL_SRC_FMT;
> +	int ret = 0;
> +
> +	if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
> +		return 0;

Why would you want to do this check?

> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_HFLIP:
> +		ctx->hflip = ctrl->val;
> +		break;
> +
> +	case V4L2_CID_VFLIP:
> +		ctx->vflip = ctrl->val;
> +		break;
> +
> +	case V4L2_CID_ROTATE:
> +		if ((ctx->state & flags) == flags) {
> +			ret = mscl_check_scaler_ratio(variant,
> +					ctx->s_frame.crop.width,
> +					ctx->s_frame.crop.height,
> +					ctx->d_frame.crop.width,
> +					ctx->d_frame.crop.height,
> +					ctx->ctrls_mscl.rotate->val);
> +
> +			if (ret)
> +				return -EINVAL;
> +		}

I think it would be good if the try_ctrl op is implemented so you can call
VIDIOC_EXT_TRY_CTRLS in the application to check if the ROTATE control can be
set.

> +
> +		ctx->rotation = ctrl->val;
> +		break;
> +
> +	case V4L2_CID_ALPHA_COMPONENT:
> +		ctx->d_frame.alpha = ctrl->val;
> +		break;
> +	}
> +
> +	ctx->state |= MSCL_PARAMS;
> +	return 0;
> +}
> +
> +static int mscl_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct mscl_ctx *ctx = ctrl_to_ctx(ctrl);
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(&ctx->mscl_dev->slock, flags);
> +	ret = __mscl_s_ctrl(ctx, ctrl);
> +	spin_unlock_irqrestore(&ctx->mscl_dev->slock, flags);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops mscl_ctrl_ops = {
> +	.s_ctrl = mscl_s_ctrl,
> +};

Thanks for the patches!

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  Powered by Linux