diff mbox

[v4,1/4,media] exynos-scaler: Add new driver for Exynos5 SCALER

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

Commit Message

Shaik Ameer Basha Oct. 4, 2013, 12:26 p.m. UTC
This patch adds support for SCALER device which is a new device
for scaling, blending, color fill  and color space conversion
on EXYNOS5410 and EXYNOS5420 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 - Exynos5420
        - Input : 16x16 to 8192x8192
        - Output:   4x4 to 8192x8192
    Size - Exynos5410
        - Input/Output: 4x4 to 4096x4096
    alpha blending, color fill

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

Comments

Hi,

I have couple minor comments. These could be addressed in follow up
patches, it you won't manage to do it today. Sorry for being late with
this.

On 04/10/13 14:26, Shaik Ameer Basha wrote:
> This patch adds support for SCALER device which is a new device
> for scaling, blending, color fill  and color space conversion
> on EXYNOS5410 and EXYNOS5420 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 - Exynos5420
>         - Input : 16x16 to 8192x8192
>         - Output:   4x4 to 8192x8192
>     Size - Exynos5410
>         - Input/Output: 4x4 to 4096x4096
>     alpha blending, color fill
> 
> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>

Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>

> +void scaler_hw_set_in_size(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->s_frame;
> +	u32 cfg;
> +
> +	/* set input pixel offset */
> +	cfg = (frame->selection.left & SCALER_SRC_YH_POS_MASK) <<
> +				  SCALER_SRC_YH_POS_SHIFT;
> +	cfg |= ((frame->selection.top & SCALER_SRC_YV_POS_MASK) <<
> +				   SCALER_SRC_YV_POS_SHIFT);
> +	scaler_write(dev, SCALER_SRC_Y_POS, cfg);
> +
> +	/* TODO: calculate 'C' plane h/v offset using 'Y' plane h/v offset */
> +
> +	/* Set input span */
> +	cfg = (frame->f_width & SCALER_SRC_Y_SPAN_MASK) <<
> +				SCALER_SRC_Y_SPAN_SHIFT;
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
> +					  SCALER_SRC_C_SPAN_SHIFT);
> +	else /* TODO: Verify */
> +		cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
> +					  SCALER_SRC_C_SPAN_SHIFT);
> +
> +	scaler_write(dev, SCALER_SRC_SPAN, cfg);
> +
> +	/* Set input cropped size */
> +	cfg = (frame->selection.width & SCALER_SRC_WIDTH_MASK) <<
> +				   SCALER_SRC_WIDTH_SHIFT;
> +	cfg |= ((frame->selection.height & SCALER_SRC_HEIGHT_MASK) <<
> +				      SCALER_SRC_HEIGHT_SHIFT);
> +	scaler_write(dev, SCALER_SRC_WH, cfg);
> +
> +	scaler_dbg(dev, "src: posx: %d, posY: %d, spanY: %d, spanC: %d, cropX: %d, cropY: %d\n",

This could be broken into two lines, it's just a debug print.

> +		frame->selection.left, frame->selection.top,
> +		frame->f_width, frame->f_width, frame->selection.width,
> +		frame->selection.height);
> +}
> +
> +void scaler_hw_set_in_image_format(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->s_frame;
> +	u32 cfg;
> +
> +	cfg = scaler_read(dev, SCALER_SRC_CFG);
> +	cfg &= ~(SCALER_SRC_COLOR_FORMAT_MASK << SCALER_SRC_COLOR_FORMAT_SHIFT);
> +	cfg |= ((frame->fmt->scaler_color & SCALER_SRC_COLOR_FORMAT_MASK) <<
> +					   SCALER_SRC_COLOR_FORMAT_SHIFT);
> +
> +	/* Setting tiled/linear format */
> +	if (is_tiled_fmt(frame->fmt))
> +		cfg |= SCALER_SRC_TILE_EN;
> +	else
> +		cfg &= ~SCALER_SRC_TILE_EN;
> +
> +	scaler_write(dev, SCALER_SRC_CFG, cfg);
> +}
> +
> +void scaler_hw_set_out_size(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->d_frame;
> +	u32 cfg;
> +
> +	/* Set output pixel offset */
> +	cfg = (frame->selection.left & SCALER_DST_H_POS_MASK) <<
> +				  SCALER_DST_H_POS_SHIFT;
> +	cfg |= (frame->selection.top & SCALER_DST_V_POS_MASK) <<
> +				  SCALER_DST_V_POS_SHIFT;
> +	scaler_write(dev, SCALER_DST_POS, cfg);
> +
> +	/* Set output span */
> +	cfg = (frame->f_width & SCALER_DST_Y_SPAN_MASK) <<
> +				SCALER_DST_Y_SPAN_SHIFT;
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= (((frame->f_width / 2) & SCALER_DST_C_SPAN_MASK) <<
> +					     SCALER_DST_C_SPAN_SHIFT);
> +	else
> +		cfg |= (((frame->f_width) & SCALER_DST_C_SPAN_MASK) <<
> +					     SCALER_DST_C_SPAN_SHIFT);
> +	scaler_write(dev, SCALER_DST_SPAN, cfg);
> +
> +	/* Set output scaled size */
> +	cfg = (frame->selection.width & SCALER_DST_WIDTH_MASK) <<
> +				   SCALER_DST_WIDTH_SHIFT;
> +	cfg |= (frame->selection.height & SCALER_DST_HEIGHT_MASK) <<
> +				     SCALER_DST_HEIGHT_SHIFT;
> +	scaler_write(dev, SCALER_DST_WH, cfg);
> +
> +	scaler_dbg(dev, "dst: pos X: %d, pos Y: %d, span Y: %d, span C: %d, crop X: %d, crop Y: %d\n",

Ditto.

> +		frame->selection.left, frame->selection.top,
> +		frame->f_width, frame->f_width, frame->selection.width,
> +		frame->selection.height);
> +}
[...]
> +struct scaler_error {
> +	u32 irq_num;
> +	const char * const name;
> +};
> +
> +static const struct scaler_error scaler_errors[] = {
> +	{SCALER_INT_TIMEOUT,			"Timeout"},

Please add spaces after { and before } for all these entries.

> +	{SCALER_INT_ILLEGAL_BLEND,		"Illegal Blend setting"},
> +	{SCALER_INT_ILLEGAL_RATIO,		"Illegal Scale ratio setting"},
> +	{SCALER_INT_ILLEGAL_DST_HEIGHT,		"Illegal Dst Height"},
> +	{SCALER_INT_ILLEGAL_DST_WIDTH,		"Illegal Dst Width"},
> +	{SCALER_INT_ILLEGAL_DST_V_POS,		"Illegal Dst V-Pos"},
> +	{SCALER_INT_ILLEGAL_DST_H_POS,		"Illegal Dst H-Pos"},
> +	{SCALER_INT_ILLEGAL_DST_C_SPAN,		"Illegal Dst C-Span"},
> +	{SCALER_INT_ILLEGAL_DST_Y_SPAN,		"Illegal Dst Y-span"},
> +	{SCALER_INT_ILLEGAL_DST_CR_BASE,	"Illegal Dst Cr-base"},
> +	{SCALER_INT_ILLEGAL_DST_CB_BASE,	"Illegal Dst Cb-base"},
> +	{SCALER_INT_ILLEGAL_DST_Y_BASE,		"Illegal Dst Y-base"},
> +	{SCALER_INT_ILLEGAL_DST_COLOR,		"Illegal Dst Color"},
> +	{SCALER_INT_ILLEGAL_SRC_HEIGHT,		"Illegal Src Height"},
> +	{SCALER_INT_ILLEGAL_SRC_WIDTH,		"Illegal Src Width"},
> +	{SCALER_INT_ILLEGAL_SRC_CV_POS,		"Illegal Src Chroma V-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_CH_POS,		"Illegal Src Chroma H-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_YV_POS,		"Illegal Src Luma V-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_YH_POS,		"Illegal Src Luma H-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_C_SPAN,		"Illegal Src C-span"},
> +	{SCALER_INT_ILLEGAL_SRC_Y_SPAN,		"Illegal Src Y-span"},
> +	{SCALER_INT_ILLEGAL_SRC_CR_BASE,	"Illegal Src Cr-base"},
> +	{SCALER_INT_ILLEGAL_SRC_CB_BASE,	"Illegal Src Cb-base"},
> +	{SCALER_INT_ILLEGAL_SRC_Y_BASE,		"Illegal Src Y-base"},
> +	{SCALER_INT_ILLEGAL_SRC_COLOR,		"Illegal Src Color setting"},

You could remove remove word "Illegal" and add it when printing
the error string for all entries except the first one. This will
slightly decrease code section size of this module.

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
Shaik Ameer Basha Oct. 20, 2013, 12:33 p.m. UTC | #2
Hi Sylwester,

On Fri, Oct 18, 2013 at 5:57 PM, Sylwester Nawrocki
<s.nawrocki@samsung.com> wrote:
> Hi,
>
> I have couple minor comments. These could be addressed in follow up
> patches, it you won't manage to do it today. Sorry for being late with
> this.

Sorry for the late reply.

Currently I am on travel and I don't have the environment to rebase
and test this driver.
I will address your comments in follow up patches.

Can you please queue this driver to your branch and send a pull
request for 3.13 ?

Regards,
Shaik Ameer Basha

>
> On 04/10/13 14:26, Shaik Ameer Basha wrote:
>> This patch adds support for SCALER device which is a new device
>> for scaling, blending, color fill  and color space conversion
>> on EXYNOS5410 and EXYNOS5420 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 - Exynos5420
>>         - Input : 16x16 to 8192x8192
>>         - Output:   4x4 to 8192x8192
>>     Size - Exynos5410
>>         - Input/Output: 4x4 to 4096x4096
>>     alpha blending, color fill
>>
>> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
>
> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
>
>> +void scaler_hw_set_in_size(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->s_frame;
>> +     u32 cfg;
>> +
>> +     /* set input pixel offset */
>> +     cfg = (frame->selection.left & SCALER_SRC_YH_POS_MASK) <<
>> +                               SCALER_SRC_YH_POS_SHIFT;
>> +     cfg |= ((frame->selection.top & SCALER_SRC_YV_POS_MASK) <<
>> +                                SCALER_SRC_YV_POS_SHIFT);
>> +     scaler_write(dev, SCALER_SRC_Y_POS, cfg);
>> +
>> +     /* TODO: calculate 'C' plane h/v offset using 'Y' plane h/v offset */
>> +
>> +     /* Set input span */
>> +     cfg = (frame->f_width & SCALER_SRC_Y_SPAN_MASK) <<
>> +                             SCALER_SRC_Y_SPAN_SHIFT;
>> +     if (is_yuv420_2p(frame->fmt))
>> +             cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
>> +                                       SCALER_SRC_C_SPAN_SHIFT);
>> +     else /* TODO: Verify */
>> +             cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
>> +                                       SCALER_SRC_C_SPAN_SHIFT);
>> +
>> +     scaler_write(dev, SCALER_SRC_SPAN, cfg);
>> +
>> +     /* Set input cropped size */
>> +     cfg = (frame->selection.width & SCALER_SRC_WIDTH_MASK) <<
>> +                                SCALER_SRC_WIDTH_SHIFT;
>> +     cfg |= ((frame->selection.height & SCALER_SRC_HEIGHT_MASK) <<
>> +                                   SCALER_SRC_HEIGHT_SHIFT);
>> +     scaler_write(dev, SCALER_SRC_WH, cfg);
>> +
>> +     scaler_dbg(dev, "src: posx: %d, posY: %d, spanY: %d, spanC: %d, cropX: %d, cropY: %d\n",
>
> This could be broken into two lines, it's just a debug print.
>
>> +             frame->selection.left, frame->selection.top,
>> +             frame->f_width, frame->f_width, frame->selection.width,
>> +             frame->selection.height);
>> +}
>> +
>> +void scaler_hw_set_in_image_format(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->s_frame;
>> +     u32 cfg;
>> +
>> +     cfg = scaler_read(dev, SCALER_SRC_CFG);
>> +     cfg &= ~(SCALER_SRC_COLOR_FORMAT_MASK << SCALER_SRC_COLOR_FORMAT_SHIFT);
>> +     cfg |= ((frame->fmt->scaler_color & SCALER_SRC_COLOR_FORMAT_MASK) <<
>> +                                        SCALER_SRC_COLOR_FORMAT_SHIFT);
>> +
>> +     /* Setting tiled/linear format */
>> +     if (is_tiled_fmt(frame->fmt))
>> +             cfg |= SCALER_SRC_TILE_EN;
>> +     else
>> +             cfg &= ~SCALER_SRC_TILE_EN;
>> +
>> +     scaler_write(dev, SCALER_SRC_CFG, cfg);
>> +}
>> +
>> +void scaler_hw_set_out_size(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->d_frame;
>> +     u32 cfg;
>> +
>> +     /* Set output pixel offset */
>> +     cfg = (frame->selection.left & SCALER_DST_H_POS_MASK) <<
>> +                               SCALER_DST_H_POS_SHIFT;
>> +     cfg |= (frame->selection.top & SCALER_DST_V_POS_MASK) <<
>> +                               SCALER_DST_V_POS_SHIFT;
>> +     scaler_write(dev, SCALER_DST_POS, cfg);
>> +
>> +     /* Set output span */
>> +     cfg = (frame->f_width & SCALER_DST_Y_SPAN_MASK) <<
>> +                             SCALER_DST_Y_SPAN_SHIFT;
>> +     if (is_yuv420_2p(frame->fmt))
>> +             cfg |= (((frame->f_width / 2) & SCALER_DST_C_SPAN_MASK) <<
>> +                                          SCALER_DST_C_SPAN_SHIFT);
>> +     else
>> +             cfg |= (((frame->f_width) & SCALER_DST_C_SPAN_MASK) <<
>> +                                          SCALER_DST_C_SPAN_SHIFT);
>> +     scaler_write(dev, SCALER_DST_SPAN, cfg);
>> +
>> +     /* Set output scaled size */
>> +     cfg = (frame->selection.width & SCALER_DST_WIDTH_MASK) <<
>> +                                SCALER_DST_WIDTH_SHIFT;
>> +     cfg |= (frame->selection.height & SCALER_DST_HEIGHT_MASK) <<
>> +                                  SCALER_DST_HEIGHT_SHIFT;
>> +     scaler_write(dev, SCALER_DST_WH, cfg);
>> +
>> +     scaler_dbg(dev, "dst: pos X: %d, pos Y: %d, span Y: %d, span C: %d, crop X: %d, crop Y: %d\n",
>
> Ditto.
>
>> +             frame->selection.left, frame->selection.top,
>> +             frame->f_width, frame->f_width, frame->selection.width,
>> +             frame->selection.height);
>> +}
> [...]
>> +struct scaler_error {
>> +     u32 irq_num;
>> +     const char * const name;
>> +};
>> +
>> +static const struct scaler_error scaler_errors[] = {
>> +     {SCALER_INT_TIMEOUT,                    "Timeout"},
>
> Please add spaces after { and before } for all these entries.
>
>> +     {SCALER_INT_ILLEGAL_BLEND,              "Illegal Blend setting"},
>> +     {SCALER_INT_ILLEGAL_RATIO,              "Illegal Scale ratio setting"},
>> +     {SCALER_INT_ILLEGAL_DST_HEIGHT,         "Illegal Dst Height"},
>> +     {SCALER_INT_ILLEGAL_DST_WIDTH,          "Illegal Dst Width"},
>> +     {SCALER_INT_ILLEGAL_DST_V_POS,          "Illegal Dst V-Pos"},
>> +     {SCALER_INT_ILLEGAL_DST_H_POS,          "Illegal Dst H-Pos"},
>> +     {SCALER_INT_ILLEGAL_DST_C_SPAN,         "Illegal Dst C-Span"},
>> +     {SCALER_INT_ILLEGAL_DST_Y_SPAN,         "Illegal Dst Y-span"},
>> +     {SCALER_INT_ILLEGAL_DST_CR_BASE,        "Illegal Dst Cr-base"},
>> +     {SCALER_INT_ILLEGAL_DST_CB_BASE,        "Illegal Dst Cb-base"},
>> +     {SCALER_INT_ILLEGAL_DST_Y_BASE,         "Illegal Dst Y-base"},
>> +     {SCALER_INT_ILLEGAL_DST_COLOR,          "Illegal Dst Color"},
>> +     {SCALER_INT_ILLEGAL_SRC_HEIGHT,         "Illegal Src Height"},
>> +     {SCALER_INT_ILLEGAL_SRC_WIDTH,          "Illegal Src Width"},
>> +     {SCALER_INT_ILLEGAL_SRC_CV_POS,         "Illegal Src Chroma V-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_CH_POS,         "Illegal Src Chroma H-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_YV_POS,         "Illegal Src Luma V-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_YH_POS,         "Illegal Src Luma H-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_C_SPAN,         "Illegal Src C-span"},
>> +     {SCALER_INT_ILLEGAL_SRC_Y_SPAN,         "Illegal Src Y-span"},
>> +     {SCALER_INT_ILLEGAL_SRC_CR_BASE,        "Illegal Src Cr-base"},
>> +     {SCALER_INT_ILLEGAL_SRC_CB_BASE,        "Illegal Src Cb-base"},
>> +     {SCALER_INT_ILLEGAL_SRC_Y_BASE,         "Illegal Src Y-base"},
>> +     {SCALER_INT_ILLEGAL_SRC_COLOR,          "Illegal Src Color setting"},
>
> You could remove remove word "Illegal" and add it when printing
> the error string for all entries except the first one. This will
> slightly decrease code section size of this module.
>
> 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
--
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 Oct. 20, 2013, 6:25 p.m. UTC | #3
Hi Shaik,

On 10/20/2013 02:33 PM, Shaik Ameer Basha wrote:
> On Fri, Oct 18, 2013 at 5:57 PM, Sylwester Nawrocki
> <s.nawrocki@samsung.com>  wrote:
>> >  Hi,
>> >
>> >  I have couple minor comments. These could be addressed in follow up
>> >  patches, it you won't manage to do it today. Sorry for being late with
>> >  this.
>
> Sorry for the late reply.
>
> Currently I am on travel and I don't have the environment to rebase
> and test this driver.
> I will address your comments in follow up patches.
>
> Can you please queue this driver to your branch and send a pull
> request for 3.13 ?

The driver seems to be in quite a good shape now and I think it would
have been bad not to merge it in this release. I'll let Kamil handle
it as he's a sub-maintainer of the v4l2 mem-to-mem drivers.

Regards,
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
Mauro Carvalho Chehab Jan. 2, 2014, 8:18 p.m. UTC | #4
Em Fri,  4 Oct 2013 17:56:31 +0530
Shaik Ameer Basha <shaik.ameer@samsung.com> escreveu:

> This patch adds support for SCALER device which is a new device
> for scaling, blending, color fill  and color space conversion
> on EXYNOS5410 and EXYNOS5420 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 - Exynos5420
>         - Input : 16x16 to 8192x8192
>         - Output:   4x4 to 8192x8192
>     Size - Exynos5410
>         - Input/Output: 4x4 to 4096x4096
>     alpha blending, color fill
> 
> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
> ---
>  drivers/media/platform/exynos-scaler/scaler-regs.c |  336 ++++++++++++++++++++
>  drivers/media/platform/exynos-scaler/scaler-regs.h |  331 +++++++++++++++++++
>  2 files changed, 667 insertions(+)
>  create mode 100644 drivers/media/platform/exynos-scaler/scaler-regs.c
>  create mode 100644 drivers/media/platform/exynos-scaler/scaler-regs.h
> 
> diff --git a/drivers/media/platform/exynos-scaler/scaler-regs.c b/drivers/media/platform/exynos-scaler/scaler-regs.c
> new file mode 100644
> index 0000000..ae4a548
> --- /dev/null
> +++ b/drivers/media/platform/exynos-scaler/scaler-regs.c
> @@ -0,0 +1,336 @@
> +/*
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Samsung EXYNOS5 SoC series 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.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/platform_device.h>
> +
> +#include "scaler-regs.h"
> +
> +/* Scaler reset timeout in milliseconds */
> +#define SCALER_RESET_TIMEOUT	50
> +
> +void scaler_hw_set_sw_reset(struct scaler_dev *dev)
> +{
> +	u32 cfg;
> +
> +	cfg = scaler_read(dev, SCALER_CFG);
> +	cfg |= SCALER_CFG_SOFT_RESET;
> +
> +	scaler_write(dev, SCALER_CFG, cfg);
> +}
> +
> +int scaler_wait_reset(struct scaler_dev *dev)
> +{
> +	unsigned long end = jiffies + msecs_to_jiffies(SCALER_RESET_TIMEOUT);
> +	u32 cfg, reset_done = 0;
> +
> +	while (time_before(jiffies, end)) {
> +		cfg = scaler_read(dev, SCALER_CFG);
> +		if (!(cfg & SCALER_CFG_SOFT_RESET)) {
> +			reset_done = 1;
> +			break;
> +		}
> +		usleep_range(10, 20);

Hmm... that doesn't seem right... the timeout can take up to 50,000 us, and
you're sleeping from 10 to 20us... that means that this loop can have up to
5000 interactions... It seems that you're wasting power here without need.

I suspect that you should consider sleeping for a longer time here.

Btw, instead of using time_before(jiffies, end), you could do:
	time_is_after_jiffies(end)

As, from jiffies.h:
	/* time_is_after_jiffies(a) return true if a is after jiffies */
	#define time_is_after_jiffies(a) time_before(jiffies, a)

> +	}
> +
> +	/*
> +	 * Write any value to read/write register and read it back.
> +	 * If the written and read value matches, then the reset process is
> +	 * succeeded.
> +	 */
> +	while (reset_done) {

This is tricky. If the reset fail, it will return busy. Otherwise, it
can loop forever here. Worse than that, you're don't even sleeping
before retries, again wasting power.

Why don't you just change it to something similar to:

	if (!reset_done)
		return -EBUSY;

	end = jiffies + msecs_to_jiffies(SCALER_RESET_TIMEOUT);
	while (time_is_after_jiffies(end)) {
		scaler_write(dev, SCALER_CFG_SOFT_RESET_CHECK_REG,
				SCALER_CFG_SOFT_RESET_CHECK_VAL);
		if (SCALER_CFG_SOFT_RESET_CHECK_VAL ==
			scaler_read(dev, SCALER_CFG_SOFT_RESET_CHECK_REG))
			return 0;
		msleep(10);
	}

> +
> +		/*
> +		 * TODO: need to define number of tries before returning
> +		 * -EBUSY to the caller
> +		 */
> +
> +		scaler_write(dev, SCALER_CFG_SOFT_RESET_CHECK_REG,
> +				SCALER_CFG_SOFT_RESET_CHECK_VAL);
> +		if (SCALER_CFG_SOFT_RESET_CHECK_VAL ==
> +			scaler_read(dev, SCALER_CFG_SOFT_RESET_CHECK_REG))
> +			return 0;
> +	}
> +
> +	return -EBUSY;
> +}
> +
> +void scaler_hw_set_irq(struct scaler_dev *dev, int irq_num, bool enable)
> +{
> +	u32 cfg;
> +
> +	if ((irq_num < SCALER_INT_FRAME_END) ||
> +	    (irq_num > SCALER_INT_TIMEOUT))
> +		return;
> +
> +	cfg = scaler_read(dev, SCALER_INT_EN);
> +	if (enable)
> +		cfg |= (1 << irq_num);

Why do you need parenthesis here?

> +	else
> +		cfg &= ~(1 << irq_num);


> +	scaler_write(dev, SCALER_INT_EN, cfg);
> +}
> +
> +void scaler_hw_set_input_addr(struct scaler_dev *dev, struct scaler_addr *addr)
> +{
> +	scaler_dbg(dev, "src_buf: 0x%x, cb: 0x%x, cr: 0x%x",
> +				addr->y, addr->cb, addr->cr);
> +	scaler_write(dev, SCALER_SRC_Y_BASE, addr->y);
> +	scaler_write(dev, SCALER_SRC_CB_BASE, addr->cb);
> +	scaler_write(dev, SCALER_SRC_CR_BASE, addr->cr);
> +}
> +
> +void scaler_hw_set_output_addr(struct scaler_dev *dev,
> +			     struct scaler_addr *addr)
> +{
> +	scaler_dbg(dev, "dst_buf: 0x%x, cb: 0x%x, cr: 0x%x",
> +			addr->y, addr->cb, addr->cr);
> +	scaler_write(dev, SCALER_DST_Y_BASE, addr->y);
> +	scaler_write(dev, SCALER_DST_CB_BASE, addr->cb);
> +	scaler_write(dev, SCALER_DST_CR_BASE, addr->cr);
> +}
> +
> +void scaler_hw_set_in_size(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->s_frame;
> +	u32 cfg;
> +
> +	/* set input pixel offset */
> +	cfg = (frame->selection.left & SCALER_SRC_YH_POS_MASK) <<
> +				  SCALER_SRC_YH_POS_SHIFT;
> +	cfg |= ((frame->selection.top & SCALER_SRC_YV_POS_MASK) <<
> +				   SCALER_SRC_YV_POS_SHIFT);
> +	scaler_write(dev, SCALER_SRC_Y_POS, cfg);
> +
> +	/* TODO: calculate 'C' plane h/v offset using 'Y' plane h/v offset */
> +
> +	/* Set input span */
> +	cfg = (frame->f_width & SCALER_SRC_Y_SPAN_MASK) <<
> +				SCALER_SRC_Y_SPAN_SHIFT;
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
> +					  SCALER_SRC_C_SPAN_SHIFT);
> +	else /* TODO: Verify */
> +		cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
> +					  SCALER_SRC_C_SPAN_SHIFT);
> +
> +	scaler_write(dev, SCALER_SRC_SPAN, cfg);
> +
> +	/* Set input cropped size */
> +	cfg = (frame->selection.width & SCALER_SRC_WIDTH_MASK) <<
> +				   SCALER_SRC_WIDTH_SHIFT;
> +	cfg |= ((frame->selection.height & SCALER_SRC_HEIGHT_MASK) <<
> +				      SCALER_SRC_HEIGHT_SHIFT);
> +	scaler_write(dev, SCALER_SRC_WH, cfg);
> +
> +	scaler_dbg(dev, "src: posx: %d, posY: %d, spanY: %d, spanC: %d, cropX: %d, cropY: %d\n",
> +		frame->selection.left, frame->selection.top,
> +		frame->f_width, frame->f_width, frame->selection.width,
> +		frame->selection.height);
> +}
> +
> +void scaler_hw_set_in_image_format(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->s_frame;
> +	u32 cfg;
> +
> +	cfg = scaler_read(dev, SCALER_SRC_CFG);
> +	cfg &= ~(SCALER_SRC_COLOR_FORMAT_MASK << SCALER_SRC_COLOR_FORMAT_SHIFT);
> +	cfg |= ((frame->fmt->scaler_color & SCALER_SRC_COLOR_FORMAT_MASK) <<
> +					   SCALER_SRC_COLOR_FORMAT_SHIFT);
> +
> +	/* Setting tiled/linear format */
> +	if (is_tiled_fmt(frame->fmt))
> +		cfg |= SCALER_SRC_TILE_EN;
> +	else
> +		cfg &= ~SCALER_SRC_TILE_EN;
> +
> +	scaler_write(dev, SCALER_SRC_CFG, cfg);
> +}
> +
> +void scaler_hw_set_out_size(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->d_frame;
> +	u32 cfg;
> +
> +	/* Set output pixel offset */
> +	cfg = (frame->selection.left & SCALER_DST_H_POS_MASK) <<
> +				  SCALER_DST_H_POS_SHIFT;
> +	cfg |= (frame->selection.top & SCALER_DST_V_POS_MASK) <<
> +				  SCALER_DST_V_POS_SHIFT;
> +	scaler_write(dev, SCALER_DST_POS, cfg);
> +
> +	/* Set output span */
> +	cfg = (frame->f_width & SCALER_DST_Y_SPAN_MASK) <<
> +				SCALER_DST_Y_SPAN_SHIFT;
> +	if (is_yuv420_2p(frame->fmt))
> +		cfg |= (((frame->f_width / 2) & SCALER_DST_C_SPAN_MASK) <<
> +					     SCALER_DST_C_SPAN_SHIFT);
> +	else
> +		cfg |= (((frame->f_width) & SCALER_DST_C_SPAN_MASK) <<
> +					     SCALER_DST_C_SPAN_SHIFT);
> +	scaler_write(dev, SCALER_DST_SPAN, cfg);
> +
> +	/* Set output scaled size */
> +	cfg = (frame->selection.width & SCALER_DST_WIDTH_MASK) <<
> +				   SCALER_DST_WIDTH_SHIFT;
> +	cfg |= (frame->selection.height & SCALER_DST_HEIGHT_MASK) <<
> +				     SCALER_DST_HEIGHT_SHIFT;
> +	scaler_write(dev, SCALER_DST_WH, cfg);
> +
> +	scaler_dbg(dev, "dst: pos X: %d, pos Y: %d, span Y: %d, span C: %d, crop X: %d, crop Y: %d\n",
> +		frame->selection.left, frame->selection.top,
> +		frame->f_width, frame->f_width, frame->selection.width,
> +		frame->selection.height);
> +}
> +
> +void scaler_hw_set_out_image_format(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_frame *frame = &ctx->d_frame;
> +	u32 cfg;
> +
> +	cfg = scaler_read(dev, SCALER_DST_CFG);
> +	cfg &= ~SCALER_DST_COLOR_FORMAT_MASK;
> +	cfg |= (frame->fmt->scaler_color & SCALER_DST_COLOR_FORMAT_MASK);
> +
> +	scaler_write(dev, SCALER_DST_CFG, cfg);
> +}
> +
> +void scaler_hw_set_scaler_ratio(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	struct scaler_scaler *sc = &ctx->scaler;
> +	u32 cfg;
> +
> +	cfg = (sc->hratio & SCALER_H_RATIO_MASK) << SCALER_H_RATIO_SHIFT;
> +	scaler_write(dev, SCALER_H_RATIO, cfg);
> +
> +	cfg = (sc->vratio & SCALER_V_RATIO_MASK) << SCALER_V_RATIO_SHIFT;
> +	scaler_write(dev, SCALER_V_RATIO, cfg);
> +}
> +
> +void scaler_hw_set_rotation(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	u32 cfg = 0;
> +
> +	cfg = ((ctx->ctrls_scaler.rotate->val / 90) & SCALER_ROTMODE_MASK) <<
> +						      SCALER_ROTMODE_SHIFT;
> +
> +	if (ctx->ctrls_scaler.hflip->val)
> +		cfg |= SCALER_FLIP_X_EN;
> +
> +	if (ctx->ctrls_scaler.vflip->val)
> +		cfg |= SCALER_FLIP_Y_EN;
> +
> +	scaler_write(dev, SCALER_ROT_CFG, cfg);
> +}
> +
> +void scaler_hw_set_csc_coeff(struct scaler_ctx *ctx)
> +{
> +	struct scaler_dev *dev = ctx->scaler_dev;
> +	enum scaler_csc_coeff type;
> +	u32 cfg = 0;
> +	int i, j;
> +	static const u32 csc_coeff[SCALER_CSC_COEFF_MAX][3][3] = {
> +		{ /* YCbCr to RGB */
> +			{0x254, 0x000, 0x331},
> +			{0x254, 0xec8, 0xFA0},
> +			{0x254, 0x409, 0x000}
> +		},
> +		{ /* RGB to YCbCr */
> +			{0x084, 0x102, 0x032},
> +			{0xe4c, 0xe95, 0x0e1},
> +			{0x0e1, 0xebc, 0xe24}
> +		} };
> +
> +	/* TODO: add check for BT.601,BT.709 narrow/wide ranges */
> +	if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt)) {
> +		type = SCALER_CSC_COEFF_NONE;
> +	} else if (is_rgb(ctx->d_frame.fmt)) {
> +		type = SCALER_CSC_COEFF_YCBCR_TO_RGB;
> +		scaler_hw_src_y_offset_en(ctx->scaler_dev, true);
> +	} else {
> +		type = SCALER_CSC_COEFF_RGB_TO_YCBCR;
> +		scaler_hw_src_y_offset_en(ctx->scaler_dev, true);
> +	}
> +
> +	if (type == ctx->scaler_dev->coeff_type || type >= SCALER_CSC_COEFF_MAX)
> +		return;
> +
> +	for (i = 0; i < 3; i++) {
> +		for (j = 0; j < 3; j++) {
> +			cfg = csc_coeff[type][i][j];
> +			scaler_write(dev, SCALER_CSC_COEF(i, j), cfg);
> +		}
> +	}
> +
> +	ctx->scaler_dev->coeff_type = type;
> +}
> +
> +void scaler_hw_src_y_offset_en(struct scaler_dev *dev, bool on)
> +{
> +	u32 cfg;
> +
> +	cfg = scaler_read(dev, SCALER_CFG);
> +	if (on)
> +		cfg |= SCALER_CFG_CSC_Y_OFFSET_SRC_EN;
> +	else
> +		cfg &= ~SCALER_CFG_CSC_Y_OFFSET_SRC_EN;
> +
> +	scaler_write(dev, SCALER_CFG, cfg);
> +}
> +
> +void scaler_hw_dst_y_offset_en(struct scaler_dev *dev, bool on)
> +{
> +	u32 cfg;
> +
> +	cfg = scaler_read(dev, SCALER_CFG);
> +	if (on)
> +		cfg |= SCALER_CFG_CSC_Y_OFFSET_DST_EN;
> +	else
> +		cfg &= ~SCALER_CFG_CSC_Y_OFFSET_DST_EN;
> +
> +	scaler_write(dev, SCALER_CFG, cfg);
> +}
> +
> +void scaler_hw_enable_control(struct scaler_dev *dev, bool on)
> +{
> +	u32 cfg;
> +
> +	if (on)
> +		scaler_write(dev, SCALER_INT_EN, 0xffffffff);
> +
> +	cfg = scaler_read(dev, SCALER_CFG);
> +	cfg |= SCALER_CFG_16_BURST_MODE;
> +	if (on)
> +		cfg |= SCALER_CFG_START_CMD;
> +	else
> +		cfg &= ~SCALER_CFG_START_CMD;
> +
> +	scaler_dbg(dev, "%s: SCALER_CFG:0x%x\n", __func__, cfg);
> +
> +	scaler_write(dev, SCALER_CFG, cfg);
> +}
> +
> +unsigned int scaler_hw_get_irq_status(struct scaler_dev *dev)
> +{
> +	return scaler_read(dev, SCALER_INT_STATUS);
> +}
> +
> +void scaler_hw_clear_irq(struct scaler_dev *dev, unsigned int irq)
> +{
> +	scaler_write(dev, SCALER_INT_STATUS, irq);
> +}
> diff --git a/drivers/media/platform/exynos-scaler/scaler-regs.h b/drivers/media/platform/exynos-scaler/scaler-regs.h
> new file mode 100644
> index 0000000..2170df5
> --- /dev/null
> +++ b/drivers/media/platform/exynos-scaler/scaler-regs.h
> @@ -0,0 +1,331 @@
> +/*
> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Samsung EXYNOS5 SoC series 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_SCALER_H_
> +#define REGS_SCALER_H_
> +
> +#include "scaler.h"
> +
> +/* SCALER status */
> +#define SCALER_STATUS				0x00
> +#define SCALER_STATUS_RUNNING			(1 << 1)
> +#define SCALER_STATUS_READY_CLK_DOWN		(1 << 0)
> +
> +/* SCALER config */
> +#define SCALER_CFG				0x04
> +#define SCALER_CFG_FILL_EN			(1 << 24)
> +#define SCALER_CFG_BLEND_CLR_DIV_ALPHA_EN	(1 << 17)
> +#define SCALER_CFG_BLEND_EN			(1 << 16)
> +#define SCALER_CFG_CSC_Y_OFFSET_SRC_EN		(1 << 10)
> +#define SCALER_CFG_CSC_Y_OFFSET_DST_EN		(1 << 9)
> +#define SCALER_CFG_16_BURST_MODE		(1 << 8)
> +#define SCALER_CFG_SOFT_RESET			(1 << 1)
> +#define SCALER_CFG_START_CMD			(1 << 0)
> +
> +/* SCALER interrupts */
> +#define SCALER_INT_TIMEOUT			31
> +#define SCALER_INT_ILLEGAL_BLEND		24
> +#define SCALER_INT_ILLEGAL_RATIO		23
> +#define SCALER_INT_ILLEGAL_DST_HEIGHT		22
> +#define SCALER_INT_ILLEGAL_DST_WIDTH		21
> +#define SCALER_INT_ILLEGAL_DST_V_POS		20
> +#define SCALER_INT_ILLEGAL_DST_H_POS		19
> +#define SCALER_INT_ILLEGAL_DST_C_SPAN		18
> +#define SCALER_INT_ILLEGAL_DST_Y_SPAN		17
> +#define SCALER_INT_ILLEGAL_DST_CR_BASE		16
> +#define SCALER_INT_ILLEGAL_DST_CB_BASE		15
> +#define SCALER_INT_ILLEGAL_DST_Y_BASE		14
> +#define SCALER_INT_ILLEGAL_DST_COLOR		13
> +#define SCALER_INT_ILLEGAL_SRC_HEIGHT		12
> +#define SCALER_INT_ILLEGAL_SRC_WIDTH		11
> +#define SCALER_INT_ILLEGAL_SRC_CV_POS		10
> +#define SCALER_INT_ILLEGAL_SRC_CH_POS		9
> +#define SCALER_INT_ILLEGAL_SRC_YV_POS		8
> +#define SCALER_INT_ILLEGAL_SRC_YH_POS		7
> +#define SCALER_INT_ILLEGAL_SRC_C_SPAN		6
> +#define SCALER_INT_ILLEGAL_SRC_Y_SPAN		5
> +#define SCALER_INT_ILLEGAL_SRC_CR_BASE		4
> +#define SCALER_INT_ILLEGAL_SRC_CB_BASE		3
> +#define SCALER_INT_ILLEGAL_SRC_Y_BASE		2
> +#define SCALER_INT_ILLEGAL_SRC_COLOR		1
> +#define SCALER_INT_FRAME_END			0
> +
> +/* SCALER interrupt enable */
> +#define SCALER_INT_EN				0x08
> +#define SCALER_INT_EN_DEFAULT			0x81ffffff
> +
> +/* SCALER interrupt status */
> +#define SCALER_INT_STATUS			0x0c
> +#define SCALER_INT_STATUS_CLEAR			0xffffffff
> +#define SCALER_INT_STATUS_ERROR			0x81fffffe
> +
> +/* SCALER source format configuration */
> +#define SCALER_SRC_CFG				0x10
> +#define SCALER_SRC_TILE_EN			(0x1 << 10)
> +#define SCALER_SRC_BYTE_SWAP_MASK		0x3
> +#define SCALER_SRC_BYTE_SWAP_SHIFT		5
> +#define SCALER_SRC_COLOR_FORMAT_MASK		0xf
> +#define SCALER_SRC_COLOR_FORMAT_SHIFT		0
> +
> +/* SCALER source y-base */
> +#define SCALER_SRC_Y_BASE			0x14
> +
> +/* SCALER source cb-base */
> +#define SCALER_SRC_CB_BASE			0x18
> +
> +/* SCALER source cr-base */
> +#define SCALER_SRC_CR_BASE			0x294
> +
> +/* SCALER source span */
> +#define SCALER_SRC_SPAN				0x1c
> +#define SCALER_SRC_C_SPAN_MASK			0x3fff
> +#define SCALER_SRC_C_SPAN_SHIFT			16
> +#define SCALER_SRC_Y_SPAN_MASK			0x3fff
> +#define SCALER_SRC_Y_SPAN_SHIFT			0
> +
> +/*
> + * SCALER source y-position
> + * 14.2 fixed-point format
> + *      - 14 bits at the MSB are for the integer part.
> + *      - 2 bits at LSB are for fractional part and always has to be set to 0.
> + */
> +#define SCALER_SRC_Y_POS			0x20
> +#define SCALER_SRC_YH_POS_MASK			0xfffc
> +#define SCALER_SRC_YH_POS_SHIFT			16
> +#define SCALER_SRC_YV_POS_MASK			0xfffc
> +#define SCALER_SRC_YV_POS_SHIFT			0
> +
> +/* SCALER source width/height */
> +#define SCALER_SRC_WH				0x24
> +#define SCALER_SRC_WIDTH_MASK			0x3fff
> +#define SCALER_SRC_WIDTH_SHIFT			16
> +#define SCALER_SRC_HEIGHT_MASK			0x3fff
> +#define SCALER_SRC_HEIGHT_SHIFT			0
> +
> +/*
> + * SCALER source c-position
> + * 14.2 fixed-point format
> + *      - 14 bits at the MSB are for the integer part.
> + *      - 2 bits at LSB are for fractional part and always has to be set to 0.
> + */
> +#define SCALER_SRC_C_POS			0x28
> +#define SCALER_SRC_CH_POS_MASK			0xfffc
> +#define SCALER_SRC_CH_POS_SHIFT			16
> +#define SCALER_SRC_CV_POS_MASK			0xfffc
> +#define SCALER_SRC_CV_POS_SHIFT			0
> +
> +/* SCALER destination format configuration */
> +#define SCALER_DST_CFG				0x30
> +#define SCALER_DST_BYTE_SWAP_MASK		0x3
> +#define SCALER_DST_BYTE_SWAP_SHIFT		5
> +#define SCALER_DST_COLOR_FORMAT_MASK		0xf
> +
> +/* SCALER destination y-base */
> +#define SCALER_DST_Y_BASE			0x34
> +
> +/* SCALER destination cb-base */
> +#define SCALER_DST_CB_BASE			0x38
> +
> +/* SCALER destination cr-base */
> +#define SCALER_DST_CR_BASE			0x298
> +
> +/* SCALER destination span */
> +#define SCALER_DST_SPAN				0x3c
> +#define SCALER_DST_C_SPAN_MASK			0x3fff
> +#define SCALER_DST_C_SPAN_SHIFT			16
> +#define SCALER_DST_Y_SPAN_MASK			0x3fff
> +#define SCALER_DST_Y_SPAN_SHIFT			0
> +
> +/* SCALER destination width/height */
> +#define SCALER_DST_WH				0x40
> +#define SCALER_DST_WIDTH_MASK			0x3fff
> +#define SCALER_DST_WIDTH_SHIFT			16
> +#define SCALER_DST_HEIGHT_MASK			0x3fff
> +#define SCALER_DST_HEIGHT_SHIFT			0
> +
> +/* SCALER destination position */
> +#define SCALER_DST_POS				0x44
> +#define SCALER_DST_H_POS_MASK			0x3fff
> +#define SCALER_DST_H_POS_SHIFT			16
> +#define SCALER_DST_V_POS_MASK			0x3fff
> +#define SCALER_DST_V_POS_SHIFT			0
> +
> +/* SCALER horizontal scale ratio */
> +#define SCALER_H_RATIO				0x50
> +#define SCALER_H_RATIO_MASK			0x7ffff
> +#define SCALER_H_RATIO_SHIFT			0
> +
> +/* SCALER vertical scale ratio */
> +#define SCALER_V_RATIO				0x54
> +#define SCALER_V_RATIO_MASK			0x7ffff
> +#define SCALER_V_RATIO_SHIFT			0
> +
> +/* SCALER rotation config */
> +#define SCALER_ROT_CFG				0x58
> +#define SCALER_FLIP_X_EN			(1 << 3)
> +#define SCALER_FLIP_Y_EN			(1 << 2)
> +#define SCALER_ROTMODE_MASK			0x3
> +#define SCALER_ROTMODE_SHIFT			0
> +
> +/* SCALER csc coefficients */
> +#define SCALER_CSC_COEF(x, y)			(0x220 + ((x * 12) + (y * 4)))
> +
> +/* SCALER dither config */
> +#define SCALER_DITH_CFG				0x250
> +#define SCALER_DITHER_R_TYPE_MASK		0x7
> +#define SCALER_DITHER_R_TYPE_SHIFT		6
> +#define SCALER_DITHER_G_TYPE_MASK		0x7
> +#define SCALER_DITHER_G_TYPE_SHIFT		3
> +#define SCALER_DITHER_B_TYPE_MASK		0x7
> +#define SCALER_DITHER_B_TYPE_SHIFT		0
> +
> +/* SCALER src blend color */
> +#define SCALER_SRC_BLEND_COLOR			0x280
> +#define SCALER_SRC_COLOR_SEL_INV		(1 << 31)
> +#define SCALER_SRC_COLOR_SEL_MASK		0x3
> +#define SCALER_SRC_COLOR_SEL_SHIFT		29
> +#define SCALER_SRC_COLOR_OP_SEL_INV		(1 << 28)
> +#define SCALER_SRC_COLOR_OP_SEL_MASK		0xf
> +#define SCALER_SRC_COLOR_OP_SEL_SHIFT		24
> +#define SCALER_SRC_GLOBAL_COLOR0_MASK		0xff
> +#define SCALER_SRC_GLOBAL_COLOR0_SHIFT		16
> +#define SCALER_SRC_GLOBAL_COLOR1_MASK		0xff
> +#define SCALER_SRC_GLOBAL_COLOR1_SHIFT		8
> +#define SCALER_SRC_GLOBAL_COLOR2_MASK		0xff
> +#define SCALER_SRC_GLOBAL_COLOR2_SHIFT		0
> +
> +/* SCALER src blend alpha */
> +#define SCALER_SRC_BLEND_ALPHA			0x284
> +#define SCALER_SRC_ALPHA_SEL_INV		(1 << 31)
> +#define SCALER_SRC_ALPHA_SEL_MASK		0x3
> +#define SCALER_SRC_ALPHA_SEL_SHIFT		29
> +#define SCALER_SRC_ALPHA_OP_SEL_INV		(1 << 28)
> +#define SCALER_SRC_ALPHA_OP_SEL_MASK		0xf
> +#define SCALER_SRC_ALPHA_OP_SEL_SHIFT		24
> +#define SCALER_SRC_GLOBAL_ALPHA_MASK		0xff
> +#define SCALER_SRC_GLOBAL_ALPHA_SHIFT		0
> +
> +/* SCALER dst blend color */
> +#define SCALER_DST_BLEND_COLOR			0x288
> +#define SCALER_DST_COLOR_SEL_INV		(1 << 31)
> +#define SCALER_DST_COLOR_SEL_MASK		0x3
> +#define SCALER_DST_COLOR_SEL_SHIFT		29
> +#define SCALER_DST_COLOR_OP_SEL_INV		(1 << 28)
> +#define SCALER_DST_COLOR_OP_SEL_MASK		0xf
> +#define SCALER_DST_COLOR_OP_SEL_SHIFT		24
> +#define SCALER_DST_GLOBAL_COLOR0_MASK		0xff
> +#define SCALER_DST_GLOBAL_COLOR0_SHIFT		16
> +#define SCALER_DST_GLOBAL_COLOR1_MASK		0xff
> +#define SCALER_DST_GLOBAL_COLOR1_SHIFT		8
> +#define SCALER_DST_GLOBAL_COLOR2_MASK		0xff
> +#define SCALER_DST_GLOBAL_COLOR2_SHIFT		0
> +
> +/* SCALER dst blend alpha */
> +#define SCALER_DST_BLEND_ALPHA			0x28c
> +#define SCALER_DST_ALPHA_SEL_INV		(1 << 31)
> +#define SCALER_DST_ALPHA_SEL_MASK		0x3
> +#define SCALER_DST_ALPHA_SEL_SHIFT		29
> +#define SCALER_DST_ALPHA_OP_SEL_INV		(1 << 28)
> +#define SCALER_DST_ALPHA_OP_SEL_MASK		0xf
> +#define SCALER_DST_ALPHA_OP_SEL_SHIFT		24
> +#define SCALER_DST_GLOBAL_ALPHA_MASK		0xff
> +#define SCALER_DST_GLOBAL_ALPHA_SHIFT		0
> +
> +/* SCALER fill color */
> +#define SCALER_FILL_COLOR			0x290
> +#define SCALER_FILL_ALPHA_MASK			0xff
> +#define SCALER_FILL_ALPHA_SHIFT			24
> +#define SCALER_FILL_COLOR0_MASK			0xff
> +#define SCALER_FILL_COLOR0_SHIFT		16
> +#define SCALER_FILL_COLOR1_MASK			0xff
> +#define SCALER_FILL_COLOR1_SHIFT		8
> +#define SCALER_FILL_COLOR2_MASK			0xff
> +#define SCALER_FILL_COLOR2_SHIFT		0
> +
> +/* SCALER address queue config */
> +#define SCALER_ADDR_QUEUE_CONFIG		0x2a0
> +#define SCALER_ADDR_QUEUE_RST			0x1
> +
> +/* Arbitrary R/W register and value to check if soft reset succeeded */
> +#define SCALER_CFG_SOFT_RESET_CHECK_REG		SCALER_SRC_CFG
> +#define SCALER_CFG_SOFT_RESET_CHECK_VAL		0x3
> +
> +struct scaler_error {
> +	u32 irq_num;
> +	const char * const name;
> +};
> +
> +static const struct scaler_error scaler_errors[] = {
> +	{SCALER_INT_TIMEOUT,			"Timeout"},
> +	{SCALER_INT_ILLEGAL_BLEND,		"Illegal Blend setting"},
> +	{SCALER_INT_ILLEGAL_RATIO,		"Illegal Scale ratio setting"},
> +	{SCALER_INT_ILLEGAL_DST_HEIGHT,		"Illegal Dst Height"},
> +	{SCALER_INT_ILLEGAL_DST_WIDTH,		"Illegal Dst Width"},
> +	{SCALER_INT_ILLEGAL_DST_V_POS,		"Illegal Dst V-Pos"},
> +	{SCALER_INT_ILLEGAL_DST_H_POS,		"Illegal Dst H-Pos"},
> +	{SCALER_INT_ILLEGAL_DST_C_SPAN,		"Illegal Dst C-Span"},
> +	{SCALER_INT_ILLEGAL_DST_Y_SPAN,		"Illegal Dst Y-span"},
> +	{SCALER_INT_ILLEGAL_DST_CR_BASE,	"Illegal Dst Cr-base"},
> +	{SCALER_INT_ILLEGAL_DST_CB_BASE,	"Illegal Dst Cb-base"},
> +	{SCALER_INT_ILLEGAL_DST_Y_BASE,		"Illegal Dst Y-base"},
> +	{SCALER_INT_ILLEGAL_DST_COLOR,		"Illegal Dst Color"},
> +	{SCALER_INT_ILLEGAL_SRC_HEIGHT,		"Illegal Src Height"},
> +	{SCALER_INT_ILLEGAL_SRC_WIDTH,		"Illegal Src Width"},
> +	{SCALER_INT_ILLEGAL_SRC_CV_POS,		"Illegal Src Chroma V-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_CH_POS,		"Illegal Src Chroma H-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_YV_POS,		"Illegal Src Luma V-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_YH_POS,		"Illegal Src Luma H-pos"},
> +	{SCALER_INT_ILLEGAL_SRC_C_SPAN,		"Illegal Src C-span"},
> +	{SCALER_INT_ILLEGAL_SRC_Y_SPAN,		"Illegal Src Y-span"},
> +	{SCALER_INT_ILLEGAL_SRC_CR_BASE,	"Illegal Src Cr-base"},
> +	{SCALER_INT_ILLEGAL_SRC_CB_BASE,	"Illegal Src Cb-base"},
> +	{SCALER_INT_ILLEGAL_SRC_Y_BASE,		"Illegal Src Y-base"},
> +	{SCALER_INT_ILLEGAL_SRC_COLOR,		"Illegal Src Color setting"},
> +};
> +
> +#define SCALER_NUM_ERRORS	ARRAY_SIZE(scaler_errors)
> +
> +static inline u32 scaler_read(struct scaler_dev *dev, u32 offset)
> +{
> +	return readl(dev->regs + offset);
> +}
> +
> +static inline void scaler_write(struct scaler_dev *dev, u32 offset, u32 value)
> +{
> +	writel(value, dev->regs + offset);
> +}
> +
> +static inline void scaler_hw_address_queue_reset(struct scaler_ctx *ctx)
> +{
> +	scaler_write(ctx->scaler_dev, SCALER_ADDR_QUEUE_CONFIG,
> +					SCALER_ADDR_QUEUE_RST);
> +}
> +
> +void scaler_hw_set_sw_reset(struct scaler_dev *dev);
> +int scaler_wait_reset(struct scaler_dev *dev);
> +void scaler_hw_set_irq(struct scaler_dev *dev, int interrupt, bool mask);
> +void scaler_hw_set_input_addr(struct scaler_dev *dev, struct scaler_addr *addr);
> +void scaler_hw_set_output_addr(struct scaler_dev *dev,
> +				struct scaler_addr *addr);
> +void scaler_hw_set_in_size(struct scaler_ctx *ctx);
> +void scaler_hw_set_in_image_format(struct scaler_ctx *ctx);
> +void scaler_hw_set_out_size(struct scaler_ctx *ctx);
> +void scaler_hw_set_out_image_format(struct scaler_ctx *ctx);
> +void scaler_hw_set_scaler_ratio(struct scaler_ctx *ctx);
> +void scaler_hw_set_rotation(struct scaler_ctx *ctx);
> +void scaler_hw_set_csc_coeff(struct scaler_ctx *ctx);
> +void scaler_hw_src_y_offset_en(struct scaler_dev *dev, bool on);
> +void scaler_hw_dst_y_offset_en(struct scaler_dev *dev, bool on);
> +void scaler_hw_enable_control(struct scaler_dev *dev, bool on);
> +unsigned int scaler_hw_get_irq_status(struct scaler_dev *dev);
> +void scaler_hw_clear_irq(struct scaler_dev *dev, unsigned int irq);
> +
> +#endif /* REGS_SCALER_H_ */
Shaik Ameer Basha Jan. 7, 2014, 3:52 a.m. UTC | #5
Hi Mauro,

Thanks for the review comments.

On Fri, Jan 3, 2014 at 1:48 AM, Mauro Carvalho Chehab
<m.chehab@samsung.com> wrote:
> Em Fri,  4 Oct 2013 17:56:31 +0530
> Shaik Ameer Basha <shaik.ameer@samsung.com> escreveu:
>
>> This patch adds support for SCALER device which is a new device
>> for scaling, blending, color fill  and color space conversion
>> on EXYNOS5410 and EXYNOS5420 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 - Exynos5420
>>         - Input : 16x16 to 8192x8192
>>         - Output:   4x4 to 8192x8192
>>     Size - Exynos5410
>>         - Input/Output: 4x4 to 4096x4096
>>     alpha blending, color fill
>>
>> Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
>> ---
>>  drivers/media/platform/exynos-scaler/scaler-regs.c |  336 ++++++++++++++++++++
>>  drivers/media/platform/exynos-scaler/scaler-regs.h |  331 +++++++++++++++++++
>>  2 files changed, 667 insertions(+)
>>  create mode 100644 drivers/media/platform/exynos-scaler/scaler-regs.c
>>  create mode 100644 drivers/media/platform/exynos-scaler/scaler-regs.h
>>
>> diff --git a/drivers/media/platform/exynos-scaler/scaler-regs.c b/drivers/media/platform/exynos-scaler/scaler-regs.c
>> new file mode 100644
>> index 0000000..ae4a548
>> --- /dev/null
>> +++ b/drivers/media/platform/exynos-scaler/scaler-regs.c
>> @@ -0,0 +1,336 @@
>> +/*
>> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
>> + *           http://www.samsung.com
>> + *
>> + * Samsung EXYNOS5 SoC series 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.
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "scaler-regs.h"
>> +
>> +/* Scaler reset timeout in milliseconds */
>> +#define SCALER_RESET_TIMEOUT 50
>> +
>> +void scaler_hw_set_sw_reset(struct scaler_dev *dev)
>> +{
>> +     u32 cfg;
>> +
>> +     cfg = scaler_read(dev, SCALER_CFG);
>> +     cfg |= SCALER_CFG_SOFT_RESET;
>> +
>> +     scaler_write(dev, SCALER_CFG, cfg);
>> +}
>> +
>> +int scaler_wait_reset(struct scaler_dev *dev)
>> +{
>> +     unsigned long end = jiffies + msecs_to_jiffies(SCALER_RESET_TIMEOUT);
>> +     u32 cfg, reset_done = 0;
>> +
>> +     while (time_before(jiffies, end)) {
>> +             cfg = scaler_read(dev, SCALER_CFG);
>> +             if (!(cfg & SCALER_CFG_SOFT_RESET)) {
>> +                     reset_done = 1;
>> +                     break;
>> +             }
>> +             usleep_range(10, 20);
>
> Hmm... that doesn't seem right... the timeout can take up to 50,000 us, and
> you're sleeping from 10 to 20us... that means that this loop can have up to
> 5000 interactions... It seems that you're wasting power here without need.
>
> I suspect that you should consider sleeping for a longer time here.

I will check what is the average time taken for the reset process.
If it is much more than 20us then i will increase this sleeping time.

>
> Btw, instead of using time_before(jiffies, end), you could do:
>         time_is_after_jiffies(end)
>

Ok. I will modify.

> As, from jiffies.h:
>         /* time_is_after_jiffies(a) return true if a is after jiffies */
>         #define time_is_after_jiffies(a) time_before(jiffies, a)
>
>> +     }
>> +
>> +     /*
>> +      * Write any value to read/write register and read it back.
>> +      * If the written and read value matches, then the reset process is
>> +      * succeeded.
>> +      */
>> +     while (reset_done) {
>
> This is tricky. If the reset fail, it will return busy. Otherwise, it
> can loop forever here. Worse than that, you're don't even sleeping
> before retries, again wasting power.
>
> Why don't you just change it to something similar to:
>
>         if (!reset_done)
>                 return -EBUSY;
>
>         end = jiffies + msecs_to_jiffies(SCALER_RESET_TIMEOUT);
>         while (time_is_after_jiffies(end)) {
>                 scaler_write(dev, SCALER_CFG_SOFT_RESET_CHECK_REG,
>                                 SCALER_CFG_SOFT_RESET_CHECK_VAL);
>                 if (SCALER_CFG_SOFT_RESET_CHECK_VAL ==
>                         scaler_read(dev, SCALER_CFG_SOFT_RESET_CHECK_REG))
>                         return 0;
>                 msleep(10);
>         }


My Intention is to complete the reset process ASAP.
Again I need to check the average time here. As per you comments if
the time taken is more
then I will go with adding sleep here.

Regards,
Shaik Ameer Basha

>
>> +
>> +             /*
>> +              * TODO: need to define number of tries before returning
>> +              * -EBUSY to the caller
>> +              */
>> +
>> +             scaler_write(dev, SCALER_CFG_SOFT_RESET_CHECK_REG,
>> +                             SCALER_CFG_SOFT_RESET_CHECK_VAL);
>> +             if (SCALER_CFG_SOFT_RESET_CHECK_VAL ==
>> +                     scaler_read(dev, SCALER_CFG_SOFT_RESET_CHECK_REG))
>> +                     return 0;
>> +     }
>> +
>> +     return -EBUSY;
>> +}
>> +
>> +void scaler_hw_set_irq(struct scaler_dev *dev, int irq_num, bool enable)
>> +{
>> +     u32 cfg;
>> +
>> +     if ((irq_num < SCALER_INT_FRAME_END) ||
>> +         (irq_num > SCALER_INT_TIMEOUT))
>> +             return;
>> +
>> +     cfg = scaler_read(dev, SCALER_INT_EN);
>> +     if (enable)
>> +             cfg |= (1 << irq_num);
>
> Why do you need parenthesis here?
>
>> +     else
>> +             cfg &= ~(1 << irq_num);
>
>
>> +     scaler_write(dev, SCALER_INT_EN, cfg);
>> +}
>> +
>> +void scaler_hw_set_input_addr(struct scaler_dev *dev, struct scaler_addr *addr)
>> +{
>> +     scaler_dbg(dev, "src_buf: 0x%x, cb: 0x%x, cr: 0x%x",
>> +                             addr->y, addr->cb, addr->cr);
>> +     scaler_write(dev, SCALER_SRC_Y_BASE, addr->y);
>> +     scaler_write(dev, SCALER_SRC_CB_BASE, addr->cb);
>> +     scaler_write(dev, SCALER_SRC_CR_BASE, addr->cr);
>> +}
>> +
>> +void scaler_hw_set_output_addr(struct scaler_dev *dev,
>> +                          struct scaler_addr *addr)
>> +{
>> +     scaler_dbg(dev, "dst_buf: 0x%x, cb: 0x%x, cr: 0x%x",
>> +                     addr->y, addr->cb, addr->cr);
>> +     scaler_write(dev, SCALER_DST_Y_BASE, addr->y);
>> +     scaler_write(dev, SCALER_DST_CB_BASE, addr->cb);
>> +     scaler_write(dev, SCALER_DST_CR_BASE, addr->cr);
>> +}
>> +
>> +void scaler_hw_set_in_size(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->s_frame;
>> +     u32 cfg;
>> +
>> +     /* set input pixel offset */
>> +     cfg = (frame->selection.left & SCALER_SRC_YH_POS_MASK) <<
>> +                               SCALER_SRC_YH_POS_SHIFT;
>> +     cfg |= ((frame->selection.top & SCALER_SRC_YV_POS_MASK) <<
>> +                                SCALER_SRC_YV_POS_SHIFT);
>> +     scaler_write(dev, SCALER_SRC_Y_POS, cfg);
>> +
>> +     /* TODO: calculate 'C' plane h/v offset using 'Y' plane h/v offset */
>> +
>> +     /* Set input span */
>> +     cfg = (frame->f_width & SCALER_SRC_Y_SPAN_MASK) <<
>> +                             SCALER_SRC_Y_SPAN_SHIFT;
>> +     if (is_yuv420_2p(frame->fmt))
>> +             cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
>> +                                       SCALER_SRC_C_SPAN_SHIFT);
>> +     else /* TODO: Verify */
>> +             cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
>> +                                       SCALER_SRC_C_SPAN_SHIFT);
>> +
>> +     scaler_write(dev, SCALER_SRC_SPAN, cfg);
>> +
>> +     /* Set input cropped size */
>> +     cfg = (frame->selection.width & SCALER_SRC_WIDTH_MASK) <<
>> +                                SCALER_SRC_WIDTH_SHIFT;
>> +     cfg |= ((frame->selection.height & SCALER_SRC_HEIGHT_MASK) <<
>> +                                   SCALER_SRC_HEIGHT_SHIFT);
>> +     scaler_write(dev, SCALER_SRC_WH, cfg);
>> +
>> +     scaler_dbg(dev, "src: posx: %d, posY: %d, spanY: %d, spanC: %d, cropX: %d, cropY: %d\n",
>> +             frame->selection.left, frame->selection.top,
>> +             frame->f_width, frame->f_width, frame->selection.width,
>> +             frame->selection.height);
>> +}
>> +
>> +void scaler_hw_set_in_image_format(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->s_frame;
>> +     u32 cfg;
>> +
>> +     cfg = scaler_read(dev, SCALER_SRC_CFG);
>> +     cfg &= ~(SCALER_SRC_COLOR_FORMAT_MASK << SCALER_SRC_COLOR_FORMAT_SHIFT);
>> +     cfg |= ((frame->fmt->scaler_color & SCALER_SRC_COLOR_FORMAT_MASK) <<
>> +                                        SCALER_SRC_COLOR_FORMAT_SHIFT);
>> +
>> +     /* Setting tiled/linear format */
>> +     if (is_tiled_fmt(frame->fmt))
>> +             cfg |= SCALER_SRC_TILE_EN;
>> +     else
>> +             cfg &= ~SCALER_SRC_TILE_EN;
>> +
>> +     scaler_write(dev, SCALER_SRC_CFG, cfg);
>> +}
>> +
>> +void scaler_hw_set_out_size(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->d_frame;
>> +     u32 cfg;
>> +
>> +     /* Set output pixel offset */
>> +     cfg = (frame->selection.left & SCALER_DST_H_POS_MASK) <<
>> +                               SCALER_DST_H_POS_SHIFT;
>> +     cfg |= (frame->selection.top & SCALER_DST_V_POS_MASK) <<
>> +                               SCALER_DST_V_POS_SHIFT;
>> +     scaler_write(dev, SCALER_DST_POS, cfg);
>> +
>> +     /* Set output span */
>> +     cfg = (frame->f_width & SCALER_DST_Y_SPAN_MASK) <<
>> +                             SCALER_DST_Y_SPAN_SHIFT;
>> +     if (is_yuv420_2p(frame->fmt))
>> +             cfg |= (((frame->f_width / 2) & SCALER_DST_C_SPAN_MASK) <<
>> +                                          SCALER_DST_C_SPAN_SHIFT);
>> +     else
>> +             cfg |= (((frame->f_width) & SCALER_DST_C_SPAN_MASK) <<
>> +                                          SCALER_DST_C_SPAN_SHIFT);
>> +     scaler_write(dev, SCALER_DST_SPAN, cfg);
>> +
>> +     /* Set output scaled size */
>> +     cfg = (frame->selection.width & SCALER_DST_WIDTH_MASK) <<
>> +                                SCALER_DST_WIDTH_SHIFT;
>> +     cfg |= (frame->selection.height & SCALER_DST_HEIGHT_MASK) <<
>> +                                  SCALER_DST_HEIGHT_SHIFT;
>> +     scaler_write(dev, SCALER_DST_WH, cfg);
>> +
>> +     scaler_dbg(dev, "dst: pos X: %d, pos Y: %d, span Y: %d, span C: %d, crop X: %d, crop Y: %d\n",
>> +             frame->selection.left, frame->selection.top,
>> +             frame->f_width, frame->f_width, frame->selection.width,
>> +             frame->selection.height);
>> +}
>> +
>> +void scaler_hw_set_out_image_format(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_frame *frame = &ctx->d_frame;
>> +     u32 cfg;
>> +
>> +     cfg = scaler_read(dev, SCALER_DST_CFG);
>> +     cfg &= ~SCALER_DST_COLOR_FORMAT_MASK;
>> +     cfg |= (frame->fmt->scaler_color & SCALER_DST_COLOR_FORMAT_MASK);
>> +
>> +     scaler_write(dev, SCALER_DST_CFG, cfg);
>> +}
>> +
>> +void scaler_hw_set_scaler_ratio(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     struct scaler_scaler *sc = &ctx->scaler;
>> +     u32 cfg;
>> +
>> +     cfg = (sc->hratio & SCALER_H_RATIO_MASK) << SCALER_H_RATIO_SHIFT;
>> +     scaler_write(dev, SCALER_H_RATIO, cfg);
>> +
>> +     cfg = (sc->vratio & SCALER_V_RATIO_MASK) << SCALER_V_RATIO_SHIFT;
>> +     scaler_write(dev, SCALER_V_RATIO, cfg);
>> +}
>> +
>> +void scaler_hw_set_rotation(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     u32 cfg = 0;
>> +
>> +     cfg = ((ctx->ctrls_scaler.rotate->val / 90) & SCALER_ROTMODE_MASK) <<
>> +                                                   SCALER_ROTMODE_SHIFT;
>> +
>> +     if (ctx->ctrls_scaler.hflip->val)
>> +             cfg |= SCALER_FLIP_X_EN;
>> +
>> +     if (ctx->ctrls_scaler.vflip->val)
>> +             cfg |= SCALER_FLIP_Y_EN;
>> +
>> +     scaler_write(dev, SCALER_ROT_CFG, cfg);
>> +}
>> +
>> +void scaler_hw_set_csc_coeff(struct scaler_ctx *ctx)
>> +{
>> +     struct scaler_dev *dev = ctx->scaler_dev;
>> +     enum scaler_csc_coeff type;
>> +     u32 cfg = 0;
>> +     int i, j;
>> +     static const u32 csc_coeff[SCALER_CSC_COEFF_MAX][3][3] = {
>> +             { /* YCbCr to RGB */
>> +                     {0x254, 0x000, 0x331},
>> +                     {0x254, 0xec8, 0xFA0},
>> +                     {0x254, 0x409, 0x000}
>> +             },
>> +             { /* RGB to YCbCr */
>> +                     {0x084, 0x102, 0x032},
>> +                     {0xe4c, 0xe95, 0x0e1},
>> +                     {0x0e1, 0xebc, 0xe24}
>> +             } };
>> +
>> +     /* TODO: add check for BT.601,BT.709 narrow/wide ranges */
>> +     if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt)) {
>> +             type = SCALER_CSC_COEFF_NONE;
>> +     } else if (is_rgb(ctx->d_frame.fmt)) {
>> +             type = SCALER_CSC_COEFF_YCBCR_TO_RGB;
>> +             scaler_hw_src_y_offset_en(ctx->scaler_dev, true);
>> +     } else {
>> +             type = SCALER_CSC_COEFF_RGB_TO_YCBCR;
>> +             scaler_hw_src_y_offset_en(ctx->scaler_dev, true);
>> +     }
>> +
>> +     if (type == ctx->scaler_dev->coeff_type || type >= SCALER_CSC_COEFF_MAX)
>> +             return;
>> +
>> +     for (i = 0; i < 3; i++) {
>> +             for (j = 0; j < 3; j++) {
>> +                     cfg = csc_coeff[type][i][j];
>> +                     scaler_write(dev, SCALER_CSC_COEF(i, j), cfg);
>> +             }
>> +     }
>> +
>> +     ctx->scaler_dev->coeff_type = type;
>> +}
>> +
>> +void scaler_hw_src_y_offset_en(struct scaler_dev *dev, bool on)
>> +{
>> +     u32 cfg;
>> +
>> +     cfg = scaler_read(dev, SCALER_CFG);
>> +     if (on)
>> +             cfg |= SCALER_CFG_CSC_Y_OFFSET_SRC_EN;
>> +     else
>> +             cfg &= ~SCALER_CFG_CSC_Y_OFFSET_SRC_EN;
>> +
>> +     scaler_write(dev, SCALER_CFG, cfg);
>> +}
>> +
>> +void scaler_hw_dst_y_offset_en(struct scaler_dev *dev, bool on)
>> +{
>> +     u32 cfg;
>> +
>> +     cfg = scaler_read(dev, SCALER_CFG);
>> +     if (on)
>> +             cfg |= SCALER_CFG_CSC_Y_OFFSET_DST_EN;
>> +     else
>> +             cfg &= ~SCALER_CFG_CSC_Y_OFFSET_DST_EN;
>> +
>> +     scaler_write(dev, SCALER_CFG, cfg);
>> +}
>> +
>> +void scaler_hw_enable_control(struct scaler_dev *dev, bool on)
>> +{
>> +     u32 cfg;
>> +
>> +     if (on)
>> +             scaler_write(dev, SCALER_INT_EN, 0xffffffff);
>> +
>> +     cfg = scaler_read(dev, SCALER_CFG);
>> +     cfg |= SCALER_CFG_16_BURST_MODE;
>> +     if (on)
>> +             cfg |= SCALER_CFG_START_CMD;
>> +     else
>> +             cfg &= ~SCALER_CFG_START_CMD;
>> +
>> +     scaler_dbg(dev, "%s: SCALER_CFG:0x%x\n", __func__, cfg);
>> +
>> +     scaler_write(dev, SCALER_CFG, cfg);
>> +}
>> +
>> +unsigned int scaler_hw_get_irq_status(struct scaler_dev *dev)
>> +{
>> +     return scaler_read(dev, SCALER_INT_STATUS);
>> +}
>> +
>> +void scaler_hw_clear_irq(struct scaler_dev *dev, unsigned int irq)
>> +{
>> +     scaler_write(dev, SCALER_INT_STATUS, irq);
>> +}
>> diff --git a/drivers/media/platform/exynos-scaler/scaler-regs.h b/drivers/media/platform/exynos-scaler/scaler-regs.h
>> new file mode 100644
>> index 0000000..2170df5
>> --- /dev/null
>> +++ b/drivers/media/platform/exynos-scaler/scaler-regs.h
>> @@ -0,0 +1,331 @@
>> +/*
>> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
>> + *           http://www.samsung.com
>> + *
>> + * Samsung EXYNOS5 SoC series 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_SCALER_H_
>> +#define REGS_SCALER_H_
>> +
>> +#include "scaler.h"
>> +
>> +/* SCALER status */
>> +#define SCALER_STATUS                                0x00
>> +#define SCALER_STATUS_RUNNING                        (1 << 1)
>> +#define SCALER_STATUS_READY_CLK_DOWN         (1 << 0)
>> +
>> +/* SCALER config */
>> +#define SCALER_CFG                           0x04
>> +#define SCALER_CFG_FILL_EN                   (1 << 24)
>> +#define SCALER_CFG_BLEND_CLR_DIV_ALPHA_EN    (1 << 17)
>> +#define SCALER_CFG_BLEND_EN                  (1 << 16)
>> +#define SCALER_CFG_CSC_Y_OFFSET_SRC_EN               (1 << 10)
>> +#define SCALER_CFG_CSC_Y_OFFSET_DST_EN               (1 << 9)
>> +#define SCALER_CFG_16_BURST_MODE             (1 << 8)
>> +#define SCALER_CFG_SOFT_RESET                        (1 << 1)
>> +#define SCALER_CFG_START_CMD                 (1 << 0)
>> +
>> +/* SCALER interrupts */
>> +#define SCALER_INT_TIMEOUT                   31
>> +#define SCALER_INT_ILLEGAL_BLEND             24
>> +#define SCALER_INT_ILLEGAL_RATIO             23
>> +#define SCALER_INT_ILLEGAL_DST_HEIGHT                22
>> +#define SCALER_INT_ILLEGAL_DST_WIDTH         21
>> +#define SCALER_INT_ILLEGAL_DST_V_POS         20
>> +#define SCALER_INT_ILLEGAL_DST_H_POS         19
>> +#define SCALER_INT_ILLEGAL_DST_C_SPAN                18
>> +#define SCALER_INT_ILLEGAL_DST_Y_SPAN                17
>> +#define SCALER_INT_ILLEGAL_DST_CR_BASE               16
>> +#define SCALER_INT_ILLEGAL_DST_CB_BASE               15
>> +#define SCALER_INT_ILLEGAL_DST_Y_BASE                14
>> +#define SCALER_INT_ILLEGAL_DST_COLOR         13
>> +#define SCALER_INT_ILLEGAL_SRC_HEIGHT                12
>> +#define SCALER_INT_ILLEGAL_SRC_WIDTH         11
>> +#define SCALER_INT_ILLEGAL_SRC_CV_POS                10
>> +#define SCALER_INT_ILLEGAL_SRC_CH_POS                9
>> +#define SCALER_INT_ILLEGAL_SRC_YV_POS                8
>> +#define SCALER_INT_ILLEGAL_SRC_YH_POS                7
>> +#define SCALER_INT_ILLEGAL_SRC_C_SPAN                6
>> +#define SCALER_INT_ILLEGAL_SRC_Y_SPAN                5
>> +#define SCALER_INT_ILLEGAL_SRC_CR_BASE               4
>> +#define SCALER_INT_ILLEGAL_SRC_CB_BASE               3
>> +#define SCALER_INT_ILLEGAL_SRC_Y_BASE                2
>> +#define SCALER_INT_ILLEGAL_SRC_COLOR         1
>> +#define SCALER_INT_FRAME_END                 0
>> +
>> +/* SCALER interrupt enable */
>> +#define SCALER_INT_EN                                0x08
>> +#define SCALER_INT_EN_DEFAULT                        0x81ffffff
>> +
>> +/* SCALER interrupt status */
>> +#define SCALER_INT_STATUS                    0x0c
>> +#define SCALER_INT_STATUS_CLEAR                      0xffffffff
>> +#define SCALER_INT_STATUS_ERROR                      0x81fffffe
>> +
>> +/* SCALER source format configuration */
>> +#define SCALER_SRC_CFG                               0x10
>> +#define SCALER_SRC_TILE_EN                   (0x1 << 10)
>> +#define SCALER_SRC_BYTE_SWAP_MASK            0x3
>> +#define SCALER_SRC_BYTE_SWAP_SHIFT           5
>> +#define SCALER_SRC_COLOR_FORMAT_MASK         0xf
>> +#define SCALER_SRC_COLOR_FORMAT_SHIFT                0
>> +
>> +/* SCALER source y-base */
>> +#define SCALER_SRC_Y_BASE                    0x14
>> +
>> +/* SCALER source cb-base */
>> +#define SCALER_SRC_CB_BASE                   0x18
>> +
>> +/* SCALER source cr-base */
>> +#define SCALER_SRC_CR_BASE                   0x294
>> +
>> +/* SCALER source span */
>> +#define SCALER_SRC_SPAN                              0x1c
>> +#define SCALER_SRC_C_SPAN_MASK                       0x3fff
>> +#define SCALER_SRC_C_SPAN_SHIFT                      16
>> +#define SCALER_SRC_Y_SPAN_MASK                       0x3fff
>> +#define SCALER_SRC_Y_SPAN_SHIFT                      0
>> +
>> +/*
>> + * SCALER source y-position
>> + * 14.2 fixed-point format
>> + *      - 14 bits at the MSB are for the integer part.
>> + *      - 2 bits at LSB are for fractional part and always has to be set to 0.
>> + */
>> +#define SCALER_SRC_Y_POS                     0x20
>> +#define SCALER_SRC_YH_POS_MASK                       0xfffc
>> +#define SCALER_SRC_YH_POS_SHIFT                      16
>> +#define SCALER_SRC_YV_POS_MASK                       0xfffc
>> +#define SCALER_SRC_YV_POS_SHIFT                      0
>> +
>> +/* SCALER source width/height */
>> +#define SCALER_SRC_WH                                0x24
>> +#define SCALER_SRC_WIDTH_MASK                        0x3fff
>> +#define SCALER_SRC_WIDTH_SHIFT                       16
>> +#define SCALER_SRC_HEIGHT_MASK                       0x3fff
>> +#define SCALER_SRC_HEIGHT_SHIFT                      0
>> +
>> +/*
>> + * SCALER source c-position
>> + * 14.2 fixed-point format
>> + *      - 14 bits at the MSB are for the integer part.
>> + *      - 2 bits at LSB are for fractional part and always has to be set to 0.
>> + */
>> +#define SCALER_SRC_C_POS                     0x28
>> +#define SCALER_SRC_CH_POS_MASK                       0xfffc
>> +#define SCALER_SRC_CH_POS_SHIFT                      16
>> +#define SCALER_SRC_CV_POS_MASK                       0xfffc
>> +#define SCALER_SRC_CV_POS_SHIFT                      0
>> +
>> +/* SCALER destination format configuration */
>> +#define SCALER_DST_CFG                               0x30
>> +#define SCALER_DST_BYTE_SWAP_MASK            0x3
>> +#define SCALER_DST_BYTE_SWAP_SHIFT           5
>> +#define SCALER_DST_COLOR_FORMAT_MASK         0xf
>> +
>> +/* SCALER destination y-base */
>> +#define SCALER_DST_Y_BASE                    0x34
>> +
>> +/* SCALER destination cb-base */
>> +#define SCALER_DST_CB_BASE                   0x38
>> +
>> +/* SCALER destination cr-base */
>> +#define SCALER_DST_CR_BASE                   0x298
>> +
>> +/* SCALER destination span */
>> +#define SCALER_DST_SPAN                              0x3c
>> +#define SCALER_DST_C_SPAN_MASK                       0x3fff
>> +#define SCALER_DST_C_SPAN_SHIFT                      16
>> +#define SCALER_DST_Y_SPAN_MASK                       0x3fff
>> +#define SCALER_DST_Y_SPAN_SHIFT                      0
>> +
>> +/* SCALER destination width/height */
>> +#define SCALER_DST_WH                                0x40
>> +#define SCALER_DST_WIDTH_MASK                        0x3fff
>> +#define SCALER_DST_WIDTH_SHIFT                       16
>> +#define SCALER_DST_HEIGHT_MASK                       0x3fff
>> +#define SCALER_DST_HEIGHT_SHIFT                      0
>> +
>> +/* SCALER destination position */
>> +#define SCALER_DST_POS                               0x44
>> +#define SCALER_DST_H_POS_MASK                        0x3fff
>> +#define SCALER_DST_H_POS_SHIFT                       16
>> +#define SCALER_DST_V_POS_MASK                        0x3fff
>> +#define SCALER_DST_V_POS_SHIFT                       0
>> +
>> +/* SCALER horizontal scale ratio */
>> +#define SCALER_H_RATIO                               0x50
>> +#define SCALER_H_RATIO_MASK                  0x7ffff
>> +#define SCALER_H_RATIO_SHIFT                 0
>> +
>> +/* SCALER vertical scale ratio */
>> +#define SCALER_V_RATIO                               0x54
>> +#define SCALER_V_RATIO_MASK                  0x7ffff
>> +#define SCALER_V_RATIO_SHIFT                 0
>> +
>> +/* SCALER rotation config */
>> +#define SCALER_ROT_CFG                               0x58
>> +#define SCALER_FLIP_X_EN                     (1 << 3)
>> +#define SCALER_FLIP_Y_EN                     (1 << 2)
>> +#define SCALER_ROTMODE_MASK                  0x3
>> +#define SCALER_ROTMODE_SHIFT                 0
>> +
>> +/* SCALER csc coefficients */
>> +#define SCALER_CSC_COEF(x, y)                        (0x220 + ((x * 12) + (y * 4)))
>> +
>> +/* SCALER dither config */
>> +#define SCALER_DITH_CFG                              0x250
>> +#define SCALER_DITHER_R_TYPE_MASK            0x7
>> +#define SCALER_DITHER_R_TYPE_SHIFT           6
>> +#define SCALER_DITHER_G_TYPE_MASK            0x7
>> +#define SCALER_DITHER_G_TYPE_SHIFT           3
>> +#define SCALER_DITHER_B_TYPE_MASK            0x7
>> +#define SCALER_DITHER_B_TYPE_SHIFT           0
>> +
>> +/* SCALER src blend color */
>> +#define SCALER_SRC_BLEND_COLOR                       0x280
>> +#define SCALER_SRC_COLOR_SEL_INV             (1 << 31)
>> +#define SCALER_SRC_COLOR_SEL_MASK            0x3
>> +#define SCALER_SRC_COLOR_SEL_SHIFT           29
>> +#define SCALER_SRC_COLOR_OP_SEL_INV          (1 << 28)
>> +#define SCALER_SRC_COLOR_OP_SEL_MASK         0xf
>> +#define SCALER_SRC_COLOR_OP_SEL_SHIFT                24
>> +#define SCALER_SRC_GLOBAL_COLOR0_MASK                0xff
>> +#define SCALER_SRC_GLOBAL_COLOR0_SHIFT               16
>> +#define SCALER_SRC_GLOBAL_COLOR1_MASK                0xff
>> +#define SCALER_SRC_GLOBAL_COLOR1_SHIFT               8
>> +#define SCALER_SRC_GLOBAL_COLOR2_MASK                0xff
>> +#define SCALER_SRC_GLOBAL_COLOR2_SHIFT               0
>> +
>> +/* SCALER src blend alpha */
>> +#define SCALER_SRC_BLEND_ALPHA                       0x284
>> +#define SCALER_SRC_ALPHA_SEL_INV             (1 << 31)
>> +#define SCALER_SRC_ALPHA_SEL_MASK            0x3
>> +#define SCALER_SRC_ALPHA_SEL_SHIFT           29
>> +#define SCALER_SRC_ALPHA_OP_SEL_INV          (1 << 28)
>> +#define SCALER_SRC_ALPHA_OP_SEL_MASK         0xf
>> +#define SCALER_SRC_ALPHA_OP_SEL_SHIFT                24
>> +#define SCALER_SRC_GLOBAL_ALPHA_MASK         0xff
>> +#define SCALER_SRC_GLOBAL_ALPHA_SHIFT                0
>> +
>> +/* SCALER dst blend color */
>> +#define SCALER_DST_BLEND_COLOR                       0x288
>> +#define SCALER_DST_COLOR_SEL_INV             (1 << 31)
>> +#define SCALER_DST_COLOR_SEL_MASK            0x3
>> +#define SCALER_DST_COLOR_SEL_SHIFT           29
>> +#define SCALER_DST_COLOR_OP_SEL_INV          (1 << 28)
>> +#define SCALER_DST_COLOR_OP_SEL_MASK         0xf
>> +#define SCALER_DST_COLOR_OP_SEL_SHIFT                24
>> +#define SCALER_DST_GLOBAL_COLOR0_MASK                0xff
>> +#define SCALER_DST_GLOBAL_COLOR0_SHIFT               16
>> +#define SCALER_DST_GLOBAL_COLOR1_MASK                0xff
>> +#define SCALER_DST_GLOBAL_COLOR1_SHIFT               8
>> +#define SCALER_DST_GLOBAL_COLOR2_MASK                0xff
>> +#define SCALER_DST_GLOBAL_COLOR2_SHIFT               0
>> +
>> +/* SCALER dst blend alpha */
>> +#define SCALER_DST_BLEND_ALPHA                       0x28c
>> +#define SCALER_DST_ALPHA_SEL_INV             (1 << 31)
>> +#define SCALER_DST_ALPHA_SEL_MASK            0x3
>> +#define SCALER_DST_ALPHA_SEL_SHIFT           29
>> +#define SCALER_DST_ALPHA_OP_SEL_INV          (1 << 28)
>> +#define SCALER_DST_ALPHA_OP_SEL_MASK         0xf
>> +#define SCALER_DST_ALPHA_OP_SEL_SHIFT                24
>> +#define SCALER_DST_GLOBAL_ALPHA_MASK         0xff
>> +#define SCALER_DST_GLOBAL_ALPHA_SHIFT                0
>> +
>> +/* SCALER fill color */
>> +#define SCALER_FILL_COLOR                    0x290
>> +#define SCALER_FILL_ALPHA_MASK                       0xff
>> +#define SCALER_FILL_ALPHA_SHIFT                      24
>> +#define SCALER_FILL_COLOR0_MASK                      0xff
>> +#define SCALER_FILL_COLOR0_SHIFT             16
>> +#define SCALER_FILL_COLOR1_MASK                      0xff
>> +#define SCALER_FILL_COLOR1_SHIFT             8
>> +#define SCALER_FILL_COLOR2_MASK                      0xff
>> +#define SCALER_FILL_COLOR2_SHIFT             0
>> +
>> +/* SCALER address queue config */
>> +#define SCALER_ADDR_QUEUE_CONFIG             0x2a0
>> +#define SCALER_ADDR_QUEUE_RST                        0x1
>> +
>> +/* Arbitrary R/W register and value to check if soft reset succeeded */
>> +#define SCALER_CFG_SOFT_RESET_CHECK_REG              SCALER_SRC_CFG
>> +#define SCALER_CFG_SOFT_RESET_CHECK_VAL              0x3
>> +
>> +struct scaler_error {
>> +     u32 irq_num;
>> +     const char * const name;
>> +};
>> +
>> +static const struct scaler_error scaler_errors[] = {
>> +     {SCALER_INT_TIMEOUT,                    "Timeout"},
>> +     {SCALER_INT_ILLEGAL_BLEND,              "Illegal Blend setting"},
>> +     {SCALER_INT_ILLEGAL_RATIO,              "Illegal Scale ratio setting"},
>> +     {SCALER_INT_ILLEGAL_DST_HEIGHT,         "Illegal Dst Height"},
>> +     {SCALER_INT_ILLEGAL_DST_WIDTH,          "Illegal Dst Width"},
>> +     {SCALER_INT_ILLEGAL_DST_V_POS,          "Illegal Dst V-Pos"},
>> +     {SCALER_INT_ILLEGAL_DST_H_POS,          "Illegal Dst H-Pos"},
>> +     {SCALER_INT_ILLEGAL_DST_C_SPAN,         "Illegal Dst C-Span"},
>> +     {SCALER_INT_ILLEGAL_DST_Y_SPAN,         "Illegal Dst Y-span"},
>> +     {SCALER_INT_ILLEGAL_DST_CR_BASE,        "Illegal Dst Cr-base"},
>> +     {SCALER_INT_ILLEGAL_DST_CB_BASE,        "Illegal Dst Cb-base"},
>> +     {SCALER_INT_ILLEGAL_DST_Y_BASE,         "Illegal Dst Y-base"},
>> +     {SCALER_INT_ILLEGAL_DST_COLOR,          "Illegal Dst Color"},
>> +     {SCALER_INT_ILLEGAL_SRC_HEIGHT,         "Illegal Src Height"},
>> +     {SCALER_INT_ILLEGAL_SRC_WIDTH,          "Illegal Src Width"},
>> +     {SCALER_INT_ILLEGAL_SRC_CV_POS,         "Illegal Src Chroma V-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_CH_POS,         "Illegal Src Chroma H-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_YV_POS,         "Illegal Src Luma V-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_YH_POS,         "Illegal Src Luma H-pos"},
>> +     {SCALER_INT_ILLEGAL_SRC_C_SPAN,         "Illegal Src C-span"},
>> +     {SCALER_INT_ILLEGAL_SRC_Y_SPAN,         "Illegal Src Y-span"},
>> +     {SCALER_INT_ILLEGAL_SRC_CR_BASE,        "Illegal Src Cr-base"},
>> +     {SCALER_INT_ILLEGAL_SRC_CB_BASE,        "Illegal Src Cb-base"},
>> +     {SCALER_INT_ILLEGAL_SRC_Y_BASE,         "Illegal Src Y-base"},
>> +     {SCALER_INT_ILLEGAL_SRC_COLOR,          "Illegal Src Color setting"},
>> +};
>> +
>> +#define SCALER_NUM_ERRORS    ARRAY_SIZE(scaler_errors)
>> +
>> +static inline u32 scaler_read(struct scaler_dev *dev, u32 offset)
>> +{
>> +     return readl(dev->regs + offset);
>> +}
>> +
>> +static inline void scaler_write(struct scaler_dev *dev, u32 offset, u32 value)
>> +{
>> +     writel(value, dev->regs + offset);
>> +}
>> +
>> +static inline void scaler_hw_address_queue_reset(struct scaler_ctx *ctx)
>> +{
>> +     scaler_write(ctx->scaler_dev, SCALER_ADDR_QUEUE_CONFIG,
>> +                                     SCALER_ADDR_QUEUE_RST);
>> +}
>> +
>> +void scaler_hw_set_sw_reset(struct scaler_dev *dev);
>> +int scaler_wait_reset(struct scaler_dev *dev);
>> +void scaler_hw_set_irq(struct scaler_dev *dev, int interrupt, bool mask);
>> +void scaler_hw_set_input_addr(struct scaler_dev *dev, struct scaler_addr *addr);
>> +void scaler_hw_set_output_addr(struct scaler_dev *dev,
>> +                             struct scaler_addr *addr);
>> +void scaler_hw_set_in_size(struct scaler_ctx *ctx);
>> +void scaler_hw_set_in_image_format(struct scaler_ctx *ctx);
>> +void scaler_hw_set_out_size(struct scaler_ctx *ctx);
>> +void scaler_hw_set_out_image_format(struct scaler_ctx *ctx);
>> +void scaler_hw_set_scaler_ratio(struct scaler_ctx *ctx);
>> +void scaler_hw_set_rotation(struct scaler_ctx *ctx);
>> +void scaler_hw_set_csc_coeff(struct scaler_ctx *ctx);
>> +void scaler_hw_src_y_offset_en(struct scaler_dev *dev, bool on);
>> +void scaler_hw_dst_y_offset_en(struct scaler_dev *dev, bool on);
>> +void scaler_hw_enable_control(struct scaler_dev *dev, bool on);
>> +unsigned int scaler_hw_get_irq_status(struct scaler_dev *dev);
>> +void scaler_hw_clear_irq(struct scaler_dev *dev, unsigned int irq);
>> +
>> +#endif /* REGS_SCALER_H_ */
>
>
> --
>
> Cheers,
> Mauro
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" 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
diff mbox

Patch

diff --git a/drivers/media/platform/exynos-scaler/scaler-regs.c b/drivers/media/platform/exynos-scaler/scaler-regs.c
new file mode 100644
index 0000000..ae4a548
--- /dev/null
+++ b/drivers/media/platform/exynos-scaler/scaler-regs.c
@@ -0,0 +1,336 @@ 
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include "scaler-regs.h"
+
+/* Scaler reset timeout in milliseconds */
+#define SCALER_RESET_TIMEOUT	50
+
+void scaler_hw_set_sw_reset(struct scaler_dev *dev)
+{
+	u32 cfg;
+
+	cfg = scaler_read(dev, SCALER_CFG);
+	cfg |= SCALER_CFG_SOFT_RESET;
+
+	scaler_write(dev, SCALER_CFG, cfg);
+}
+
+int scaler_wait_reset(struct scaler_dev *dev)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(SCALER_RESET_TIMEOUT);
+	u32 cfg, reset_done = 0;
+
+	while (time_before(jiffies, end)) {
+		cfg = scaler_read(dev, SCALER_CFG);
+		if (!(cfg & SCALER_CFG_SOFT_RESET)) {
+			reset_done = 1;
+			break;
+		}
+		usleep_range(10, 20);
+	}
+
+	/*
+	 * Write any value to read/write register and read it back.
+	 * If the written and read value matches, then the reset process is
+	 * succeeded.
+	 */
+	while (reset_done) {
+
+		/*
+		 * TODO: need to define number of tries before returning
+		 * -EBUSY to the caller
+		 */
+
+		scaler_write(dev, SCALER_CFG_SOFT_RESET_CHECK_REG,
+				SCALER_CFG_SOFT_RESET_CHECK_VAL);
+		if (SCALER_CFG_SOFT_RESET_CHECK_VAL ==
+			scaler_read(dev, SCALER_CFG_SOFT_RESET_CHECK_REG))
+			return 0;
+	}
+
+	return -EBUSY;
+}
+
+void scaler_hw_set_irq(struct scaler_dev *dev, int irq_num, bool enable)
+{
+	u32 cfg;
+
+	if ((irq_num < SCALER_INT_FRAME_END) ||
+	    (irq_num > SCALER_INT_TIMEOUT))
+		return;
+
+	cfg = scaler_read(dev, SCALER_INT_EN);
+	if (enable)
+		cfg |= (1 << irq_num);
+	else
+		cfg &= ~(1 << irq_num);
+	scaler_write(dev, SCALER_INT_EN, cfg);
+}
+
+void scaler_hw_set_input_addr(struct scaler_dev *dev, struct scaler_addr *addr)
+{
+	scaler_dbg(dev, "src_buf: 0x%x, cb: 0x%x, cr: 0x%x",
+				addr->y, addr->cb, addr->cr);
+	scaler_write(dev, SCALER_SRC_Y_BASE, addr->y);
+	scaler_write(dev, SCALER_SRC_CB_BASE, addr->cb);
+	scaler_write(dev, SCALER_SRC_CR_BASE, addr->cr);
+}
+
+void scaler_hw_set_output_addr(struct scaler_dev *dev,
+			     struct scaler_addr *addr)
+{
+	scaler_dbg(dev, "dst_buf: 0x%x, cb: 0x%x, cr: 0x%x",
+			addr->y, addr->cb, addr->cr);
+	scaler_write(dev, SCALER_DST_Y_BASE, addr->y);
+	scaler_write(dev, SCALER_DST_CB_BASE, addr->cb);
+	scaler_write(dev, SCALER_DST_CR_BASE, addr->cr);
+}
+
+void scaler_hw_set_in_size(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	struct scaler_frame *frame = &ctx->s_frame;
+	u32 cfg;
+
+	/* set input pixel offset */
+	cfg = (frame->selection.left & SCALER_SRC_YH_POS_MASK) <<
+				  SCALER_SRC_YH_POS_SHIFT;
+	cfg |= ((frame->selection.top & SCALER_SRC_YV_POS_MASK) <<
+				   SCALER_SRC_YV_POS_SHIFT);
+	scaler_write(dev, SCALER_SRC_Y_POS, cfg);
+
+	/* TODO: calculate 'C' plane h/v offset using 'Y' plane h/v offset */
+
+	/* Set input span */
+	cfg = (frame->f_width & SCALER_SRC_Y_SPAN_MASK) <<
+				SCALER_SRC_Y_SPAN_SHIFT;
+	if (is_yuv420_2p(frame->fmt))
+		cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
+					  SCALER_SRC_C_SPAN_SHIFT);
+	else /* TODO: Verify */
+		cfg |= ((frame->f_width & SCALER_SRC_C_SPAN_MASK) <<
+					  SCALER_SRC_C_SPAN_SHIFT);
+
+	scaler_write(dev, SCALER_SRC_SPAN, cfg);
+
+	/* Set input cropped size */
+	cfg = (frame->selection.width & SCALER_SRC_WIDTH_MASK) <<
+				   SCALER_SRC_WIDTH_SHIFT;
+	cfg |= ((frame->selection.height & SCALER_SRC_HEIGHT_MASK) <<
+				      SCALER_SRC_HEIGHT_SHIFT);
+	scaler_write(dev, SCALER_SRC_WH, cfg);
+
+	scaler_dbg(dev, "src: posx: %d, posY: %d, spanY: %d, spanC: %d, cropX: %d, cropY: %d\n",
+		frame->selection.left, frame->selection.top,
+		frame->f_width, frame->f_width, frame->selection.width,
+		frame->selection.height);
+}
+
+void scaler_hw_set_in_image_format(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	struct scaler_frame *frame = &ctx->s_frame;
+	u32 cfg;
+
+	cfg = scaler_read(dev, SCALER_SRC_CFG);
+	cfg &= ~(SCALER_SRC_COLOR_FORMAT_MASK << SCALER_SRC_COLOR_FORMAT_SHIFT);
+	cfg |= ((frame->fmt->scaler_color & SCALER_SRC_COLOR_FORMAT_MASK) <<
+					   SCALER_SRC_COLOR_FORMAT_SHIFT);
+
+	/* Setting tiled/linear format */
+	if (is_tiled_fmt(frame->fmt))
+		cfg |= SCALER_SRC_TILE_EN;
+	else
+		cfg &= ~SCALER_SRC_TILE_EN;
+
+	scaler_write(dev, SCALER_SRC_CFG, cfg);
+}
+
+void scaler_hw_set_out_size(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	struct scaler_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	/* Set output pixel offset */
+	cfg = (frame->selection.left & SCALER_DST_H_POS_MASK) <<
+				  SCALER_DST_H_POS_SHIFT;
+	cfg |= (frame->selection.top & SCALER_DST_V_POS_MASK) <<
+				  SCALER_DST_V_POS_SHIFT;
+	scaler_write(dev, SCALER_DST_POS, cfg);
+
+	/* Set output span */
+	cfg = (frame->f_width & SCALER_DST_Y_SPAN_MASK) <<
+				SCALER_DST_Y_SPAN_SHIFT;
+	if (is_yuv420_2p(frame->fmt))
+		cfg |= (((frame->f_width / 2) & SCALER_DST_C_SPAN_MASK) <<
+					     SCALER_DST_C_SPAN_SHIFT);
+	else
+		cfg |= (((frame->f_width) & SCALER_DST_C_SPAN_MASK) <<
+					     SCALER_DST_C_SPAN_SHIFT);
+	scaler_write(dev, SCALER_DST_SPAN, cfg);
+
+	/* Set output scaled size */
+	cfg = (frame->selection.width & SCALER_DST_WIDTH_MASK) <<
+				   SCALER_DST_WIDTH_SHIFT;
+	cfg |= (frame->selection.height & SCALER_DST_HEIGHT_MASK) <<
+				     SCALER_DST_HEIGHT_SHIFT;
+	scaler_write(dev, SCALER_DST_WH, cfg);
+
+	scaler_dbg(dev, "dst: pos X: %d, pos Y: %d, span Y: %d, span C: %d, crop X: %d, crop Y: %d\n",
+		frame->selection.left, frame->selection.top,
+		frame->f_width, frame->f_width, frame->selection.width,
+		frame->selection.height);
+}
+
+void scaler_hw_set_out_image_format(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	struct scaler_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	cfg = scaler_read(dev, SCALER_DST_CFG);
+	cfg &= ~SCALER_DST_COLOR_FORMAT_MASK;
+	cfg |= (frame->fmt->scaler_color & SCALER_DST_COLOR_FORMAT_MASK);
+
+	scaler_write(dev, SCALER_DST_CFG, cfg);
+}
+
+void scaler_hw_set_scaler_ratio(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	struct scaler_scaler *sc = &ctx->scaler;
+	u32 cfg;
+
+	cfg = (sc->hratio & SCALER_H_RATIO_MASK) << SCALER_H_RATIO_SHIFT;
+	scaler_write(dev, SCALER_H_RATIO, cfg);
+
+	cfg = (sc->vratio & SCALER_V_RATIO_MASK) << SCALER_V_RATIO_SHIFT;
+	scaler_write(dev, SCALER_V_RATIO, cfg);
+}
+
+void scaler_hw_set_rotation(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	u32 cfg = 0;
+
+	cfg = ((ctx->ctrls_scaler.rotate->val / 90) & SCALER_ROTMODE_MASK) <<
+						      SCALER_ROTMODE_SHIFT;
+
+	if (ctx->ctrls_scaler.hflip->val)
+		cfg |= SCALER_FLIP_X_EN;
+
+	if (ctx->ctrls_scaler.vflip->val)
+		cfg |= SCALER_FLIP_Y_EN;
+
+	scaler_write(dev, SCALER_ROT_CFG, cfg);
+}
+
+void scaler_hw_set_csc_coeff(struct scaler_ctx *ctx)
+{
+	struct scaler_dev *dev = ctx->scaler_dev;
+	enum scaler_csc_coeff type;
+	u32 cfg = 0;
+	int i, j;
+	static const u32 csc_coeff[SCALER_CSC_COEFF_MAX][3][3] = {
+		{ /* YCbCr to RGB */
+			{0x254, 0x000, 0x331},
+			{0x254, 0xec8, 0xFA0},
+			{0x254, 0x409, 0x000}
+		},
+		{ /* RGB to YCbCr */
+			{0x084, 0x102, 0x032},
+			{0xe4c, 0xe95, 0x0e1},
+			{0x0e1, 0xebc, 0xe24}
+		} };
+
+	/* TODO: add check for BT.601,BT.709 narrow/wide ranges */
+	if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt)) {
+		type = SCALER_CSC_COEFF_NONE;
+	} else if (is_rgb(ctx->d_frame.fmt)) {
+		type = SCALER_CSC_COEFF_YCBCR_TO_RGB;
+		scaler_hw_src_y_offset_en(ctx->scaler_dev, true);
+	} else {
+		type = SCALER_CSC_COEFF_RGB_TO_YCBCR;
+		scaler_hw_src_y_offset_en(ctx->scaler_dev, true);
+	}
+
+	if (type == ctx->scaler_dev->coeff_type || type >= SCALER_CSC_COEFF_MAX)
+		return;
+
+	for (i = 0; i < 3; i++) {
+		for (j = 0; j < 3; j++) {
+			cfg = csc_coeff[type][i][j];
+			scaler_write(dev, SCALER_CSC_COEF(i, j), cfg);
+		}
+	}
+
+	ctx->scaler_dev->coeff_type = type;
+}
+
+void scaler_hw_src_y_offset_en(struct scaler_dev *dev, bool on)
+{
+	u32 cfg;
+
+	cfg = scaler_read(dev, SCALER_CFG);
+	if (on)
+		cfg |= SCALER_CFG_CSC_Y_OFFSET_SRC_EN;
+	else
+		cfg &= ~SCALER_CFG_CSC_Y_OFFSET_SRC_EN;
+
+	scaler_write(dev, SCALER_CFG, cfg);
+}
+
+void scaler_hw_dst_y_offset_en(struct scaler_dev *dev, bool on)
+{
+	u32 cfg;
+
+	cfg = scaler_read(dev, SCALER_CFG);
+	if (on)
+		cfg |= SCALER_CFG_CSC_Y_OFFSET_DST_EN;
+	else
+		cfg &= ~SCALER_CFG_CSC_Y_OFFSET_DST_EN;
+
+	scaler_write(dev, SCALER_CFG, cfg);
+}
+
+void scaler_hw_enable_control(struct scaler_dev *dev, bool on)
+{
+	u32 cfg;
+
+	if (on)
+		scaler_write(dev, SCALER_INT_EN, 0xffffffff);
+
+	cfg = scaler_read(dev, SCALER_CFG);
+	cfg |= SCALER_CFG_16_BURST_MODE;
+	if (on)
+		cfg |= SCALER_CFG_START_CMD;
+	else
+		cfg &= ~SCALER_CFG_START_CMD;
+
+	scaler_dbg(dev, "%s: SCALER_CFG:0x%x\n", __func__, cfg);
+
+	scaler_write(dev, SCALER_CFG, cfg);
+}
+
+unsigned int scaler_hw_get_irq_status(struct scaler_dev *dev)
+{
+	return scaler_read(dev, SCALER_INT_STATUS);
+}
+
+void scaler_hw_clear_irq(struct scaler_dev *dev, unsigned int irq)
+{
+	scaler_write(dev, SCALER_INT_STATUS, irq);
+}
diff --git a/drivers/media/platform/exynos-scaler/scaler-regs.h b/drivers/media/platform/exynos-scaler/scaler-regs.h
new file mode 100644
index 0000000..2170df5
--- /dev/null
+++ b/drivers/media/platform/exynos-scaler/scaler-regs.h
@@ -0,0 +1,331 @@ 
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series 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_SCALER_H_
+#define REGS_SCALER_H_
+
+#include "scaler.h"
+
+/* SCALER status */
+#define SCALER_STATUS				0x00
+#define SCALER_STATUS_RUNNING			(1 << 1)
+#define SCALER_STATUS_READY_CLK_DOWN		(1 << 0)
+
+/* SCALER config */
+#define SCALER_CFG				0x04
+#define SCALER_CFG_FILL_EN			(1 << 24)
+#define SCALER_CFG_BLEND_CLR_DIV_ALPHA_EN	(1 << 17)
+#define SCALER_CFG_BLEND_EN			(1 << 16)
+#define SCALER_CFG_CSC_Y_OFFSET_SRC_EN		(1 << 10)
+#define SCALER_CFG_CSC_Y_OFFSET_DST_EN		(1 << 9)
+#define SCALER_CFG_16_BURST_MODE		(1 << 8)
+#define SCALER_CFG_SOFT_RESET			(1 << 1)
+#define SCALER_CFG_START_CMD			(1 << 0)
+
+/* SCALER interrupts */
+#define SCALER_INT_TIMEOUT			31
+#define SCALER_INT_ILLEGAL_BLEND		24
+#define SCALER_INT_ILLEGAL_RATIO		23
+#define SCALER_INT_ILLEGAL_DST_HEIGHT		22
+#define SCALER_INT_ILLEGAL_DST_WIDTH		21
+#define SCALER_INT_ILLEGAL_DST_V_POS		20
+#define SCALER_INT_ILLEGAL_DST_H_POS		19
+#define SCALER_INT_ILLEGAL_DST_C_SPAN		18
+#define SCALER_INT_ILLEGAL_DST_Y_SPAN		17
+#define SCALER_INT_ILLEGAL_DST_CR_BASE		16
+#define SCALER_INT_ILLEGAL_DST_CB_BASE		15
+#define SCALER_INT_ILLEGAL_DST_Y_BASE		14
+#define SCALER_INT_ILLEGAL_DST_COLOR		13
+#define SCALER_INT_ILLEGAL_SRC_HEIGHT		12
+#define SCALER_INT_ILLEGAL_SRC_WIDTH		11
+#define SCALER_INT_ILLEGAL_SRC_CV_POS		10
+#define SCALER_INT_ILLEGAL_SRC_CH_POS		9
+#define SCALER_INT_ILLEGAL_SRC_YV_POS		8
+#define SCALER_INT_ILLEGAL_SRC_YH_POS		7
+#define SCALER_INT_ILLEGAL_SRC_C_SPAN		6
+#define SCALER_INT_ILLEGAL_SRC_Y_SPAN		5
+#define SCALER_INT_ILLEGAL_SRC_CR_BASE		4
+#define SCALER_INT_ILLEGAL_SRC_CB_BASE		3
+#define SCALER_INT_ILLEGAL_SRC_Y_BASE		2
+#define SCALER_INT_ILLEGAL_SRC_COLOR		1
+#define SCALER_INT_FRAME_END			0
+
+/* SCALER interrupt enable */
+#define SCALER_INT_EN				0x08
+#define SCALER_INT_EN_DEFAULT			0x81ffffff
+
+/* SCALER interrupt status */
+#define SCALER_INT_STATUS			0x0c
+#define SCALER_INT_STATUS_CLEAR			0xffffffff
+#define SCALER_INT_STATUS_ERROR			0x81fffffe
+
+/* SCALER source format configuration */
+#define SCALER_SRC_CFG				0x10
+#define SCALER_SRC_TILE_EN			(0x1 << 10)
+#define SCALER_SRC_BYTE_SWAP_MASK		0x3
+#define SCALER_SRC_BYTE_SWAP_SHIFT		5
+#define SCALER_SRC_COLOR_FORMAT_MASK		0xf
+#define SCALER_SRC_COLOR_FORMAT_SHIFT		0
+
+/* SCALER source y-base */
+#define SCALER_SRC_Y_BASE			0x14
+
+/* SCALER source cb-base */
+#define SCALER_SRC_CB_BASE			0x18
+
+/* SCALER source cr-base */
+#define SCALER_SRC_CR_BASE			0x294
+
+/* SCALER source span */
+#define SCALER_SRC_SPAN				0x1c
+#define SCALER_SRC_C_SPAN_MASK			0x3fff
+#define SCALER_SRC_C_SPAN_SHIFT			16
+#define SCALER_SRC_Y_SPAN_MASK			0x3fff
+#define SCALER_SRC_Y_SPAN_SHIFT			0
+
+/*
+ * SCALER source y-position
+ * 14.2 fixed-point format
+ *      - 14 bits at the MSB are for the integer part.
+ *      - 2 bits at LSB are for fractional part and always has to be set to 0.
+ */
+#define SCALER_SRC_Y_POS			0x20
+#define SCALER_SRC_YH_POS_MASK			0xfffc
+#define SCALER_SRC_YH_POS_SHIFT			16
+#define SCALER_SRC_YV_POS_MASK			0xfffc
+#define SCALER_SRC_YV_POS_SHIFT			0
+
+/* SCALER source width/height */
+#define SCALER_SRC_WH				0x24
+#define SCALER_SRC_WIDTH_MASK			0x3fff
+#define SCALER_SRC_WIDTH_SHIFT			16
+#define SCALER_SRC_HEIGHT_MASK			0x3fff
+#define SCALER_SRC_HEIGHT_SHIFT			0
+
+/*
+ * SCALER source c-position
+ * 14.2 fixed-point format
+ *      - 14 bits at the MSB are for the integer part.
+ *      - 2 bits at LSB are for fractional part and always has to be set to 0.
+ */
+#define SCALER_SRC_C_POS			0x28
+#define SCALER_SRC_CH_POS_MASK			0xfffc
+#define SCALER_SRC_CH_POS_SHIFT			16
+#define SCALER_SRC_CV_POS_MASK			0xfffc
+#define SCALER_SRC_CV_POS_SHIFT			0
+
+/* SCALER destination format configuration */
+#define SCALER_DST_CFG				0x30
+#define SCALER_DST_BYTE_SWAP_MASK		0x3
+#define SCALER_DST_BYTE_SWAP_SHIFT		5
+#define SCALER_DST_COLOR_FORMAT_MASK		0xf
+
+/* SCALER destination y-base */
+#define SCALER_DST_Y_BASE			0x34
+
+/* SCALER destination cb-base */
+#define SCALER_DST_CB_BASE			0x38
+
+/* SCALER destination cr-base */
+#define SCALER_DST_CR_BASE			0x298
+
+/* SCALER destination span */
+#define SCALER_DST_SPAN				0x3c
+#define SCALER_DST_C_SPAN_MASK			0x3fff
+#define SCALER_DST_C_SPAN_SHIFT			16
+#define SCALER_DST_Y_SPAN_MASK			0x3fff
+#define SCALER_DST_Y_SPAN_SHIFT			0
+
+/* SCALER destination width/height */
+#define SCALER_DST_WH				0x40
+#define SCALER_DST_WIDTH_MASK			0x3fff
+#define SCALER_DST_WIDTH_SHIFT			16
+#define SCALER_DST_HEIGHT_MASK			0x3fff
+#define SCALER_DST_HEIGHT_SHIFT			0
+
+/* SCALER destination position */
+#define SCALER_DST_POS				0x44
+#define SCALER_DST_H_POS_MASK			0x3fff
+#define SCALER_DST_H_POS_SHIFT			16
+#define SCALER_DST_V_POS_MASK			0x3fff
+#define SCALER_DST_V_POS_SHIFT			0
+
+/* SCALER horizontal scale ratio */
+#define SCALER_H_RATIO				0x50
+#define SCALER_H_RATIO_MASK			0x7ffff
+#define SCALER_H_RATIO_SHIFT			0
+
+/* SCALER vertical scale ratio */
+#define SCALER_V_RATIO				0x54
+#define SCALER_V_RATIO_MASK			0x7ffff
+#define SCALER_V_RATIO_SHIFT			0
+
+/* SCALER rotation config */
+#define SCALER_ROT_CFG				0x58
+#define SCALER_FLIP_X_EN			(1 << 3)
+#define SCALER_FLIP_Y_EN			(1 << 2)
+#define SCALER_ROTMODE_MASK			0x3
+#define SCALER_ROTMODE_SHIFT			0
+
+/* SCALER csc coefficients */
+#define SCALER_CSC_COEF(x, y)			(0x220 + ((x * 12) + (y * 4)))
+
+/* SCALER dither config */
+#define SCALER_DITH_CFG				0x250
+#define SCALER_DITHER_R_TYPE_MASK		0x7
+#define SCALER_DITHER_R_TYPE_SHIFT		6
+#define SCALER_DITHER_G_TYPE_MASK		0x7
+#define SCALER_DITHER_G_TYPE_SHIFT		3
+#define SCALER_DITHER_B_TYPE_MASK		0x7
+#define SCALER_DITHER_B_TYPE_SHIFT		0
+
+/* SCALER src blend color */
+#define SCALER_SRC_BLEND_COLOR			0x280
+#define SCALER_SRC_COLOR_SEL_INV		(1 << 31)
+#define SCALER_SRC_COLOR_SEL_MASK		0x3
+#define SCALER_SRC_COLOR_SEL_SHIFT		29
+#define SCALER_SRC_COLOR_OP_SEL_INV		(1 << 28)
+#define SCALER_SRC_COLOR_OP_SEL_MASK		0xf
+#define SCALER_SRC_COLOR_OP_SEL_SHIFT		24
+#define SCALER_SRC_GLOBAL_COLOR0_MASK		0xff
+#define SCALER_SRC_GLOBAL_COLOR0_SHIFT		16
+#define SCALER_SRC_GLOBAL_COLOR1_MASK		0xff
+#define SCALER_SRC_GLOBAL_COLOR1_SHIFT		8
+#define SCALER_SRC_GLOBAL_COLOR2_MASK		0xff
+#define SCALER_SRC_GLOBAL_COLOR2_SHIFT		0
+
+/* SCALER src blend alpha */
+#define SCALER_SRC_BLEND_ALPHA			0x284
+#define SCALER_SRC_ALPHA_SEL_INV		(1 << 31)
+#define SCALER_SRC_ALPHA_SEL_MASK		0x3
+#define SCALER_SRC_ALPHA_SEL_SHIFT		29
+#define SCALER_SRC_ALPHA_OP_SEL_INV		(1 << 28)
+#define SCALER_SRC_ALPHA_OP_SEL_MASK		0xf
+#define SCALER_SRC_ALPHA_OP_SEL_SHIFT		24
+#define SCALER_SRC_GLOBAL_ALPHA_MASK		0xff
+#define SCALER_SRC_GLOBAL_ALPHA_SHIFT		0
+
+/* SCALER dst blend color */
+#define SCALER_DST_BLEND_COLOR			0x288
+#define SCALER_DST_COLOR_SEL_INV		(1 << 31)
+#define SCALER_DST_COLOR_SEL_MASK		0x3
+#define SCALER_DST_COLOR_SEL_SHIFT		29
+#define SCALER_DST_COLOR_OP_SEL_INV		(1 << 28)
+#define SCALER_DST_COLOR_OP_SEL_MASK		0xf
+#define SCALER_DST_COLOR_OP_SEL_SHIFT		24
+#define SCALER_DST_GLOBAL_COLOR0_MASK		0xff
+#define SCALER_DST_GLOBAL_COLOR0_SHIFT		16
+#define SCALER_DST_GLOBAL_COLOR1_MASK		0xff
+#define SCALER_DST_GLOBAL_COLOR1_SHIFT		8
+#define SCALER_DST_GLOBAL_COLOR2_MASK		0xff
+#define SCALER_DST_GLOBAL_COLOR2_SHIFT		0
+
+/* SCALER dst blend alpha */
+#define SCALER_DST_BLEND_ALPHA			0x28c
+#define SCALER_DST_ALPHA_SEL_INV		(1 << 31)
+#define SCALER_DST_ALPHA_SEL_MASK		0x3
+#define SCALER_DST_ALPHA_SEL_SHIFT		29
+#define SCALER_DST_ALPHA_OP_SEL_INV		(1 << 28)
+#define SCALER_DST_ALPHA_OP_SEL_MASK		0xf
+#define SCALER_DST_ALPHA_OP_SEL_SHIFT		24
+#define SCALER_DST_GLOBAL_ALPHA_MASK		0xff
+#define SCALER_DST_GLOBAL_ALPHA_SHIFT		0
+
+/* SCALER fill color */
+#define SCALER_FILL_COLOR			0x290
+#define SCALER_FILL_ALPHA_MASK			0xff
+#define SCALER_FILL_ALPHA_SHIFT			24
+#define SCALER_FILL_COLOR0_MASK			0xff
+#define SCALER_FILL_COLOR0_SHIFT		16
+#define SCALER_FILL_COLOR1_MASK			0xff
+#define SCALER_FILL_COLOR1_SHIFT		8
+#define SCALER_FILL_COLOR2_MASK			0xff
+#define SCALER_FILL_COLOR2_SHIFT		0
+
+/* SCALER address queue config */
+#define SCALER_ADDR_QUEUE_CONFIG		0x2a0
+#define SCALER_ADDR_QUEUE_RST			0x1
+
+/* Arbitrary R/W register and value to check if soft reset succeeded */
+#define SCALER_CFG_SOFT_RESET_CHECK_REG		SCALER_SRC_CFG
+#define SCALER_CFG_SOFT_RESET_CHECK_VAL		0x3
+
+struct scaler_error {
+	u32 irq_num;
+	const char * const name;
+};
+
+static const struct scaler_error scaler_errors[] = {
+	{SCALER_INT_TIMEOUT,			"Timeout"},
+	{SCALER_INT_ILLEGAL_BLEND,		"Illegal Blend setting"},
+	{SCALER_INT_ILLEGAL_RATIO,		"Illegal Scale ratio setting"},
+	{SCALER_INT_ILLEGAL_DST_HEIGHT,		"Illegal Dst Height"},
+	{SCALER_INT_ILLEGAL_DST_WIDTH,		"Illegal Dst Width"},
+	{SCALER_INT_ILLEGAL_DST_V_POS,		"Illegal Dst V-Pos"},
+	{SCALER_INT_ILLEGAL_DST_H_POS,		"Illegal Dst H-Pos"},
+	{SCALER_INT_ILLEGAL_DST_C_SPAN,		"Illegal Dst C-Span"},
+	{SCALER_INT_ILLEGAL_DST_Y_SPAN,		"Illegal Dst Y-span"},
+	{SCALER_INT_ILLEGAL_DST_CR_BASE,	"Illegal Dst Cr-base"},
+	{SCALER_INT_ILLEGAL_DST_CB_BASE,	"Illegal Dst Cb-base"},
+	{SCALER_INT_ILLEGAL_DST_Y_BASE,		"Illegal Dst Y-base"},
+	{SCALER_INT_ILLEGAL_DST_COLOR,		"Illegal Dst Color"},
+	{SCALER_INT_ILLEGAL_SRC_HEIGHT,		"Illegal Src Height"},
+	{SCALER_INT_ILLEGAL_SRC_WIDTH,		"Illegal Src Width"},
+	{SCALER_INT_ILLEGAL_SRC_CV_POS,		"Illegal Src Chroma V-pos"},
+	{SCALER_INT_ILLEGAL_SRC_CH_POS,		"Illegal Src Chroma H-pos"},
+	{SCALER_INT_ILLEGAL_SRC_YV_POS,		"Illegal Src Luma V-pos"},
+	{SCALER_INT_ILLEGAL_SRC_YH_POS,		"Illegal Src Luma H-pos"},
+	{SCALER_INT_ILLEGAL_SRC_C_SPAN,		"Illegal Src C-span"},
+	{SCALER_INT_ILLEGAL_SRC_Y_SPAN,		"Illegal Src Y-span"},
+	{SCALER_INT_ILLEGAL_SRC_CR_BASE,	"Illegal Src Cr-base"},
+	{SCALER_INT_ILLEGAL_SRC_CB_BASE,	"Illegal Src Cb-base"},
+	{SCALER_INT_ILLEGAL_SRC_Y_BASE,		"Illegal Src Y-base"},
+	{SCALER_INT_ILLEGAL_SRC_COLOR,		"Illegal Src Color setting"},
+};
+
+#define SCALER_NUM_ERRORS	ARRAY_SIZE(scaler_errors)
+
+static inline u32 scaler_read(struct scaler_dev *dev, u32 offset)
+{
+	return readl(dev->regs + offset);
+}
+
+static inline void scaler_write(struct scaler_dev *dev, u32 offset, u32 value)
+{
+	writel(value, dev->regs + offset);
+}
+
+static inline void scaler_hw_address_queue_reset(struct scaler_ctx *ctx)
+{
+	scaler_write(ctx->scaler_dev, SCALER_ADDR_QUEUE_CONFIG,
+					SCALER_ADDR_QUEUE_RST);
+}
+
+void scaler_hw_set_sw_reset(struct scaler_dev *dev);
+int scaler_wait_reset(struct scaler_dev *dev);
+void scaler_hw_set_irq(struct scaler_dev *dev, int interrupt, bool mask);
+void scaler_hw_set_input_addr(struct scaler_dev *dev, struct scaler_addr *addr);
+void scaler_hw_set_output_addr(struct scaler_dev *dev,
+				struct scaler_addr *addr);
+void scaler_hw_set_in_size(struct scaler_ctx *ctx);
+void scaler_hw_set_in_image_format(struct scaler_ctx *ctx);
+void scaler_hw_set_out_size(struct scaler_ctx *ctx);
+void scaler_hw_set_out_image_format(struct scaler_ctx *ctx);
+void scaler_hw_set_scaler_ratio(struct scaler_ctx *ctx);
+void scaler_hw_set_rotation(struct scaler_ctx *ctx);
+void scaler_hw_set_csc_coeff(struct scaler_ctx *ctx);
+void scaler_hw_src_y_offset_en(struct scaler_dev *dev, bool on);
+void scaler_hw_dst_y_offset_en(struct scaler_dev *dev, bool on);
+void scaler_hw_enable_control(struct scaler_dev *dev, bool on);
+unsigned int scaler_hw_get_irq_status(struct scaler_dev *dev);
+void scaler_hw_clear_irq(struct scaler_dev *dev, unsigned int irq);
+
+#endif /* REGS_SCALER_H_ */