diff mbox

[v2,1/5,media] exynos-mscl: Add new driver for M-Scaler

Message ID 1376909932-23644-2-git-send-email-shaik.ameer@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shaik Ameer Basha Aug. 19, 2013, 10:58 a.m. UTC
This patch adds support for M-Scaler (M2M Scaler) device which is a
new device for scaling, blending, color fill  and color space
conversion on EXYNOS5 SoCs.

This device supports the followings as key feature.
    input image format
        - YCbCr420 2P(UV/VU), 3P
        - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
        - YCbCr444 2P(UV,VU), 3P
        - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
        - Pre-multiplexed ARGB8888, L8A8 and L8
    output image format
        - YCbCr420 2P(UV/VU), 3P
        - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
        - YCbCr444 2P(UV,VU), 3P
        - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
        - Pre-multiplexed ARGB8888
    input rotation
        - 0/90/180/270 degree, X/Y/XY Flip
    scale ratio
        - 1/4 scale down to 16 scale up
    color space conversion
        - RGB to YUV / YUV to RGB
    Size
        - Input : 16x16 to 8192x8192
        - Output:   4x4 to 8192x8192
    alpha blending, color fill

Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
---
 drivers/media/platform/exynos-mscl/mscl-regs.c |  318 ++++++++++++++++++++++++
 drivers/media/platform/exynos-mscl/mscl-regs.h |  282 +++++++++++++++++++++
 2 files changed, 600 insertions(+)
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h

Comments

Inki Dae Aug. 19, 2013, 12:48 p.m. UTC | #1
Just quick review.

> -----Original Message-----
> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
> owner@vger.kernel.org] On Behalf Of Shaik Ameer Basha
> Sent: Monday, August 19, 2013 7:59 PM
> To: linux-media@vger.kernel.org; linux-samsung-soc@vger.kernel.org
> Cc: s.nawrocki@samsung.com; posciak@google.com; arun.kk@samsung.com;
> shaik.ameer@samsung.com
> Subject: [PATCH v2 1/5] [media] exynos-mscl: Add new driver for M-Scaler
> 
> This patch adds support for M-Scaler (M2M Scaler) device which is a
> new device for scaling, blending, color fill  and color space
> conversion on EXYNOS5 SoCs.
> 
> This device supports the followings as key feature.
>     input image format
>         - YCbCr420 2P(UV/VU), 3P
>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>         - YCbCr444 2P(UV,VU), 3P
>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>         - Pre-multiplexed ARGB8888, L8A8 and L8
>     output image format
>         - YCbCr420 2P(UV/VU), 3P
>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>         - YCbCr444 2P(UV,VU), 3P
>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>         - Pre-multiplexed ARGB8888
>     input rotation
>         - 0/90/180/270 degree, X/Y/XY Flip
>     scale ratio
>         - 1/4 scale down to 16 scale up
>     color space conversion
>         - RGB to YUV / YUV to RGB
>     Size
>         - Input : 16x16 to 8192x8192
>         - Output:   4x4 to 8192x8192
>     alpha blending, color fill
> 
> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
> ---
>  drivers/media/platform/exynos-mscl/mscl-regs.c |  318
> ++++++++++++++++++++++++
>  drivers/media/platform/exynos-mscl/mscl-regs.h |  282
> +++++++++++++++++++++
>  2 files changed, 600 insertions(+)
>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h
> 
> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c
> b/drivers/media/platform/exynos-mscl/mscl-regs.c
> new file mode 100644
> index 0000000..9354afc
> --- /dev/null
> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
> @@ -0,0 +1,318 @@
> +/*
> + * 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/delay.h>
> +#include <linux/platform_device.h>
> +
> +#include "mscl-core.h"
> +
> +void mscl_hw_set_sw_reset(struct mscl_dev *dev)
> +{
> +	u32 cfg;
> +
> +	cfg = readl(dev->regs + MSCL_CFG);
> +	cfg |= MSCL_CFG_SOFT_RESET;
> +
> +	writel(cfg, dev->regs + MSCL_CFG);
> +}
> +
> +int mscl_wait_reset(struct mscl_dev *dev)
> +{
> +	unsigned long end = jiffies + msecs_to_jiffies(50);

What does 50 mean?

> +	u32 cfg, reset_done = 0;
> +

Please describe why the below codes are needed.

> +	while (time_before(jiffies, end)) {
> +		cfg = readl(dev->regs + MSCL_CFG);
> +		if (!(cfg & MSCL_CFG_SOFT_RESET)) {
> +			reset_done = 1;
> +			break;
> +		}
> +		usleep_range(10, 20);
> +	}
> +
> +	/* write any value to r/w reg and read it back */
> +	while (reset_done) {
> +
> +		/* [TBD] need to define number of tries before returning
> +		 * -EBUSY to the caller
> +		 */
> +
> +		writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
> +				dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
> +		if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
> +			readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
> +			return 0;
> +	}
> +
> +	return -EBUSY;
> +}
> +
> +void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool mask)
> +{
> +	u32 cfg;
> +
> +	switch (interrupt) {
> +	case MSCL_INT_TIMEOUT:
> +	case MSCL_INT_ILLEGAL_BLEND:
> +	case MSCL_INT_ILLEGAL_RATIO:
> +	case MSCL_INT_ILLEGAL_DST_HEIGHT:
> +	case MSCL_INT_ILLEGAL_DST_WIDTH:
> +	case MSCL_INT_ILLEGAL_DST_V_POS:
> +	case MSCL_INT_ILLEGAL_DST_H_POS:
> +	case MSCL_INT_ILLEGAL_DST_C_SPAN:
> +	case MSCL_INT_ILLEGAL_DST_Y_SPAN:
> +	case MSCL_INT_ILLEGAL_DST_CR_BASE:
> +	case MSCL_INT_ILLEGAL_DST_CB_BASE:
> +	case MSCL_INT_ILLEGAL_DST_Y_BASE:
> +	case MSCL_INT_ILLEGAL_DST_COLOR:
> +	case MSCL_INT_ILLEGAL_SRC_HEIGHT:
> +	case MSCL_INT_ILLEGAL_SRC_WIDTH:
> +	case MSCL_INT_ILLEGAL_SRC_CV_POS:
> +	case MSCL_INT_ILLEGAL_SRC_CH_POS:
> +	case MSCL_INT_ILLEGAL_SRC_YV_POS:
> +	case MSCL_INT_ILLEGAL_SRC_YH_POS:
> +	case MSCL_INT_ILLEGAL_SRC_C_SPAN:
> +	case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
> +	case MSCL_INT_ILLEGAL_SRC_CR_BASE:
> +	case MSCL_INT_ILLEGAL_SRC_CB_BASE:
> +	case MSCL_INT_ILLEGAL_SRC_Y_BASE:
> +	case MSCL_INT_ILLEGAL_SRC_COLOR:
> +	case MSCL_INT_FRAME_END:
> +		break;
> +	default:
> +		return;
> +	}

It seems that the above codes could be more simple,


> +	cfg = readl(dev->regs + MSCL_INT_EN);
> +	if (mask)
> +		cfg |= interrupt;
> +	else
> +		cfg &= ~interrupt;
> +	writel(cfg, dev->regs + MSCL_INT_EN);
> +}
> +
> +void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr *addr)
> +{
> +	dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
> +				addr->y, addr->cb, addr->cr);
> +	writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
> +	writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
> +	writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
> +}
> +
> +void mscl_hw_set_output_addr(struct mscl_dev *dev,
> +			     struct mscl_addr *addr)
> +{
> +	dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
> +				addr->y, addr->cb, addr->cr);
> +	writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
> +	writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
> +	writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
> +}
> +
> +void mscl_hw_set_in_size(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame = &ctx->s_frame;
> +	u32 cfg;
> +
> +	/* set input pixel offset */
> +	cfg = MSCL_SRC_YH_POS(frame->crop.left);
> +	cfg |= MSCL_SRC_YV_POS(frame->crop.top);

Where are the limitations to left and top checked?.

> +	writel(cfg, dev->regs + MSCL_SRC_Y_POS);
> +
> +	/* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset
> */
> +
> +	/* set input span */
> +	cfg = MSCL_SRC_Y_SPAN(frame->f_width);
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= MSCL_SRC_C_SPAN(frame->f_width);
> +	else
> +		cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */
> +
> +	writel(cfg, dev->regs + MSCL_SRC_SPAN);
> +
> +	/* Set input cropped size */
> +	cfg = MSCL_SRC_WIDTH(frame->crop.width);
> +	cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
> +	writel(cfg, dev->regs + MSCL_SRC_WH);
> +
> +	dev_dbg(&dev->pdev->dev,
> +		"src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
> +		"cropX: %d, cropY: %d\n",
> +		frame->crop.left, frame->crop.top, frame->f_width,
> +		frame->f_width, frame->crop.width, frame->crop.height);
> +}
> +
> +void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame = &ctx->s_frame;
> +	u32 cfg;
> +
> +	cfg = readl(dev->regs + MSCL_SRC_CFG);
> +	cfg &= ~MSCL_SRC_COLOR_FORMAT_MASK;
> +	cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
> +
> +	/* setting tile/linear format */
> +	if (frame->fmt->is_tiled)
> +		cfg |= MSCL_SRC_TILE_EN;
> +	else
> +		cfg &= ~MSCL_SRC_TILE_EN;
> +
> +	writel(cfg, dev->regs + MSCL_SRC_CFG);
> +}
> +
> +void mscl_hw_set_out_size(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame = &ctx->d_frame;
> +	u32 cfg;
> +
> +	/* set output pixel offset */
> +	cfg = MSCL_DST_H_POS(frame->crop.left);
> +	cfg |= MSCL_DST_V_POS(frame->crop.top);

Ditto.

> +	writel(cfg, dev->regs + MSCL_DST_POS);
> +
> +	/* set output span */
> +	cfg = MSCL_DST_Y_SPAN(frame->f_width);
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
> +	else
> +		cfg |= MSCL_DST_C_SPAN(frame->f_width);
> +	writel(cfg, dev->regs + MSCL_DST_SPAN);
> +
> +	/* set output scaled size */
> +	cfg = MSCL_DST_WIDTH(frame->crop.width);
> +	cfg |= MSCL_DST_HEIGHT(frame->crop.height);
> +	writel(cfg, dev->regs + MSCL_DST_WH);
> +
> +	dev_dbg(&dev->pdev->dev,
> +		"dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
> +		"cropX: %d, cropY: %d\n",
> +		frame->crop.left, frame->crop.top, frame->f_width,
> +		frame->f_width, frame->crop.width, frame->crop.height);
> +}
> +
> +void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame = &ctx->d_frame;
> +	u32 cfg;
> +
> +	cfg = readl(dev->regs + MSCL_DST_CFG);
> +	cfg &= ~MSCL_DST_COLOR_FORMAT_MASK;
> +	cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);
> +
> +	writel(cfg, dev->regs + MSCL_DST_CFG);
> +}
> +
> +void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_scaler *sc = &ctx->scaler;
> +	u32 cfg;
> +
> +	cfg = MSCL_H_RATIO_VALUE(sc->hratio);
> +	writel(cfg, dev->regs + MSCL_H_RATIO);
> +
> +	cfg = MSCL_V_RATIO_VALUE(sc->vratio);
> +	writel(cfg, dev->regs + MSCL_V_RATIO);
> +}
> +
> +void mscl_hw_set_rotation(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	u32 cfg = 0;
> +
> +	cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);
> +
> +	if (ctx->ctrls_mscl.hflip->val)
> +		cfg |= MSCL_FLIP_X_EN;
> +
> +	if (ctx->ctrls_mscl.vflip->val)
> +		cfg |= MSCL_FLIP_Y_EN;
> +
> +	writel(cfg, dev->regs + MSCL_ROT_CFG);
> +}
> +
> +void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +
> +	writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);
> +}
> +
> +void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	enum mscl_csc_coeff type;
> +	u32 cfg = 0;
> +	int i, j;
> +	static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
> +		{ /* YCbCr to RGB */
> +			{0x200, 0x000, 0x2be},
> +			{0x200, 0xeac, 0x165},
> +			{0x200, 0x377, 0x000}
> +		},
> +		{ /* YCbCr to RGB with -16 offset */
> +			{0x254, 0x000, 0x331},
> +			{0x254, 0xec8, 0xFA0},
> +			{0x254, 0x409, 0x000}
> +		},
> +		{ /* RGB to YCbCr */
> +			{0x099, 0x12d, 0x03a},
> +			{0xe58, 0xeae, 0x106},
> +			{0x106, 0xedb, 0xe2a}
> +		},
> +		{ /* RGB to YCbCr with -16 offset */
> +			{0x084, 0x102, 0x032},
> +			{0xe4c, 0xe95, 0x0e1},
> +			{0x0e1, 0xebc, 0xe24}
> +		} };
> +
> +	if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
> +		type = MSCL_CSC_COEFF_NONE;
> +	else if (is_rgb(ctx->d_frame.fmt))
> +		type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
> +	else
> +		type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
> +
> +	if ((type == ctx->mscl_dev->coeff_type) || (type >=
> MSCL_CSC_COEFF_MAX))
> +		return;
> +
> +	for (i = 0; i < 3; i++) {
> +		for (j = 0; j < 3; j++) {
> +			cfg = csc_coeff[type][i][j];
> +			writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
> +		}
> +	}
> +
> +	switch (type) {
> +	case MSCL_CSC_COEFF_YCBCR_TO_RGB:

Is there this case?

> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);

And this switch-case could be removed if you move the above line to the
above if-sentence.


> +		break;
> +	case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);

Ditto.

> +		break;
> +	case MSCL_CSC_COEFF_RGB_TO_YCBCR:

Seems no case.

> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);

Could be moved to the above if-sentence.

> +		break;
> +	case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);

Ditto.

> +		break;
> +	default:
> +		return;
> +	}
> +
> +	ctx->mscl_dev->coeff_type = type;
> +	return;
> +}
> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.h
> b/drivers/media/platform/exynos-mscl/mscl-regs.h
> new file mode 100644
> index 0000000..02e2294d
> --- /dev/null
> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.h
> @@ -0,0 +1,282 @@
> +/*
> + * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Register definition file for Samsung 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 version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef REGS_MSCL_H_
> +#define REGS_MSCL_H_
> +
> +/* m2m-scaler status */
> +#define MSCL_STATUS				0x00
> +#define MSCL_STATUS_RUNNING			(1 << 1)
> +#define MSCL_STATUS_READY_CLK_DOWN		(1 << 0)
> +
> +/* m2m-scaler config */
> +#define MSCL_CFG				0x04
> +#define MSCL_CFG_FILL_EN			(1 << 24)
> +#define MSCL_CFG_BLEND_CLR_DIV_ALPHA_EN		(1 << 17)
> +#define MSCL_CFG_BLEND_EN			(1 << 16)
> +#define MSCL_CFG_CSC_Y_OFFSET_SRC_EN		(1 << 10)
> +#define MSCL_CFG_CSC_Y_OFFSET_DST_EN		(1 << 9)
> +#define MSCL_CFG_16_BURST_MODE			(1 << 8)
> +#define MSCL_CFG_SOFT_RESET			(1 << 1)
> +#define MSCL_CFG_START_CMD			(1 << 0)
> +
> +/* m2m-scaler interrupt enable */
> +#define MSCL_INT_EN				0x08
> +#define MSCL_INT_EN_DEFAULT			0x81ffffff
> +#define MSCL_INT_EN_TIMEOUT			(1 << 31)
> +#define MSCL_INT_EN_ILLEGAL_BLEND		(1 << 24)
> +#define MSCL_INT_EN_ILLEGAL_RATIO		(1 << 23)
> +#define MSCL_INT_EN_ILLEGAL_DST_HEIGHT		(1 << 22)
> +#define MSCL_INT_EN_ILLEGAL_DST_WIDTH		(1 << 21)
> +#define MSCL_INT_EN_ILLEGAL_DST_V_POS		(1 << 20)
> +#define MSCL_INT_EN_ILLEGAL_DST_H_POS		(1 << 19)
> +#define MSCL_INT_EN_ILLEGAL_DST_C_SPAN		(1 << 18)
> +#define MSCL_INT_EN_ILLEGAL_DST_Y_SPAN		(1 << 17)
> +#define MSCL_INT_EN_ILLEGAL_DST_CR_BASE		(1 << 16)
> +#define MSCL_INT_EN_ILLEGAL_DST_CB_BASE		(1 << 15)
> +#define MSCL_INT_EN_ILLEGAL_DST_Y_BASE		(1 << 14)
> +#define MSCL_INT_EN_ILLEGAL_DST_COLOR		(1 << 13)
> +#define MSCL_INT_EN_ILLEGAL_SRC_HEIGHT		(1 << 12)
> +#define MSCL_INT_EN_ILLEGAL_SRC_WIDTH		(1 << 11)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CV_POS		(1 << 10)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CH_POS		(1 << 9)
> +#define MSCL_INT_EN_ILLEGAL_SRC_YV_POS		(1 << 8)
> +#define MSCL_INT_EN_ILLEGAL_SRC_YH_POS		(1 << 7)
> +#define MSCL_INT_EN_ILLEGAL_SRC_C_SPAN		(1 << 6)
> +#define MSCL_INT_EN_ILLEGAL_SRC_Y_SPAN		(1 << 5)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CR_BASE		(1 << 4)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CB_BASE		(1 << 3)
> +#define MSCL_INT_EN_ILLEGAL_SRC_Y_BASE		(1 << 2)
> +#define MSCL_INT_EN_ILLEGAL_SRC_COLOR		(1 << 1)
> +#define MSCL_INT_EN_FRAME_END			(1 << 0)
> +
> +/* m2m-scaler interrupt status */
> +#define MSCL_INT_STATUS				0x0c
> +#define MSCL_INT_STATUS_CLEAR			(0xffffffff)
> +#define MSCL_INT_STATUS_ERROR			(0x81fffffe)
> +#define MSCL_INT_STATUS_TIMEOUT			(1 << 31)
> +#define MSCL_INT_STATUS_ILLEGAL_BLEND		(1 << 24)
> +#define MSCL_INT_STATUS_ILLEGAL_RATIO		(1 << 23)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_HEIGHT	(1 << 22)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_WIDTH	(1 << 21)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_V_POS	(1 << 20)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_H_POS	(1 << 19)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_C_SPAN	(1 << 18)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_Y_SPAN	(1 << 17)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_CR_BASE	(1 << 16)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_CB_BASE	(1 << 15)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_Y_BASE	(1 << 14)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_COLOR	(1 << 13)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_HEIGHT	(1 << 12)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_WIDTH	(1 << 11)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CV_POS	(1 << 10)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CH_POS	(1 << 9)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_YV_POS	(1 << 8)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_YH_POS	(1 << 7)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_C_SPAN	(1 << 6)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_SPAN	(1 << 5)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CR_BASE	(1 << 4)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CB_BASE	(1 << 3)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_BASE	(1 << 2)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_COLOR	(1 << 1)
> +#define MSCL_INT_STATUS_FRAME_END		(1 << 0)
> +
> +/* m2m-scaler source format configuration */
> +#define MSCL_SRC_CFG				0x10
> +#define MSCL_SRC_TILE_EN			(0x1 << 10)
> +#define MSCL_SRC_BYTE_SWAP_MASK			(0x3 << 5)
> +#define MSCL_SRC_BYTE_SWAP(x)			(((x) & 0x3) << 5)
> +#define MSCL_SRC_COLOR_FORMAT_MASK		(0xf << 0)
> +#define MSCL_SRC_COLOR_FORMAT(x)		(((x) & 0xf) << 0)
> +
> +/* m2m-scaler source y-base */
> +#define MSCL_SRC_Y_BASE				0x14
> +
> +/* m2m-scaler source cb-base */
> +#define MSCL_SRC_CB_BASE			0x18
> +
> +/* m2m-scaler source cr-base */
> +#define MSCL_SRC_CR_BASE			0x294
> +
> +/* m2m-scaler source span */
> +#define MSCL_SRC_SPAN				0x1c
> +#define MSCL_SRC_C_SPAN_MASK			(0x3fff << 16)
> +#define MSCL_SRC_C_SPAN(x)			(((x) & 0x3fff) << 16)
> +#define MSCL_SRC_Y_SPAN_MASK			(0x3fff << 0)
> +#define MSCL_SRC_Y_SPAN(x)			(((x) & 0x3fff) << 0)
> +
> +/* m2m-scaler source y-position */
> +#define MSCL_SRC_Y_POS				0x20
> +#define MSCL_SRC_YH_POS_MASK			(0xffff << (16 + 2))
> +#define MSCL_SRC_YH_POS(x)			(((x) & 0xffff) << (16 + 2))
> +#define MSCL_SRC_YV_POS_MASK			(0xffff << (0 + 2))
> +#define MSCL_SRC_YV_POS(x)			(((x) & 0xffff) << (0 + 2))
> +
> +/* m2m-scaler source width/height */
> +#define MSCL_SRC_WH				0x24
> +#define MSCL_SRC_WIDTH_MASK			(0x3fff << 16)
> +#define MSCL_SRC_WIDTH(x)			(((x) & 0x3fff) << 16)
> +#define MSCL_SRC_HEIGHT_MASK			(0x3fff << 0)
> +#define MSCL_SRC_HEIGHT(x)			(((x) & 0x3fff) << 0)
> +
> +/* m2m-scaler source c-position */
> +#define MSCL_SRC_C_POS				0x28
> +#define MSCL_SRC_CH_POS_MASK			(0xffff << (16 + 2))
> +#define MSCL_SRC_CH_POS(x)			(((x) & 0xffff) << (16 + 2))
> +#define MSCL_SRC_CV_POS_MASK			(0xffff << (0 + 2))
> +#define MSCL_SRC_CV_POS(x)			(((x) & 0xffff) << (0 + 2))
> +
> +/* m2m-scaler destination format configuration */
> +#define MSCL_DST_CFG				0x30
> +#define MSCL_DST_BYTE_SWAP_MASK			(0x3 << 5)
> +#define MSCL_DST_BYTE_SWAP(x)			(((x) & 0x3) << 5)
> +#define MSCL_DST_COLOR_FORMAT_MASK		(0xf << 0)
> +#define MSCL_DST_COLOR_FORMAT(x)		(((x) & 0xf) << 0)
> +
> +/* m2m-scaler destination y-base */
> +#define MSCL_DST_Y_BASE				0x34
> +
> +/* m2m-scaler destination cb-base */
> +#define MSCL_DST_CB_BASE			0x38
> +
> +/* m2m-scaler destination cr-base */
> +#define MSCL_DST_CR_BASE			0x298
> +
> +/* m2m-scaler destination span */
> +#define MSCL_DST_SPAN				0x3c
> +#define MSCL_DST_C_SPAN_MASK			(0x3fff << 16)
> +#define MSCL_DST_C_SPAN(x)			(((x) & 0x3fff) << 16)
> +#define MSCL_DST_Y_SPAN_MASK			(0x3fff << 0)
> +#define MSCL_DST_Y_SPAN(x)			(((x) & 0x3fff) << 0)
> +
> +/* m2m-scaler destination width/height */
> +#define MSCL_DST_WH				0x40
> +#define MSCL_DST_WIDTH_MASK			(0x3fff << 16)
> +#define MSCL_DST_WIDTH(x)			(((x) & 0x3fff) << 16)
> +#define MSCL_DST_HEIGHT_MASK			(0x3fff << 0)
> +#define MSCL_DST_HEIGHT(x)			(((x) & 0x3fff) << 0)
> +
> +/* m2m-scaler destination position */
> +#define MSCL_DST_POS				0x44
> +#define MSCL_DST_H_POS_MASK			(0x3fff << 16)
> +#define MSCL_DST_H_POS(x)			(((x) & 0x3fff) << 16)
> +#define MSCL_DST_V_POS_MASK			(0x3fff << 0)
> +#define MSCL_DST_V_POS(x)			(((x) & 0x3fff) << 0)
> +
> +/* m2m-scaler horizontal scale ratio */
> +#define MSCL_H_RATIO				0x50
> +#define MSCL_H_RATIO_VALUE(x)			(((x) & 0x7ffff) <<
0)
> +
> +/* m2m-scaler vertical scale ratio */
> +#define MSCL_V_RATIO				0x54
> +#define MSCL_V_RATIO_VALUE(x)			(((x) & 0x7ffff) <<
0)
> +
> +/* m2m-scaler rotation config */
> +#define MSCL_ROT_CFG				0x58
> +#define MSCL_FLIP_X_EN				(1 << 3)
> +#define MSCL_FLIP_Y_EN				(1 << 2)
> +#define MSCL_ROTMODE_MASK			(0x3 << 0)
> +#define MSCL_ROTMODE(x)				(((x) & 0x3) << 0)
> +
> +/* m2m-scaler csc coefficients */
> +#define MSCL_CSC_COEF_00			0x220
> +#define MSCL_CSC_COEF_10			0x224
> +#define MSCL_CSC_COEF_20			0x228
> +#define MSCL_CSC_COEF_01			0x22C
> +#define MSCL_CSC_COEF_11			0x230
> +#define MSCL_CSC_COEF_21			0x234
> +#define MSCL_CSC_COEF_02			0x238
> +#define MSCL_CSC_COEF_12			0x23C
> +#define MSCL_CSC_COEF_22			0x240
> +
> +#define MSCL_CSC_COEF(x, y)			(0x220 + ((x * 12) + (y *
> 4)))
> +
> +/* m2m-scaler dither config */
> +#define MSCL_DITH_CFG				0x250
> +#define MSCL_DITHER_R_TYPE_MASK			(0x7 << 6)
> +#define MSCL_DITHER_R_TYPE(x)			(((x) & 0x7) << 6)
> +#define MSCL_DITHER_G_TYPE_MASK			(0x7 << 3)
> +#define MSCL_DITHER_G_TYPE(x)			(((x) & 0x7) << 3)
> +#define MSCL_DITHER_B_TYPE_MASK			(0x7 << 0)
> +#define MSCL_DITHER_B_TYPE(x)			(((x) & 0x7) << 0)
> +
> +/* m2m-scaler src blend color */
> +#define MSCL_SRC_BLEND_COLOR			0x280
> +#define MSCL_SRC_COLOR_SEL_INV			(1 << 31)
> +#define MSCL_SRC_COLOR_SEL_MASK			(0x3 << 29)
> +#define MSCL_SRC_COLOR_SEL(x)			(((x) & 0x3) << 29)
> +#define MSCL_SRC_COLOR_OP_SEL_INV		(1 << 28)
> +#define MSCL_SRC_COLOR_OP_SEL_MASK		(0xf << 24)
> +#define MSCL_SRC_COLOR_OP_SEL(x)		(((x) & 0xf) << 24)
> +#define MSCL_SRC_GLOBAL_COLOR0_MASK		(0xff << 16)
> +#define MSCL_SRC_GLOBAL_COLOR0(x)		(((x) & 0xff) << 16)
> +#define MSCL_SRC_GLOBAL_COLOR1_MASK		(0xff << 8)
> +#define MSCL_SRC_GLOBAL_COLOR1(x)		(((x) & 0xff) << 8)
> +#define MSCL_SRC_GLOBAL_COLOR2_MASK		(0xff << 0)
> +#define MSCL_SRC_GLOBAL_COLOR2(x)		(((x) & 0xff) << 0)
> +
> +/* m2m-scaler src blend alpha */
> +#define MSCL_SRC_BLEND_ALPHA			0x284
> +#define MSCL_SRC_ALPHA_SEL_INV			(1 << 31)
> +#define MSCL_SRC_ALPHA_SEL_MASK			(0x3 << 29)
> +#define MSCL_SRC_ALPHA_SEL(x)			(((x) & 0x3) << 29)
> +#define MSCL_SRC_ALPHA_OP_SEL_INV		(1 << 28)
> +#define MSCL_SRC_ALPHA_OP_SEL_MASK		(0xf << 24)
> +#define MSCL_SRC_ALPHA_OP_SEL(x)		(((x) & 0xf) << 24)
> +#define MSCL_SRC_GLOBAL_ALPHA_MASK		(0xff << 0)
> +#define MSCL_SRC_GLOBAL_ALPHA(x)		(((x) & 0xff) << 0)
> +
> +/* m2m-scaler dst blend color */
> +#define MSCL_DST_BLEND_COLOR			0x288
> +#define MSCL_DST_COLOR_SEL_INV			(1 << 31)
> +#define MSCL_DST_COLOR_SEL_MASK			(0x3 << 29)
> +#define MSCL_DST_COLOR_SEL(x)			(((x) & 0x3) << 29)
> +#define MSCL_DST_COLOR_OP_SEL_INV		(1 << 28)
> +#define MSCL_DST_COLOR_OP_SEL_MASK		(0xf << 24)
> +#define MSCL_DST_COLOR_OP_SEL(x)		(((x) & 0xf) << 24)
> +#define MSCL_DST_GLOBAL_COLOR0_MASK		(0xff << 16)
> +#define MSCL_DST_GLOBAL_COLOR0(x)		(((x) & 0xff) << 16)
> +#define MSCL_DST_GLOBAL_COLOR1_MASK		(0xff << 8)
> +#define MSCL_DST_GLOBAL_COLOR1(x)		(((x) & 0xff) << 8)
> +#define MSCL_DST_GLOBAL_COLOR2_MASK		(0xff << 0)
> +#define MSCL_DST_GLOBAL_COLOR2(x)		(((x) & 0xff) << 0)
> +
> +/* m2m-scaler dst blend alpha */
> +#define MSCL_DST_BLEND_ALPHA			0x28C
> +#define MSCL_DST_ALPHA_SEL_INV			(1 << 31)
> +#define MSCL_DST_ALPHA_SEL_MASK			(0x3 << 29)
> +#define MSCL_DST_ALPHA_SEL(x)			(((x) & 0x3) << 29)
> +#define MSCL_DST_ALPHA_OP_SEL_INV		(1 << 28)
> +#define MSCL_DST_ALPHA_OP_SEL_MASK		(0xf << 24)
> +#define MSCL_DST_ALPHA_OP_SEL(x)		(((x) & 0xf) << 24)
> +#define MSCL_DST_GLOBAL_ALPHA_MASK		(0xff << 0)
> +#define MSCL_DST_GLOBAL_ALPHA(x)		(((x) & 0xff) << 0)
> +
> +/* m2m-scaler fill color */
> +#define MSCL_FILL_COLOR				0x290
> +#define MSCL_FILL_ALPHA_MASK			(0xff << 24)
> +#define MSCL_FILL_ALPHA(x)			(((x) & 0xff) << 24)
> +#define MSCL_FILL_COLOR0_MASK			(0xff << 16)
> +#define MSCL_FILL_COLOR0(x)			(((x) & 0xff) << 16)
> +#define MSCL_FILL_COLOR1_MASK			(0xff << 8)
> +#define MSCL_FILL_COLOR1(x)			(((x) & 0xff) << 8)
> +#define MSCL_FILL_COLOR2_MASK			(0xff << 0)
> +#define MSCL_FILL_COLOR2(x)			(((x) & 0xff) << 0)
> +
> +/* m2m-scaler address queue config */
> +#define MSCL_ADDR_QUEUE_CONFIG			0x2a0
> +#define MSCL_ADDR_QUEUE_RST			(1 << 0)
> +
> +/* arbitrary r/w register and reg-value to check soft reset is success */
> +#define MSCL_CFG_SOFT_RESET_CHECK_REG		MSCL_SRC_CFG
> +#define MSCL_CFG_SOFT_RESET_CHECK_VAL		0x3
> +
> +#endif /* REGS_MSCL_H_ */
> --
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shaik Ameer Basha Aug. 20, 2013, 8:07 a.m. UTC | #2
Hi Inki Dae,

Thanks for the review.


