viafb: add initial VX900 support
[pandora-kernel.git] / drivers / video / via / viafbdev.c
index 80ce43a..d298cfc 100644 (file)
@@ -56,6 +56,32 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
 
 static struct fb_ops viafb_ops;
 
+/* supported output devices on each IGP
+ * only CX700, VX800, VX855, VX900 were documented
+ * VIA_CRT should be everywhere
+ * VIA_6C can be onle pre-CX700 (probably only on CLE266) as 6C is used for PLL
+ * source selection on CX700 and later
+ * K400 seems to support VIA_96, VIA_DVP1, VIA_LVDS{1,2} as in viamode.c
+ */
+static const u32 supported_odev_map[] = {
+       [UNICHROME_CLE266]      = VIA_CRT | VIA_LDVP0 | VIA_LDVP1,
+       [UNICHROME_K400]        = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+                               | VIA_LVDS2,
+       [UNICHROME_K800]        = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+                               | VIA_LVDS2,
+       [UNICHROME_PM800]       = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+                               | VIA_LVDS2,
+       [UNICHROME_CN700]       = VIA_CRT | VIA_DVP0 | VIA_DVP1 | VIA_LVDS1
+                               | VIA_LVDS2,
+       [UNICHROME_CX700]       = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_CN750]       = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_K8M890]      = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_P4M890]      = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_P4M900]      = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_VX800]       = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_VX855]       = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+       [UNICHROME_VX900]       = VIA_CRT | VIA_DVP1 | VIA_LVDS1 | VIA_LVDS2,
+};
 
 static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth)
 {
@@ -332,22 +358,22 @@ static int viafb_blank(int blank_mode, struct fb_info *info)
        case FB_BLANK_UNBLANK:
                /* Screen: On, HSync: On, VSync: On */
                /* control CRT monitor power management */
-               viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+               via_set_state(VIA_CRT, VIA_STATE_ON);
                break;
        case FB_BLANK_HSYNC_SUSPEND:
                /* Screen: Off, HSync: Off, VSync: On */
                /* control CRT monitor power management */
-               viafb_write_reg_mask(CR36, VIACR, 0x10, BIT4 + BIT5);
+               via_set_state(VIA_CRT, VIA_STATE_STANDBY);
                break;
        case FB_BLANK_VSYNC_SUSPEND:
                /* Screen: Off, HSync: On, VSync: Off */
                /* control CRT monitor power management */
-               viafb_write_reg_mask(CR36, VIACR, 0x20, BIT4 + BIT5);
+               via_set_state(VIA_CRT, VIA_STATE_SUSPEND);
                break;
        case FB_BLANK_POWERDOWN:
                /* Screen: Off, HSync: Off, VSync: Off */
                /* control CRT monitor power management */
-               viafb_write_reg_mask(CR36, VIACR, 0x30, BIT4 + BIT5);
+               via_set_state(VIA_CRT, VIA_STATE_OFF);
                break;
        }
 
@@ -457,7 +483,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
                if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
                        return -EFAULT;
                if (gpu32 & CRT_Device)
-                       viafb_crt_enable();
+                       via_set_state(VIA_CRT, VIA_STATE_ON);
                if (gpu32 & DVI_Device)
                        viafb_dvi_enable();
                if (gpu32 & LCD_Device)
@@ -467,7 +493,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
                if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
                        return -EFAULT;
                if (gpu32 & CRT_Device)
-                       viafb_crt_disable();
+                       via_set_state(VIA_CRT, VIA_STATE_OFF);
                if (gpu32 & DVI_Device)
                        viafb_dvi_disable();
                if (gpu32 & LCD_Device)
