From: Ben Dooks <ben-linux@fluff.org>
To: linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 6/6] s3c-fb: Add wait for VSYNC ioctl
Date: Mon, 31 May 2010 11:40:06 +0000 [thread overview]
Message-ID: <20100531114006.GR4720@trinity.fluff.org> (raw)
In-Reply-To: <1275296935-2693-7-git-send-email-p.osciak@samsung.com>
On Mon, May 31, 2010 at 11:08:55AM +0200, Pawel Osciak wrote:
> Add VSYNC interrupt support and an ioctl that allows waiting for it.
> Interrupts are turned on only when needed.
>
> Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> arch/arm/plat-samsung/include/plat/regs-fb.h | 1 +
> drivers/video/s3c-fb.c | 171 +++++++++++++++++++++++++-
> 2 files changed, 171 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h
> index f454e32..5bcdd09 100644
> --- a/arch/arm/plat-samsung/include/plat/regs-fb.h
> +++ b/arch/arm/plat-samsung/include/plat/regs-fb.h
> @@ -298,6 +298,7 @@
> #define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
>
> #define VIDINTCON0_FRAMESEL1 (1 << 13)
> +#define VIDINTCON0_FRAMESEL1_MASK (0x3 << 13)
> #define VIDINTCON0_FRAMESEL1_NONE (0x0 << 13)
> #define VIDINTCON0_FRAMESEL1_BACKPORCH (0x1 << 13)
> #define VIDINTCON0_FRAMESEL1_VSYNC (0x2 << 13)
> diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> index 4f3680d..0dfa8b0 100644
> --- a/drivers/video/s3c-fb.c
> +++ b/drivers/video/s3c-fb.c
> @@ -21,6 +21,8 @@
> #include <linux/clk.h>
> #include <linux/fb.h>
> #include <linux/io.h>
> +#include <linux/uaccess.h>
> +#include <linux/interrupt.h>
>
> #include <mach/map.h>
> #include <plat/regs-fb-v4.h>
> @@ -48,6 +50,15 @@
> __raw_writel(v, r); } while(0)
> #endif /* FB_S3C_DEBUG_REGWRITE */
>
> +/* irq_flags bits */
> +#define S3C_FB_VSYNC_IRQ_EN 0
> +
> +#ifndef FBIO_WAITFORVSYNC
> +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
> +#endif
> +
> +#define VSYNC_TIMEOUT_MSEC 50
why are you testign for this, surely you need t oget FBIO_WAITFORVSYNC
from a header file.
> struct s3c_fb;
>
> #define VALID_BPP(x) (1 << ((x) - 1))
> @@ -156,6 +167,16 @@ struct s3c_fb_win {
> };
>
> /**
> + * struct s3c_fb_vsync - vsync information
> + * @wait: a queue for processes waiting for vsync
> + * @count: vsync interrupt count
> + */
> +struct s3c_fb_vsync {
> + wait_queue_head_t wait;
> + unsigned int count;
> +};
> +
> +/**
> * struct s3c_fb - overall hardware state of the hardware
> * @dev: The device that we bound to, for printing, etc.
> * @regs_res: The resource we claimed for the IO registers.
> @@ -165,6 +186,9 @@ struct s3c_fb_win {
> * @enabled: A bitmask of enabled hardware windows.
> * @pdata: The platform configuration data passed with the device.
> * @windows: The hardware windows that have been claimed.
> + * @irq_no: IRQ line number
> + * @irq_flags: irq flags
> + * @vsync_info: VSYNC-related information (count, queues...)
> */
> struct s3c_fb {
> struct device *dev;
> @@ -177,6 +201,10 @@ struct s3c_fb {
>
> struct s3c_fb_platdata *pdata;
> struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
> +
> + int irq_no;
> + unsigned long irq_flags;
> + struct s3c_fb_vsync vsync_info;
> };
>
> /**
> @@ -801,6 +829,124 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
> return 0;
> }
>
> +/**
> + * s3c_fb_enable_irq() - enable framebuffer interrupts
> + * @sfb: main hardware state
> + */
> +static void s3c_fb_enable_irq(struct s3c_fb *sfb)
> +{
> + void __iomem *regs = sfb->regs;
> + u32 irq_ctrl_reg;
> +
> + if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
> + /* IRQ disabled, enable it */
> + irq_ctrl_reg = readl(regs + VIDINTCON0);
> +
> + irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
> + irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
> +
> + irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
> + irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
> + irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
> + irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
> +
> + writel(irq_ctrl_reg, regs + VIDINTCON0);
> + }
> +}
> +
> +/**
> + * s3c_fb_disable_irq() - disable framebuffer interrupts
> + * @sfb: main hardware state
> + */
> +static void s3c_fb_disable_irq(struct s3c_fb *sfb)
> +{
> + void __iomem *regs = sfb->regs;
> + u32 irq_ctrl_reg;
> +
> + if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
> + /* IRQ enabled, disable it */
> + irq_ctrl_reg = readl(regs + VIDINTCON0);
> +
> + irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
> + irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
> +
> + writel(irq_ctrl_reg, regs + VIDINTCON0);
> + }
> +}
> +
> +static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
> +{
> + struct s3c_fb *sfb = dev_id;
> + void __iomem *regs = sfb->regs;
> + u32 irq_sts_reg;
> +
> + irq_sts_reg = readl(regs + VIDINTCON1);
> +
> + if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
> +
> + /* VSYNC interrupt, accept it */
> + writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
> +
> + sfb->vsync_info.count++;
> + wake_up_interruptible(&sfb->vsync_info.wait);
> + }
> +
> + /* We only support waiting for VSYNC for now, so it's safe
> + * to always disable irqs here.
> + */
> + s3c_fb_disable_irq(sfb);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
> + * @sfb: main hardware state
> + * @crtc: head index.
> + */
> +static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
> +{
> + unsigned long count;
> + int ret;
> +
> + if (crtc != 0)
> + return -ENODEV;
> +
> + s3c_fb_enable_irq(sfb);
> + count = sfb->vsync_info.count;
> + ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
> + count != sfb->vsync_info.count,
> + msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
> + if (ret = 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct s3c_fb_win *win = info->par;
> + struct s3c_fb *sfb = win->parent;
> + int ret;
> + u32 crtc;
> +
> + switch (cmd) {
> + case FBIO_WAITFORVSYNC:
> + if (get_user(crtc, (u32 __user *)arg)) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + ret = s3c_fb_wait_for_vsync(sfb, crtc);
> + break;
> + default:
> + ret = -ENOTTY;
> + }
> +
> + return ret;
> +}
> +
> static struct fb_ops s3c_fb_ops = {
> .owner = THIS_MODULE,
> .fb_check_var = s3c_fb_check_var,
> @@ -811,6 +957,7 @@ static struct fb_ops s3c_fb_ops = {
> .fb_copyarea = cfb_copyarea,
> .fb_imageblit = cfb_imageblit,
> .fb_pan_display = s3c_fb_pan_display,
> + .fb_ioctl = s3c_fb_ioctl,
> };
>
> /**
> @@ -917,6 +1064,8 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
>
> dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
>
> + init_waitqueue_head(&sfb->vsync_info.wait);
> +
> palette_size = variant->palette_sz * 4;
>
> fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
> @@ -1096,6 +1245,20 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> goto err_req_region;
> }
>
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!res) {
> + dev_err(dev, "failed to acquire irq resource\n");
> + ret = -ENOENT;
> + goto err_ioremap;
> + }
> + sfb->irq_no = res->start;
> + ret = request_irq(sfb->irq_no, s3c_fb_irq,
> + 0, "s3c_fb", sfb);
> + if (ret) {
> + dev_err(dev, "irq request failed\n");
> + goto err_ioremap;
> + }
> +
> dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
>
> /* setup gpio and output polarity controls */
> @@ -1130,7 +1293,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> dev_err(dev, "failed to create window %d\n", win);
> for (; win >= 0; win--)
> s3c_fb_release_win(sfb, sfb->windows[win]);
> - goto err_ioremap;
> + goto err_irq;
> }
> }
>
> @@ -1138,6 +1301,9 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
>
> return 0;
>
> +err_irq:
> + free_irq(sfb->irq_no, sfb);
> +
> err_ioremap:
> iounmap(sfb->regs);
>
> @@ -1170,6 +1336,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
> if (sfb->windows[win])
> s3c_fb_release_win(sfb, sfb->windows[win]);
>
> + free_irq(sfb->irq_no, sfb);
> +
> iounmap(sfb->regs);
>
> clk_disable(sfb->bus_clk);
> @@ -1370,6 +1538,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 __devinitdata = {
> [3] = 0x3000,
> [4] = 0x3400,
> },
> +
> },
> .win[0] = &s3c_fb_data_64xx_wins[0],
> .win[1] = &s3c_fb_data_64xx_wins[1],
> --
> 1.7.0.4
>
--
--
Ben
Q: What's a light-year?
A: One-third less calories than a regular year.
WARNING: multiple messages have this Message-ID (diff)
From: Ben Dooks <ben-linux@fluff.org>
To: Pawel Osciak <p.osciak@samsung.com>
Cc: linux-fbdev@vger.kernel.org, linux-samsung-soc@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, kyungmin.park@samsung.com,
ben-linux@fluff.org
Subject: Re: [PATCH 6/6] s3c-fb: Add wait for VSYNC ioctl
Date: Mon, 31 May 2010 12:40:06 +0100 [thread overview]
Message-ID: <20100531114006.GR4720@trinity.fluff.org> (raw)
In-Reply-To: <1275296935-2693-7-git-send-email-p.osciak@samsung.com>
On Mon, May 31, 2010 at 11:08:55AM +0200, Pawel Osciak wrote:
> Add VSYNC interrupt support and an ioctl that allows waiting for it.
> Interrupts are turned on only when needed.
>
> Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> arch/arm/plat-samsung/include/plat/regs-fb.h | 1 +
> drivers/video/s3c-fb.c | 171 +++++++++++++++++++++++++-
> 2 files changed, 171 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h
> index f454e32..5bcdd09 100644
> --- a/arch/arm/plat-samsung/include/plat/regs-fb.h
> +++ b/arch/arm/plat-samsung/include/plat/regs-fb.h
> @@ -298,6 +298,7 @@
> #define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
>
> #define VIDINTCON0_FRAMESEL1 (1 << 13)
> +#define VIDINTCON0_FRAMESEL1_MASK (0x3 << 13)
> #define VIDINTCON0_FRAMESEL1_NONE (0x0 << 13)
> #define VIDINTCON0_FRAMESEL1_BACKPORCH (0x1 << 13)
> #define VIDINTCON0_FRAMESEL1_VSYNC (0x2 << 13)
> diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> index 4f3680d..0dfa8b0 100644
> --- a/drivers/video/s3c-fb.c
> +++ b/drivers/video/s3c-fb.c
> @@ -21,6 +21,8 @@
> #include <linux/clk.h>
> #include <linux/fb.h>
> #include <linux/io.h>
> +#include <linux/uaccess.h>
> +#include <linux/interrupt.h>
>
> #include <mach/map.h>
> #include <plat/regs-fb-v4.h>
> @@ -48,6 +50,15 @@
> __raw_writel(v, r); } while(0)
> #endif /* FB_S3C_DEBUG_REGWRITE */
>
> +/* irq_flags bits */
> +#define S3C_FB_VSYNC_IRQ_EN 0
> +
> +#ifndef FBIO_WAITFORVSYNC
> +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
> +#endif
> +
> +#define VSYNC_TIMEOUT_MSEC 50
why are you testign for this, surely you need t oget FBIO_WAITFORVSYNC
from a header file.
> struct s3c_fb;
>
> #define VALID_BPP(x) (1 << ((x) - 1))
> @@ -156,6 +167,16 @@ struct s3c_fb_win {
> };
>
> /**
> + * struct s3c_fb_vsync - vsync information
> + * @wait: a queue for processes waiting for vsync
> + * @count: vsync interrupt count
> + */
> +struct s3c_fb_vsync {
> + wait_queue_head_t wait;
> + unsigned int count;
> +};
> +
> +/**
> * struct s3c_fb - overall hardware state of the hardware
> * @dev: The device that we bound to, for printing, etc.
> * @regs_res: The resource we claimed for the IO registers.
> @@ -165,6 +186,9 @@ struct s3c_fb_win {
> * @enabled: A bitmask of enabled hardware windows.
> * @pdata: The platform configuration data passed with the device.
> * @windows: The hardware windows that have been claimed.
> + * @irq_no: IRQ line number
> + * @irq_flags: irq flags
> + * @vsync_info: VSYNC-related information (count, queues...)
> */
> struct s3c_fb {
> struct device *dev;
> @@ -177,6 +201,10 @@ struct s3c_fb {
>
> struct s3c_fb_platdata *pdata;
> struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
> +
> + int irq_no;
> + unsigned long irq_flags;
> + struct s3c_fb_vsync vsync_info;
> };
>
> /**
> @@ -801,6 +829,124 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
> return 0;
> }
>
> +/**
> + * s3c_fb_enable_irq() - enable framebuffer interrupts
> + * @sfb: main hardware state
> + */
> +static void s3c_fb_enable_irq(struct s3c_fb *sfb)
> +{
> + void __iomem *regs = sfb->regs;
> + u32 irq_ctrl_reg;
> +
> + if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
> + /* IRQ disabled, enable it */
> + irq_ctrl_reg = readl(regs + VIDINTCON0);
> +
> + irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
> + irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
> +
> + irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
> + irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
> + irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
> + irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
> +
> + writel(irq_ctrl_reg, regs + VIDINTCON0);
> + }
> +}
> +
> +/**
> + * s3c_fb_disable_irq() - disable framebuffer interrupts
> + * @sfb: main hardware state
> + */
> +static void s3c_fb_disable_irq(struct s3c_fb *sfb)
> +{
> + void __iomem *regs = sfb->regs;
> + u32 irq_ctrl_reg;
> +
> + if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
> + /* IRQ enabled, disable it */
> + irq_ctrl_reg = readl(regs + VIDINTCON0);
> +
> + irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
> + irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
> +
> + writel(irq_ctrl_reg, regs + VIDINTCON0);
> + }
> +}
> +
> +static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
> +{
> + struct s3c_fb *sfb = dev_id;
> + void __iomem *regs = sfb->regs;
> + u32 irq_sts_reg;
> +
> + irq_sts_reg = readl(regs + VIDINTCON1);
> +
> + if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
> +
> + /* VSYNC interrupt, accept it */
> + writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
> +
> + sfb->vsync_info.count++;
> + wake_up_interruptible(&sfb->vsync_info.wait);
> + }
> +
> + /* We only support waiting for VSYNC for now, so it's safe
> + * to always disable irqs here.
> + */
> + s3c_fb_disable_irq(sfb);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
> + * @sfb: main hardware state
> + * @crtc: head index.
> + */
> +static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
> +{
> + unsigned long count;
> + int ret;
> +
> + if (crtc != 0)
> + return -ENODEV;
> +
> + s3c_fb_enable_irq(sfb);
> + count = sfb->vsync_info.count;
> + ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
> + count != sfb->vsync_info.count,
> + msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
> + if (ret == 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct s3c_fb_win *win = info->par;
> + struct s3c_fb *sfb = win->parent;
> + int ret;
> + u32 crtc;
> +
> + switch (cmd) {
> + case FBIO_WAITFORVSYNC:
> + if (get_user(crtc, (u32 __user *)arg)) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + ret = s3c_fb_wait_for_vsync(sfb, crtc);
> + break;
> + default:
> + ret = -ENOTTY;
> + }
> +
> + return ret;
> +}
> +
> static struct fb_ops s3c_fb_ops = {
> .owner = THIS_MODULE,
> .fb_check_var = s3c_fb_check_var,
> @@ -811,6 +957,7 @@ static struct fb_ops s3c_fb_ops = {
> .fb_copyarea = cfb_copyarea,
> .fb_imageblit = cfb_imageblit,
> .fb_pan_display = s3c_fb_pan_display,
> + .fb_ioctl = s3c_fb_ioctl,
> };
>
> /**
> @@ -917,6 +1064,8 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
>
> dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
>
> + init_waitqueue_head(&sfb->vsync_info.wait);
> +
> palette_size = variant->palette_sz * 4;
>
> fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
> @@ -1096,6 +1245,20 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> goto err_req_region;
> }
>
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!res) {
> + dev_err(dev, "failed to acquire irq resource\n");
> + ret = -ENOENT;
> + goto err_ioremap;
> + }
> + sfb->irq_no = res->start;
> + ret = request_irq(sfb->irq_no, s3c_fb_irq,
> + 0, "s3c_fb", sfb);
> + if (ret) {
> + dev_err(dev, "irq request failed\n");
> + goto err_ioremap;
> + }
> +
> dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
>
> /* setup gpio and output polarity controls */
> @@ -1130,7 +1293,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> dev_err(dev, "failed to create window %d\n", win);
> for (; win >= 0; win--)
> s3c_fb_release_win(sfb, sfb->windows[win]);
> - goto err_ioremap;
> + goto err_irq;
> }
> }
>
> @@ -1138,6 +1301,9 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
>
> return 0;
>
> +err_irq:
> + free_irq(sfb->irq_no, sfb);
> +
> err_ioremap:
> iounmap(sfb->regs);
>
> @@ -1170,6 +1336,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
> if (sfb->windows[win])
> s3c_fb_release_win(sfb, sfb->windows[win]);
>
> + free_irq(sfb->irq_no, sfb);
> +
> iounmap(sfb->regs);
>
> clk_disable(sfb->bus_clk);
> @@ -1370,6 +1538,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 __devinitdata = {
> [3] = 0x3000,
> [4] = 0x3400,
> },
> +
> },
> .win[0] = &s3c_fb_data_64xx_wins[0],
> .win[1] = &s3c_fb_data_64xx_wins[1],
> --
> 1.7.0.4
>
--
--
Ben
Q: What's a light-year?
A: One-third less calories than a regular year.
WARNING: multiple messages have this Message-ID (diff)
From: ben-linux@fluff.org (Ben Dooks)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 6/6] s3c-fb: Add wait for VSYNC ioctl
Date: Mon, 31 May 2010 12:40:06 +0100 [thread overview]
Message-ID: <20100531114006.GR4720@trinity.fluff.org> (raw)
In-Reply-To: <1275296935-2693-7-git-send-email-p.osciak@samsung.com>
On Mon, May 31, 2010 at 11:08:55AM +0200, Pawel Osciak wrote:
> Add VSYNC interrupt support and an ioctl that allows waiting for it.
> Interrupts are turned on only when needed.
>
> Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> arch/arm/plat-samsung/include/plat/regs-fb.h | 1 +
> drivers/video/s3c-fb.c | 171 +++++++++++++++++++++++++-
> 2 files changed, 171 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/plat-samsung/include/plat/regs-fb.h b/arch/arm/plat-samsung/include/plat/regs-fb.h
> index f454e32..5bcdd09 100644
> --- a/arch/arm/plat-samsung/include/plat/regs-fb.h
> +++ b/arch/arm/plat-samsung/include/plat/regs-fb.h
> @@ -298,6 +298,7 @@
> #define VIDINTCON0_FRAMESEL0_FRONTPORCH (0x3 << 15)
>
> #define VIDINTCON0_FRAMESEL1 (1 << 13)
> +#define VIDINTCON0_FRAMESEL1_MASK (0x3 << 13)
> #define VIDINTCON0_FRAMESEL1_NONE (0x0 << 13)
> #define VIDINTCON0_FRAMESEL1_BACKPORCH (0x1 << 13)
> #define VIDINTCON0_FRAMESEL1_VSYNC (0x2 << 13)
> diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> index 4f3680d..0dfa8b0 100644
> --- a/drivers/video/s3c-fb.c
> +++ b/drivers/video/s3c-fb.c
> @@ -21,6 +21,8 @@
> #include <linux/clk.h>
> #include <linux/fb.h>
> #include <linux/io.h>
> +#include <linux/uaccess.h>
> +#include <linux/interrupt.h>
>
> #include <mach/map.h>
> #include <plat/regs-fb-v4.h>
> @@ -48,6 +50,15 @@
> __raw_writel(v, r); } while(0)
> #endif /* FB_S3C_DEBUG_REGWRITE */
>
> +/* irq_flags bits */
> +#define S3C_FB_VSYNC_IRQ_EN 0
> +
> +#ifndef FBIO_WAITFORVSYNC
> +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
> +#endif
> +
> +#define VSYNC_TIMEOUT_MSEC 50
why are you testign for this, surely you need t oget FBIO_WAITFORVSYNC
from a header file.
> struct s3c_fb;
>
> #define VALID_BPP(x) (1 << ((x) - 1))
> @@ -156,6 +167,16 @@ struct s3c_fb_win {
> };
>
> /**
> + * struct s3c_fb_vsync - vsync information
> + * @wait: a queue for processes waiting for vsync
> + * @count: vsync interrupt count
> + */
> +struct s3c_fb_vsync {
> + wait_queue_head_t wait;
> + unsigned int count;
> +};
> +
> +/**
> * struct s3c_fb - overall hardware state of the hardware
> * @dev: The device that we bound to, for printing, etc.
> * @regs_res: The resource we claimed for the IO registers.
> @@ -165,6 +186,9 @@ struct s3c_fb_win {
> * @enabled: A bitmask of enabled hardware windows.
> * @pdata: The platform configuration data passed with the device.
> * @windows: The hardware windows that have been claimed.
> + * @irq_no: IRQ line number
> + * @irq_flags: irq flags
> + * @vsync_info: VSYNC-related information (count, queues...)
> */
> struct s3c_fb {
> struct device *dev;
> @@ -177,6 +201,10 @@ struct s3c_fb {
>
> struct s3c_fb_platdata *pdata;
> struct s3c_fb_win *windows[S3C_FB_MAX_WIN];
> +
> + int irq_no;
> + unsigned long irq_flags;
> + struct s3c_fb_vsync vsync_info;
> };
>
> /**
> @@ -801,6 +829,124 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
> return 0;
> }
>
> +/**
> + * s3c_fb_enable_irq() - enable framebuffer interrupts
> + * @sfb: main hardware state
> + */
> +static void s3c_fb_enable_irq(struct s3c_fb *sfb)
> +{
> + void __iomem *regs = sfb->regs;
> + u32 irq_ctrl_reg;
> +
> + if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
> + /* IRQ disabled, enable it */
> + irq_ctrl_reg = readl(regs + VIDINTCON0);
> +
> + irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
> + irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
> +
> + irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
> + irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
> + irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
> + irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
> +
> + writel(irq_ctrl_reg, regs + VIDINTCON0);
> + }
> +}
> +
> +/**
> + * s3c_fb_disable_irq() - disable framebuffer interrupts
> + * @sfb: main hardware state
> + */
> +static void s3c_fb_disable_irq(struct s3c_fb *sfb)
> +{
> + void __iomem *regs = sfb->regs;
> + u32 irq_ctrl_reg;
> +
> + if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
> + /* IRQ enabled, disable it */
> + irq_ctrl_reg = readl(regs + VIDINTCON0);
> +
> + irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
> + irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
> +
> + writel(irq_ctrl_reg, regs + VIDINTCON0);
> + }
> +}
> +
> +static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
> +{
> + struct s3c_fb *sfb = dev_id;
> + void __iomem *regs = sfb->regs;
> + u32 irq_sts_reg;
> +
> + irq_sts_reg = readl(regs + VIDINTCON1);
> +
> + if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
> +
> + /* VSYNC interrupt, accept it */
> + writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
> +
> + sfb->vsync_info.count++;
> + wake_up_interruptible(&sfb->vsync_info.wait);
> + }
> +
> + /* We only support waiting for VSYNC for now, so it's safe
> + * to always disable irqs here.
> + */
> + s3c_fb_disable_irq(sfb);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> + * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
> + * @sfb: main hardware state
> + * @crtc: head index.
> + */
> +static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
> +{
> + unsigned long count;
> + int ret;
> +
> + if (crtc != 0)
> + return -ENODEV;
> +
> + s3c_fb_enable_irq(sfb);
> + count = sfb->vsync_info.count;
> + ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
> + count != sfb->vsync_info.count,
> + msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
> + if (ret == 0)
> + return -ETIMEDOUT;
> +
> + return 0;
> +}
> +
> +static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
> + unsigned long arg)
> +{
> + struct s3c_fb_win *win = info->par;
> + struct s3c_fb *sfb = win->parent;
> + int ret;
> + u32 crtc;
> +
> + switch (cmd) {
> + case FBIO_WAITFORVSYNC:
> + if (get_user(crtc, (u32 __user *)arg)) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + ret = s3c_fb_wait_for_vsync(sfb, crtc);
> + break;
> + default:
> + ret = -ENOTTY;
> + }
> +
> + return ret;
> +}
> +
> static struct fb_ops s3c_fb_ops = {
> .owner = THIS_MODULE,
> .fb_check_var = s3c_fb_check_var,
> @@ -811,6 +957,7 @@ static struct fb_ops s3c_fb_ops = {
> .fb_copyarea = cfb_copyarea,
> .fb_imageblit = cfb_imageblit,
> .fb_pan_display = s3c_fb_pan_display,
> + .fb_ioctl = s3c_fb_ioctl,
> };
>
> /**
> @@ -917,6 +1064,8 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
>
> dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
>
> + init_waitqueue_head(&sfb->vsync_info.wait);
> +
> palette_size = variant->palette_sz * 4;
>
> fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
> @@ -1096,6 +1245,20 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> goto err_req_region;
> }
>
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (!res) {
> + dev_err(dev, "failed to acquire irq resource\n");
> + ret = -ENOENT;
> + goto err_ioremap;
> + }
> + sfb->irq_no = res->start;
> + ret = request_irq(sfb->irq_no, s3c_fb_irq,
> + 0, "s3c_fb", sfb);
> + if (ret) {
> + dev_err(dev, "irq request failed\n");
> + goto err_ioremap;
> + }
> +
> dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
>
> /* setup gpio and output polarity controls */
> @@ -1130,7 +1293,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> dev_err(dev, "failed to create window %d\n", win);
> for (; win >= 0; win--)
> s3c_fb_release_win(sfb, sfb->windows[win]);
> - goto err_ioremap;
> + goto err_irq;
> }
> }
>
> @@ -1138,6 +1301,9 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
>
> return 0;
>
> +err_irq:
> + free_irq(sfb->irq_no, sfb);
> +
> err_ioremap:
> iounmap(sfb->regs);
>
> @@ -1170,6 +1336,8 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
> if (sfb->windows[win])
> s3c_fb_release_win(sfb, sfb->windows[win]);
>
> + free_irq(sfb->irq_no, sfb);
> +
> iounmap(sfb->regs);
>
> clk_disable(sfb->bus_clk);
> @@ -1370,6 +1538,7 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 __devinitdata = {
> [3] = 0x3000,
> [4] = 0x3400,
> },
> +
> },
> .win[0] = &s3c_fb_data_64xx_wins[0],
> .win[1] = &s3c_fb_data_64xx_wins[1],
> --
> 1.7.0.4
>
--
--
Ben
Q: What's a light-year?
A: One-third less calories than a regular year.
next prev parent reply other threads:[~2010-05-31 11:40 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-05-31 9:08 [PATCH 0/6] Various s3c-fb updates Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` [PATCH 1/6] s3c-fb: Fix various null references on framebuffer memory Pawel Osciak
2010-05-31 9:08 ` [PATCH 1/6] s3c-fb: Fix various null references on framebuffer memory alloc failure Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` [PATCH 2/6] s3c-fb: Correct FRAMESEL1 bitfield defines for VIDINTCON0 Pawel Osciak
2010-05-31 9:08 ` [PATCH 2/6] s3c-fb: Correct FRAMESEL1 bitfield defines for VIDINTCON0 register Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-06-01 4:17 ` [PATCH 2/6] s3c-fb: Correct FRAMESEL1 bitfield defines for Ben Dooks
2010-06-01 4:17 ` [PATCH 2/6] s3c-fb: Correct FRAMESEL1 bitfield defines for VIDINTCON0 register Ben Dooks
2010-06-01 4:17 ` Ben Dooks
2010-06-01 6:49 ` [PATCH 2/6] s3c-fb: Correct FRAMESEL1 bitfield defines for Pawel Osciak
2010-06-01 6:49 ` [PATCH 2/6] s3c-fb: Correct FRAMESEL1 bitfield defines for VIDINTCON0 register Pawel Osciak
2010-06-01 6:49 ` Pawel Osciak
2010-05-31 9:08 ` [PATCH 3/6] s3c-fb: Add device name initialization Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` [PATCH 4/6] s3c-fb: Separate S5PC100 and S5PV210 framebuffer driver Pawel Osciak
2010-05-31 9:08 ` [PATCH 4/6] s3c-fb: Separate S5PC100 and S5PV210 framebuffer driver data structures Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` [PATCH 5/6] s3c-fb: Add support for display panning Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` [PATCH 6/6] s3c-fb: Add wait for VSYNC ioctl Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 9:08 ` Pawel Osciak
2010-05-31 11:40 ` Ben Dooks [this message]
2010-05-31 11:40 ` Ben Dooks
2010-05-31 11:40 ` Ben Dooks
2010-06-11 5:32 ` [PATCH 0/6] Various s3c-fb updates Ben Dooks
2010-06-11 5:32 ` Ben Dooks
2010-06-11 5:32 ` Ben Dooks
2010-06-16 9:34 ` [PATCH v2] " Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 1/9] s3c-fb: Fix various null references on framebuffer memory Marek Szyprowski
2010-06-16 9:34 ` [PATCH 1/9] s3c-fb: Fix various null references on framebuffer memory alloc failure Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 2/9] s3c-fb: Correct FRAMESEL1 bitfield defines for VIDINTCON0 Marek Szyprowski
2010-06-16 9:34 ` [PATCH 2/9] s3c-fb: Correct FRAMESEL1 bitfield defines for VIDINTCON0 register Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 3/9] s3c-fb: Add device name initialization Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 4/9] s3c-fb: Separate S5PC100 and S5PV210 framebuffer driver Marek Szyprowski
2010-06-16 9:34 ` [PATCH 4/9] s3c-fb: Separate S5PC100 and S5PV210 framebuffer driver data structures Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 5/9] s3c-fb: Add support for display panning Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 6/9] s3c-fb: Add wait for VSYNC ioctl Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 7/9] s3c-fb: window 3 of 64xx+ does not have an osd_d register Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 8/9] s3c-fb: Add SHADOWCON shadow register locking support for Marek Szyprowski
2010-06-16 9:34 ` [PATCH 8/9] s3c-fb: Add SHADOWCON shadow register locking support for S5PV210 Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` [PATCH 9/9] s3c-fb: Correct window osd size and alpha register handling Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
2010-06-16 9:34 ` Marek Szyprowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100531114006.GR4720@trinity.fluff.org \
--to=ben-linux@fluff.org \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.