On Mon, Aug 19, 2013 at 6:18 PM, Inki Dae <inki.dae@samsung.com> wrote:
> Just quick review.
>
>> -----Original Message-----
>> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
>> owner@vger.kernel.org] On Behalf Of Shaik Ameer Basha
>> Sent: Monday, August 19, 2013 7:59 PM
>> To: linux-media@vger.kernel.org; linux-samsung-soc@vger.kernel.org
>> Cc: s.nawrocki@samsung.com; posciak@google.com; arun.kk@samsung.com;
>> shaik.ameer@samsung.com
>> Subject: [PATCH v2 1/5] [media] exynos-mscl: Add new driver for M-Scaler
>>
>> This patch adds support for M-Scaler (M2M Scaler) device which is a
>> new device for scaling, blending, color fill  and color space
>> conversion on EXYNOS5 SoCs.
>>
>> This device supports the followings as key feature.
>>     input image format
>>         - YCbCr420 2P(UV/VU), 3P
>>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>>         - YCbCr444 2P(UV,VU), 3P
>>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>>         - Pre-multiplexed ARGB8888, L8A8 and L8
>>     output image format
>>         - YCbCr420 2P(UV/VU), 3P
>>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>>         - YCbCr444 2P(UV,VU), 3P
>>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>>         - Pre-multiplexed ARGB8888
>>     input rotation
>>         - 0/90/180/270 degree, X/Y/XY Flip
>>     scale ratio
>>         - 1/4 scale down to 16 scale up
>>     color space conversion
>>         - RGB to YUV / YUV to RGB
>>     Size
>>         - Input : 16x16 to 8192x8192
>>         - Output:   4x4 to 8192x8192
>>     alpha blending, color fill
>>
>> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
>> ---
>>  drivers/media/platform/exynos-mscl/mscl-regs.c |  318
>> ++++++++++++++++++++++++
>>  drivers/media/platform/exynos-mscl/mscl-regs.h |  282
>> +++++++++++++++++++++
>>  2 files changed, 600 insertions(+)
>>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
>>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h
>>
>> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c
>> b/drivers/media/platform/exynos-mscl/mscl-regs.c
>> new file mode 100644
>> index 0000000..9354afc
>> --- /dev/null
>> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
>> @@ -0,0 +1,318 @@
>> +/*
>> + * 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/delay.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "mscl-core.h"
>> +
>> +void mscl_hw_set_sw_reset(struct mscl_dev *dev)
>> +{
>> +     u32 cfg;
>> +
>> +     cfg = readl(dev->regs + MSCL_CFG);
>> +     cfg |= MSCL_CFG_SOFT_RESET;
>> +
>> +     writel(cfg, dev->regs + MSCL_CFG);
>> +}
>> +
>> +int mscl_wait_reset(struct mscl_dev *dev)
>> +{
>> +     unsigned long end = jiffies + msecs_to_jiffies(50);
>
> What does 50 mean?
>
>> +     u32 cfg, reset_done = 0;
>> +
>
> Please describe why the below codes are needed.


As per the Documentation,

" SOFT RESET: Writing "1" to this bit generates software reset. To
check the completion of the reset, wait until this
field becomes zero, then wrie an arbitrary value to any of RW
registers and read it. If the read data matches the written data,
 it means SW reset succeeded. Otherwise, repeat write & read until matched."


Thie below code tries to do the same (as per user manual). and in the
above msec_to_jiffies(50), 50 is the 50msec wait. before
checking the SOFT RESET is really done.

Is it good to ignore this checks?



>
>> +     while (time_before(jiffies, end)) {
>> +             cfg = readl(dev->regs + MSCL_CFG);
>> +             if (!(cfg & MSCL_CFG_SOFT_RESET)) {
>> +                     reset_done = 1;
>> +                     break;
>> +             }
>> +             usleep_range(10, 20);
>> +     }
>> +
>> +     /* write any value to r/w reg and read it back */
>> +     while (reset_done) {
>> +
>> +             /* [TBD] need to define number of tries before returning
>> +              * -EBUSY to the caller
>> +              */
>> +
>> +             writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
>> +                             dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
>> +             if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
>> +                     readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
>> +                     return 0;
>> +     }
>> +
>> +     return -EBUSY;
>> +}
>> +
>> +void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool mask)
>> +{
>> +     u32 cfg;
>> +
>> +     switch (interrupt) {
>> +     case MSCL_INT_TIMEOUT:
>> +     case MSCL_INT_ILLEGAL_BLEND:
>> +     case MSCL_INT_ILLEGAL_RATIO:
>> +     case MSCL_INT_ILLEGAL_DST_HEIGHT:
>> +     case MSCL_INT_ILLEGAL_DST_WIDTH:
>> +     case MSCL_INT_ILLEGAL_DST_V_POS:
>> +     case MSCL_INT_ILLEGAL_DST_H_POS:
>> +     case MSCL_INT_ILLEGAL_DST_C_SPAN:
>> +     case MSCL_INT_ILLEGAL_DST_Y_SPAN:
>> +     case MSCL_INT_ILLEGAL_DST_CR_BASE:
>> +     case MSCL_INT_ILLEGAL_DST_CB_BASE:
>> +     case MSCL_INT_ILLEGAL_DST_Y_BASE:
>> +     case MSCL_INT_ILLEGAL_DST_COLOR:
>> +     case MSCL_INT_ILLEGAL_SRC_HEIGHT:
>> +     case MSCL_INT_ILLEGAL_SRC_WIDTH:
>> +     case MSCL_INT_ILLEGAL_SRC_CV_POS:
>> +     case MSCL_INT_ILLEGAL_SRC_CH_POS:
>> +     case MSCL_INT_ILLEGAL_SRC_YV_POS:
>> +     case MSCL_INT_ILLEGAL_SRC_YH_POS:
>> +     case MSCL_INT_ILLEGAL_SRC_C_SPAN:
>> +     case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
>> +     case MSCL_INT_ILLEGAL_SRC_CR_BASE:
>> +     case MSCL_INT_ILLEGAL_SRC_CB_BASE:
>> +     case MSCL_INT_ILLEGAL_SRC_Y_BASE:
>> +     case MSCL_INT_ILLEGAL_SRC_COLOR:
>> +     case MSCL_INT_FRAME_END:
>> +             break;
>> +     default:
>> +             return;
>> +     }
>
> It seems that the above codes could be more simple,


ok. will change this.


>
>
>> +     cfg = readl(dev->regs + MSCL_INT_EN);
>> +     if (mask)
>> +             cfg |= interrupt;
>> +     else
>> +             cfg &= ~interrupt;
>> +     writel(cfg, dev->regs + MSCL_INT_EN);
>> +}
>> +
>> +void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr *addr)
>> +{
>> +     dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
>> +                             addr->y, addr->cb, addr->cr);
>> +     writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
>> +     writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
>> +     writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
>> +}
>> +
>> +void mscl_hw_set_output_addr(struct mscl_dev *dev,
>> +                          struct mscl_addr *addr)
>> +{
>> +     dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
>> +                             addr->y, addr->cb, addr->cr);
>> +     writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
>> +     writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
>> +     writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
>> +}
>> +
>> +void mscl_hw_set_in_size(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     struct mscl_frame *frame = &ctx->s_frame;
>> +     u32 cfg;
>> +
>> +     /* set input pixel offset */
>> +     cfg = MSCL_SRC_YH_POS(frame->crop.left);
>> +     cfg |= MSCL_SRC_YV_POS(frame->crop.top);
>
> Where are the limitations to left and top checked?.



mscl_try_crop() does this checking.



>
>> +     writel(cfg, dev->regs + MSCL_SRC_Y_POS);
>> +
>> +     /* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset
>> */
>> +
>> +     /* set input span */
>> +     cfg = MSCL_SRC_Y_SPAN(frame->f_width);
>> +     if (is_yuv420_2p(frame->fmt))
>> +             cfg |= MSCL_SRC_C_SPAN(frame->f_width);
>> +     else
>> +             cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */
>> +
>> +     writel(cfg, dev->regs + MSCL_SRC_SPAN);
>> +
>> +     /* Set input cropped size */
>> +     cfg = MSCL_SRC_WIDTH(frame->crop.width);
>> +     cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
>> +     writel(cfg, dev->regs + MSCL_SRC_WH);
>> +
>> +     dev_dbg(&dev->pdev->dev,
>> +             "src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
>> +             "cropX: %d, cropY: %d\n",
>> +             frame->crop.left, frame->crop.top, frame->f_width,
>> +             frame->f_width, frame->crop.width, frame->crop.height);
>> +}
>> +
>> +void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     struct mscl_frame *frame = &ctx->s_frame;
>> +     u32 cfg;
>> +
>> +     cfg = readl(dev->regs + MSCL_SRC_CFG);
>> +     cfg &= ~MSCL_SRC_COLOR_FORMAT_MASK;
>> +     cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
>> +
>> +     /* setting tile/linear format */
>> +     if (frame->fmt->is_tiled)
>> +             cfg |= MSCL_SRC_TILE_EN;
>> +     else
>> +             cfg &= ~MSCL_SRC_TILE_EN;
>> +
>> +     writel(cfg, dev->regs + MSCL_SRC_CFG);
>> +}
>> +
>> +void mscl_hw_set_out_size(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     struct mscl_frame *frame = &ctx->d_frame;
>> +     u32 cfg;
>> +
>> +     /* set output pixel offset */
>> +     cfg = MSCL_DST_H_POS(frame->crop.left);
>> +     cfg |= MSCL_DST_V_POS(frame->crop.top);
>
> Ditto.
>
>> +     writel(cfg, dev->regs + MSCL_DST_POS);
>> +
>> +     /* set output span */
>> +     cfg = MSCL_DST_Y_SPAN(frame->f_width);
>> +     if (is_yuv420_2p(frame->fmt))
>> +             cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
>> +     else
>> +             cfg |= MSCL_DST_C_SPAN(frame->f_width);
>> +     writel(cfg, dev->regs + MSCL_DST_SPAN);
>> +
>> +     /* set output scaled size */
>> +     cfg = MSCL_DST_WIDTH(frame->crop.width);
>> +     cfg |= MSCL_DST_HEIGHT(frame->crop.height);
>> +     writel(cfg, dev->regs + MSCL_DST_WH);
>> +
>> +     dev_dbg(&dev->pdev->dev,
>> +             "dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
>> +             "cropX: %d, cropY: %d\n",
>> +             frame->crop.left, frame->crop.top, frame->f_width,
>> +             frame->f_width, frame->crop.width, frame->crop.height);
>> +}
>> +
>> +void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     struct mscl_frame *frame = &ctx->d_frame;
>> +     u32 cfg;
>> +
>> +     cfg = readl(dev->regs + MSCL_DST_CFG);
>> +     cfg &= ~MSCL_DST_COLOR_FORMAT_MASK;
>> +     cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);
>> +
>> +     writel(cfg, dev->regs + MSCL_DST_CFG);
>> +}
>> +
>> +void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     struct mscl_scaler *sc = &ctx->scaler;
>> +     u32 cfg;
>> +
>> +     cfg = MSCL_H_RATIO_VALUE(sc->hratio);
>> +     writel(cfg, dev->regs + MSCL_H_RATIO);
>> +
>> +     cfg = MSCL_V_RATIO_VALUE(sc->vratio);
>> +     writel(cfg, dev->regs + MSCL_V_RATIO);
>> +}
>> +
>> +void mscl_hw_set_rotation(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     u32 cfg = 0;
>> +
>> +     cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);
>> +
>> +     if (ctx->ctrls_mscl.hflip->val)
>> +             cfg |= MSCL_FLIP_X_EN;
>> +
>> +     if (ctx->ctrls_mscl.vflip->val)
>> +             cfg |= MSCL_FLIP_Y_EN;
>> +
>> +     writel(cfg, dev->regs + MSCL_ROT_CFG);
>> +}
>> +
>> +void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +
>> +     writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);
>> +}
>> +
>> +void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
>> +{
>> +     struct mscl_dev *dev = ctx->mscl_dev;
>> +     enum mscl_csc_coeff type;
>> +     u32 cfg = 0;
>> +     int i, j;
>> +     static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
>> +             { /* YCbCr to RGB */
>> +                     {0x200, 0x000, 0x2be},
>> +                     {0x200, 0xeac, 0x165},
>> +                     {0x200, 0x377, 0x000}
>> +             },
>> +             { /* YCbCr to RGB with -16 offset */
>> +                     {0x254, 0x000, 0x331},
>> +                     {0x254, 0xec8, 0xFA0},
>> +                     {0x254, 0x409, 0x000}
>> +             },
>> +             { /* RGB to YCbCr */
>> +                     {0x099, 0x12d, 0x03a},
>> +                     {0xe58, 0xeae, 0x106},
>> +                     {0x106, 0xedb, 0xe2a}
>> +             },
>> +             { /* RGB to YCbCr with -16 offset */
>> +                     {0x084, 0x102, 0x032},
>> +                     {0xe4c, 0xe95, 0x0e1},
>> +                     {0x0e1, 0xebc, 0xe24}
>> +             } };
>> +
>> +     if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
>> +             type = MSCL_CSC_COEFF_NONE;
>> +     else if (is_rgb(ctx->d_frame.fmt))
>> +             type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
>> +     else
>> +             type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
>> +
>> +     if ((type == ctx->mscl_dev->coeff_type) || (type >=
>> MSCL_CSC_COEFF_MAX))
>> +             return;
>> +
>> +     for (i = 0; i < 3; i++) {
>> +             for (j = 0; j < 3; j++) {
>> +                     cfg = csc_coeff[type][i][j];
>> +                     writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
>> +             }
>> +     }
>> +
>> +     switch (type) {
>> +     case MSCL_CSC_COEFF_YCBCR_TO_RGB:
>
> Is there this case?
>
>> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
>
> And this switch-case could be removed if you move the above line to the
> above if-sentence.
>
>
>> +             break;
>> +     case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
>> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
>
> Ditto.
>
>> +             break;
>> +     case MSCL_CSC_COEFF_RGB_TO_YCBCR:
>
> Seems no case.
>
>> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
>
> Could be moved to the above if-sentence.



I think MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16, MSCL_CSC_COEFF_YCBCR_TO_RGB
belongs to different color spaces.
Anyways, will remove the unused cases and will reorganize the code as
per your comments.

Regards,
Shaik Ameer Basha



>
>> +             break;
>> +     case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
>> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
>
> Ditto.
>
>> +             break;
>> +     default:
>> +             return;
>> +     }
>> +
>> +     ctx->mscl_dev->coeff_type = type;
>> +     return;
>> +}

