Merge branch 'merge'
[pandora-kernel.git] / drivers / video / riva / fbdev.c
index 3e9f96e..511c362 100644 (file)
  *     doublescan modes are broken
  */
 
-#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/init.h>
 #include <linux/pci.h>
+#include <linux/backlight.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -49,6 +48,7 @@
 #include <asm/pci-bridge.h>
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/machdep.h>
 #include <asm/backlight.h>
 #endif
 
@@ -271,34 +271,182 @@ static const struct riva_regs reg_template = {
 /*
  * Backlight control
  */
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
 
-static int riva_backlight_levels[] = {
-    0x158,
-    0x192,
-    0x1c6,
-    0x200,
-    0x234,
-    0x268,
-    0x2a2,
-    0x2d6,
-    0x310,
-    0x344,
-    0x378,
-    0x3b2,
-    0x3e6,
-    0x41a,
-    0x454,
-    0x534,
-};
+static struct backlight_properties riva_bl_data;
+
+/* Call with fb_info->bl_mutex held */
+static int riva_bl_get_level_brightness(struct riva_par *par,
+               int level)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       int nlevel;
+
+       /* Get and convert the value */
+       nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
+
+       if (nlevel < 0)
+               nlevel = 0;
+       else if (nlevel < MIN_LEVEL)
+               nlevel = MIN_LEVEL;
+       else if (nlevel > MAX_LEVEL)
+               nlevel = MAX_LEVEL;
+
+       return nlevel;
+}
+
+/* Call with fb_info->bl_mutex held */
+static int __riva_bl_update_status(struct backlight_device *bd)
+{
+       struct riva_par *par = class_get_devdata(&bd->class_dev);
+       U032 tmp_pcrt, tmp_pmc;
+       int level;
+
+       if (bd->props->power != FB_BLANK_UNBLANK ||
+           bd->props->fb_blank != FB_BLANK_UNBLANK)
+               level = 0;
+       else
+               level = bd->props->brightness;
+
+       tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
+       tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+       if(level > 0) {
+               tmp_pcrt |= 0x1;
+               tmp_pmc |= (1 << 31); /* backlight bit */
+               tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
+       }
+       par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
+       par->riva.PMC[0x10F0/4] = tmp_pmc;
+
+       return 0;
+}
+
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+       struct riva_par *par = class_get_devdata(&bd->class_dev);
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       int ret;
+
+       mutex_lock(&info->bl_mutex);
+       ret = __riva_bl_update_status(bd);
+       mutex_unlock(&info->bl_mutex);
+
+       return ret;
+}
+
+static int riva_bl_get_brightness(struct backlight_device *bd)
+{
+       return bd->props->brightness;
+}
 
