Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 208497
b: refs/heads/master
c: efdc846
h: refs/heads/master
i:
  208495: 7871046
v: v3
  • Loading branch information
Pawel Osciak authored and Linus Torvalds committed Aug 11, 2010
1 parent defdcd4 commit 533e372
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 067b226b9e8e20463e0937344c93101ac8d8d2b1
refs/heads/master: efdc846d2f7190c8f3092c09975c0ebba30a95ba
1 change: 1 addition & 0 deletions trunk/arch/arm/plat-samsung/include/plat/regs-fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,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)
Expand Down
166 changes: 165 additions & 1 deletion trunk/drivers/video/s3c-fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -48,6 +50,11 @@
__raw_writel(v, r); } while(0)
#endif /* FB_S3C_DEBUG_REGWRITE */

/* irq_flags bits */
#define S3C_FB_VSYNC_IRQ_EN 0

#define VSYNC_TIMEOUT_MSEC 50

struct s3c_fb;

#define VALID_BPP(x) (1 << ((x) - 1))
Expand Down Expand Up @@ -155,6 +162,16 @@ struct s3c_fb_win {
unsigned int index;
};

/**
* 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.
Expand All @@ -165,6 +182,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;
Expand All @@ -177,6 +197,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;
};

/**
Expand Down Expand Up @@ -798,6 +822,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;

count = sfb->vsync_info.count;
s3c_fb_enable_irq(sfb);
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,
Expand All @@ -808,6 +950,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,
};

/**
Expand Down Expand Up @@ -914,6 +1057,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) +
Expand Down Expand Up @@ -1093,6 +1238,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 */
Expand Down Expand Up @@ -1127,14 +1286,17 @@ 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;
}
}

platform_set_drvdata(pdev, sfb);

return 0;

err_irq:
free_irq(sfb->irq_no, sfb);

err_ioremap:
iounmap(sfb->regs);

Expand Down Expand Up @@ -1167,6 +1329,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);
Expand Down

0 comments on commit 533e372

Please sign in to comment.