[snip]
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Inki Dae Aug. 20, 2013, 8:43 a.m. UTC | #3
> -----Original Message-----
> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
> owner@vger.kernel.org] On Behalf Of Shaik Ameer Basha
> Sent: Tuesday, August 20, 2013 5:07 PM
> To: Inki Dae
> Cc: Shaik Ameer Basha; LMML; linux-samsung-soc@vger.kernel.org;
> cpgs@samsung.com; Sylwester Nawrocki; posciak@google.com; Arun Kumar K
> Subject: Re: [PATCH v2 1/5] [media] exynos-mscl: Add new driver for M-
> Scaler
> 
> Hi Inki Dae,
> 
> Thanks for the review.
> 
> 
> On Mon, Aug 19, 2013 at 6:18 PM, Inki Dae <inki.dae@samsung.com> wrote:
> > Just quick review.
> >
> >> -----Original Message-----
> >> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
> >> owner@vger.kernel.org] On Behalf Of Shaik Ameer Basha
> >> Sent: Monday, August 19, 2013 7:59 PM
> >> To: linux-media@vger.kernel.org; linux-samsung-soc@vger.kernel.org
> >> Cc: s.nawrocki@samsung.com; posciak@google.com; arun.kk@samsung.com;
> >> shaik.ameer@samsung.com
> >> Subject: [PATCH v2 1/5] [media] exynos-mscl: Add new driver for M-
> Scaler
> >>
> >> This patch adds support for M-Scaler (M2M Scaler) device which is a
> >> new device for scaling, blending, color fill  and color space
> >> conversion on EXYNOS5 SoCs.
> >>
> >> This device supports the followings as key feature.
> >>     input image format
> >>         - YCbCr420 2P(UV/VU), 3P
> >>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
> >>         - YCbCr444 2P(UV,VU), 3P
> >>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
> >>         - Pre-multiplexed ARGB8888, L8A8 and L8
> >>     output image format
> >>         - YCbCr420 2P(UV/VU), 3P
> >>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
> >>         - YCbCr444 2P(UV,VU), 3P
> >>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
> >>         - Pre-multiplexed ARGB8888
> >>     input rotation
> >>         - 0/90/180/270 degree, X/Y/XY Flip
> >>     scale ratio
> >>         - 1/4 scale down to 16 scale up
> >>     color space conversion
> >>         - RGB to YUV / YUV to RGB
> >>     Size
> >>         - Input : 16x16 to 8192x8192
> >>         - Output:   4x4 to 8192x8192
> >>     alpha blending, color fill
> >>
> >> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
> >> ---
> >>  drivers/media/platform/exynos-mscl/mscl-regs.c |  318
> >> ++++++++++++++++++++++++
> >>  drivers/media/platform/exynos-mscl/mscl-regs.h |  282
> >> +++++++++++++++++++++
> >>  2 files changed, 600 insertions(+)
> >>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
> >>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h
> >>
> >> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c
> >> b/drivers/media/platform/exynos-mscl/mscl-regs.c
> >> new file mode 100644
> >> index 0000000..9354afc
> >> --- /dev/null
> >> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
> >> @@ -0,0 +1,318 @@
> >> +/*
> >> + * 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/delay.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +#include "mscl-core.h"
> >> +
> >> +void mscl_hw_set_sw_reset(struct mscl_dev *dev)
> >> +{
> >> +     u32 cfg;
> >> +
> >> +     cfg = readl(dev->regs + MSCL_CFG);
> >> +     cfg |= MSCL_CFG_SOFT_RESET;
> >> +
> >> +     writel(cfg, dev->regs + MSCL_CFG);
> >> +}
> >> +
> >> +int mscl_wait_reset(struct mscl_dev *dev)
> >> +{
> >> +     unsigned long end = jiffies + msecs_to_jiffies(50);
> >
> > What does 50 mean?
> >
> >> +     u32 cfg, reset_done = 0;
> >> +
> >
> > Please describe why the below codes are needed.
> 
> 
> As per the Documentation,
> 
> " SOFT RESET: Writing "1" to this bit generates software reset. To
> check the completion of the reset, wait until this
> field becomes zero, then wrie an arbitrary value to any of RW
> registers and read it. If the read data matches the written data,
>  it means SW reset succeeded. Otherwise, repeat write & read until
> matched."
> 
> 
> Thie below code tries to do the same (as per user manual). and in the
> above msec_to_jiffies(50), 50 is the 50msec wait. before
> checking the SOFT RESET is really done.
> 
> Is it good to ignore this checks?
> 

No, I mean that someone may want to understand your codes so leave comments enough for them.

Thanks,
Inki Dae

> 
> 
> >
> >> +     while (time_before(jiffies, end)) {
> >> +             cfg = readl(dev->regs + MSCL_CFG);
> >> +             if (!(cfg & MSCL_CFG_SOFT_RESET)) {
> >> +                     reset_done = 1;
> >> +                     break;
> >> +             }
> >> +             usleep_range(10, 20);
> >> +     }
> >> +
> >> +     /* write any value to r/w reg and read it back */
> >> +     while (reset_done) {
> >> +
> >> +             /* [TBD] need to define number of tries before returning
> >> +              * -EBUSY to the caller
> >> +              */
> >> +
> >> +             writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
> >> +                             dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
> >> +             if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
> >> +                     readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
> >> +                     return 0;
> >> +     }
> >> +
> >> +     return -EBUSY;
> >> +}
> >> +
> >> +void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool
> mask)
> >> +{
> >> +     u32 cfg;
> >> +
> >> +     switch (interrupt) {
> >> +     case MSCL_INT_TIMEOUT:
> >> +     case MSCL_INT_ILLEGAL_BLEND:
> >> +     case MSCL_INT_ILLEGAL_RATIO:
> >> +     case MSCL_INT_ILLEGAL_DST_HEIGHT:
> >> +     case MSCL_INT_ILLEGAL_DST_WIDTH:
> >> +     case MSCL_INT_ILLEGAL_DST_V_POS:
> >> +     case MSCL_INT_ILLEGAL_DST_H_POS:
> >> +     case MSCL_INT_ILLEGAL_DST_C_SPAN:
> >> +     case MSCL_INT_ILLEGAL_DST_Y_SPAN:
> >> +     case MSCL_INT_ILLEGAL_DST_CR_BASE:
> >> +     case MSCL_INT_ILLEGAL_DST_CB_BASE:
> >> +     case MSCL_INT_ILLEGAL_DST_Y_BASE:
> >> +     case MSCL_INT_ILLEGAL_DST_COLOR:
> >> +     case MSCL_INT_ILLEGAL_SRC_HEIGHT:
> >> +     case MSCL_INT_ILLEGAL_SRC_WIDTH:
> >> +     case MSCL_INT_ILLEGAL_SRC_CV_POS:
> >> +     case MSCL_INT_ILLEGAL_SRC_CH_POS:
> >> +     case MSCL_INT_ILLEGAL_SRC_YV_POS:
> >> +     case MSCL_INT_ILLEGAL_SRC_YH_POS:
> >> +     case MSCL_INT_ILLEGAL_SRC_C_SPAN:
> >> +     case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
> >> +     case MSCL_INT_ILLEGAL_SRC_CR_BASE:
> >> +     case MSCL_INT_ILLEGAL_SRC_CB_BASE:
> >> +     case MSCL_INT_ILLEGAL_SRC_Y_BASE:
> >> +     case MSCL_INT_ILLEGAL_SRC_COLOR:
> >> +     case MSCL_INT_FRAME_END:
> >> +             break;
> >> +     default:
> >> +             return;
> >> +     }
> >
> > It seems that the above codes could be more simple,
> 
> 
> ok. will change this.
> 
> 
> >
> >
> >> +     cfg = readl(dev->regs + MSCL_INT_EN);
> >> +     if (mask)
> >> +             cfg |= interrupt;
> >> +     else
> >> +             cfg &= ~interrupt;
> >> +     writel(cfg, dev->regs + MSCL_INT_EN);
> >> +}
> >> +
> >> +void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr
> *addr)
> >> +{
> >> +     dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
> >> +                             addr->y, addr->cb, addr->cr);
> >> +     writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
> >> +     writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
> >> +     writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
> >> +}
> >> +
> >> +void mscl_hw_set_output_addr(struct mscl_dev *dev,
> >> +                          struct mscl_addr *addr)
> >> +{
> >> +     dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
> >> +                             addr->y, addr->cb, addr->cr);
> >> +     writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
> >> +     writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
> >> +     writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
> >> +}
> >> +
> >> +void mscl_hw_set_in_size(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     struct mscl_frame *frame = &ctx->s_frame;
> >> +     u32 cfg;
> >> +
> >> +     /* set input pixel offset */
> >> +     cfg = MSCL_SRC_YH_POS(frame->crop.left);
> >> +     cfg |= MSCL_SRC_YV_POS(frame->crop.top);
> >
> > Where are the limitations to left and top checked?.
> 
> 
> 
> mscl_try_crop() does this checking.
> 
> 
> 
> >
> >> +     writel(cfg, dev->regs + MSCL_SRC_Y_POS);
> >> +
> >> +     /* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset
> >> */
> >> +
> >> +     /* set input span */
> >> +     cfg = MSCL_SRC_Y_SPAN(frame->f_width);
> >> +     if (is_yuv420_2p(frame->fmt))
> >> +             cfg |= MSCL_SRC_C_SPAN(frame->f_width);
> >> +     else
> >> +             cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */
> >> +
> >> +     writel(cfg, dev->regs + MSCL_SRC_SPAN);
> >> +
> >> +     /* Set input cropped size */
> >> +     cfg = MSCL_SRC_WIDTH(frame->crop.width);
> >> +     cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
> >> +     writel(cfg, dev->regs + MSCL_SRC_WH);
> >> +
> >> +     dev_dbg(&dev->pdev->dev,
> >> +             "src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
> >> +             "cropX: %d, cropY: %d\n",
> >> +             frame->crop.left, frame->crop.top, frame->f_width,
> >> +             frame->f_width, frame->crop.width, frame->crop.height);
> >> +}
> >> +
> >> +void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     struct mscl_frame *frame = &ctx->s_frame;
> >> +     u32 cfg;
> >> +
> >> +     cfg = readl(dev->regs + MSCL_SRC_CFG);
> >> +     cfg &= ~MSCL_SRC_COLOR_FORMAT_MASK;
> >> +     cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
> >> +
> >> +     /* setting tile/linear format */
> >> +     if (frame->fmt->is_tiled)
> >> +             cfg |= MSCL_SRC_TILE_EN;
> >> +     else
> >> +             cfg &= ~MSCL_SRC_TILE_EN;
> >> +
> >> +     writel(cfg, dev->regs + MSCL_SRC_CFG);
> >> +}
> >> +
> >> +void mscl_hw_set_out_size(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     struct mscl_frame *frame = &ctx->d_frame;
> >> +     u32 cfg;
> >> +
> >> +     /* set output pixel offset */
> >> +     cfg = MSCL_DST_H_POS(frame->crop.left);
> >> +     cfg |= MSCL_DST_V_POS(frame->crop.top);
> >
> > Ditto.
> >
> >> +     writel(cfg, dev->regs + MSCL_DST_POS);
> >> +
> >> +     /* set output span */
> >> +     cfg = MSCL_DST_Y_SPAN(frame->f_width);
> >> +     if (is_yuv420_2p(frame->fmt))
> >> +             cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
> >> +     else
> >> +             cfg |= MSCL_DST_C_SPAN(frame->f_width);
> >> +     writel(cfg, dev->regs + MSCL_DST_SPAN);
> >> +
> >> +     /* set output scaled size */
> >> +     cfg = MSCL_DST_WIDTH(frame->crop.width);
> >> +     cfg |= MSCL_DST_HEIGHT(frame->crop.height);
> >> +     writel(cfg, dev->regs + MSCL_DST_WH);
> >> +
> >> +     dev_dbg(&dev->pdev->dev,
> >> +             "dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
> >> +             "cropX: %d, cropY: %d\n",
> >> +             frame->crop.left, frame->crop.top, frame->f_width,
> >> +             frame->f_width, frame->crop.width, frame->crop.height);
> >> +}
> >> +
> >> +void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     struct mscl_frame *frame = &ctx->d_frame;
> >> +     u32 cfg;
> >> +
> >> +     cfg = readl(dev->regs + MSCL_DST_CFG);
> >> +     cfg &= ~MSCL_DST_COLOR_FORMAT_MASK;
> >> +     cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);
> >> +
> >> +     writel(cfg, dev->regs + MSCL_DST_CFG);
> >> +}
> >> +
> >> +void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     struct mscl_scaler *sc = &ctx->scaler;
> >> +     u32 cfg;
> >> +
> >> +     cfg = MSCL_H_RATIO_VALUE(sc->hratio);
> >> +     writel(cfg, dev->regs + MSCL_H_RATIO);
> >> +
> >> +     cfg = MSCL_V_RATIO_VALUE(sc->vratio);
> >> +     writel(cfg, dev->regs + MSCL_V_RATIO);
> >> +}
> >> +
> >> +void mscl_hw_set_rotation(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     u32 cfg = 0;
> >> +
> >> +     cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);
> >> +
> >> +     if (ctx->ctrls_mscl.hflip->val)
> >> +             cfg |= MSCL_FLIP_X_EN;
> >> +
> >> +     if (ctx->ctrls_mscl.vflip->val)
> >> +             cfg |= MSCL_FLIP_Y_EN;
> >> +
> >> +     writel(cfg, dev->regs + MSCL_ROT_CFG);
> >> +}
> >> +
> >> +void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +
> >> +     writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);
> >> +}
> >> +
> >> +void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
> >> +{
> >> +     struct mscl_dev *dev = ctx->mscl_dev;
> >> +     enum mscl_csc_coeff type;
> >> +     u32 cfg = 0;
> >> +     int i, j;
> >> +     static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
> >> +             { /* YCbCr to RGB */
> >> +                     {0x200, 0x000, 0x2be},
> >> +                     {0x200, 0xeac, 0x165},
> >> +                     {0x200, 0x377, 0x000}
> >> +             },
> >> +             { /* YCbCr to RGB with -16 offset */
> >> +                     {0x254, 0x000, 0x331},
> >> +                     {0x254, 0xec8, 0xFA0},
> >> +                     {0x254, 0x409, 0x000}
> >> +             },
> >> +             { /* RGB to YCbCr */
> >> +                     {0x099, 0x12d, 0x03a},
> >> +                     {0xe58, 0xeae, 0x106},
> >> +                     {0x106, 0xedb, 0xe2a}
> >> +             },
> >> +             { /* RGB to YCbCr with -16 offset */
> >> +                     {0x084, 0x102, 0x032},
> >> +                     {0xe4c, 0xe95, 0x0e1},
> >> +                     {0x0e1, 0xebc, 0xe24}
> >> +             } };
> >> +
> >> +     if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
> >> +             type = MSCL_CSC_COEFF_NONE;
> >> +     else if (is_rgb(ctx->d_frame.fmt))
> >> +             type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
> >> +     else
> >> +             type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
> >> +
> >> +     if ((type == ctx->mscl_dev->coeff_type) || (type >=
> >> MSCL_CSC_COEFF_MAX))
> >> +             return;
> >> +
> >> +     for (i = 0; i < 3; i++) {
> >> +             for (j = 0; j < 3; j++) {
> >> +                     cfg = csc_coeff[type][i][j];
> >> +                     writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
> >> +             }
> >> +     }
> >> +
> >> +     switch (type) {
> >> +     case MSCL_CSC_COEFF_YCBCR_TO_RGB:
> >
> > Is there this case?
> >
> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
> >
> > And this switch-case could be removed if you move the above line to the
> > above if-sentence.
> >
> >
> >> +             break;
> >> +     case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
> >
> > Ditto.
> >
> >> +             break;
> >> +     case MSCL_CSC_COEFF_RGB_TO_YCBCR:
> >
> > Seems no case.
> >
> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
> >
> > Could be moved to the above if-sentence.
> 
> 
> 
> I think MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16, MSCL_CSC_COEFF_YCBCR_TO_RGB
> belongs to different color spaces.
> Anyways, will remove the unused cases and will reorganize the code as
> per your comments.
> 
> Regards,
> Shaik Ameer Basha
> 
> 
> 
> >
> >> +             break;
> >> +     case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
> >
> > Ditto.
> >
> >> +             break;
> >> +     default:
> >> +             return;
> >> +     }
> >> +
> >> +     ctx->mscl_dev->coeff_type = type;
> >> +     return;
> >> +}
> 
> [snip]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Shaik Ameer Basha Aug. 20, 2013, 8:49 a.m. UTC | #4
On Tue, Aug 20, 2013 at 2:13 PM, Inki Dae <inki.dae@samsung.com> wrote:
>
>
>> -----Original Message-----
>> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
>> owner@vger.kernel.org] On Behalf Of Shaik Ameer Basha
>> Sent: Tuesday, August 20, 2013 5:07 PM
>> To: Inki Dae
>> Cc: Shaik Ameer Basha; LMML; linux-samsung-soc@vger.kernel.org;
>> cpgs@samsung.com; Sylwester Nawrocki; posciak@google.com; Arun Kumar K
>> Subject: Re: [PATCH v2 1/5] [media] exynos-mscl: Add new driver for M-
>> Scaler
>>
>> Hi Inki Dae,
>>
>> Thanks for the review.
>>
>>
>> On Mon, Aug 19, 2013 at 6:18 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> > Just quick review.
>> >
>> >> -----Original Message-----
>> >> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
>> >> owner@vger.kernel.org] On Behalf Of Shaik Ameer Basha
>> >> Sent: Monday, August 19, 2013 7:59 PM
>> >> To: linux-media@vger.kernel.org; linux-samsung-soc@vger.kernel.org
>> >> Cc: s.nawrocki@samsung.com; posciak@google.com; arun.kk@samsung.com;
>> >> shaik.ameer@samsung.com
>> >> Subject: [PATCH v2 1/5] [media] exynos-mscl: Add new driver for M-
>> Scaler
>> >>
>> >> This patch adds support for M-Scaler (M2M Scaler) device which is a
>> >> new device for scaling, blending, color fill  and color space
>> >> conversion on EXYNOS5 SoCs.
>> >>
>> >> This device supports the followings as key feature.
>> >>     input image format
>> >>         - YCbCr420 2P(UV/VU), 3P
>> >>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>> >>         - YCbCr444 2P(UV,VU), 3P
>> >>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>> >>         - Pre-multiplexed ARGB8888, L8A8 and L8
>> >>     output image format
>> >>         - YCbCr420 2P(UV/VU), 3P
>> >>         - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>> >>         - YCbCr444 2P(UV,VU), 3P
>> >>         - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>> >>         - Pre-multiplexed ARGB8888
>> >>     input rotation
>> >>         - 0/90/180/270 degree, X/Y/XY Flip
>> >>     scale ratio
>> >>         - 1/4 scale down to 16 scale up
>> >>     color space conversion
>> >>         - RGB to YUV / YUV to RGB
>> >>     Size
>> >>         - Input : 16x16 to 8192x8192
>> >>         - Output:   4x4 to 8192x8192
>> >>     alpha blending, color fill
>> >>
>> >> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
>> >> ---
>> >>  drivers/media/platform/exynos-mscl/mscl-regs.c |  318
>> >> ++++++++++++++++++++++++
>> >>  drivers/media/platform/exynos-mscl/mscl-regs.h |  282
>> >> +++++++++++++++++++++
>> >>  2 files changed, 600 insertions(+)
>> >>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
>> >>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h
>> >>
>> >> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c
>> >> b/drivers/media/platform/exynos-mscl/mscl-regs.c
>> >> new file mode 100644
>> >> index 0000000..9354afc
>> >> --- /dev/null
>> >> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
>> >> @@ -0,0 +1,318 @@
>> >> +/*
>> >> + * 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/delay.h>
>> >> +#include <linux/platform_device.h>
>> >> +
>> >> +#include "mscl-core.h"
>> >> +
>> >> +void mscl_hw_set_sw_reset(struct mscl_dev *dev)
>> >> +{
>> >> +     u32 cfg;
>> >> +
>> >> +     cfg = readl(dev->regs + MSCL_CFG);
>> >> +     cfg |= MSCL_CFG_SOFT_RESET;
>> >> +
>> >> +     writel(cfg, dev->regs + MSCL_CFG);
>> >> +}
>> >> +
>> >> +int mscl_wait_reset(struct mscl_dev *dev)
>> >> +{
>> >> +     unsigned long end = jiffies + msecs_to_jiffies(50);
>> >
>> > What does 50 mean?
>> >
>> >> +     u32 cfg, reset_done = 0;
>> >> +
>> >
>> > Please describe why the below codes are needed.
>>
>>
>> As per the Documentation,
>>
>> " SOFT RESET: Writing "1" to this bit generates software reset. To
>> check the completion of the reset, wait until this
>> field becomes zero, then wrie an arbitrary value to any of RW
>> registers and read it. If the read data matches the written data,
>>  it means SW reset succeeded. Otherwise, repeat write & read until
>> matched."
>>
>>
>> Thie below code tries to do the same (as per user manual). and in the
>> above msec_to_jiffies(50), 50 is the 50msec wait. before
>> checking the SOFT RESET is really done.
>>
>> Is it good to ignore this checks?
>>
>
> No, I mean that someone may want to understand your codes so leave comments enough for them.


Ok. thanks. I will add more comments. :)

Regards,
Shaik Ameer Basha

>
> Thanks,
> Inki Dae
>
>>
>>
>> >
>> >> +     while (time_before(jiffies, end)) {
>> >> +             cfg = readl(dev->regs + MSCL_CFG);
>> >> +             if (!(cfg & MSCL_CFG_SOFT_RESET)) {
>> >> +                     reset_done = 1;
>> >> +                     break;
>> >> +             }
>> >> +             usleep_range(10, 20);
>> >> +     }
>> >> +
>> >> +     /* write any value to r/w reg and read it back */
>> >> +     while (reset_done) {
>> >> +
>> >> +             /* [TBD] need to define number of tries before returning
>> >> +              * -EBUSY to the caller
>> >> +              */
>> >> +
>> >> +             writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
>> >> +                             dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
>> >> +             if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
>> >> +                     readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
>> >> +                     return 0;
>> >> +     }
>> >> +
>> >> +     return -EBUSY;
>> >> +}
>> >> +
>> >> +void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool
>> mask)
>> >> +{
>> >> +     u32 cfg;
>> >> +
>> >> +     switch (interrupt) {
>> >> +     case MSCL_INT_TIMEOUT:
>> >> +     case MSCL_INT_ILLEGAL_BLEND:
>> >> +     case MSCL_INT_ILLEGAL_RATIO:
>> >> +     case MSCL_INT_ILLEGAL_DST_HEIGHT:
>> >> +     case MSCL_INT_ILLEGAL_DST_WIDTH:
>> >> +     case MSCL_INT_ILLEGAL_DST_V_POS:
>> >> +     case MSCL_INT_ILLEGAL_DST_H_POS:
>> >> +     case MSCL_INT_ILLEGAL_DST_C_SPAN:
>> >> +     case MSCL_INT_ILLEGAL_DST_Y_SPAN:
>> >> +     case MSCL_INT_ILLEGAL_DST_CR_BASE:
>> >> +     case MSCL_INT_ILLEGAL_DST_CB_BASE:
>> >> +     case MSCL_INT_ILLEGAL_DST_Y_BASE:
>> >> +     case MSCL_INT_ILLEGAL_DST_COLOR:
>> >> +     case MSCL_INT_ILLEGAL_SRC_HEIGHT:
>> >> +     case MSCL_INT_ILLEGAL_SRC_WIDTH:
>> >> +     case MSCL_INT_ILLEGAL_SRC_CV_POS:
>> >> +     case MSCL_INT_ILLEGAL_SRC_CH_POS:
>> >> +     case MSCL_INT_ILLEGAL_SRC_YV_POS:
>> >> +     case MSCL_INT_ILLEGAL_SRC_YH_POS:
>> >> +     case MSCL_INT_ILLEGAL_SRC_C_SPAN:
>> >> +     case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
>> >> +     case MSCL_INT_ILLEGAL_SRC_CR_BASE:
>> >> +     case MSCL_INT_ILLEGAL_SRC_CB_BASE:
>> >> +     case MSCL_INT_ILLEGAL_SRC_Y_BASE:
>> >> +     case MSCL_INT_ILLEGAL_SRC_COLOR:
>> >> +     case MSCL_INT_FRAME_END:
>> >> +             break;
>> >> +     default:
>> >> +             return;
>> >> +     }
>> >
>> > It seems that the above codes could be more simple,
>>
>>
>> ok. will change this.
>>
>>
>> >
>> >
>> >> +     cfg = readl(dev->regs + MSCL_INT_EN);
>> >> +     if (mask)
>> >> +             cfg |= interrupt;
>> >> +     else
>> >> +             cfg &= ~interrupt;
>> >> +     writel(cfg, dev->regs + MSCL_INT_EN);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr
>> *addr)
>> >> +{
>> >> +     dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
>> >> +                             addr->y, addr->cb, addr->cr);
>> >> +     writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
>> >> +     writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
>> >> +     writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_output_addr(struct mscl_dev *dev,
>> >> +                          struct mscl_addr *addr)
>> >> +{
>> >> +     dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
>> >> +                             addr->y, addr->cb, addr->cr);
>> >> +     writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
>> >> +     writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
>> >> +     writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_in_size(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     struct mscl_frame *frame = &ctx->s_frame;
>> >> +     u32 cfg;
>> >> +
>> >> +     /* set input pixel offset */
>> >> +     cfg = MSCL_SRC_YH_POS(frame->crop.left);
>> >> +     cfg |= MSCL_SRC_YV_POS(frame->crop.top);
>> >
>> > Where are the limitations to left and top checked?.
>>
>>
>>
>> mscl_try_crop() does this checking.
>>
>>
>>
>> >
>> >> +     writel(cfg, dev->regs + MSCL_SRC_Y_POS);
>> >> +
>> >> +     /* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset
>> >> */
>> >> +
>> >> +     /* set input span */
>> >> +     cfg = MSCL_SRC_Y_SPAN(frame->f_width);
>> >> +     if (is_yuv420_2p(frame->fmt))
>> >> +             cfg |= MSCL_SRC_C_SPAN(frame->f_width);
>> >> +     else
>> >> +             cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */
>> >> +
>> >> +     writel(cfg, dev->regs + MSCL_SRC_SPAN);
>> >> +
>> >> +     /* Set input cropped size */
>> >> +     cfg = MSCL_SRC_WIDTH(frame->crop.width);
>> >> +     cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
>> >> +     writel(cfg, dev->regs + MSCL_SRC_WH);
>> >> +
>> >> +     dev_dbg(&dev->pdev->dev,
>> >> +             "src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
>> >> +             "cropX: %d, cropY: %d\n",
>> >> +             frame->crop.left, frame->crop.top, frame->f_width,
>> >> +             frame->f_width, frame->crop.width, frame->crop.height);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     struct mscl_frame *frame = &ctx->s_frame;
>> >> +     u32 cfg;
>> >> +
>> >> +     cfg = readl(dev->regs + MSCL_SRC_CFG);
>> >> +     cfg &= ~MSCL_SRC_COLOR_FORMAT_MASK;
>> >> +     cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
>> >> +
>> >> +     /* setting tile/linear format */
>> >> +     if (frame->fmt->is_tiled)
>> >> +             cfg |= MSCL_SRC_TILE_EN;
>> >> +     else
>> >> +             cfg &= ~MSCL_SRC_TILE_EN;
>> >> +
>> >> +     writel(cfg, dev->regs + MSCL_SRC_CFG);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_out_size(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     struct mscl_frame *frame = &ctx->d_frame;
>> >> +     u32 cfg;
>> >> +
>> >> +     /* set output pixel offset */
>> >> +     cfg = MSCL_DST_H_POS(frame->crop.left);
>> >> +     cfg |= MSCL_DST_V_POS(frame->crop.top);
>> >
>> > Ditto.
>> >
>> >> +     writel(cfg, dev->regs + MSCL_DST_POS);
>> >> +
>> >> +     /* set output span */
>> >> +     cfg = MSCL_DST_Y_SPAN(frame->f_width);
>> >> +     if (is_yuv420_2p(frame->fmt))
>> >> +             cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
>> >> +     else
>> >> +             cfg |= MSCL_DST_C_SPAN(frame->f_width);
>> >> +     writel(cfg, dev->regs + MSCL_DST_SPAN);
>> >> +
>> >> +     /* set output scaled size */
>> >> +     cfg = MSCL_DST_WIDTH(frame->crop.width);
>> >> +     cfg |= MSCL_DST_HEIGHT(frame->crop.height);
>> >> +     writel(cfg, dev->regs + MSCL_DST_WH);
>> >> +
>> >> +     dev_dbg(&dev->pdev->dev,
>> >> +             "dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
>> >> +             "cropX: %d, cropY: %d\n",
>> >> +             frame->crop.left, frame->crop.top, frame->f_width,
>> >> +             frame->f_width, frame->crop.width, frame->crop.height);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     struct mscl_frame *frame = &ctx->d_frame;
>> >> +     u32 cfg;
>> >> +
>> >> +     cfg = readl(dev->regs + MSCL_DST_CFG);
>> >> +     cfg &= ~MSCL_DST_COLOR_FORMAT_MASK;
>> >> +     cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);
>> >> +
>> >> +     writel(cfg, dev->regs + MSCL_DST_CFG);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     struct mscl_scaler *sc = &ctx->scaler;
>> >> +     u32 cfg;
>> >> +
>> >> +     cfg = MSCL_H_RATIO_VALUE(sc->hratio);
>> >> +     writel(cfg, dev->regs + MSCL_H_RATIO);
>> >> +
>> >> +     cfg = MSCL_V_RATIO_VALUE(sc->vratio);
>> >> +     writel(cfg, dev->regs + MSCL_V_RATIO);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_rotation(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     u32 cfg = 0;
>> >> +
>> >> +     cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);
>> >> +
>> >> +     if (ctx->ctrls_mscl.hflip->val)
>> >> +             cfg |= MSCL_FLIP_X_EN;
>> >> +
>> >> +     if (ctx->ctrls_mscl.vflip->val)
>> >> +             cfg |= MSCL_FLIP_Y_EN;
>> >> +
>> >> +     writel(cfg, dev->regs + MSCL_ROT_CFG);
>> >> +}
>> >> +
>> >> +void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +
>> >> +     writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);
>> >> +}
>> >> +
>> >> +void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
>> >> +{
>> >> +     struct mscl_dev *dev = ctx->mscl_dev;
>> >> +     enum mscl_csc_coeff type;
>> >> +     u32 cfg = 0;
>> >> +     int i, j;
>> >> +     static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
>> >> +             { /* YCbCr to RGB */
>> >> +                     {0x200, 0x000, 0x2be},
>> >> +                     {0x200, 0xeac, 0x165},
>> >> +                     {0x200, 0x377, 0x000}
>> >> +             },
>> >> +             { /* YCbCr to RGB with -16 offset */
>> >> +                     {0x254, 0x000, 0x331},
>> >> +                     {0x254, 0xec8, 0xFA0},
>> >> +                     {0x254, 0x409, 0x000}
>> >> +             },
>> >> +             { /* RGB to YCbCr */
>> >> +                     {0x099, 0x12d, 0x03a},
>> >> +                     {0xe58, 0xeae, 0x106},
>> >> +                     {0x106, 0xedb, 0xe2a}
>> >> +             },
>> >> +             { /* RGB to YCbCr with -16 offset */
>> >> +                     {0x084, 0x102, 0x032},
>> >> +                     {0xe4c, 0xe95, 0x0e1},
>> >> +                     {0x0e1, 0xebc, 0xe24}
>> >> +             } };
>> >> +
>> >> +     if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
>> >> +             type = MSCL_CSC_COEFF_NONE;
>> >> +     else if (is_rgb(ctx->d_frame.fmt))
>> >> +             type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
>> >> +     else
>> >> +             type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
>> >> +
>> >> +     if ((type == ctx->mscl_dev->coeff_type) || (type >=
>> >> MSCL_CSC_COEFF_MAX))
>> >> +             return;
>> >> +
>> >> +     for (i = 0; i < 3; i++) {
>> >> +             for (j = 0; j < 3; j++) {
>> >> +                     cfg = csc_coeff[type][i][j];
>> >> +                     writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
>> >> +             }
>> >> +     }
>> >> +
>> >> +     switch (type) {
>> >> +     case MSCL_CSC_COEFF_YCBCR_TO_RGB:
>> >
>> > Is there this case?
>> >
>> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
>> >
>> > And this switch-case could be removed if you move the above line to the
>> > above if-sentence.
>> >
>> >
>> >> +             break;
>> >> +     case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
>> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
>> >
>> > Ditto.
>> >
>> >> +             break;
>> >> +     case MSCL_CSC_COEFF_RGB_TO_YCBCR:
>> >
>> > Seems no case.
>> >
>> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
>> >
>> > Could be moved to the above if-sentence.
>>
>>
>>
>> I think MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16, MSCL_CSC_COEFF_YCBCR_TO_RGB
>> belongs to different color spaces.
>> Anyways, will remove the unused cases and will reorganize the code as
>> per your comments.
>>
>> Regards,
>> Shaik Ameer Basha
>>
>>
>>
>> >
>> >> +             break;
>> >> +     case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
>> >> +             mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
>> >
>> > Ditto.
>> >
>> >> +             break;
>> >> +     default:
>> >> +             return;
>> >> +     }
>> >> +
>> >> +     ctx->mscl_dev->coeff_type = type;
>> >> +     return;
>> >> +}
>>
>> [snip]
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sylwester Nawrocki Aug. 26, 2013, 8:45 p.m. UTC | #5
On 08/19/2013 12:58 PM, Shaik Ameer Basha wrote:
> This patch adds support for M-Scaler (M2M Scaler) device which is a
> new device for scaling, blending, color fill  and color space
> conversion on EXYNOS5 SoCs.
>
> This device supports the followings as key feature.
>      input image format
>          - YCbCr420 2P(UV/VU), 3P
>          - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>          - YCbCr444 2P(UV,VU), 3P
>          - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>          - Pre-multiplexed ARGB8888, L8A8 and L8
>      output image format
>          - YCbCr420 2P(UV/VU), 3P
>          - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
>          - YCbCr444 2P(UV,VU), 3P
>          - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
>          - Pre-multiplexed ARGB8888
>      input rotation
>          - 0/90/180/270 degree, X/Y/XY Flip
>      scale ratio
>          - 1/4 scale down to 16 scale up
>      color space conversion
>          - RGB to YUV / YUV to RGB
>      Size
>          - Input : 16x16 to 8192x8192
>          - Output:   4x4 to 8192x8192
>      alpha blending, color fill

