diff options
Diffstat (limited to 'drivers/video/aty/atyfb_base.c')
-rw-r--r-- | drivers/video/aty/atyfb_base.c | 141 |
1 files changed, 120 insertions, 21 deletions
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 1207c208a30b..63d3739d43a8 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -66,6 +66,8 @@ | |||
66 | #include <linux/spinlock.h> | 66 | #include <linux/spinlock.h> |
67 | #include <linux/wait.h> | 67 | #include <linux/wait.h> |
68 | #include <linux/backlight.h> | 68 | #include <linux/backlight.h> |
69 | #include <linux/reboot.h> | ||
70 | #include <linux/dmi.h> | ||
69 | 71 | ||
70 | #include <asm/io.h> | 72 | #include <asm/io.h> |
71 | #include <linux/uaccess.h> | 73 | #include <linux/uaccess.h> |
@@ -249,8 +251,6 @@ static int aty_init(struct fb_info *info); | |||
249 | static int store_video_par(char *videopar, unsigned char m64_num); | 251 | static int store_video_par(char *videopar, unsigned char m64_num); |
250 | #endif | 252 | #endif |
251 | 253 | ||
252 | static struct crtc saved_crtc; | ||
253 | static union aty_pll saved_pll; | ||
254 | static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); | 254 | static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); |
255 | 255 | ||
256 | static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); | 256 | static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc); |
@@ -261,6 +261,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info); | |||
261 | static int read_aty_sense(const struct atyfb_par *par); | 261 | static int read_aty_sense(const struct atyfb_par *par); |
262 | #endif | 262 | #endif |
263 | 263 | ||
264 | static DEFINE_MUTEX(reboot_lock); | ||
265 | static struct fb_info *reboot_info; | ||
264 | 266 | ||
265 | /* | 267 | /* |
266 | * Interface used by the world | 268 | * Interface used by the world |
@@ -361,8 +363,8 @@ static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, }; | |||
361 | #define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) | 363 | #define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) |
362 | #define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) | 364 | #define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) |
363 | 365 | ||
364 | #define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4) | 366 | #define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM) |
365 | #define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS) | 367 | #define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS) |
366 | 368 | ||
367 | static struct { | 369 | static struct { |
368 | u16 pci_id; | 370 | u16 pci_id; |
@@ -539,6 +541,7 @@ static char ram_edo[] __devinitdata = "EDO"; | |||
539 | static char ram_sdram[] __devinitdata = "SDRAM (1:1)"; | 541 | static char ram_sdram[] __devinitdata = "SDRAM (1:1)"; |
540 | static char ram_sgram[] __devinitdata = "SGRAM (1:1)"; | 542 | static char ram_sgram[] __devinitdata = "SGRAM (1:1)"; |
541 | static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)"; | 543 | static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)"; |
544 | static char ram_wram[] __devinitdata = "WRAM"; | ||
542 | static char ram_off[] __devinitdata = "OFF"; | 545 | static char ram_off[] __devinitdata = "OFF"; |
543 | #endif /* CONFIG_FB_ATY_CT */ | 546 | #endif /* CONFIG_FB_ATY_CT */ |
544 | 547 | ||
@@ -553,6 +556,10 @@ static char *aty_gx_ram[8] __devinitdata = { | |||
553 | #ifdef CONFIG_FB_ATY_CT | 556 | #ifdef CONFIG_FB_ATY_CT |
554 | static char *aty_ct_ram[8] __devinitdata = { | 557 | static char *aty_ct_ram[8] __devinitdata = { |
555 | ram_off, ram_dram, ram_edo, ram_edo, | 558 | ram_off, ram_dram, ram_edo, ram_edo, |
559 | ram_sdram, ram_sgram, ram_wram, ram_resv | ||
560 | }; | ||
561 | static char *aty_xl_ram[8] __devinitdata = { | ||
562 | ram_off, ram_dram, ram_edo, ram_edo, | ||
556 | ram_sdram, ram_sgram, ram_sdram32, ram_resv | 563 | ram_sdram, ram_sgram, ram_sdram32, ram_resv |
557 | }; | 564 | }; |
558 | #endif /* CONFIG_FB_ATY_CT */ | 565 | #endif /* CONFIG_FB_ATY_CT */ |
@@ -760,6 +767,17 @@ static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc) | |||
760 | #endif /* CONFIG_FB_ATY_GENERIC_LCD */ | 767 | #endif /* CONFIG_FB_ATY_GENERIC_LCD */ |
761 | } | 768 | } |
762 | 769 | ||
770 | static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp) | ||
771 | { | ||
772 | u32 line_length = vxres * bpp / 8; | ||
773 | |||
774 | if (par->ram_type == SGRAM || | ||
775 | (!M64_HAS(XL_MEM) && par->ram_type == WRAM)) | ||
776 | line_length = (line_length + 63) & ~63; | ||
777 | |||
778 | return line_length; | ||
779 | } | ||
780 | |||
763 | static int aty_var_to_crtc(const struct fb_info *info, | 781 | static int aty_var_to_crtc(const struct fb_info *info, |
764 | const struct fb_var_screeninfo *var, struct crtc *crtc) | 782 | const struct fb_var_screeninfo *var, struct crtc *crtc) |
765 | { | 783 | { |
@@ -769,13 +787,14 @@ static int aty_var_to_crtc(const struct fb_info *info, | |||
769 | u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol; | 787 | u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol; |
770 | u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync; | 788 | u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync; |
771 | u32 pix_width, dp_pix_width, dp_chain_mask; | 789 | u32 pix_width, dp_pix_width, dp_chain_mask; |
790 | u32 line_length; | ||
772 | 791 | ||
773 | /* input */ | 792 | /* input */ |
774 | xres = var->xres; | 793 | xres = (var->xres + 7) & ~7; |
775 | yres = var->yres; | 794 | yres = var->yres; |
776 | vxres = var->xres_virtual; | 795 | vxres = (var->xres_virtual + 7) & ~7; |
777 | vyres = var->yres_virtual; | 796 | vyres = var->yres_virtual; |
778 | xoffset = var->xoffset; | 797 | xoffset = (var->xoffset + 7) & ~7; |
779 | yoffset = var->yoffset; | 798 | yoffset = var->yoffset; |
780 | bpp = var->bits_per_pixel; | 799 | bpp = var->bits_per_pixel; |
781 | if (bpp == 16) | 800 | if (bpp == 16) |
@@ -827,7 +846,9 @@ static int aty_var_to_crtc(const struct fb_info *info, | |||
827 | } else | 846 | } else |
828 | FAIL("invalid bpp"); | 847 | FAIL("invalid bpp"); |
829 | 848 | ||
830 | if (vxres * vyres * bpp / 8 > info->fix.smem_len) | 849 | line_length = calc_line_length(par, vxres, bpp); |
850 | |||
851 | if (vyres * line_length > info->fix.smem_len) | ||
831 | FAIL("not enough video RAM"); | 852 | FAIL("not enough video RAM"); |
832 | 853 | ||
833 | h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; | 854 | h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; |
@@ -969,7 +990,9 @@ static int aty_var_to_crtc(const struct fb_info *info, | |||
969 | crtc->xoffset = xoffset; | 990 | crtc->xoffset = xoffset; |
970 | crtc->yoffset = yoffset; | 991 | crtc->yoffset = yoffset; |
971 | crtc->bpp = bpp; | 992 | crtc->bpp = bpp; |
972 | crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); | 993 | crtc->off_pitch = |
994 | ((yoffset * line_length + xoffset * bpp / 8) / 8) | | ||
995 | ((line_length / bpp) << 22); | ||
973 | crtc->vline_crnt_vline = 0; | 996 | crtc->vline_crnt_vline = 0; |
974 | 997 | ||
975 | crtc->h_tot_disp = h_total | (h_disp<<16); | 998 | crtc->h_tot_disp = h_total | (h_disp<<16); |
@@ -1394,7 +1417,9 @@ static int atyfb_set_par(struct fb_info *info) | |||
1394 | } | 1417 | } |
1395 | aty_st_8(DAC_MASK, 0xff, par); | 1418 | aty_st_8(DAC_MASK, 0xff, par); |
1396 | 1419 | ||
1397 | info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8; | 1420 | info->fix.line_length = calc_line_length(par, var->xres_virtual, |
1421 | var->bits_per_pixel); | ||
1422 | |||
1398 | info->fix.visual = var->bits_per_pixel <= 8 ? | 1423 | info->fix.visual = var->bits_per_pixel <= 8 ? |
1399 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; | 1424 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; |
1400 | 1425 | ||
@@ -1505,10 +1530,12 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info) | |||
1505 | { | 1530 | { |
1506 | u32 xoffset = info->var.xoffset; | 1531 | u32 xoffset = info->var.xoffset; |
1507 | u32 yoffset = info->var.yoffset; | 1532 | u32 yoffset = info->var.yoffset; |
1508 | u32 vxres = par->crtc.vxres; | 1533 | u32 line_length = info->fix.line_length; |
1509 | u32 bpp = info->var.bits_per_pixel; | 1534 | u32 bpp = info->var.bits_per_pixel; |
1510 | 1535 | ||
1511 | par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19); | 1536 | par->crtc.off_pitch = |
1537 | ((yoffset * line_length + xoffset * bpp / 8) / 8) | | ||
1538 | ((line_length / bpp) << 22); | ||
1512 | } | 1539 | } |
1513 | 1540 | ||
1514 | 1541 | ||
@@ -2201,7 +2228,7 @@ static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk) | |||
2201 | const int *refresh_tbl; | 2228 | const int *refresh_tbl; |
2202 | int i, size; | 2229 | int i, size; |
2203 | 2230 | ||
2204 | if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) { | 2231 | if (M64_HAS(XL_MEM)) { |
2205 | refresh_tbl = ragexl_tbl; | 2232 | refresh_tbl = ragexl_tbl; |
2206 | size = ARRAY_SIZE(ragexl_tbl); | 2233 | size = ARRAY_SIZE(ragexl_tbl); |
2207 | } else { | 2234 | } else { |
@@ -2335,7 +2362,10 @@ static int __devinit aty_init(struct fb_info *info) | |||
2335 | par->pll_ops = &aty_pll_ct; | 2362 | par->pll_ops = &aty_pll_ct; |
2336 | par->bus_type = PCI; | 2363 | par->bus_type = PCI; |
2337 | par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07); | 2364 | par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07); |
2338 | ramname = aty_ct_ram[par->ram_type]; | 2365 | if (M64_HAS(XL_MEM)) |
2366 | ramname = aty_xl_ram[par->ram_type]; | ||
2367 | else | ||
2368 | ramname = aty_ct_ram[par->ram_type]; | ||
2339 | /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ | 2369 | /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ |
2340 | if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM) | 2370 | if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM) |
2341 | par->pll_limits.mclk = 63; | 2371 | par->pll_limits.mclk = 63; |
@@ -2390,9 +2420,9 @@ static int __devinit aty_init(struct fb_info *info) | |||
2390 | #endif /* CONFIG_FB_ATY_CT */ | 2420 | #endif /* CONFIG_FB_ATY_CT */ |
2391 | 2421 | ||
2392 | /* save previous video mode */ | 2422 | /* save previous video mode */ |
2393 | aty_get_crtc(par, &saved_crtc); | 2423 | aty_get_crtc(par, &par->saved_crtc); |
2394 | if(par->pll_ops->get_pll) | 2424 | if(par->pll_ops->get_pll) |
2395 | par->pll_ops->get_pll(info, &saved_pll); | 2425 | par->pll_ops->get_pll(info, &par->saved_pll); |
2396 | 2426 | ||
2397 | par->mem_cntl = aty_ld_le32(MEM_CNTL, par); | 2427 | par->mem_cntl = aty_ld_le32(MEM_CNTL, par); |
2398 | gtb_memsize = M64_HAS(GTB_DSP); | 2428 | gtb_memsize = M64_HAS(GTB_DSP); |
@@ -2667,8 +2697,8 @@ static int __devinit aty_init(struct fb_info *info) | |||
2667 | 2697 | ||
2668 | aty_init_exit: | 2698 | aty_init_exit: |
2669 | /* restore video mode */ | 2699 | /* restore video mode */ |
2670 | aty_set_crtc(par, &saved_crtc); | 2700 | aty_set_crtc(par, &par->saved_crtc); |
2671 | par->pll_ops->set_pll(info, &saved_pll); | 2701 | par->pll_ops->set_pll(info, &par->saved_pll); |
2672 | 2702 | ||
2673 | #ifdef CONFIG_MTRR | 2703 | #ifdef CONFIG_MTRR |
2674 | if (par->mtrr_reg >= 0) { | 2704 | if (par->mtrr_reg >= 0) { |
@@ -3502,6 +3532,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi | |||
3502 | par->mmap_map[1].prot_flag = _PAGE_E; | 3532 | par->mmap_map[1].prot_flag = _PAGE_E; |
3503 | #endif /* __sparc__ */ | 3533 | #endif /* __sparc__ */ |
3504 | 3534 | ||
3535 | mutex_lock(&reboot_lock); | ||
3536 | if (!reboot_info) | ||
3537 | reboot_info = info; | ||
3538 | mutex_unlock(&reboot_lock); | ||
3539 | |||
3505 | return 0; | 3540 | return 0; |
3506 | 3541 | ||
3507 | err_release_io: | 3542 | err_release_io: |
@@ -3614,8 +3649,8 @@ static void __devexit atyfb_remove(struct fb_info *info) | |||
3614 | struct atyfb_par *par = (struct atyfb_par *) info->par; | 3649 | struct atyfb_par *par = (struct atyfb_par *) info->par; |
3615 | 3650 | ||
3616 | /* restore video mode */ | 3651 | /* restore video mode */ |
3617 | aty_set_crtc(par, &saved_crtc); | 3652 | aty_set_crtc(par, &par->saved_crtc); |
3618 | par->pll_ops->set_pll(info, &saved_pll); | 3653 | par->pll_ops->set_pll(info, &par->saved_pll); |
3619 | 3654 | ||
3620 | unregister_framebuffer(info); | 3655 | unregister_framebuffer(info); |
3621 | 3656 | ||
@@ -3661,6 +3696,11 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev) | |||
3661 | { | 3696 | { |
3662 | struct fb_info *info = pci_get_drvdata(pdev); | 3697 | struct fb_info *info = pci_get_drvdata(pdev); |
3663 | 3698 | ||
3699 | mutex_lock(&reboot_lock); | ||
3700 | if (reboot_info == info) | ||
3701 | reboot_info = NULL; | ||
3702 | mutex_unlock(&reboot_lock); | ||
3703 | |||
3664 | atyfb_remove(info); | 3704 | atyfb_remove(info); |
3665 | } | 3705 | } |
3666 | 3706 | ||
@@ -3808,6 +3848,56 @@ static int __init atyfb_setup(char *options) | |||
3808 | } | 3848 | } |
3809 | #endif /* MODULE */ | 3849 | #endif /* MODULE */ |
3810 | 3850 | ||
3851 | static int atyfb_reboot_notify(struct notifier_block *nb, | ||
3852 | unsigned long code, void *unused) | ||
3853 | { | ||
3854 | struct atyfb_par *par; | ||
3855 | |||
3856 | if (code != SYS_RESTART) | ||
3857 | return NOTIFY_DONE; | ||
3858 | |||
3859 | mutex_lock(&reboot_lock); | ||
3860 | |||
3861 | if (!reboot_info) | ||
3862 | goto out; | ||
3863 | |||
3864 | if (!lock_fb_info(reboot_info)) | ||
3865 | goto out; | ||
3866 | |||
3867 | par = reboot_info->par; | ||
3868 | |||
3869 | /* | ||
3870 | * HP OmniBook 500's BIOS doesn't like the state of the | ||
3871 | * hardware after atyfb has been used. Restore the hardware | ||
3872 | * to the original state to allow successful reboots. | ||
3873 | */ | ||
3874 | aty_set_crtc(par, &par->saved_crtc); | ||
3875 | par->pll_ops->set_pll(reboot_info, &par->saved_pll); | ||
3876 | |||
3877 | unlock_fb_info(reboot_info); | ||
3878 | out: | ||
3879 | mutex_unlock(&reboot_lock); | ||
3880 | |||
3881 | return NOTIFY_DONE; | ||
3882 | } | ||
3883 | |||
3884 | static struct notifier_block atyfb_reboot_notifier = { | ||
3885 | .notifier_call = atyfb_reboot_notify, | ||
3886 | }; | ||
3887 | |||
3888 | static const struct dmi_system_id atyfb_reboot_ids[] = { | ||
3889 | { | ||
3890 | .ident = "HP OmniBook 500", | ||
3891 | .matches = { | ||
3892 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
3893 | DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"), | ||
3894 | DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"), | ||
3895 | }, | ||
3896 | }, | ||
3897 | |||
3898 | { } | ||
3899 | }; | ||
3900 | |||
3811 | static int __init atyfb_init(void) | 3901 | static int __init atyfb_init(void) |
3812 | { | 3902 | { |
3813 | int err1 = 1, err2 = 1; | 3903 | int err1 = 1, err2 = 1; |
@@ -3826,11 +3916,20 @@ static int __init atyfb_init(void) | |||
3826 | err2 = atyfb_atari_probe(); | 3916 | err2 = atyfb_atari_probe(); |
3827 | #endif | 3917 | #endif |
3828 | 3918 | ||
3829 | return (err1 && err2) ? -ENODEV : 0; | 3919 | if (err1 && err2) |
3920 | return -ENODEV; | ||
3921 | |||
3922 | if (dmi_check_system(atyfb_reboot_ids)) | ||
3923 | register_reboot_notifier(&atyfb_reboot_notifier); | ||
3924 | |||
3925 | return 0; | ||
3830 | } | 3926 | } |
3831 | 3927 | ||
3832 | static void __exit atyfb_exit(void) | 3928 | static void __exit atyfb_exit(void) |
3833 | { | 3929 | { |
3930 | if (dmi_check_system(atyfb_reboot_ids)) | ||
3931 | unregister_reboot_notifier(&atyfb_reboot_notifier); | ||
3932 | |||
3834 | #ifdef CONFIG_PCI | 3933 | #ifdef CONFIG_PCI |
3835 | pci_unregister_driver(&atyfb_driver); | 3934 | pci_unregister_driver(&atyfb_driver); |
3836 | #endif | 3935 | #endif |