@@ -787,7 +813,8 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
                bg_color = cursor->image.bg_color;
                if (chip_name == UNICHROME_CX700 ||
                        chip_name == UNICHROME_VX800 ||
-                       chip_name == UNICHROME_VX855) {
+                       chip_name == UNICHROME_VX855 ||
+                       chip_name == UNICHROME_VX900) {
                        fg_color =
                                ((info->cmap.red[fg_color] & 0xFFC0) << 14) |
                                ((info->cmap.green[fg_color] & 0xFFC0) << 4) |
@@ -1433,6 +1460,26 @@ static const struct file_operations viafb_vt1636_proc_fops = {
 
 #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
 
+static int viafb_sup_odev_proc_show(struct seq_file *m, void *v)
+{
+       via_odev_to_seq(m, supported_odev_map[
+               viaparinfo->shared->chip_info.gfx_chip_name]);
+       return 0;
+}
+
+static int viafb_sup_odev_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, viafb_sup_odev_proc_show, NULL);
+}
+
+static const struct file_operations viafb_sup_odev_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = viafb_sup_odev_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static ssize_t odev_update(const char __user *buffer, size_t count, u32 *odev)
 {
        char buf[64], *ptr = buf;
@@ -1487,7 +1534,9 @@ static ssize_t viafb_iga1_odev_proc_write(struct file *file,
        dev_on = dev_new & ~dev_old;
        viaparinfo->shared->iga1_devices = dev_new;
        viaparinfo->shared->iga2_devices &= ~dev_new;
+       via_set_state(dev_off, VIA_STATE_OFF);
        via_set_source(dev_new, IGA1);
+       via_set_state(dev_on, VIA_STATE_ON);
        return res;
 }
 
@@ -1525,7 +1574,9 @@ static ssize_t viafb_iga2_odev_proc_write(struct file *file,
        dev_on = dev_new & ~dev_old;
        viaparinfo->shared->iga2_devices = dev_new;
        viaparinfo->shared->iga1_devices &= ~dev_new;
+       via_set_state(dev_off, VIA_STATE_OFF);
        via_set_source(dev_new, IGA2);
+       via_set_state(dev_on, VIA_STATE_ON);
        return res;
 }
 
@@ -1557,6 +1608,8 @@ static void viafb_init_proc(struct viafb_shared *shared)
                                &viafb_vt1636_proc_fops);
 #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
 
+               proc_create("supported_output_devices", 0, viafb_entry,
+                       &viafb_sup_odev_proc_fops);
                iga1_entry = proc_mkdir("iga1", viafb_entry);
                shared->iga1_proc_entry = iga1_entry;
                proc_create("output_devices", 0, iga1_entry,
@@ -1580,6 +1633,7 @@ static void viafb_remove_proc(struct viafb_shared *shared)
        remove_proc_entry("iga2", viafb_entry);
        remove_proc_entry("output_devices", iga1_entry);
        remove_proc_entry("iga1", viafb_entry);
+       remove_proc_entry("supported_output_devices", viafb_entry);
 
 #ifdef CONFIG_FB_VIA_DIRECT_PROCFS
        remove_proc_entry("dvp0", viafb_entry);/* parent dir */
@@ -1617,6 +1671,47 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
 }
 
 
+#ifdef CONFIG_PM
+int viafb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       if (state.event == PM_EVENT_SUSPEND) {
+               acquire_console_sem();
+               fb_set_suspend(viafbinfo, 1);
+
+               viafb_sync(viafbinfo);
+
+               pci_save_state(pdev);
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, pci_choose_state(pdev, state));
+               release_console_sem();
+       }
+
+       return 0;
+}
+
+int viafb_resume(struct pci_dev *pdev)
+{
+       acquire_console_sem();
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       if (pci_enable_device(pdev))
+               goto fail;
+       pci_set_master(pdev);
+       if (viaparinfo->shared->vdev->engine_mmio)
+               viafb_reset_engine(viaparinfo);
+       viafb_set_par(viafbinfo);
+       if (viafb_dual_fb)
+               viafb_set_par(viafbinfo1);
+       fb_set_suspend(viafbinfo, 0);
+
+fail:
+       release_console_sem();
+       return 0;
+}
+
+#endif
+
+
 int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
 {
        u32 default_xres, default_yres;
@@ -1675,7 +1770,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
        viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 
        viafbinfo->pseudo_palette = pseudo_pal;
-       if (viafb_accel && !viafb_init_engine(viafbinfo)) {
+       if (viafb_accel && !viafb_setup_engine(viafbinfo)) {
                viafbinfo->flags |= FBINFO_HWACCEL_COPYAREA |
                        FBINFO_HWACCEL_FILLRECT |  FBINFO_HWACCEL_IMAGEBLIT;
                default_var.accel_flags = FB_ACCELF_TEXT;