We don't have good support for alpha blending in v4l2. For example, the
s5p-g2d v4l2 driver only supports a subset of features of the device.
The G2D IP is probably better utilized through the exynos drm driver.

It might be a matter of designing proper controls though for such devices
that generate image by blending data from the output and capture buffers.

> Signed-off-by: Shaik Ameer Basha<shaik.ameer@samsung.com>
> ---
>   drivers/media/platform/exynos-mscl/mscl-regs.c |  318 ++++++++++++++++++++++++
>   drivers/media/platform/exynos-mscl/mscl-regs.h |  282 +++++++++++++++++++++

Shouldn't we call this driver exynos5-scaler and this files would be
renamed to drivers/media/platform/exynos5-scaler/scaler-regs.[ch].

Or maybe put maybe put the SCALER, G-SCALER drivers into common exynos5-is
directory ? I don't have strong preference. But we planned gscaler to be
moved into the exynos5-is directory.

>   2 files changed, 600 insertions(+)
>   create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
>   create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h
>
> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c b/drivers/media/platform/exynos-mscl/mscl-regs.c
> new file mode 100644
> index 0000000..9354afc
> --- /dev/null
> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
> @@ -0,0 +1,318 @@
> +/*
> + * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.

Just make it 2013 ? I think we can manage to merge this diver this year :)

> + *		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.

Are you sure you want to have this "or (at your option) any later version"
clause ?

> + */
> +
> +#include<linux/delay.h>
> +#include<linux/platform_device.h>
> +
> +#include "mscl-core.h"

How about defining register access helpers like:

u32 mscl_read(struct mscl_dev *dev, u32 offset)
{
	readl(dev->regs + offset);
}

void mscl_write(struct mscl_dev *dev, u32 offset, u32 value)
{
	writel(value, dev->regs + offset);
}

perhaps as static inline in mscl-regs.h ?

> +void mscl_hw_set_sw_reset(struct mscl_dev *dev)
> +{
> +	u32 cfg;
> +
> +	cfg = readl(dev->regs + MSCL_CFG);
> +	cfg |= MSCL_CFG_SOFT_RESET;
> +
> +	writel(cfg, dev->regs + MSCL_CFG);
> +}
> +
> +int mscl_wait_reset(struct mscl_dev *dev)
> +{
> +	unsigned long end = jiffies + msecs_to_jiffies(50);

Don't you want a #define for this timeout ?

> +	u32 cfg, reset_done = 0;
> +
> +	while (time_before(jiffies, end)) {
> +		cfg = readl(dev->regs + MSCL_CFG);
> +		if (!(cfg&  MSCL_CFG_SOFT_RESET)) {
> +			reset_done = 1;
> +			break;
> +		}
> +		usleep_range(10, 20);
> +	}
> +
> +	/* write any value to r/w reg and read it back */
> +	while (reset_done) {
> +
> +		/* [TBD] need to define number of tries before returning
> +		 * -EBUSY to the caller
> +		 */

CodingStyle: wrong multi-line comment style

> +		writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
> +				dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
> +		if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
> +			readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
> +			return 0;
> +	}
> +
> +	return -EBUSY;
> +}
> +
> +void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool mask)
> +{
> +	u32 cfg;
> +
> +	switch (interrupt) {
> +	case MSCL_INT_TIMEOUT:
> +	case MSCL_INT_ILLEGAL_BLEND:
> +	case MSCL_INT_ILLEGAL_RATIO:
> +	case MSCL_INT_ILLEGAL_DST_HEIGHT:
> +	case MSCL_INT_ILLEGAL_DST_WIDTH:
> +	case MSCL_INT_ILLEGAL_DST_V_POS:
> +	case MSCL_INT_ILLEGAL_DST_H_POS:
> +	case MSCL_INT_ILLEGAL_DST_C_SPAN:
> +	case MSCL_INT_ILLEGAL_DST_Y_SPAN:
> +	case MSCL_INT_ILLEGAL_DST_CR_BASE:
> +	case MSCL_INT_ILLEGAL_DST_CB_BASE:
> +	case MSCL_INT_ILLEGAL_DST_Y_BASE:
> +	case MSCL_INT_ILLEGAL_DST_COLOR:
> +	case MSCL_INT_ILLEGAL_SRC_HEIGHT:
> +	case MSCL_INT_ILLEGAL_SRC_WIDTH:
> +	case MSCL_INT_ILLEGAL_SRC_CV_POS:
> +	case MSCL_INT_ILLEGAL_SRC_CH_POS:
> +	case MSCL_INT_ILLEGAL_SRC_YV_POS:
> +	case MSCL_INT_ILLEGAL_SRC_YH_POS:
> +	case MSCL_INT_ILLEGAL_SRC_C_SPAN:
> +	case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
> +	case MSCL_INT_ILLEGAL_SRC_CR_BASE:
> +	case MSCL_INT_ILLEGAL_SRC_CB_BASE:
> +	case MSCL_INT_ILLEGAL_SRC_Y_BASE:
> +	case MSCL_INT_ILLEGAL_SRC_COLOR:
> +	case MSCL_INT_FRAME_END:

What if more than one of those flag is set in 'interrupt' argument ?
You probably want to add a single macro definition for all the above
bits.

> +		break;
> +	default:
> +		return;
> +	}
> +	cfg = readl(dev->regs + MSCL_INT_EN);
> +	if (mask)
> +		cfg |= interrupt;
> +	else
> +		cfg&= ~interrupt;
> +	writel(cfg, dev->regs + MSCL_INT_EN);
> +}
> +
> +void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr *addr)
> +{
> +	dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
> +				addr->y, addr->cb, addr->cr);

Hmm, perhaps add a macro to simply these dev_dbg() calls, e.g.

#define mscl_dbg(_dev, fmt, args...) dev_dbg(&_dev->pdev->dev, fmt, ##args)

