RE: [PATCH v2] media: rotator: Add new image rotator driver for EXYNOS

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

 



Hi Sylwester

Thanks for the review.
God bless you! :)


>On 03/15/2012 06:21 AM, Sylwester Nawrocki wrote:
>Hi Sunyoung,
>
>thank you for addressing my previous comments. It looks much better now.
>I have is a few more comments...
>
>On 03/14/2012 09:00 AM, Sunyoung Kang wrote:
>> This patch adds new rotator driver which is a device for
>> rotation on EXYNOS SoCs.
>>
>> This rotator device supports the belows as key feature.
>>   1) Image format
>>     : RGB565/888, YUV422 1p, YUV420 2p/3p
>>   2) rotation
>>     : 0/90/180/270 and X/Y Flip
>>
>> Signed-off-by: Sunyoung Kang<sy0816.kang@xxxxxxxxxxx>
>> Signed-off-by: Ayoung Sim<a.sim@xxxxxxxxxxx>
>> ---NOTE:
>
>It's almost right;) After the "---" there must be immediately a new
>line character. So "NOTE" should be in a new line.
>
Oh.. ok. Thanks.

>> This patch has been created based on following
>>   - media: media-dev: Add media devices for EXYNOS5 by Sungchun Kang
>>   - media: fimc-lite: Add new driver for camera interface by Sungchun Kang
>>
>> Changes since v1:
>>   - address comments from Sylwester Nawrocki
>>
>>   drivers/media/video/exynos/Kconfig                |    1 +
>>   drivers/media/video/exynos/Makefile               |    1 +
>>   drivers/media/video/exynos/rotator/Kconfig        |    7 +
>>   drivers/media/video/exynos/rotator/Makefile       |    9 +
>>   drivers/media/video/exynos/rotator/rotator-core.c | 1344 +++++++++++++++++++++
>>   drivers/media/video/exynos/rotator/rotator-regs.c |  215 ++++
>>   drivers/media/video/exynos/rotator/rotator-regs.h |   70 ++
>>   drivers/media/video/exynos/rotator/rotator.h      |  286 +++++
>>   8 files changed, 1933 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/media/video/exynos/rotator/Kconfig
>>   create mode 100644 drivers/media/video/exynos/rotator/Makefile
>>   create mode 100644 drivers/media/video/exynos/rotator/rotator-core.c
>>   create mode 100644 drivers/media/video/exynos/rotator/rotator-regs.c
>>   create mode 100644 drivers/media/video/exynos/rotator/rotator-regs.h
>>   create mode 100644 drivers/media/video/exynos/rotator/rotator.h
>>
>...
>> diff --git a/drivers/media/video/exynos/rotator/Kconfig b/drivers/media/video/exynos/rotator/Kconfig
>> new file mode 100644
>> index 0000000..977423a
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/rotator/Kconfig
>> @@ -0,0 +1,7 @@
>> +config VIDEO_EXYNOS_ROTATOR
>> +	bool "EXYNOS Image Rotator Driver"
>> +	select V4L2_MEM2MEM_DEV
>> +	select VIDEOBUF2_DMA_CONTIG
>> +	default n
>
>No need, the default default already is "n".
>
OK.
>> +	---help---
>> +	  Support for Image Rotator Driver with v4l2 on EXYNOS SoCs
>> diff --git a/drivers/media/video/exynos/rotator/Makefile
>b/drivers/media/video/exynos/rotator/Makefile
>> new file mode 100644
>> index 0000000..6f74403
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/rotator/Makefile
>> @@ -0,0 +1,9 @@
>> +#
>> +# Copyright (c) 2012 Samsung Electronics Co., Ltd.
>> +#		http://www.samsung.com
>> +#
>> +# Licensed under GPLv2
>> +#
>> +
>> +rotator-objs				:= rotator-core.o rotator-regs.o
>> +obj-$(CONFIG_VIDEO_EXYNOS_ROTATOR)	+= rotator.o
>> diff --git a/drivers/media/video/exynos/rotator/rotator-core.c
>b/drivers/media/video/exynos/rotator/rotator-core.c
>> new file mode 100644
>> index 0000000..75d28f2
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/rotator/rotator-core.c
>> @@ -0,0 +1,1344 @@
>> +/*
>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>> + *		http://www.samsung.com
>> + *
>> + * Core file for Samsung EXYNOS Image Rotator 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/module.h>
>> +#include<linux/kernel.h>
>> +#include<linux/version.h>
>> +#include<linux/platform_device.h>
>> +#include<linux/interrupt.h>
>> +#include<linux/clk.h>
>> +#include<linux/slab.h>
>> +
>> +#include<media/v4l2-ioctl.h>
>> +#include<media/videobuf2-dma-contig.h>
>> +
>> +#include "rotator.h"
>> +
>> +int log_level;
>> +module_param_named(log_level, log_level, uint, 0644);
>> +
>> +static struct rot_fmt rot_formats[] = {
>> +	{
>> +		.name		= "RGB565",
>> +		.pixelformat	= V4L2_PIX_FMT_RGB565,
>> +		.num_planes	= 1,
>> +		.num_comp	= 1,
>> +		.bitperpixel	= { 16 },
>> +	}, {
>> +		.name		= "XRGB-8888, 32 bps",
>
>What 'bps' stands for ?
>
Oops.. it should be 'bpp' means bit per pixel..  thanks.

>> +		.pixelformat	= V4L2_PIX_FMT_RGB32,
>> +		.num_planes	= 1,
>> +		.num_comp	= 1,
>> +		.bitperpixel	= { 32 },
>> +	}, {
>> +		.name		= "YUV 4:2:2 packed, YCbYCr",
>> +		.pixelformat	= V4L2_PIX_FMT_YUYV,
>> +		.num_planes	= 1,
>> +		.num_comp	= 1,
>> +		.bitperpixel	= { 16 },
>> +	}, {
>> +		.name		= "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
>> +		.pixelformat	= V4L2_PIX_FMT_NV12M,
>> +		.num_planes	= 2,
>> +		.num_comp	= 2,
>> +		.bitperpixel	= { 8, 4 },
>> +	}, {
>> +		.name		= "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
>> +		.pixelformat	= V4L2_PIX_FMT_YUV420M,
>> +		.num_planes	= 3,
>> +		.num_comp	= 3,
>> +		.bitperpixel	= { 8, 2, 2 },
>> +	},
>> +};
>> +
>...
>> +static int rot_s_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +	struct rot_ctx *ctx;
>> +	unsigned long flags;
>> +	int ret = 0;
>> +
>> +	ctx = container_of(ctrl->handler, struct rot_ctx, ctrl_handler);
>> +	spin_lock_irqsave(&ctx->slock, flags);
>> +
>> +	rot_dbg("ctrl ID:%d, value:%d\n", ctrl->id, ctrl->val);
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_VFLIP:
>> +		if (ctrl->val)
>> +			ctx->flip |= ROT_VFLIP;
>> +		else
>> +			ctx->flip&= ~ROT_VFLIP;
>> +		break;
>> +	case V4L2_CID_HFLIP:
>> +		if (ctrl->val)
>> +			ctx->flip |= ROT_HFLIP;
>> +		else
>> +			ctx->flip&= ~ROT_HFLIP;
>> +		break;
>> +	case V4L2_CID_ROTATE:
>> +		ctx->rotation = ctrl->val;
>> +		break;
>> +	default:
>> +		v4l2_err(&ctx->rot_dev->m2m.v4l2_dev, "invalid control id\n");
>> +		ret = -EINVAL;
>
>These 3 lines can be removed, rot_s_ctrl can be called only with ctrl->id
>from the set of controls added to control handler.
>
OK. I'll remove it.

>> +	}
>> +
>> +	spin_unlock_irqrestore(&ctx->slock, flags);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops rot_ctrl_ops = {
>> +	.s_ctrl = rot_s_ctrl,
>> +};
>> +
>> +static int rot_add_ctrls(struct rot_ctx *ctx)
>> +{
>> +	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
>
>There are only 3 controls, so s/3/4.
>
You're right. Just 3 controls are in here.

>> +	v4l2_ctrl_new_std(&ctx->ctrl_handler,&rot_ctrl_ops,
>> +			V4L2_CID_VFLIP, 0, 1, 1, 0);
>> +	v4l2_ctrl_new_std(&ctx->ctrl_handler,&rot_ctrl_ops,
>> +			V4L2_CID_HFLIP, 0, 1, 1, 0);
>> +	v4l2_ctrl_new_std(&ctx->ctrl_handler,&rot_ctrl_ops,
>> +			V4L2_CID_ROTATE, 0, 270, 90, 0);
>> +
>> +	if (ctx->ctrl_handler.error) {
>> +		int err = ctx->ctrl_handler.error;
>> +		v4l2_err(&ctx->rot_dev->m2m.v4l2_dev,
>> +				"v4l2_ctrl_handler_init failed\n");
>> +		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>> +		return err;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int rot_open(struct file *file)
>> +{
>> +	struct rot_dev *rot = video_drvdata(file);
>> +	struct rot_ctx *ctx = NULL;
>
>No need to initialize here.
>
OK.
>> +	int ret;
>> +
>> +	ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
>> +	if (!ctx) {
>> +		dev_err(rot->dev, "no memory for open context\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	atomic_inc(&rot->m2m.in_use);
>> +	ctx->rot_dev = rot;
>> +
>> +	v4l2_fh_init(&ctx->fh, rot->m2m.vfd);
>> +	ret = rot_add_ctrls(ctx);
>> +	if (ret)
>> +		goto err_fh;
>> +
>> +	ctx->fh.ctrl_handler =&ctx->ctrl_handler;
>> +	file->private_data =&ctx->fh;
>> +	v4l2_fh_add(&ctx->fh);
>> +
>> +	/* Default color format */
>> +	ctx->s_frame.rot_fmt =&rot_formats[0];
>> +	ctx->d_frame.rot_fmt =&rot_formats[0];
>> +	init_waitqueue_head(&rot->irq.wait);
>> +	spin_lock_init(&ctx->slock);
>> +
>> +	/* Setup the device context for mem2mem mode. */
>> +	ctx->m2m_ctx = v4l2_m2m_ctx_init(rot->m2m.m2m_dev, ctx, queue_init);
>> +	if (IS_ERR(ctx->m2m_ctx)) {
>> +		ret = -EINVAL;
>> +		goto err_ctx;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_ctx:
>> +	v4l2_fh_del(&ctx->fh);
>> +err_fh:
>> +	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>> +	v4l2_fh_exit(&ctx->fh);
>> +	atomic_dec(&rot->m2m.in_use);
>> +	kfree(ctx);
>> +
>> +	return ret;
>> +}
>> +
>...
>> +static irqreturn_t rot_irq_handler(int irq, void *priv)
>> +{
>> +	struct rot_dev *rot = priv;
>> +	struct rot_ctx *ctx;
>> +	struct vb2_buffer *src_vb, *dst_vb;
>> +	unsigned int irq_src;
>> +
>> +	spin_lock(&rot->slock);
>> +
>> +	clear_bit(DEV_RUN,&rot->state);
>> +	if (timer_pending(&rot->wdt.timer))
>> +		del_timer(&rot->wdt.timer);
>> +
>> +	rot_hwget_irq_src(rot,&irq_src);
>> +	rot_hwset_irq_clear(rot,&irq_src);
>> +
>> +	if (irq_src != ISR_PEND_DONE) {
>> +		dev_err(rot->dev, "####################\n");
>> +		dev_err(rot->dev, "set SFR illegally\n");
>> +		dev_err(rot->dev, "maybe the result is wrong\n");
>> +		dev_err(rot->dev, "####################\n");
>> +		rot_dump_register(rot);
>> +	}
>
>How about following instead:
>
>	if (WARN_ON(irq_src != ISR_PEND_DONE),
>	    "Illegal SFR configuration, the result might be wrong\n") {
>		rot_dump_register(rot);
>	}
>?
Um.. I think, here doesn't need debugging information.
I'd like to just inform the wrong result.
But the log message will be changed as your guide.

>> +
>> +	ctx = v4l2_m2m_get_curr_priv(rot->m2m.m2m_dev);
>> +	if (!ctx || !ctx->m2m_ctx) {
>> +		dev_err(rot->dev, "current ctx is NULL\n");
>> +		goto isr_unlock;
>> +	}
>> +
>> +	clear_bit(CTX_RUN,&ctx->flags);
>> +
>> +	src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
>> +	dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
>> +
>> +	if (src_vb&&  dst_vb) {
>> +		v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
>> +		v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
>> +
>> +		if (test_bit(DEV_SUSPEND,&rot->state)) {
>> +			rot_dbg("wake up blocked process by suspend\n");
>> +			wake_up(&rot->irq.wait);
>> +		} else {
>> +			v4l2_m2m_job_finish(rot->m2m.m2m_dev, ctx->m2m_ctx);
>> +		}
>> +
>> +		/* Wake up from CTX_ABORT state */
>> +		if (test_and_clear_bit(CTX_ABORT,&ctx->flags))
>> +			wake_up(&rot->irq.wait);
>> +
>> +		pm_runtime_put(rot->dev);
>> +	} else {
>> +		dev_err(rot->dev, "failed to get the buffer done\n");
>> +	}
>> +
>> +isr_unlock:
>> +	spin_unlock(&rot->slock);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>...
>> +static void rot_m2m_device_run(void *priv)
>> +{
>> +	struct rot_ctx *ctx = priv;
>> +	struct rot_frame *s_frame, *d_frame;
>> +	struct rot_dev *rot;
>> +	unsigned long flags, tmp;
>> +	u32 degree = 0, flip = 0;
>> +
>> +	spin_lock_irqsave(&ctx->slock, flags);
>> +
>> +	rot = ctx->rot_dev;
>> +
>> +	if (test_bit(DEV_RUN,&rot->state)) {
>> +		dev_err(rot->dev, "Rotator is already in progress\n");
>> +		goto run_unlock;
>> +	}
>> +
>> +	if (test_bit(DEV_SUSPEND,&rot->state)) {
>> +		dev_err(rot->dev, "Rotator is in suspend state\n");
>> +		goto run_unlock;
>> +	}
>> +
>> +	if (test_bit(CTX_ABORT,&ctx->flags)) {
>> +		rot_dbg("aborted rot device run\n");
>> +		goto run_unlock;
>> +	}
>> +
>> +	pm_runtime_get_sync(ctx->rot_dev->dev);
>> +
>> +	s_frame =&ctx->s_frame;
>> +	d_frame =&ctx->d_frame;
>> +
>> +	/* Configuration rotator registers */
>> +	rot_hwset_image_format(rot, s_frame->rot_fmt->pixelformat);
>> +	rot_mapping_flip(ctx,&degree,&flip);
>> +	rot_hwset_flip(rot, flip);
>> +	rot_hwset_rotation(rot, degree);
>> +
>> +	if (ctx->rotation == 90 || ctx->rotation == 270) {
>> +		tmp                     = d_frame->pix_mp.height;
>> +		d_frame->pix_mp.height  = d_frame->pix_mp.width;
>> +		d_frame->pix_mp.width   = tmp;
>
>Do you mean:
>		swap(d_frame->pix_mp.height, d_frame->pix_mp.width);
>?
>
>Does it mean setting rotation to 90 or 270 deg changes the output (capture)
>format ? Maybe you want to do this swapping on temporary variables, that
>would be used to configure the hardware ?
>
>The rotation is a bit tricky, AFAIK the application should swap width/and
>height. And the driver should scale an image (change aspect ratio) when
>width/height isn't swapped and 90/270 deg rotation is set. Or return an
>error when the device doesn't support resizing.
>

Ok. As you mentioned, if the application should know about width/height for output,
 driver doesn't need to care about it. I'll remove this code.

>> +	}
>> +
>> +	rot_hwset_src_imgsize(rot, s_frame);
>> +	rot_hwset_dst_imgsize(rot, d_frame);
>> +
>> +	rot_hwset_src_crop(rot,&s_frame->crop);
>> +	rot_hwset_dst_crop(rot,&d_frame->crop);
>> +
>> +	rot_set_frame_addr(ctx);
>> +
>> +	/* Enable rotator interrupt */
>> +	rot_hwset_irq_frame_done(rot, 1);
>> +	rot_hwset_irq_illegal_config(rot, 1);
>> +
>> +	set_bit(DEV_RUN,&rot->state);
>> +	set_bit(CTX_RUN,&ctx->flags);
>> +
>> +	/* Start rotate operation */
>> +	rot_hwset_start(rot);
>> +
>> +	/* Start watchdog timer */
>> +	rot->wdt.timer.expires = jiffies + ROT_TIMEOUT;
>> +	if (timer_pending(&rot->wdt.timer) == 0)
>> +		add_timer(&rot->wdt.timer);
>> +	else
>> +		mod_timer(&rot->wdt.timer, rot->wdt.timer.expires);
>> +
>> +run_unlock:
>> +	spin_unlock_irqrestore(&ctx->slock, flags);
>> +}
>> +
>...
>> +static int rot_suspend(struct device *dev)
>> +{
>> +	struct rot_dev *rot;
>
>How about assigning here directly,
>
>	struct rot_dev *rot = dev_get_drvdata(dev);
>?
>> +	int ret = 0;
>
>No need to initialize.
>
OK. I'll change it.
>> +
>> +	rot = dev_get_drvdata(dev);
>> +	set_bit(DEV_SUSPEND,&rot->state);
>> +
>> +	ret = wait_event_timeout(rot->irq.wait,
>> +			!test_bit(DEV_RUN,&rot->state), ROT_TIMEOUT);
>> +	if (ret == 0)
>> +		dev_err(rot->dev, "wait timeout\n");
>> +
>> +	return 0;
>> +}
>> +
>> +static int rot_resume(struct device *dev)
>> +{
>> +	struct rot_dev *rot;
>> +
>> +	rot = dev_get_drvdata(dev);
>
>	struct rot_dev *rot = dev_get_drvdata(dev);
> ?
>
Ditto.
>> +	clear_bit(DEV_SUSPEND,&rot->state);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rot_runtime_suspend(struct device *dev)
>> +{
>> +	struct rot_dev *rot;
>> +	struct platform_device *pdev;
>> +
>> +	pdev = to_platform_device(dev);
>> +	rot = (struct rot_dev *)platform_get_drvdata(pdev);
>
>
>I think, you've forgotten to update that one?
>
Yes. :)

>> +	clk_disable(rot->clock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int rot_runtime_resume(struct device *dev)
>> +{
>> +	struct rot_dev *rot;
>> +	struct platform_device *pdev;
>> +
>> +	pdev = to_platform_device(dev);
>> +	rot = (struct rot_dev *)platform_get_drvdata(pdev);
>
>And here (struct rot_dev *rot = dev_get_drvdata(dev);) ?
>
I missed it. :)

>> +	clk_enable(rot->clock);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct dev_pm_ops rot_pm_ops = {
>> +	.suspend		= rot_suspend,
>> +	.resume			= rot_resume,
>> +	.runtime_suspend	= rot_runtime_suspend,
>> +	.runtime_resume		= rot_runtime_resume,
>> +};
>> +
>> +static int rot_probe(struct platform_device *pdev)
>> +{
>> +	struct exynos_rot_driverdata *drv_data;
>> +	struct rot_dev *rot;
>> +	struct resource *res;
>> +	int variant_num, ret = 0;
>> +
>> +	dev_info(&pdev->dev, "++%s\n", __func__);
>> +	drv_data = (struct exynos_rot_driverdata *)
>> +			platform_get_device_id(pdev)->driver_data;
>> +
>> +	if (pdev->id>= drv_data->nr_dev) {
>> +		dev_err(&pdev->dev, "Invalid platform device id\n");
>> +		return -EINVAL;
>> +	}
>
>If there is always only one device, is this needed ?
>
Now the EXYNOS SoCs have only one rotator device, but the number can be increased in future.
So I considered about it. Should this be removed including the code related with this?

>> +	rot = devm_kzalloc(&pdev->dev, sizeof(struct rot_dev), GFP_KERNEL);
>> +	if (!rot) {
>> +		dev_err(&pdev->dev, "no memory for rotator device\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	rot->dev =&pdev->dev;
>> +	rot->id = pdev->id;
>> +	variant_num = (rot->id<  0) ? 0 : rot->id;
>> +	rot->variant = drv_data->variant[variant_num];
>> +
>> +	spin_lock_init(&rot->slock);
>> +
>> +	/* Get memory resource and map SFR region. */
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	rot->regs = devm_request_and_ioremap(&pdev->dev, res);
>> +	if (rot->regs == NULL) {
>> +		dev_err(&pdev->dev, "failed to claim register region\n");
>> +		return -ENOENT;
>> +	}
>> +
>> +	/* Get IRQ resource and register IRQ handler. */
>> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +	if (res == NULL) {
>> +		dev_err(&pdev->dev, "failed to get IRQ resource\n");
>> +		return -ENXIO;
>> +	}
>> +	rot->irq.num = res->start;
>> +
>> +	ret = devm_request_irq(&pdev->dev, rot->irq.num, rot_irq_handler, 0,
>
>I think you can use res->start directly, and remove irq.num, since the interrupt
>is now being released dynamically and we don't need to sore the interrupt number.
>
OK. Thanks.
>> +			pdev->name, rot);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "failed to install irq\n");
>> +		return ret;
>> +	}
>> +
>> +	atomic_set(&rot->wdt.cnt, 0);
>> +	setup_timer(&rot->wdt.timer, rot_watchdog, (unsigned long)rot);
>> +
>> +	rot->clock = clk_get(rot->dev, "rotator");
>> +	if (IS_ERR(rot->clock)) {
>> +		dev_err(&pdev->dev, "failed to get clock for rotator\n");
>> +		return -ENXIO;
>> +	}
>> +
>> +	rot->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
>> +	if (IS_ERR(rot->alloc_ctx)) {
>> +		dev_err(&pdev->dev, "failed to get alloc_ctx\n");
>> +		ret = -EPERM;
>> +		goto err;
>> +	}
>> +
>> +	ret = rot_register_m2m_device(rot);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "failed to register m2m device\n");
>> +		ret = -EPERM;
>> +		goto err;
>> +	}
>> +
>> +#ifdef CONFIG_PM_RUNTIME
>> +	pm_runtime_enable(&pdev->dev);
>> +#else
>> +	rot_runtime_resume(&pdev->dev);
>> +#endif
>
>Hmm, not very pretty. At least it could be simplified to:
>
>	pm_runtime_enable(&pdev->dev);
>
>#ifndef CONFIG_PM_RUNTIME
>	rot_runtime_resume(&pdev->dev);
>#endif
>

I'll make more pretty~!

>> +	dev_info(&pdev->dev, "rotator registered successfully\n");
>> +
>> +	return 0;
>> +
>> +err:
>> +	clk_put(rot->clock);
>> +	return ret;
>> +}
>> +
>> +static int rot_remove(struct platform_device *pdev)
>> +{
>> +	struct rot_dev *rot = (struct rot_dev *)platform_get_drvdata(pdev);
>
>The is no need for casting from void *.
>
OK. I'll change it.

>> +	clk_put(rot->clock);
>> +#ifdef CONFIG_PM_RUNTIME
>> +	pm_runtime_disable(&pdev->dev);
>> +#else
>> +	rot_runtime_suspend(&pdev->dev);
>> +#endif
>
>pm_runtime_disable() is a no op when CONFIG_PM_RUNTIME is disabled.
>So it could be changed to:
>
>	pm_runtime_disable(&pdev->dev);
>
>#ifndef CONFIG_PM_RUNTIME
>	rot_runtime_suspend(&pdev->dev);
>#endif
>
OK.

>> +	if (timer_pending(&rot->wdt.timer))
>> +		del_timer(&rot->wdt.timer);
>> +
>> +	return 0;
>> +}
>> +
>...
>> +void rot_dump_register(struct rot_dev *rot)
>
>rot_dump_registers ?
>
OK. :)
>> +{
>> +	unsigned int tmp, i;
>> +
>> +	rot_dbg("dump rotator registers\n");
>> +	for (i = 0; i<= ROTATOR_DST; i += 0x4) {
>> +		tmp = readl(rot->regs + i);
>> +		rot_dbg("0x%08x: 0x%08x", i, tmp);
>> +	}
>> +}
>...
>> diff --git a/drivers/media/video/exynos/rotator/rotator.h
>b/drivers/media/video/exynos/rotator/rotator.h
>> new file mode 100644
>> index 0000000..4034383
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/rotator/rotator.h
>> @@ -0,0 +1,286 @@
>> +/*
>> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
>> + *		http://www.samsung.com
>> + *
>> + * Header file for Exynos Rotator 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 ROTATOR__H_
>> +#define ROTATOR__H_
>> +
>> +#include<linux/delay.h>
>> +#include<linux/sched.h>
>> +#include<linux/spinlock.h>
>> +#include<linux/types.h>
>> +#include<linux/videodev2.h>
>> +#include<linux/io.h>
>
>> +#include<linux/pm_runtime.h>
>
>Probably this one should be included explicitly only in the .c files.
>
I'll move it into .c file.

>> +#include<media/videobuf2-core.h>
>> +#include<media/v4l2-ctrls.h>
>> +#include<media/v4l2-device.h>
>> +#include<media/v4l2-mem2mem.h>
>> +
>> +#include "rotator-regs.h"
>> +
>> +extern int log_level;
>> +
>> +#define rot_dbg(fmt, args...)						\
>> +	do {								\
>> +		if (log_level)						\
>> +			printk(KERN_DEBUG "[%s:%d] "			\
>> +			fmt, __func__, __LINE__, ##args);		\
>> +	} while (0)
>> +
>> +/* Time to wait for frame done interrupt */
>> +#define ROT_TIMEOUT			(2 * HZ)
>> +#define ROT_WDT_CNT			5
>> +#define MODULE_NAME		"exynos-rot"
>> +#define ROT_MAX_DEVS			1
>
>If there is no more than one hardware instance in each SoC maybe it's worth
>to drop ROT_MAX_DEVS and all the code around it ?
>
>> +
>> +/* Address index */
>> +#define ROT_ADDR_RGB			0
>> +#define ROT_ADDR_Y			0
>> +#define ROT_ADDR_CB			1
>> +#define ROT_ADDR_CBCR			1
>> +#define ROT_ADDR_CR			2
>> +
>> +/* Rotator flip direction */
>> +#define ROT_NOFLIP		(1<<  0)
>> +#define ROT_VFLIP		(1<<  1)
>> +#define ROT_HFLIP		(1<<  2)
>> +
>> +/* Rotator hardware device state */
>> +#define DEV_RUN			(1<<  0)
>> +#define DEV_SUSPEND		(1<<  1)
>> +
>> +/* Rotator m2m context state */
>> +#define CTX_PARAMS		(1<<  0)
>> +#define CTX_STREAMING		(1<<  1)
>> +#define CTX_RUN			(1<<  2)
>> +#define CTX_ABORT		(1<<  3)
>> +#define CTX_SRC			(1<<  4)
>> +#define CTX_DST			(1<<  5)
>> +
>> +enum rot_irq_src {
>> +	ISR_PEND_DONE = 8,
>> +	ISR_PEND_ILLEGAL = 9,
>> +};
>> +
>> +enum rot_status {
>> +	ROT_IDLE,
>> +	ROT_RESERVED,
>> +	ROT_RUNNING,
>> +	ROT_RUNNING_REMAIN,
>> +};
>> +
>> +/*
>> + * struct exynos_rot_size_limit - Rotator variant size  information
>> + *
>> + * @min_x: minimum pixel x size
>> + * @min_y: minimum pixel y size
>> + * @max_x: maximum pixel x size
>> + * @max_y: maximum pixel y size
>> + */
>> +struct exynos_rot_size_limit {
>> +	u32 min_x;
>> +	u32 min_y;
>> +	u32 max_x;
>> +	u32 max_y;
>> +	u32 align;
>> +};
>> +
>> +struct exynos_rot_variant {
>> +	struct exynos_rot_size_limit limit_rgb565;
>> +	struct exynos_rot_size_limit limit_rgb888;
>> +	struct exynos_rot_size_limit limit_yuv422;
>> +	struct exynos_rot_size_limit limit_yuv420_2p;
>> +	struct exynos_rot_size_limit limit_yuv420_3p;
>> +};
>> +
>> +/*
>> + * struct exynos_rot_driverdata - per device type driver data for init time.
>> + *
>> + * @variant: the variant information for this driver.
>> + * @nr_dev: number of devices available in SoC
>> + */
>> +struct exynos_rot_driverdata {
>> +	struct exynos_rot_variant	*variant[ROT_MAX_DEVS];
>> +	int				nr_dev;
>
>Probably not needed.
>
>> +};
>> +
>> +/**
>> + * struct rot_fmt - the driver's internal color format data
>> + * @name: format description
>> + * @pixelformat: the fourcc code for this format, 0 if not applicable
>> + * @num_planes: number of physically non-contiguous data planes
>> + * @num_comp: number of color components(ex. RGB, Y, Cb, Cr)
>> + * @bitperpixel: bits per pixel
>> + */
>> +struct rot_fmt {
>> +	char	*name;
>> +	u32	pixelformat;
>> +	u16	num_planes;
>> +	u16	num_comp;
>> +	u32	bitperpixel[VIDEO_MAX_PLANES];
>> +};
>> +
>> +struct rot_addr {
>> +	dma_addr_t	y;
>> +	dma_addr_t	cb;
>> +	dma_addr_t	cr;
>> +};
>> +
>> +/*
>> + * struct rot_frame - source/target frame properties
>> + * @fmt:	buffer format(like virtual screen)
>> + * @crop:	image size / position
>> + * @addr:	buffer start address(access using ROT_ADDR_XXX)
>> + * @bytesused:	image size in bytes (w x h x bpp)
>> + * @cacheable:	cache property for image address
>> + */
>> +struct rot_frame {
>> +	struct rot_fmt			*rot_fmt;
>> +	struct v4l2_pix_format_mplane	pix_mp;
>> +	struct v4l2_rect		crop;
>> +	struct rot_addr			addr;
>> +	unsigned long			bytesused[VIDEO_MAX_PLANES];
>> +	bool				cacheable;
>
>It's also unused, what was this needed for (if at all) ?
>
Yes. I'll remove it.

>> +};
>> +
>> +/*
>> + * struct rot_m2m_device - v4l2 memory-to-memory device data
>> + * @v4l2_dev: v4l2 device
>> + * @vfd: the video device node
>> + * @m2m_dev: v4l2 memory-to-memory device data
>> + * @in_use: the open count
>> + */
>> +struct rot_m2m_device {
>> +	struct v4l2_device	v4l2_dev;
>> +	struct video_device	*vfd;
>> +	struct v4l2_m2m_dev	*m2m_dev;
>> +	atomic_t		in_use;
>> +};
>> +
>> +/*
>> + * struct rot_irq - Rotator irq information
>> + * @num:	Rotator interrupt number
>> + * @wait:	interrupt handler waitqueue
>> + */
>> +struct rot_irq {
>> +	int			num;
>
>It's unused, you can remove it.
>
OK.
>> +	wait_queue_head_t	wait;
>> +};
>> +
>> +struct rot_wdt {
>> +	struct timer_list	timer;
>> +	atomic_t		cnt;
>> +};
>> +
>> +struct rot_ctx;
>> +struct rot_vb2;
>> +
>> +/*
>> + * struct rot_dev - the abstraction for Rotator device
>> + * @dev:	pointer to the Rotator device
>> + * @pdata:	pointer to the device platform data
>> + * @variant:	the IP variant information
>> + * @m2m:	memory-to-memory V4L2 device information
>> + * @id:		Rotator device index (0..ROT_MAX_DEVS)
>> + * @clock:	clock required for Rotator operation
>> + * @regs:	the mapped hardware registers
>> + * @regs_res:	the resource claimed for IO registers
>> + * @irq:	irq information
>> + * @ws:		work struct
>> + * @state:	device state flags
>> + * @alloc_ctx:	videobuf2 memory allocator context
>> + * @rot_vb2:	videobuf2 memory allocator callbacks
>> + * @slock:	the spinlock protecting this data structure
>> + * @lock:	the mutex protecting this data structure
>> + * @wdt:	watchdog timer information
>> + */
>> +struct rot_dev {
>> +	struct device			*dev;
>> +	struct exynos_platform_rot	*pdata;
>> +	struct exynos_rot_variant	*variant;
>> +	struct rot_m2m_device		m2m;
>> +	int				id;
>> +	struct clk			*clock;
>> +	void __iomem			*regs;
>> +	struct rot_irq			irq;
>> +	struct work_struct		ws;
>
>irq and ws are not used, are they ?
>
I missed it and it will be removed.

>> +	unsigned long			state;
>> +	struct vb2_alloc_ctx		*alloc_ctx;
>> +	const struct rot_vb2		*vb2;
>> +	spinlock_t			slock;
>> +	struct mutex			lock;
>> +	struct rot_wdt			wdt;
>> +};
>> +
>> +/*
>> + * rot_ctx - the abstration for Rotator open context
>> + * @rot_dev:		the Rotator device this context applies to
>> + * @m2m_ctx:		memory-to-memory device context
>> + * @frame:		source frame properties
>> + * @ctrl_handler:	v4l2 controls handler
>> + * @fh:			v4l2 file handle
>> + * @rotation:		image clockwise rotation in degrees
>> + * @flip:		image flip mode
>> + * @state:		context state flags
>> + * @slock:		spinlock protecting this data structure
>> + */
>> +struct rot_ctx {
>> +	struct rot_dev		*rot_dev;
>> +	struct v4l2_m2m_ctx	*m2m_ctx;
>> +	struct rot_frame	s_frame;
>> +	struct rot_frame	d_frame;
>> +	struct v4l2_ctrl_handler	ctrl_handler;
>> +	struct v4l2_fh			fh;
>> +	int			rotation;
>> +	u32			flip;
>> +	unsigned long		flags;
>> +	spinlock_t		slock;
>> +};
>...
>> +#endif /* ROTATOR__H_ */
>
>Otherwise looks good.
>
>--
>
>Regards,
>Sylwester

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


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux