Merge branch 'intelfb-patches' of master.kernel.org:/pub/scm/linux/kernel/git/airlied...
[linux-drm-fsl-dcu.git] / drivers / video / intelfb / intelfbdrv.c
index 076fa56be192a3df28d06f7ad41903f8ba54ad86..6f9de04193d216d62f62511f7bbb0cd821d3c0df 100644 (file)
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/tty.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
+#include <linux/screen_info.h>
 
 #include <asm/io.h>
 
 static void __devinit get_initial_mode(struct intelfb_info *dinfo);
 static void update_dinfo(struct intelfb_info *dinfo,
                         struct fb_var_screeninfo *var);
+static int intelfb_open(struct fb_info *info, int user);
+static int intelfb_release(struct fb_info *info, int user);
 static int intelfb_check_var(struct fb_var_screeninfo *var,
                             struct fb_info *info);
 static int intelfb_set_par(struct fb_info *info);
@@ -195,6 +196,8 @@ static int num_registered = 0;
 /* fb ops */
 static struct fb_ops intel_fb_ops = {
        .owner =                THIS_MODULE,
+       .fb_open =              intelfb_open,
+       .fb_release =           intelfb_release,
        .fb_check_var =         intelfb_check_var,
        .fb_set_par =           intelfb_set_par,
        .fb_setcolreg =         intelfb_setcolreg,
@@ -447,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
        if (!dinfo)
                return;
 
+       intelfbhw_disable_irq(dinfo);
+
        fb_dealloc_cmap(&dinfo->info->cmap);
        kfree(dinfo->info->pixmap.addr);
 
@@ -468,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
                agp_free_memory(dinfo->gtt_ring_mem);
        }
 
+#ifdef CONFIG_FB_INTEL_I2C
+       /* un-register I2C bus */
+       intelfb_delete_i2c_busses(dinfo);
+#endif
+
        if (dinfo->mmio_base)
                iounmap((void __iomem *)dinfo->mmio_base);
        if (dinfo->aperture.virtual)
@@ -707,7 +717,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
                        + (dinfo->ring.offset << 12);
                dinfo->ring.virtual  = dinfo->aperture.virtual
                        + (dinfo->ring.offset << 12);
-               dinfo->ring_head = dinfo->ring.virtual;
+               dinfo->ring_head = 0;
        }
        if (dinfo->hwcursor) {
                agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
@@ -766,18 +776,18 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (mtrr)
                set_mtrr(dinfo);
 
-       DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%x)\n",
+       DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n",
                dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size,
-               (u32 __iomem ) dinfo->fb.virtual);
-       DBG_MSG("MMIO: 0x%x/0x%x (0x%x)\n",
+               dinfo->fb.virtual);
+       DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n",
                dinfo->mmio_base_phys, INTEL_REG_SIZE,
-               (u32 __iomem) dinfo->mmio_base);
-       DBG_MSG("ring buffer: 0x%x/0x%x (0x%x)\n",
+               dinfo->mmio_base);
+       DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n",
                dinfo->ring.physical, dinfo->ring.size,
-               (u32 __iomem ) dinfo->ring.virtual);
-       DBG_MSG("HW cursor: 0x%x/0x%x (0x%x) (offset 0x%x) (phys 0x%x)\n",
+               dinfo->ring.virtual);
+       DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n",
                dinfo->cursor.physical, dinfo->cursor.size,
-               (u32 __iomem ) dinfo->cursor.virtual, dinfo->cursor.offset,
+               dinfo->cursor.virtual, dinfo->cursor.offset,
                dinfo->cursor.physical);
 
        DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, "
@@ -845,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (bailearly == 5)
                bailout(dinfo);
 
+#ifdef CONFIG_FB_INTEL_I2C
+       /* register I2C bus */
+       intelfb_create_i2c_busses(dinfo);
+#endif
+
        if (bailearly == 6)
                bailout(dinfo);
 
@@ -889,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        dinfo->registered = 1;
+       dinfo->open = 0;
+
+       init_waitqueue_head(&dinfo->vsync.wait);
+       spin_lock_init(&dinfo->int_lock);
+       dinfo->irq_flags = 0;
+       dinfo->vsync.pan_display = 0;
+       dinfo->vsync.pan_offset = 0;
 
        return 0;
 
@@ -1188,6 +1210,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
  *                       fbdev interface                       *
  ***************************************************************/
 
+static int
+intelfb_open(struct fb_info *info, int user)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+
+       if (user) {
+               dinfo->open++;
+       }
+
+       return 0;
+}
+
+static int
+intelfb_release(struct fb_info *info, int user)
+{
+       struct intelfb_info *dinfo = GET_DINFO(info);
+
+       if (user) {
+               dinfo->open--;
+               msleep(1);
+               if (!dinfo->open) {
+                       intelfbhw_disable_irq(dinfo);
+               }
+       }
+
+       return 0;
+}
+
 static int
 intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
@@ -1434,6 +1484,19 @@ static int
 intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        int retval = 0;
+       struct intelfb_info *dinfo = GET_DINFO(info);
+       u32 pipe = 0;
+
+       switch (cmd) {
+               case FBIO_WAITFORVSYNC:
+                       if (get_user(pipe, (__u32 __user *)arg))
+                               return -EFAULT;
+
+                       retval = intelfbhw_wait_for_vsync(dinfo, pipe);
+                       break;
+               default:
+                       break;
+       }
 
        return retval;
 }