?
> +	writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
> +	writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
> +	writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
> +}
> +
> +void mscl_hw_set_output_addr(struct mscl_dev *dev,
> +			     struct mscl_addr *addr)
> +{
> +	dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
> +				addr->y, addr->cb, addr->cr);
> +	writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
> +	writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
> +	writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
> +}
> +
> +void mscl_hw_set_in_size(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame =&ctx->s_frame;
> +	u32 cfg;
> +
> +	/* set input pixel offset */
> +	cfg = MSCL_SRC_YH_POS(frame->crop.left);
> +	cfg |= MSCL_SRC_YV_POS(frame->crop.top);
> +	writel(cfg, dev->regs + MSCL_SRC_Y_POS);
> +
> +	/* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset */
> +
> +	/* set input span */
> +	cfg = MSCL_SRC_Y_SPAN(frame->f_width);
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= MSCL_SRC_C_SPAN(frame->f_width);
> +	else
> +		cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */

s/[TBD]/TODO: ?

> +	writel(cfg, dev->regs + MSCL_SRC_SPAN);
> +
> +	/* Set input cropped size */
> +	cfg = MSCL_SRC_WIDTH(frame->crop.width);
> +	cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
> +	writel(cfg, dev->regs + MSCL_SRC_WH);
> +
> +	dev_dbg(&dev->pdev->dev,
> +		"src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
> +		"cropX: %d, cropY: %d\n",
> +		frame->crop.left, frame->crop.top, frame->f_width,
> +		frame->f_width, frame->crop.width, frame->crop.height);
> +}
> +
> +void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame =&ctx->s_frame;
> +	u32 cfg;
> +
> +	cfg = readl(dev->regs + MSCL_SRC_CFG);
> +	cfg&= ~MSCL_SRC_COLOR_FORMAT_MASK;
> +	cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
> +
> +	/* setting tile/linear format */

s/tile/tiled ?

> +	if (frame->fmt->is_tiled)
> +		cfg |= MSCL_SRC_TILE_EN;
> +	else
> +		cfg&= ~MSCL_SRC_TILE_EN;
> +
> +	writel(cfg, dev->regs + MSCL_SRC_CFG);
> +}
> +
> +void mscl_hw_set_out_size(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame =&ctx->d_frame;
> +	u32 cfg;
> +
> +	/* set output pixel offset */
> +	cfg = MSCL_DST_H_POS(frame->crop.left);
> +	cfg |= MSCL_DST_V_POS(frame->crop.top);

I personally find this kind of macros rather confusing - it's not clear
whether they prepare a value to be applied to a register or extract some
property from a value read from the register. I would suggest open coding
this with proper shifts and only #defined masks. But it's up to you,
I personally find such a coding style a bit disturbing :)

> +	writel(cfg, dev->regs + MSCL_DST_POS);
> +
> +	/* set output span */
> +	cfg = MSCL_DST_Y_SPAN(frame->f_width);
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
> +	else
> +		cfg |= MSCL_DST_C_SPAN(frame->f_width);
> +	writel(cfg, dev->regs + MSCL_DST_SPAN);
> +
> +	/* set output scaled size */
> +	cfg = MSCL_DST_WIDTH(frame->crop.width);
> +	cfg |= MSCL_DST_HEIGHT(frame->crop.height);
> +	writel(cfg, dev->regs + MSCL_DST_WH);
> +
> +	dev_dbg(&dev->pdev->dev,
> +		"dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
> +		"cropX: %d, cropY: %d\n",

		"DST: pos X: %d, pos Y: %d, span Y: %d, span C: %d, "
		"crop X: %d, crop Y: %d\n",

?
> +		frame->crop.left, frame->crop.top, frame->f_width,
> +		frame->f_width, frame->crop.width, frame->crop.height);
> +}
> +
> +void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_frame *frame =&ctx->d_frame;
> +	u32 cfg;
> +
> +	cfg = readl(dev->regs + MSCL_DST_CFG);
> +	cfg&= ~MSCL_DST_COLOR_FORMAT_MASK;
> +	cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);

This kind of macros really obfuscate code, this could be simply written as:

	cfg |= (frame->fmt->mscl_color & MSCL_DST_COLOR_FORMAT_MASK);

And these macros are usually used only in single place and IMHO they
aren't horribly helpful.

> +
> +	writel(cfg, dev->regs + MSCL_DST_CFG);
> +}
> +
> +void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	struct mscl_scaler *sc =&ctx->scaler;
> +	u32 cfg;
> +
> +	cfg = MSCL_H_RATIO_VALUE(sc->hratio);
> +	writel(cfg, dev->regs + MSCL_H_RATIO);
> +
> +	cfg = MSCL_V_RATIO_VALUE(sc->vratio);
> +	writel(cfg, dev->regs + MSCL_V_RATIO);
> +}
> +
> +void mscl_hw_set_rotation(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	u32 cfg = 0;
> +
> +	cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);

nit: missing spaces around '/'

> +	if (ctx->ctrls_mscl.hflip->val)
> +		cfg |= MSCL_FLIP_X_EN;
> +
> +	if (ctx->ctrls_mscl.vflip->val)
> +		cfg |= MSCL_FLIP_Y_EN;
> +
> +	writel(cfg, dev->regs + MSCL_ROT_CFG);
> +}
> +
> +void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +
> +	writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);

With mscl_write() (or scaler_write()) this would become a one-liner
and could be moved to the .h file.

> +}
> +
> +void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
> +{
> +	struct mscl_dev *dev = ctx->mscl_dev;
> +	enum mscl_csc_coeff type;
> +	u32 cfg = 0;
> +	int i, j;
> +	static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
> +		{ /* YCbCr to RGB */
> +			{0x200, 0x000, 0x2be},
> +			{0x200, 0xeac, 0x165},
> +			{0x200, 0x377, 0x000}
> +		},
> +		{ /* YCbCr to RGB with -16 offset */
> +			{0x254, 0x000, 0x331},
> +			{0x254, 0xec8, 0xFA0},

nit: please use lower case for hexadecimal numbers consistently.

> +			{0x254, 0x409, 0x000}
> +		},
> +		{ /* RGB to YCbCr */
> +			{0x099, 0x12d, 0x03a},
> +			{0xe58, 0xeae, 0x106},
> +			{0x106, 0xedb, 0xe2a}
> +		},
> +		{ /* RGB to YCbCr with -16 offset */
> +			{0x084, 0x102, 0x032},
> +			{0xe4c, 0xe95, 0x0e1},
> +			{0x0e1, 0xebc, 0xe24}
> +		} };
> +
> +	if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
> +		type = MSCL_CSC_COEFF_NONE;
> +	else if (is_rgb(ctx->d_frame.fmt))
> +		type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
> +	else
> +		type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
> +
> +	if ((type == ctx->mscl_dev->coeff_type) || (type>= MSCL_CSC_COEFF_MAX))

nit: superfluous braces

> +		return;
> +
> +	for (i = 0; i<  3; i++) {
> +		for (j = 0; j<  3; j++) {
> +			cfg = csc_coeff[type][i][j];
> +			writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
> +		}
> +	}
> +
> +	switch (type) {
> +	case MSCL_CSC_COEFF_YCBCR_TO_RGB:
> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
> +		break;
> +	case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
> +		break;
> +	case MSCL_CSC_COEFF_RGB_TO_YCBCR:
> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
> +		break;
> +	case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
> +		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	ctx->mscl_dev->coeff_type = type;
> +	return;

This could be removed.

> +}
> diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.h b/drivers/media/platform/exynos-mscl/mscl-regs.h
> new file mode 100644
> index 0000000..02e2294d
> --- /dev/null
> +++ b/drivers/media/platform/exynos-mscl/mscl-regs.h
> @@ -0,0 +1,282 @@
> +/*
> + * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Register definition file for Samsung 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 version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef REGS_MSCL_H_
> +#define REGS_MSCL_H_
> +
> +/* m2m-scaler status */

nit: perhaps use M-Scaler (or SCALER) name consistently, or omit m2m-scaler
since all these registers are for the SCALER only ?

> +#define MSCL_STATUS				0x00
> +#define MSCL_STATUS_RUNNING			(1<<  1)
> +#define MSCL_STATUS_READY_CLK_DOWN		(1<<  0)
> +
> +/* m2m-scaler config */
> +#define MSCL_CFG				0x04
> +#define MSCL_CFG_FILL_EN			(1<<  24)
> +#define MSCL_CFG_BLEND_CLR_DIV_ALPHA_EN		(1<<  17)
> +#define MSCL_CFG_BLEND_EN			(1<<  16)
> +#define MSCL_CFG_CSC_Y_OFFSET_SRC_EN		(1<<  10)
> +#define MSCL_CFG_CSC_Y_OFFSET_DST_EN		(1<<  9)
> +#define MSCL_CFG_16_BURST_MODE			(1<<  8)
> +#define MSCL_CFG_SOFT_RESET			(1<<  1)
> +#define MSCL_CFG_START_CMD			(1<<  0)
> +
> +/* m2m-scaler interrupt enable */
> +#define MSCL_INT_EN				0x08
> +#define MSCL_INT_EN_DEFAULT			0x81ffffff
> +#define MSCL_INT_EN_TIMEOUT			(1<<  31)
> +#define MSCL_INT_EN_ILLEGAL_BLEND		(1<<  24)
> +#define MSCL_INT_EN_ILLEGAL_RATIO		(1<<  23)
> +#define MSCL_INT_EN_ILLEGAL_DST_HEIGHT		(1<<  22)
> +#define MSCL_INT_EN_ILLEGAL_DST_WIDTH		(1<<  21)
> +#define MSCL_INT_EN_ILLEGAL_DST_V_POS		(1<<  20)
> +#define MSCL_INT_EN_ILLEGAL_DST_H_POS		(1<<  19)
> +#define MSCL_INT_EN_ILLEGAL_DST_C_SPAN		(1<<  18)
> +#define MSCL_INT_EN_ILLEGAL_DST_Y_SPAN		(1<<  17)
> +#define MSCL_INT_EN_ILLEGAL_DST_CR_BASE		(1<<  16)
> +#define MSCL_INT_EN_ILLEGAL_DST_CB_BASE		(1<<  15)
> +#define MSCL_INT_EN_ILLEGAL_DST_Y_BASE		(1<<  14)
> +#define MSCL_INT_EN_ILLEGAL_DST_COLOR		(1<<  13)
> +#define MSCL_INT_EN_ILLEGAL_SRC_HEIGHT		(1<<  12)
> +#define MSCL_INT_EN_ILLEGAL_SRC_WIDTH		(1<<  11)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CV_POS		(1<<  10)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CH_POS		(1<<  9)
> +#define MSCL_INT_EN_ILLEGAL_SRC_YV_POS		(1<<  8)
> +#define MSCL_INT_EN_ILLEGAL_SRC_YH_POS		(1<<  7)
> +#define MSCL_INT_EN_ILLEGAL_SRC_C_SPAN		(1<<  6)
> +#define MSCL_INT_EN_ILLEGAL_SRC_Y_SPAN		(1<<  5)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CR_BASE		(1<<  4)
> +#define MSCL_INT_EN_ILLEGAL_SRC_CB_BASE		(1<<  3)
> +#define MSCL_INT_EN_ILLEGAL_SRC_Y_BASE		(1<<  2)
> +#define MSCL_INT_EN_ILLEGAL_SRC_COLOR		(1<<  1)
> +#define MSCL_INT_EN_FRAME_END			(1<<  0)
> +
> +/* m2m-scaler interrupt status */
> +#define MSCL_INT_STATUS				0x0c

> +#define MSCL_INT_STATUS_CLEAR			(0xffffffff)
> +#define MSCL_INT_STATUS_ERROR			(0x81fffffe)

nit: Superfluous braces

> +#define MSCL_INT_STATUS_TIMEOUT			(1<<  31)
> +#define MSCL_INT_STATUS_ILLEGAL_BLEND		(1<<  24)
> +#define MSCL_INT_STATUS_ILLEGAL_RATIO		(1<<  23)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_HEIGHT	(1<<  22)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_WIDTH	(1<<  21)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_V_POS	(1<<  20)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_H_POS	(1<<  19)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_C_SPAN	(1<<  18)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_Y_SPAN	(1<<  17)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_CR_BASE	(1<<  16)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_CB_BASE	(1<<  15)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_Y_BASE	(1<<  14)
> +#define MSCL_INT_STATUS_ILLEGAL_DST_COLOR	(1<<  13)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_HEIGHT	(1<<  12)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_WIDTH	(1<<  11)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CV_POS	(1<<  10)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CH_POS	(1<<  9)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_YV_POS	(1<<  8)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_YH_POS	(1<<  7)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_C_SPAN	(1<<  6)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_SPAN	(1<<  5)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CR_BASE	(1<<  4)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_CB_BASE	(1<<  3)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_BASE	(1<<  2)
> +#define MSCL_INT_STATUS_ILLEGAL_SRC_COLOR	(1<<  1)
> +#define MSCL_INT_STATUS_FRAME_END		(1<<  0)
> +
> +/* m2m-scaler source format configuration */
> +#define MSCL_SRC_CFG				0x10
> +#define MSCL_SRC_TILE_EN			(0x1<<  10)
> +#define MSCL_SRC_BYTE_SWAP_MASK			(0x3<<  5)
> +#define MSCL_SRC_BYTE_SWAP(x)			(((x)&  0x3)<<  5)
> +#define MSCL_SRC_COLOR_FORMAT_MASK		(0xf<<  0)
> +#define MSCL_SRC_COLOR_FORMAT(x)		(((x)&  0xf)<<  0)

((x) & 0xf) ?

> +
> +/* m2m-scaler source y-base */
> +#define MSCL_SRC_Y_BASE				0x14
> +
> +/* m2m-scaler source cb-base */
> +#define MSCL_SRC_CB_BASE			0x18
> +
> +/* m2m-scaler source cr-base */
> +#define MSCL_SRC_CR_BASE			0x294
> +
> +/* m2m-scaler source span */
> +#define MSCL_SRC_SPAN				0x1c
> +#define MSCL_SRC_C_SPAN_MASK			(0x3fff<<  16)
> +#define MSCL_SRC_C_SPAN(x)			(((x)&  0x3fff)<<  16)
> +#define MSCL_SRC_Y_SPAN_MASK			(0x3fff<<  0)
> +#define MSCL_SRC_Y_SPAN(x)			(((x)&  0x3fff)<<  0)

((x) & 0x3fff) ? And there is couple more occurences like this.

> +/* m2m-scaler source y-position */
> +#define MSCL_SRC_Y_POS				0x20
> +#define MSCL_SRC_YH_POS_MASK			(0xffff<<  (16 + 2))
> +#define MSCL_SRC_YH_POS(x)			(((x)&  0xffff)<<  (16 + 2))
> +#define MSCL_SRC_YV_POS_MASK			(0xffff<<  (0 + 2))
> +#define MSCL_SRC_YV_POS(x)			(((x)&  0xffff)<<  (0 + 2))
> +
> +/* m2m-scaler source width/height */
> +#define MSCL_SRC_WH				0x24
> +#define MSCL_SRC_WIDTH_MASK			(0x3fff<<  16)
> +#define MSCL_SRC_WIDTH(x)			(((x)&  0x3fff)<<  16)
> +#define MSCL_SRC_HEIGHT_MASK			(0x3fff<<  0)
> +#define MSCL_SRC_HEIGHT(x)			(((x)&  0x3fff)<<  0)

> +/* m2m-scaler source c-position */
> +#define MSCL_SRC_C_POS				0x28
> +#define MSCL_SRC_CH_POS_MASK			(0xffff<<  (16 + 2))
> +#define MSCL_SRC_CH_POS(x)			(((x)&  0xffff)<<  (16 + 2))
> +#define MSCL_SRC_CV_POS_MASK			(0xffff<<  (0 + 2))
> +#define MSCL_SRC_CV_POS(x)			(((x)&  0xffff)<<  (0 + 2))
> +
> +/* m2m-scaler destination format configuration */
> +#define MSCL_DST_CFG				0x30
> +#define MSCL_DST_BYTE_SWAP_MASK			(0x3<<  5)
> +#define MSCL_DST_BYTE_SWAP(x)			(((x)&  0x3)<<  5)
> +#define MSCL_DST_COLOR_FORMAT_MASK		(0xf<<  0)

Is just 0xf, using zero shits like this for me just makes it harder
to read.

