diff options
Diffstat (limited to 'drivers/video/via/viafbdev.c')
-rw-r--r-- | drivers/video/via/viafbdev.c | 294 |
1 files changed, 258 insertions, 36 deletions
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index bdd0e4130f4e..d298cfccd6fc 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -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) | @@ -961,7 +988,7 @@ static void retrieve_device_setting(struct viafb_ioctl_setting setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode; } -static int parse_active_dev(void) +static int __init parse_active_dev(void) { viafb_CRT_ON = STATE_OFF; viafb_DVI_ON = STATE_OFF; @@ -1031,7 +1058,7 @@ static int parse_active_dev(void) return 0; } -static int parse_port(char *opt_str, int *output_interface) +static int __devinit parse_port(char *opt_str, int *output_interface) { if (!strncmp(opt_str, "DVP0", 4)) *output_interface = INTERFACE_DVP0; @@ -1048,7 +1075,7 @@ static int parse_port(char *opt_str, int *output_interface) return 0; } -static void parse_lcd_port(void) +static void __devinit parse_lcd_port(void) { parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info. output_interface); @@ -1061,7 +1088,7 @@ static void parse_lcd_port(void) output_interface); } -static void parse_dvi_port(void) +static void __devinit parse_dvi_port(void) { parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info. output_interface); @@ -1431,38 +1458,196 @@ static const struct file_operations viafb_vt1636_proc_fops = { .write = viafb_vt1636_proc_write, }; -static void viafb_init_proc(struct proc_dir_entry **viafb_entry) +#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ + +static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) { - *viafb_entry = proc_mkdir("viafb", NULL); - if (*viafb_entry) { - proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); - proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); - proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); - proc_create("dfpl", 0, *viafb_entry, &viafb_dfpl_proc_fops); - if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info. - lvds_chip_name || VT1636_LVDS == - viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) { - proc_create("vt1636", 0, *viafb_entry, &viafb_vt1636_proc_fops); - } + 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; + u32 devices; + bool add, sub; + + if (count < 1 || count > 63) + return -EINVAL; + if (copy_from_user(&buf[0], buffer, count)) + return -EFAULT; + buf[count] = '\0'; + add = buf[0] == '+'; + sub = buf[0] == '-'; + if (add || sub) + ptr++; + devices = via_parse_odev(ptr, &ptr); + if (*ptr == '\n') + ptr++; + if (*ptr != 0) + return -EINVAL; + if (add) + *odev |= devices; + else if (sub) + *odev &= ~devices; + else + *odev = devices; + return count; +} + +static int viafb_iga1_odev_proc_show(struct seq_file *m, void *v) +{ + via_odev_to_seq(m, viaparinfo->shared->iga1_devices); + return 0; +} + +static int viafb_iga1_odev_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, viafb_iga1_odev_proc_show, NULL); +} + +static ssize_t viafb_iga1_odev_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) +{ + u32 dev_on, dev_off, dev_old, dev_new; + ssize_t res; + + dev_old = dev_new = viaparinfo->shared->iga1_devices; + res = odev_update(buffer, count, &dev_new); + if (res != count) + return res; + dev_off = dev_old & ~dev_new; + 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; +} + +static const struct file_operations viafb_iga1_odev_proc_fops = { + .owner = THIS_MODULE, + .open = viafb_iga1_odev_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = viafb_iga1_odev_proc_write, +}; + +static int viafb_iga2_odev_proc_show(struct seq_file *m, void *v) +{ + via_odev_to_seq(m, viaparinfo->shared->iga2_devices); + return 0; +} +static int viafb_iga2_odev_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, viafb_iga2_odev_proc_show, NULL); +} + +static ssize_t viafb_iga2_odev_proc_write(struct file *file, + const char __user *buffer, size_t count, loff_t *pos) +{ + u32 dev_on, dev_off, dev_old, dev_new; + ssize_t res; + + dev_old = dev_new = viaparinfo->shared->iga2_devices; + res = odev_update(buffer, count, &dev_new); + if (res != count) + return res; + dev_off = dev_old & ~dev_new; + 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; +} + +static const struct file_operations viafb_iga2_odev_proc_fops = { + .owner = THIS_MODULE, + .open = viafb_iga2_odev_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = viafb_iga2_odev_proc_write, +}; + +#define IS_VT1636(lvds_chip) ((lvds_chip).lvds_chip_name == VT1636_LVDS) +static void viafb_init_proc(struct viafb_shared *shared) +{ + struct proc_dir_entry *iga1_entry, *iga2_entry, + *viafb_entry = proc_mkdir("viafb", NULL); + + shared->proc_entry = viafb_entry; + if (viafb_entry) { +#ifdef CONFIG_FB_VIA_DIRECT_PROCFS + proc_create("dvp0", 0, viafb_entry, &viafb_dvp0_proc_fops); + proc_create("dvp1", 0, viafb_entry, &viafb_dvp1_proc_fops); + proc_create("dfph", 0, viafb_entry, &viafb_dfph_proc_fops); + proc_create("dfpl", 0, viafb_entry, &viafb_dfpl_proc_fops); + if (IS_VT1636(shared->chip_info.lvds_chip_info) + || IS_VT1636(shared->chip_info.lvds_chip_info2)) + proc_create("vt1636", 0, viafb_entry, + &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, + &viafb_iga1_odev_proc_fops); + iga2_entry = proc_mkdir("iga2", viafb_entry); + shared->iga2_proc_entry = iga2_entry; + proc_create("output_devices", 0, iga2_entry, + &viafb_iga2_odev_proc_fops); } } -static void viafb_remove_proc(struct proc_dir_entry *viafb_entry) +static void viafb_remove_proc(struct viafb_shared *shared) { - struct chip_information *chip_info = &viaparinfo->shared->chip_info; + struct proc_dir_entry *viafb_entry = shared->proc_entry, + *iga1_entry = shared->iga1_proc_entry, + *iga2_entry = shared->iga2_proc_entry; + if (!viafb_entry) + return; + + remove_proc_entry("output_devices", iga2_entry); + 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 */ remove_proc_entry("dvp1", viafb_entry); remove_proc_entry("dfph", viafb_entry); remove_proc_entry("dfpl", viafb_entry); - if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS - || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS) + if (IS_VT1636(shared->chip_info.lvds_chip_info) + || IS_VT1636(shared->chip_info.lvds_chip_info2)) remove_proc_entry("vt1636", viafb_entry); +#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ remove_proc_entry("viafb", NULL); } - -#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ +#undef IS_VT1636 static int parse_mode(const char *str, u32 *xres, u32 *yres) { @@ -1486,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; @@ -1544,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; @@ -1671,9 +1897,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) viafbinfo->node, viafbinfo->fix.id, default_var.xres, default_var.yres, default_var.bits_per_pixel); -#ifdef CONFIG_FB_VIA_DIRECT_PROCFS - viafb_init_proc(&viaparinfo->shared->proc_entry); -#endif + viafb_init_proc(viaparinfo->shared); viafb_init_dac(IGA2); return 0; @@ -1700,9 +1924,7 @@ void __devexit via_fb_pci_remove(struct pci_dev *pdev) unregister_framebuffer(viafbinfo); if (viafb_dual_fb) unregister_framebuffer(viafbinfo1); -#ifdef CONFIG_FB_VIA_DIRECT_PROCFS - viafb_remove_proc(viaparinfo->shared->proc_entry); -#endif + viafb_remove_proc(viaparinfo->shared); framebuffer_release(viafbinfo); if (viafb_dual_fb) framebuffer_release(viafbinfo1); |