-static int riva_set_backlight_enable(int on, int level, void *data);
-static int riva_set_backlight_level(int level, void *data);
-static struct backlight_controller riva_backlight_controller = {
-       riva_set_backlight_enable,
-       riva_set_backlight_level
+static struct backlight_properties riva_bl_data = {
+       .owner    = THIS_MODULE,
+       .get_brightness = riva_bl_get_brightness,
+       .update_status  = riva_bl_update_status,
+       .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
 };
-#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void riva_bl_set_power(struct fb_info *info, int power)
+{
+       if (info->bl_dev == NULL)
+               return;
+
+       mutex_lock(&info->bl_mutex);
+       up(&info->bl_dev->sem);
+       info->bl_dev->props->power = power;
+       __riva_bl_update_status(info->bl_dev);
+       down(&info->bl_dev->sem);
+       mutex_unlock(&info->bl_mutex);
+}
+
+static void riva_bl_init(struct riva_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+       struct backlight_device *bd;
+       char name[12];
+
+       if (!par->FlatPanel)
+               return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       if (!machine_is(powermac) ||
+           !pmac_has_backlight_type("mnca"))
+               return;
+#endif
+
+       snprintf(name, sizeof(name), "rivabl%d", info->node);
+
+       bd = backlight_device_register(name, par, &riva_bl_data);
+       if (IS_ERR(bd)) {
+               info->bl_dev = NULL;
+               printk(KERN_WARNING "riva: Backlight registration failed\n");
+               goto error;
+       }
+
+       mutex_lock(&info->bl_mutex);
+       info->bl_dev = bd;
+       fb_bl_default_curve(info, 0,
+               0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+               0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+       mutex_unlock(&info->bl_mutex);
+
+       up(&bd->sem);
+       bd->props->brightness = riva_bl_data.max_brightness;
+       bd->props->power = FB_BLANK_UNBLANK;
+       bd->props->update_status(bd);
+       down(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+       if (!pmac_backlight)
+               pmac_backlight = bd;
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+       printk("riva: Backlight initialized (%s)\n", name);
+
+       return;
+
+error:
+       return;
+}
+
+static void riva_bl_exit(struct riva_par *par)
+{
+       struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_lock(&pmac_backlight_mutex);
+#endif
+
+       mutex_lock(&info->bl_mutex);
+       if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+               if (pmac_backlight == info->bl_dev)
+                       pmac_backlight = NULL;
+#endif
+
+               backlight_device_unregister(info->bl_dev);
+
+               printk("riva: Backlight unloaded\n");
+       }
+       mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+       mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#else
+static inline void riva_bl_init(struct riva_par *par) {}
+static inline void riva_bl_exit(struct riva_par *par) {}
+static inline void riva_bl_set_power(struct fb_info *info, int power) {}
+#endif /* CONFIG_FB_RIVA_BACKLIGHT */
 
 /* ------------------------------------------------------------------------- *
  *
@@ -630,7 +778,7 @@ static void riva_load_video_mode(struct fb_info *info)
        int bpp, width, hDisplaySize, hDisplay, hStart,
            hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
        int hBlankStart, hBlankEnd, vBlankStart, vBlankEnd;
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        struct riva_regs newmode;
        
        NVTRACE_ENTER();
@@ -925,7 +1073,7 @@ riva_set_rop_solid(struct riva_par *par, int rop)
 
 static void riva_setup_accel(struct fb_info *info)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
 
        RIVA_FIFO_FREE(par->riva, Clip, 2);
        NV_WR32(&par->riva.Clip->TopLeft, 0, 0x0);
@@ -970,36 +1118,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
        return rc;
 }
 
-/* ------------------------------------------------------------------------- *
- *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int riva_set_backlight_enable(int on, int level, void *data)
-{
-       struct riva_par *par = (struct riva_par *)data;
-       U032 tmp_pcrt, tmp_pmc;
-
-       tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
-       tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
-       if(on && (level > BACKLIGHT_OFF)) {
-               tmp_pcrt |= 0x1;
-               tmp_pmc |= (1 << 31); // backlight bit
-               tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
-       }
-       par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
-       par->riva.PMC[0x10F0/4] = tmp_pmc;
-       return 0;
-}
-
-static int riva_set_backlight_level(int level, void *data)
-{
-       return riva_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
 /* ------------------------------------------------------------------------- *
  *
  * framebuffer operations
@@ -1008,7 +1126,7 @@ static int riva_set_backlight_level(int level, void *data)
 
 static int rivafb_open(struct fb_info *info, int user)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        int cnt = atomic_read(&par->ref_count);
 
        NVTRACE_ENTER();
@@ -1034,7 +1152,7 @@ static int rivafb_open(struct fb_info *info, int user)
 
 static int rivafb_release(struct fb_info *info, int user)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        int cnt = atomic_read(&par->ref_count);
 
        NVTRACE_ENTER();
@@ -1057,7 +1175,7 @@ static int rivafb_release(struct fb_info *info, int user)
 static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct fb_videomode *mode;
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        int nom, den;           /* translating from pixels->bytes */
        int mode_valid = 0;
        
@@ -1166,7 +1284,7 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 
 static int rivafb_set_par(struct fb_info *info)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
 
        NVTRACE_ENTER();
        /* vgaHWunlock() + riva unlock (0x7F) */
@@ -1205,43 +1323,19 @@ static int rivafb_set_par(struct fb_info *info)
 static int rivafb_pan_display(struct fb_var_screeninfo *var,
                              struct fb_info *info)
 {
-       struct riva_par *par = (struct riva_par *)info->par;
+       struct riva_par *par = info->par;
        unsigned int base;
 
        NVTRACE_ENTER();
-       if (var->xoffset > (var->xres_virtual - var->xres))
-               return -EINVAL;
-       if (var->yoffset > (var->yres_virtual - var->yres))
-               return -EINVAL;
-
-       if (var->vmode & FB_VMODE_YWRAP) {
-               if (var->yoffset < 0
-                   || var->yoffset >= info->var.yres_virtual
-                   || var->xoffset) return -EINVAL;
-       } else {
-               if (var->xoffset + info->var.xres > info->var.xres_virtual ||
-                   var->yoffset + info->var.yres > info->var.yres_virtual)
-                       return -EINVAL;
-       }
-
        base = var->yoffset * info->fix.line_length + var->xoffset;
-
        par->riva.SetStartAddress(&par->riva, base);
-
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-
-       if (var->vmode & FB_VMODE_YWRAP)
-               info->var.vmode |= FB_VMODE_YWRAP;
-       else
-               info->var.vmode &= ~FB_VMODE_YWRAP;
        NVTRACE_LEAVE();
        return 0;
 }
 
 static int rivafb_blank(int blank, struct fb_info *info)
 {
-       struct riva_par *par= (struct riva_par *)info->par;
+       struct riva_par *par= info->par;
        unsigned char tmp, vesa;
 
        tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */
@@ -1270,11 +1364,7 @@ static int rivafb_blank(int blank, struct fb_info *info)
        SEQout(par, 0x01, tmp);
        CRTCout(par, 0x1a, vesa);
 
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if ( par->FlatPanel && _machine == _MACH_Pmac) {
-               set_backlight_enable(!blank);
-       }
-#endif
+       riva_bl_set_power(info, blank);
 
        NVTRACE_LEAVE();
 
@@ -1304,7 +1394,7 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
                          unsigned blue, unsigned transp,
                          struct fb_info *info)
 {
-       struct riva_par *par = (struct riva_par *)info->par;
+       struct riva_par *par = info->par;
        RIVA_HW_INST *chip = &par->riva;
        int i;
 
@@ -1393,7 +1483,7 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
  */
 static void rivafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        u_int color, rop = 0;
 
        if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
@@ -1449,7 +1539,7 @@ static void rivafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect
  */
 static void rivafb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
 
        if ((info->flags & FBINFO_HWACCEL_DISABLED)) {
                cfb_copyarea(info, region);
@@ -1495,7 +1585,7 @@ static inline void convert_bgcolor_16(u32 *col)
 static void rivafb_imageblit(struct fb_info *info, 
                             const struct fb_image *image)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        u32 fgx = 0, bgx = 0, width, tmp;
        u8 *cdat = (u8 *) image->data;
        volatile u32 __iomem *d;
@@ -1580,7 +1670,7 @@ static void rivafb_imageblit(struct fb_info *info,
  */
 static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        u8 data[MAX_CURS * MAX_CURS/8];
        int i, set = cursor->set;
        u16 fg, bg;
@@ -1664,7 +1754,7 @@ static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 
 static int rivafb_sync(struct fb_info *info)
 {
-       struct riva_par *par = (struct riva_par *)info->par;
+       struct riva_par *par = info->par;
 
        wait_for_idle(par);
        return 0;
@@ -1696,7 +1786,7 @@ static struct fb_ops riva_fb_ops = {
 static int __devinit riva_set_fbinfo(struct fb_info *info)
 {
        unsigned int cmap_len;
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
 
        NVTRACE_ENTER();
        info->flags = FBINFO_DEFAULT
@@ -1733,7 +1823,7 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
 #ifdef CONFIG_PPC_OF
 static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        struct device_node *dp;
        unsigned char *pedid = NULL;
        unsigned char *disptype = NULL;
@@ -1744,14 +1834,13 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
        NVTRACE_ENTER();
        dp = pci_device_to_OF_node(pd);
        for (; dp != NULL; dp = dp->child) {
-               disptype = (unsigned char *)get_property(dp, "display-type", NULL);
+               disptype = get_property(dp, "display-type", NULL);
                if (disptype == NULL)
                        continue;
                if (strncmp(disptype, "LCD", 3) != 0)
                        continue;
                for (i = 0; propnames[i] != NULL; ++i) {
-                       pedid = (unsigned char *)
-                               get_property(dp, propnames[i], NULL);
+                       pedid = get_property(dp, propnames[i], NULL);
                        if (pedid != NULL) {
                                par->EDID = pedid;
                                NVTRACE("LCD found.\n");
@@ -1767,7 +1856,7 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
 #if defined(CONFIG_FB_RIVA_I2C) && !defined(CONFIG_PPC_OF)
 static int __devinit riva_get_EDID_i2c(struct fb_info *info)
 {
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        struct fb_var_screeninfo var;
        int i;
 
@@ -1837,7 +1926,7 @@ static void __devinit riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
 static void __devinit riva_get_edidinfo(struct fb_info *info)
 {
        struct fb_var_screeninfo *var = &rivafb_default_var;
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
 
        fb_edid_to_monspecs(par->EDID, &info->monspecs);
        fb_videomode_to_modelist(info->monspecs.modedb, info->monspecs.modedb_len,
@@ -1909,7 +1998,7 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
                ret = -ENOMEM;
                goto err_ret;
        }
-       default_par = (struct riva_par *) info->par;
+       default_par = info->par;
        default_par->pdev = pd;
 
        info->pixmap.addr = kmalloc(8 * 1024, GFP_KERNEL);
@@ -2045,6 +2134,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
 
        fb_destroy_modedb(info->monspecs.modedb);
        info->monspecs.modedb = NULL;
+
+       pci_set_drvdata(pd, info);
+       riva_bl_init(info->par);
        ret = register_framebuffer(info);
        if (ret < 0) {
                printk(KERN_ERR PFX
@@ -2052,25 +2144,19 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
                goto err_iounmap_screen_base;
        }
 
-       pci_set_drvdata(pd, info);
-
        printk(KERN_INFO PFX
                "PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n",
                info->fix.id,
                RIVAFB_VERSION,
                info->fix.smem_len / (1024 * 1024),
                info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (default_par->FlatPanel && _machine == _MACH_Pmac)
-       register_backlight_controller(&riva_backlight_controller,
-                                               default_par, "mnca");
-#endif
+
        NVTRACE_LEAVE();
        return 0;
 
 err_iounmap_screen_base:
 #ifdef CONFIG_FB_RIVA_I2C
-       riva_delete_i2c_busses((struct riva_par *) info->par);
+       riva_delete_i2c_busses(info->par);
 #endif
        iounmap(info->screen_base);
 err_iounmap_pramin:
@@ -2081,7 +2167,6 @@ err_iounmap_ctrl_base:
 err_release_region:
        pci_release_regions(pd);
 err_disable_device:
-       pci_disable_device(pd);
 err_free_pixmap:
        kfree(info->pixmap.addr);
 err_framebuffer_release:
@@ -2093,11 +2178,11 @@ err_ret:
 static void __exit rivafb_remove(struct pci_dev *pd)
 {
        struct fb_info *info = pci_get_drvdata(pd);
-       struct riva_par *par = (struct riva_par *) info->par;
+       struct riva_par *par = info->par;
        
        NVTRACE_ENTER();
-       if (!info)
-               return;
+
+       riva_bl_exit(par);
 
 #ifdef CONFIG_FB_RIVA_I2C
        riva_delete_i2c_busses(par);
@@ -2116,7 +2201,6 @@ static void __exit rivafb_remove(struct pci_dev *pd)
        if (par->riva.Architecture == NV_ARCH_03)
                iounmap(par->riva.PRAMIN);
        pci_release_regions(pd);
-       pci_disable_device(pd);
        kfree(info->pixmap.addr);
        framebuffer_release(info);
        pci_set_drvdata(pd, NULL);