> +#define MSCL_DST_COLOR_FORMAT(x)		(((x)&  0xf)<<  0)
> +
> +/* m2m-scaler destination y-base */
> +#define MSCL_DST_Y_BASE				0x34
> +
> +/* m2m-scaler destination cb-base */
> +#define MSCL_DST_CB_BASE			0x38
> +
> +/* m2m-scaler destination cr-base */
> +#define MSCL_DST_CR_BASE			0x298
> +
> +/* m2m-scaler destination span */
> +#define MSCL_DST_SPAN				0x3c
> +#define MSCL_DST_C_SPAN_MASK			(0x3fff<<  16)
> +#define MSCL_DST_C_SPAN(x)			(((x)&  0x3fff)<<  16)
> +#define MSCL_DST_Y_SPAN_MASK			(0x3fff<<  0)
> +#define MSCL_DST_Y_SPAN(x)			(((x)&  0x3fff)<<  0)
> +
> +/* m2m-scaler destination width/height */
> +#define MSCL_DST_WH				0x40
> +#define MSCL_DST_WIDTH_MASK			(0x3fff<<  16)
> +#define MSCL_DST_WIDTH(x)			(((x)&  0x3fff)<<  16)
> +#define MSCL_DST_HEIGHT_MASK			(0x3fff<<  0)
> +#define MSCL_DST_HEIGHT(x)			(((x)&  0x3fff)<<  0)
> +
> +/* m2m-scaler destination position */
> +#define MSCL_DST_POS				0x44
> +#define MSCL_DST_H_POS_MASK			(0x3fff<<  16)
> +#define MSCL_DST_H_POS(x)			(((x)&  0x3fff)<<  16)
> +#define MSCL_DST_V_POS_MASK			(0x3fff<<  0)
> +#define MSCL_DST_V_POS(x)			(((x)&  0x3fff)<<  0)
> +
> +/* m2m-scaler horizontal scale ratio */
> +#define MSCL_H_RATIO				0x50
> +#define MSCL_H_RATIO_VALUE(x)			(((x)&  0x7ffff)<<  0)
> +
> +/* m2m-scaler vertical scale ratio */
> +#define MSCL_V_RATIO				0x54
> +#define MSCL_V_RATIO_VALUE(x)			(((x)&  0x7ffff)<<  0)
> +
> +/* m2m-scaler rotation config */
> +#define MSCL_ROT_CFG				0x58
> +#define MSCL_FLIP_X_EN				(1<<  3)
> +#define MSCL_FLIP_Y_EN				(1<<  2)
> +#define MSCL_ROTMODE_MASK			(0x3<<  0)
> +#define MSCL_ROTMODE(x)				(((x)&  0x3)<<  0)
> +
> +/* m2m-scaler csc coefficients */

> +#define MSCL_CSC_COEF_00			0x220
> +#define MSCL_CSC_COEF_10			0x224
> +#define MSCL_CSC_COEF_20			0x228
> +#define MSCL_CSC_COEF_01			0x22C
> +#define MSCL_CSC_COEF_11			0x230
> +#define MSCL_CSC_COEF_21			0x234
> +#define MSCL_CSC_COEF_02			0x238
> +#define MSCL_CSC_COEF_12			0x23C
> +#define MSCL_CSC_COEF_22			0x240

Why are these needed when below there is a common macro ?

> +#define MSCL_CSC_COEF(x, y)			(0x220 + ((x * 12) + (y * 4)))

> +/* m2m-scaler dither config */
> +#define MSCL_DITH_CFG				0x250
> +#define MSCL_DITHER_R_TYPE_MASK			(0x7<<  6)
> +#define MSCL_DITHER_R_TYPE(x)			(((x)&  0x7)<<  6)
> +#define MSCL_DITHER_G_TYPE_MASK			(0x7<<  3)
> +#define MSCL_DITHER_G_TYPE(x)			(((x)&  0x7)<<  3)
> +#define MSCL_DITHER_B_TYPE_MASK			(0x7<<  0)
> +#define MSCL_DITHER_B_TYPE(x)			(((x)&  0x7)<<  0)
> +
> +/* m2m-scaler src blend color */
> +#define MSCL_SRC_BLEND_COLOR			0x280
> +#define MSCL_SRC_COLOR_SEL_INV			(1<<  31)
> +#define MSCL_SRC_COLOR_SEL_MASK			(0x3<<  29)
> +#define MSCL_SRC_COLOR_SEL(x)			(((x)&  0x3)<<  29)
> +#define MSCL_SRC_COLOR_OP_SEL_INV		(1<<  28)
> +#define MSCL_SRC_COLOR_OP_SEL_MASK		(0xf<<  24)
> +#define MSCL_SRC_COLOR_OP_SEL(x)		(((x)&  0xf)<<  24)
> +#define MSCL_SRC_GLOBAL_COLOR0_MASK		(0xff<<  16)
> +#define MSCL_SRC_GLOBAL_COLOR0(x)		(((x)&  0xff)<<  16)
> +#define MSCL_SRC_GLOBAL_COLOR1_MASK		(0xff<<  8)
> +#define MSCL_SRC_GLOBAL_COLOR1(x)		(((x)&  0xff)<<  8)
> +#define MSCL_SRC_GLOBAL_COLOR2_MASK		(0xff<<  0)
> +#define MSCL_SRC_GLOBAL_COLOR2(x)		(((x)&  0xff)<<  0)
> +
> +/* m2m-scaler src blend alpha */
> +#define MSCL_SRC_BLEND_ALPHA			0x284
> +#define MSCL_SRC_ALPHA_SEL_INV			(1<<  31)
> +#define MSCL_SRC_ALPHA_SEL_MASK			(0x3<<  29)
> +#define MSCL_SRC_ALPHA_SEL(x)			(((x)&  0x3)<<  29)
> +#define MSCL_SRC_ALPHA_OP_SEL_INV		(1<<  28)
> +#define MSCL_SRC_ALPHA_OP_SEL_MASK		(0xf<<  24)
> +#define MSCL_SRC_ALPHA_OP_SEL(x)		(((x)&  0xf)<<  24)
> +#define MSCL_SRC_GLOBAL_ALPHA_MASK		(0xff<<  0)
> +#define MSCL_SRC_GLOBAL_ALPHA(x)		(((x)&  0xff)<<  0)
> +
> +/* m2m-scaler dst blend color */
> +#define MSCL_DST_BLEND_COLOR			0x288
> +#define MSCL_DST_COLOR_SEL_INV			(1<<  31)
> +#define MSCL_DST_COLOR_SEL_MASK			(0x3<<  29)
> +#define MSCL_DST_COLOR_SEL(x)			(((x)&  0x3)<<  29)
> +#define MSCL_DST_COLOR_OP_SEL_INV		(1<<  28)
> +#define MSCL_DST_COLOR_OP_SEL_MASK		(0xf<<  24)
> +#define MSCL_DST_COLOR_OP_SEL(x)		(((x)&  0xf)<<  24)
> +#define MSCL_DST_GLOBAL_COLOR0_MASK		(0xff<<  16)
> +#define MSCL_DST_GLOBAL_COLOR0(x)		(((x)&  0xff)<<  16)
> +#define MSCL_DST_GLOBAL_COLOR1_MASK		(0xff<<  8)
> +#define MSCL_DST_GLOBAL_COLOR1(x)		(((x)&  0xff)<<  8)
> +#define MSCL_DST_GLOBAL_COLOR2_MASK		(0xff<<  0)
> +#define MSCL_DST_GLOBAL_COLOR2(x)		(((x)&  0xff)<<  0)
> +
> +/* m2m-scaler dst blend alpha */
> +#define MSCL_DST_BLEND_ALPHA			0x28C
> +#define MSCL_DST_ALPHA_SEL_INV			(1<<  31)
> +#define MSCL_DST_ALPHA_SEL_MASK			(0x3<<  29)
> +#define MSCL_DST_ALPHA_SEL(x)			(((x)&  0x3)<<  29)
> +#define MSCL_DST_ALPHA_OP_SEL_INV		(1<<  28)
> +#define MSCL_DST_ALPHA_OP_SEL_MASK		(0xf<<  24)
> +#define MSCL_DST_ALPHA_OP_SEL(x)		(((x)&  0xf)<<  24)
> +#define MSCL_DST_GLOBAL_ALPHA_MASK		(0xff<<  0)
> +#define MSCL_DST_GLOBAL_ALPHA(x)		(((x)&  0xff)<<  0)
> +
> +/* m2m-scaler fill color */
> +#define MSCL_FILL_COLOR				0x290
> +#define MSCL_FILL_ALPHA_MASK			(0xff<<  24)
> +#define MSCL_FILL_ALPHA(x)			(((x)&  0xff)<<  24)
> +#define MSCL_FILL_COLOR0_MASK			(0xff<<  16)
> +#define MSCL_FILL_COLOR0(x)			(((x)&  0xff)<<  16)
> +#define MSCL_FILL_COLOR1_MASK			(0xff<<  8)
> +#define MSCL_FILL_COLOR1(x)			(((x)&  0xff)<<  8)
> +#define MSCL_FILL_COLOR2_MASK			(0xff<<  0)
> +#define MSCL_FILL_COLOR2(x)			(((x)&  0xff)<<  0)

Seems like there is no user interface exposed for the blending control
in this driver yet.

> +/* m2m-scaler address queue config */
> +#define MSCL_ADDR_QUEUE_CONFIG			0x2a0
> +#define MSCL_ADDR_QUEUE_RST			(1<<  0)
> +
> +/* arbitrary r/w register and reg-value to check soft reset is success */

How about:

  /* Arbitrary R/W register address and value to check if soft reset 
succeeded */

?
> +#define MSCL_CFG_SOFT_RESET_CHECK_REG		MSCL_SRC_CFG
> +#define MSCL_CFG_SOFT_RESET_CHECK_VAL		0x3
> +
> +#endif /* REGS_MSCL_H_ */

--
Thanks,
Sylwester
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c b/drivers/media/platform/exynos-mscl/mscl-regs.c
new file mode 100644
index 0000000..9354afc
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
@@ -0,0 +1,318 @@ 
+/*
+ * 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/delay.h>
+#include <linux/platform_device.h>
+
+#include "mscl-core.h"
+
+void mscl_hw_set_sw_reset(struct mscl_dev *dev)
+{
+	u32 cfg;
+
+	cfg = readl(dev->regs + MSCL_CFG);
+	cfg |= MSCL_CFG_SOFT_RESET;
+
+	writel(cfg, dev->regs + MSCL_CFG);
+}
+
+int mscl_wait_reset(struct mscl_dev *dev)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(50);
+	u32 cfg, reset_done = 0;
+
+	while (time_before(jiffies, end)) {
+		cfg = readl(dev->regs + MSCL_CFG);
+		if (!(cfg & MSCL_CFG_SOFT_RESET)) {
+			reset_done = 1;
+			break;
+		}
+		usleep_range(10, 20);
+	}
+
+	/* write any value to r/w reg and read it back */
+	while (reset_done) {
+
+		/* [TBD] need to define number of tries before returning
+		 * -EBUSY to the caller
+		 */
+
+		writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
+				dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
+		if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
+			readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
+			return 0;
+	}
+
+	return -EBUSY;
+}
+
+void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool mask)
+{
+	u32 cfg;
+
+	switch (interrupt) {
+	case MSCL_INT_TIMEOUT:
+	case MSCL_INT_ILLEGAL_BLEND:
+	case MSCL_INT_ILLEGAL_RATIO:
+	case MSCL_INT_ILLEGAL_DST_HEIGHT:
+	case MSCL_INT_ILLEGAL_DST_WIDTH:
+	case MSCL_INT_ILLEGAL_DST_V_POS:
+	case MSCL_INT_ILLEGAL_DST_H_POS:
+	case MSCL_INT_ILLEGAL_DST_C_SPAN:
+	case MSCL_INT_ILLEGAL_DST_Y_SPAN:
+	case MSCL_INT_ILLEGAL_DST_CR_BASE:
+	case MSCL_INT_ILLEGAL_DST_CB_BASE:
+	case MSCL_INT_ILLEGAL_DST_Y_BASE:
+	case MSCL_INT_ILLEGAL_DST_COLOR:
+	case MSCL_INT_ILLEGAL_SRC_HEIGHT:
+	case MSCL_INT_ILLEGAL_SRC_WIDTH:
+	case MSCL_INT_ILLEGAL_SRC_CV_POS:
+	case MSCL_INT_ILLEGAL_SRC_CH_POS:
+	case MSCL_INT_ILLEGAL_SRC_YV_POS:
+	case MSCL_INT_ILLEGAL_SRC_YH_POS:
+	case MSCL_INT_ILLEGAL_SRC_C_SPAN:
+	case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
+	case MSCL_INT_ILLEGAL_SRC_CR_BASE:
+	case MSCL_INT_ILLEGAL_SRC_CB_BASE:
+	case MSCL_INT_ILLEGAL_SRC_Y_BASE:
+	case MSCL_INT_ILLEGAL_SRC_COLOR:
+	case MSCL_INT_FRAME_END:
+		break;
+	default:
+		return;
+	}
+	cfg = readl(dev->regs + MSCL_INT_EN);
+	if (mask)
+		cfg |= interrupt;
+	else
+		cfg &= ~interrupt;
+	writel(cfg, dev->regs + MSCL_INT_EN);
+}
+
+void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr *addr)
+{
+	dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
+				addr->y, addr->cb, addr->cr);
+	writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
+	writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
+	writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
+}
+
+void mscl_hw_set_output_addr(struct mscl_dev *dev,
+			     struct mscl_addr *addr)
+{
+	dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
+				addr->y, addr->cb, addr->cr);
+	writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
+	writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
+	writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
+}
+
+void mscl_hw_set_in_size(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->s_frame;
+	u32 cfg;
+
+	/* set input pixel offset */
+	cfg = MSCL_SRC_YH_POS(frame->crop.left);
+	cfg |= MSCL_SRC_YV_POS(frame->crop.top);
+	writel(cfg, dev->regs + MSCL_SRC_Y_POS);
+
+	/* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset */
+
+	/* set input span */
+	cfg = MSCL_SRC_Y_SPAN(frame->f_width);
+	if (is_yuv420_2p(frame->fmt))
+		cfg |= MSCL_SRC_C_SPAN(frame->f_width);
+	else
+		cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */
+
+	writel(cfg, dev->regs + MSCL_SRC_SPAN);
+
+	/* Set input cropped size */
+	cfg = MSCL_SRC_WIDTH(frame->crop.width);
+	cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
+	writel(cfg, dev->regs + MSCL_SRC_WH);
+
+	dev_dbg(&dev->pdev->dev,
+		"src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
+		"cropX: %d, cropY: %d\n",
+		frame->crop.left, frame->crop.top, frame->f_width,
+		frame->f_width, frame->crop.width, frame->crop.height);
+}
+
+void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->s_frame;
+	u32 cfg;
+
+	cfg = readl(dev->regs + MSCL_SRC_CFG);
+	cfg &= ~MSCL_SRC_COLOR_FORMAT_MASK;
+	cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
+
+	/* setting tile/linear format */
+	if (frame->fmt->is_tiled)
+		cfg |= MSCL_SRC_TILE_EN;
+	else
+		cfg &= ~MSCL_SRC_TILE_EN;
+
+	writel(cfg, dev->regs + MSCL_SRC_CFG);
+}
+
+void mscl_hw_set_out_size(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	/* set output pixel offset */
+	cfg = MSCL_DST_H_POS(frame->crop.left);
+	cfg |= MSCL_DST_V_POS(frame->crop.top);
+	writel(cfg, dev->regs + MSCL_DST_POS);
+
+	/* set output span */
+	cfg = MSCL_DST_Y_SPAN(frame->f_width);
+	if (is_yuv420_2p(frame->fmt))
+		cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
+	else
+		cfg |= MSCL_DST_C_SPAN(frame->f_width);
+	writel(cfg, dev->regs + MSCL_DST_SPAN);
+
+	/* set output scaled size */
+	cfg = MSCL_DST_WIDTH(frame->crop.width);
+	cfg |= MSCL_DST_HEIGHT(frame->crop.height);
+	writel(cfg, dev->regs + MSCL_DST_WH);
+
+	dev_dbg(&dev->pdev->dev,
+		"dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
+		"cropX: %d, cropY: %d\n",
+		frame->crop.left, frame->crop.top, frame->f_width,
+		frame->f_width, frame->crop.width, frame->crop.height);
+}
+
+void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	cfg = readl(dev->regs + MSCL_DST_CFG);
+	cfg &= ~MSCL_DST_COLOR_FORMAT_MASK;
+	cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);
+
+	writel(cfg, dev->regs + MSCL_DST_CFG);
+}
+
+void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_scaler *sc = &ctx->scaler;
+	u32 cfg;
+
+	cfg = MSCL_H_RATIO_VALUE(sc->hratio);
+	writel(cfg, dev->regs + MSCL_H_RATIO);
+
+	cfg = MSCL_V_RATIO_VALUE(sc->vratio);
+	writel(cfg, dev->regs + MSCL_V_RATIO);
+}
+
+void mscl_hw_set_rotation(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	u32 cfg = 0;
+
+	cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);
+
+	if (ctx->ctrls_mscl.hflip->val)
+		cfg |= MSCL_FLIP_X_EN;
+
+	if (ctx->ctrls_mscl.vflip->val)
+		cfg |= MSCL_FLIP_Y_EN;
+
+	writel(cfg, dev->regs + MSCL_ROT_CFG);
+}
+
+void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+
+	writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);
+}
+
+void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	enum mscl_csc_coeff type;
+	u32 cfg = 0;
+	int i, j;
+	static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
+		{ /* YCbCr to RGB */
+			{0x200, 0x000, 0x2be},
+			{0x200, 0xeac, 0x165},
+			{0x200, 0x377, 0x000}
+		},
+		{ /* YCbCr to RGB with -16 offset */
+			{0x254, 0x000, 0x331},
+			{0x254, 0xec8, 0xFA0},
+			{0x254, 0x409, 0x000}
+		},
+		{ /* RGB to YCbCr */
+			{0x099, 0x12d, 0x03a},
+			{0xe58, 0xeae, 0x106},
+			{0x106, 0xedb, 0xe2a}
+		},
+		{ /* RGB to YCbCr with -16 offset */
+			{0x084, 0x102, 0x032},
+			{0xe4c, 0xe95, 0x0e1},
+			{0x0e1, 0xebc, 0xe24}
+		} };
+
+	if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
+		type = MSCL_CSC_COEFF_NONE;
+	else if (is_rgb(ctx->d_frame.fmt))
+		type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
+	else
+		type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
+
+	if ((type == ctx->mscl_dev->coeff_type) || (type >= MSCL_CSC_COEFF_MAX))
+		return;
+
+	for (i = 0; i < 3; i++) {
+		for (j = 0; j < 3; j++) {
+			cfg = csc_coeff[type][i][j];
+			writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
+		}
+	}
+
+	switch (type) {
+	case MSCL_CSC_COEFF_YCBCR_TO_RGB:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
+		break;
+	case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
+		break;
+	case MSCL_CSC_COEFF_RGB_TO_YCBCR:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
+		break;
+	case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
+		break;
+	default:
+		return;
+	}
+
+	ctx->mscl_dev->coeff_type = type;
+	return;
+}
diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.h b/drivers/media/platform/exynos-mscl/mscl-regs.h
new file mode 100644
index 0000000..02e2294d
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-regs.h
@@ -0,0 +1,282 @@ 
+/*
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Register definition file for Samsung 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef REGS_MSCL_H_
+#define REGS_MSCL_H_
+
+/* m2m-scaler status */
+#define MSCL_STATUS				0x00
+#define MSCL_STATUS_RUNNING			(1 << 1)
+#define MSCL_STATUS_READY_CLK_DOWN		(1 << 0)
+
+/* m2m-scaler config */
+#define MSCL_CFG				0x04
+#define MSCL_CFG_FILL_EN			(1 << 24)
+#define MSCL_CFG_BLEND_CLR_DIV_ALPHA_EN		(1 << 17)
+#define MSCL_CFG_BLEND_EN			(1 << 16)
+#define MSCL_CFG_CSC_Y_OFFSET_SRC_EN		(1 << 10)
+#define MSCL_CFG_CSC_Y_OFFSET_DST_EN		(1 << 9)
+#define MSCL_CFG_16_BURST_MODE			(1 << 8)
+#define MSCL_CFG_SOFT_RESET			(1 << 1)
+#define MSCL_CFG_START_CMD			(1 << 0)
+
+/* m2m-scaler interrupt enable */
+#define MSCL_INT_EN				0x08
+#define MSCL_INT_EN_DEFAULT			0x81ffffff
+#define MSCL_INT_EN_TIMEOUT			(1 << 31)
+#define MSCL_INT_EN_ILLEGAL_BLEND		(1 << 24)
+#define MSCL_INT_EN_ILLEGAL_RATIO		(1 << 23)
+#define MSCL_INT_EN_ILLEGAL_DST_HEIGHT		(1 << 22)
+#define MSCL_INT_EN_ILLEGAL_DST_WIDTH		(1 << 21)
+#define MSCL_INT_EN_ILLEGAL_DST_V_POS		(1 << 20)
+#define MSCL_INT_EN_ILLEGAL_DST_H_POS		(1 << 19)
+#define MSCL_INT_EN_ILLEGAL_DST_C_SPAN		(1 << 18)
+#define MSCL_INT_EN_ILLEGAL_DST_Y_SPAN		(1 << 17)
+#define MSCL_INT_EN_ILLEGAL_DST_CR_BASE		(1 << 16)
+#define MSCL_INT_EN_ILLEGAL_DST_CB_BASE		(1 << 15)
+#define MSCL_INT_EN_ILLEGAL_DST_Y_BASE		(1 << 14)
+#define MSCL_INT_EN_ILLEGAL_DST_COLOR		(1 << 13)
+#define MSCL_INT_EN_ILLEGAL_SRC_HEIGHT		(1 << 12)
+#define MSCL_INT_EN_ILLEGAL_SRC_WIDTH		(1 << 11)
+#define MSCL_INT_EN_ILLEGAL_SRC_CV_POS		(1 << 10)
+#define MSCL_INT_EN_ILLEGAL_SRC_CH_POS		(1 << 9)
+#define MSCL_INT_EN_ILLEGAL_SRC_YV_POS		(1 << 8)
+#define MSCL_INT_EN_ILLEGAL_SRC_YH_POS		(1 << 7)
+#define MSCL_INT_EN_ILLEGAL_SRC_C_SPAN		(1 << 6)
+#define MSCL_INT_EN_ILLEGAL_SRC_Y_SPAN		(1 << 5)
+#define MSCL_INT_EN_ILLEGAL_SRC_CR_BASE		(1 << 4)
+#define MSCL_INT_EN_ILLEGAL_SRC_CB_BASE		(1 << 3)
+#define MSCL_INT_EN_ILLEGAL_SRC_Y_BASE		(1 << 2)
+#define MSCL_INT_EN_ILLEGAL_SRC_COLOR		(1 << 1)
+#define MSCL_INT_EN_FRAME_END			(1 << 0)
+
+/* m2m-scaler interrupt status */
+#define MSCL_INT_STATUS				0x0c
+#define MSCL_INT_STATUS_CLEAR			(0xffffffff)
+#define MSCL_INT_STATUS_ERROR			(0x81fffffe)
+#define MSCL_INT_STATUS_TIMEOUT			(1 << 31)
+#define MSCL_INT_STATUS_ILLEGAL_BLEND		(1 << 24)
+#define MSCL_INT_STATUS_ILLEGAL_RATIO		(1 << 23)
+#define MSCL_INT_STATUS_ILLEGAL_DST_HEIGHT	(1 << 22)
+#define MSCL_INT_STATUS_ILLEGAL_DST_WIDTH	(1 << 21)
+#define MSCL_INT_STATUS_ILLEGAL_DST_V_POS	(1 << 20)
+#define MSCL_INT_STATUS_ILLEGAL_DST_H_POS	(1 << 19)
+#define MSCL_INT_STATUS_ILLEGAL_DST_C_SPAN	(1 << 18)
+#define MSCL_INT_STATUS_ILLEGAL_DST_Y_SPAN	(1 << 17)
+#define MSCL_INT_STATUS_ILLEGAL_DST_CR_BASE	(1 << 16)
+#define MSCL_INT_STATUS_ILLEGAL_DST_CB_BASE	(1 << 15)
+#define MSCL_INT_STATUS_ILLEGAL_DST_Y_BASE	(1 << 14)
+#define MSCL_INT_STATUS_ILLEGAL_DST_COLOR	(1 << 13)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_HEIGHT	(1 << 12)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_WIDTH	(1 << 11)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CV_POS	(1 << 10)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CH_POS	(1 << 9)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_YV_POS	(1 << 8)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_YH_POS	(1 << 7)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_C_SPAN	(1 << 6)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_SPAN	(1 << 5)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CR_BASE	(1 << 4)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CB_BASE	(1 << 3)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_BASE	(1 << 2)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_COLOR	(1 << 1)
+#define MSCL_INT_STATUS_FRAME_END		(1 << 0)
+
+/* m2m-scaler source format configuration */
+#define MSCL_SRC_CFG				0x10
+#define MSCL_SRC_TILE_EN			(0x1 << 10)
+#define MSCL_SRC_BYTE_SWAP_MASK			(0x3 << 5)
+#define MSCL_SRC_BYTE_SWAP(x)			(((x) & 0x3) << 5)
+#define MSCL_SRC_COLOR_FORMAT_MASK		(0xf << 0)
+#define MSCL_SRC_COLOR_FORMAT(x)		(((x) & 0xf) << 0)
+
+/* m2m-scaler source y-base */
+#define MSCL_SRC_Y_BASE				0x14
+
+/* m2m-scaler source cb-base */
+#define MSCL_SRC_CB_BASE			0x18
+
+/* m2m-scaler source cr-base */
+#define MSCL_SRC_CR_BASE			0x294
+
+/* m2m-scaler source span */
+#define MSCL_SRC_SPAN				0x1c
+#define MSCL_SRC_C_SPAN_MASK			(0x3fff << 16)
+#define MSCL_SRC_C_SPAN(x)			(((x) & 0x3fff) << 16)
+#define MSCL_SRC_Y_SPAN_MASK			(0x3fff << 0)
+#define MSCL_SRC_Y_SPAN(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler source y-position */
+#define MSCL_SRC_Y_POS				0x20
+#define MSCL_SRC_YH_POS_MASK			(0xffff << (16 + 2))
+#define MSCL_SRC_YH_POS(x)			(((x) & 0xffff) << (16 + 2))
+#define MSCL_SRC_YV_POS_MASK			(0xffff << (0 + 2))
+#define MSCL_SRC_YV_POS(x)			(((x) & 0xffff) << (0 + 2))
+
+/* m2m-scaler source width/height */
+#define MSCL_SRC_WH				0x24
+#define MSCL_SRC_WIDTH_MASK			(0x3fff << 16)
+#define MSCL_SRC_WIDTH(x)			(((x) & 0x3fff) << 16)
+#define MSCL_SRC_HEIGHT_MASK			(0x3fff << 0)
+#define MSCL_SRC_HEIGHT(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler source c-position */
+#define MSCL_SRC_C_POS				0x28
+#define MSCL_SRC_CH_POS_MASK			(0xffff << (16 + 2))
+#define MSCL_SRC_CH_POS(x)			(((x) & 0xffff) << (16 + 2))
+#define MSCL_SRC_CV_POS_MASK			(0xffff << (0 + 2))
+#define MSCL_SRC_CV_POS(x)			(((x) & 0xffff) << (0 + 2))
+
+/* m2m-scaler destination format configuration */
+#define MSCL_DST_CFG				0x30
+#define MSCL_DST_BYTE_SWAP_MASK			(0x3 << 5)
+#define MSCL_DST_BYTE_SWAP(x)			(((x) & 0x3) << 5)
+#define MSCL_DST_COLOR_FORMAT_MASK		(0xf << 0)
+#define MSCL_DST_COLOR_FORMAT(x)		(((x) & 0xf) << 0)
+
+/* m2m-scaler destination y-base */
+#define MSCL_DST_Y_BASE				0x34
+
+/* m2m-scaler destination cb-base */
+#define MSCL_DST_CB_BASE			0x38
+
+/* m2m-scaler destination cr-base */
+#define MSCL_DST_CR_BASE			0x298
+
+/* m2m-scaler destination span */
+#define MSCL_DST_SPAN				0x3c
+#define MSCL_DST_C_SPAN_MASK			(0x3fff << 16)
+#define MSCL_DST_C_SPAN(x)			(((x) & 0x3fff) << 16)
+#define MSCL_DST_Y_SPAN_MASK			(0x3fff << 0)
+#define MSCL_DST_Y_SPAN(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler destination width/height */
+#define MSCL_DST_WH				0x40
+#define MSCL_DST_WIDTH_MASK			(0x3fff << 16)
+#define MSCL_DST_WIDTH(x)			(((x) & 0x3fff) << 16)
+#define MSCL_DST_HEIGHT_MASK			(0x3fff << 0)
+#define MSCL_DST_HEIGHT(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler destination position */
+#define MSCL_DST_POS				0x44
+#define MSCL_DST_H_POS_MASK			(0x3fff << 16)
+#define MSCL_DST_H_POS(x)			(((x) & 0x3fff) << 16)
+#define MSCL_DST_V_POS_MASK			(0x3fff << 0)
+#define MSCL_DST_V_POS(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler horizontal scale ratio */
+#define MSCL_H_RATIO				0x50
+#define MSCL_H_RATIO_VALUE(x)			(((x) & 0x7ffff) << 0)
+
+/* m2m-scaler vertical scale ratio */
+#define MSCL_V_RATIO				0x54
+#define MSCL_V_RATIO_VALUE(x)			(((x) & 0x7ffff) << 0)
+
+/* m2m-scaler rotation config */
+#define MSCL_ROT_CFG				0x58
+#define MSCL_FLIP_X_EN				(1 << 3)
+#define MSCL_FLIP_Y_EN				(1 << 2)
+#define MSCL_ROTMODE_MASK			(0x3 << 0)
+#define MSCL_ROTMODE(x)				(((x) & 0x3) << 0)
+
+/* m2m-scaler csc coefficients */
+#define MSCL_CSC_COEF_00			0x220
+#define MSCL_CSC_COEF_10			0x224
+#define MSCL_CSC_COEF_20			0x228
+#define MSCL_CSC_COEF_01			0x22C
+#define MSCL_CSC_COEF_11			0x230
+#define MSCL_CSC_COEF_21			0x234
+#define MSCL_CSC_COEF_02			0x238
+#define MSCL_CSC_COEF_12			0x23C
+#define MSCL_CSC_COEF_22			0x240
+
+#define MSCL_CSC_COEF(x, y)			(0x220 + ((x * 12) + (y * 4)))
+
+/* m2m-scaler dither config */
+#define MSCL_DITH_CFG				0x250
+#define MSCL_DITHER_R_TYPE_MASK			(0x7 << 6)
+#define MSCL_DITHER_R_TYPE(x)			(((x) & 0x7) << 6)
+#define MSCL_DITHER_G_TYPE_MASK			(0x7 << 3)
+#define MSCL_DITHER_G_TYPE(x)			(((x) & 0x7) << 3)
+#define MSCL_DITHER_B_TYPE_MASK			(0x7 << 0)
+#define MSCL_DITHER_B_TYPE(x)			(((x) & 0x7) << 0)
+
+/* m2m-scaler src blend color */
+#define MSCL_SRC_BLEND_COLOR			0x280
+#define MSCL_SRC_COLOR_SEL_INV			(1 << 31)
+#define MSCL_SRC_COLOR_SEL_MASK			(0x3 << 29)
+#define MSCL_SRC_COLOR_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_SRC_COLOR_OP_SEL_INV		(1 << 28)
+#define MSCL_SRC_COLOR_OP_SEL_MASK		(0xf << 24)
+#define MSCL_SRC_COLOR_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_SRC_GLOBAL_COLOR0_MASK		(0xff << 16)
+#define MSCL_SRC_GLOBAL_COLOR0(x)		(((x) & 0xff) << 16)
+#define MSCL_SRC_GLOBAL_COLOR1_MASK		(0xff << 8)
+#define MSCL_SRC_GLOBAL_COLOR1(x)		(((x) & 0xff) << 8)
+#define MSCL_SRC_GLOBAL_COLOR2_MASK		(0xff << 0)
+#define MSCL_SRC_GLOBAL_COLOR2(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler src blend alpha */
+#define MSCL_SRC_BLEND_ALPHA			0x284
+#define MSCL_SRC_ALPHA_SEL_INV			(1 << 31)
+#define MSCL_SRC_ALPHA_SEL_MASK			(0x3 << 29)
+#define MSCL_SRC_ALPHA_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_SRC_ALPHA_OP_SEL_INV		(1 << 28)
+#define MSCL_SRC_ALPHA_OP_SEL_MASK		(0xf << 24)
+#define MSCL_SRC_ALPHA_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_SRC_GLOBAL_ALPHA_MASK		(0xff << 0)
+#define MSCL_SRC_GLOBAL_ALPHA(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler dst blend color */
+#define MSCL_DST_BLEND_COLOR			0x288
+#define MSCL_DST_COLOR_SEL_INV			(1 << 31)
+#define MSCL_DST_COLOR_SEL_MASK			(0x3 << 29)
+#define MSCL_DST_COLOR_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_DST_COLOR_OP_SEL_INV		(1 << 28)
+#define MSCL_DST_COLOR_OP_SEL_MASK		(0xf << 24)
+#define MSCL_DST_COLOR_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_DST_GLOBAL_COLOR0_MASK		(0xff << 16)
+#define MSCL_DST_GLOBAL_COLOR0(x)		(((x) & 0xff) << 16)
+#define MSCL_DST_GLOBAL_COLOR1_MASK		(0xff << 8)
+#define MSCL_DST_GLOBAL_COLOR1(x)		(((x) & 0xff) << 8)
+#define MSCL_DST_GLOBAL_COLOR2_MASK		(0xff << 0)
+#define MSCL_DST_GLOBAL_COLOR2(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler dst blend alpha */
+#define MSCL_DST_BLEND_ALPHA			0x28C
+#define MSCL_DST_ALPHA_SEL_INV			(1 << 31)
+#define MSCL_DST_ALPHA_SEL_MASK			(0x3 << 29)
+#define MSCL_DST_ALPHA_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_DST_ALPHA_OP_SEL_INV		(1 << 28)
+#define MSCL_DST_ALPHA_OP_SEL_MASK		(0xf << 24)
+#define MSCL_DST_ALPHA_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_DST_GLOBAL_ALPHA_MASK		(0xff << 0)
+#define MSCL_DST_GLOBAL_ALPHA(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler fill color */
+#define MSCL_FILL_COLOR				0x290
+#define MSCL_FILL_ALPHA_MASK			(0xff << 24)
+#define MSCL_FILL_ALPHA(x)			(((x) & 0xff) << 24)
+#define MSCL_FILL_COLOR0_MASK			(0xff << 16)
+#define MSCL_FILL_COLOR0(x)			(((x) & 0xff) << 16)
+#define MSCL_FILL_COLOR1_MASK			(0xff << 8)
+#define MSCL_FILL_COLOR1(x)			(((x) & 0xff) << 8)
+#define MSCL_FILL_COLOR2_MASK			(0xff << 0)
+#define MSCL_FILL_COLOR2(x)			(((x) & 0xff) << 0)
+
+/* m2m-scaler address queue config */
+#define MSCL_ADDR_QUEUE_CONFIG			0x2a0
+#define MSCL_ADDR_QUEUE_RST			(1 << 0)
+
+/* arbitrary r/w register and reg-value to check soft reset is success */
+#define MSCL_CFG_SOFT_RESET_CHECK_REG		MSCL_SRC_CFG
+#define MSCL_CFG_SOFT_RESET_CHECK_VAL		0x3
+
+#endif /* REGS_MSCL_H_ */