## Automatically generated incremental diff ## From: linux-2.4.22-bk11 ## To: linux-2.4.22-bk12 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.4.22-bk11/Documentation/Configure.help linux-2.4.22-bk12/Documentation/Configure.help --- linux-2.4.22-bk11/Documentation/Configure.help 2003-09-06 02:59:46.000000000 -0700 +++ linux-2.4.22-bk12/Documentation/Configure.help 2003-09-06 03:00:13.000000000 -0700 @@ -5486,6 +5486,17 @@ is at . +Mach64 Generic LCD support +CONFIG_FB_ATY_GENERIC_LCD + Enabling this option enables the Atyfb driver to drive LCD panels. It + will autodetect the resulution and format of your display and emulate + other resolutions using the hardware stretcher on the chip. + Say Y here if you have computer with a Rage LT Pro, Rage Mobility M1, + Rage XC or Rage XL chip and a laptop LCD display or any other LCD display + that needs to be digitally driven. It is not necessary to enable this + option if you are using an LCD display with a normal VGA connector, + but it won't hurt if you do. + ATI Radeon display support CONFIG_FB_RADEON Choose this option if you want to use an ATI Radeon graphics card as diff -urN linux-2.4.22-bk11/Makefile linux-2.4.22-bk12/Makefile --- linux-2.4.22-bk11/Makefile 2003-09-06 02:59:47.000000000 -0700 +++ linux-2.4.22-bk12/Makefile 2003-09-06 03:00:13.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 22 -EXTRAVERSION = -bk11 +EXTRAVERSION = -bk12 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -urN linux-2.4.22-bk11/drivers/atm/he.c linux-2.4.22-bk12/drivers/atm/he.c --- linux-2.4.22-bk11/drivers/atm/he.c 2003-09-06 02:59:49.000000000 -0700 +++ linux-2.4.22-bk12/drivers/atm/he.c 2003-09-06 03:00:18.000000000 -0700 @@ -109,10 +109,6 @@ #define pci_get_drvdata(pci_dev) (pci_dev)->driver_data #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44) -#define pci_pool_create(a, b, c, d, e) pci_pool_create(a, b, c, d, e, SLAB_KERNEL) -#endif - #include "he.h" #include "suni.h" @@ -785,7 +781,7 @@ /* small buffer pool */ #ifdef USE_RBPS_POOL he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev, - CONFIG_RBPS_BUFSIZE, 8, 0); + CONFIG_RBPS_BUFSIZE, 8, 0, SLAB_KERNEL); if (he_dev->rbps_pool == NULL) { hprintk("unable to create rbps pages\n"); return -ENOMEM; @@ -849,7 +845,7 @@ /* large buffer pool */ #ifdef USE_RBPL_POOL he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, - CONFIG_RBPL_BUFSIZE, 8, 0); + CONFIG_RBPL_BUFSIZE, 8, 0, SLAB_KERNEL); if (he_dev->rbpl_pool == NULL) { hprintk("unable to create rbpl pool\n"); return -ENOMEM; @@ -1475,7 +1471,7 @@ #ifdef USE_TPD_POOL he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev, - sizeof(struct he_tpd), TPD_ALIGNMENT, 0); + sizeof(struct he_tpd), TPD_ALIGNMENT, 0, SLAB_KERNEL); if (he_dev->tpd_pool == NULL) { hprintk("unable to create tpd pci_pool\n"); return -ENOMEM; diff -urN linux-2.4.22-bk11/drivers/video/Config.in linux-2.4.22-bk12/drivers/video/Config.in --- linux-2.4.22-bk11/drivers/video/Config.in 2003-09-06 02:59:59.000000000 -0700 +++ linux-2.4.22-bk12/drivers/video/Config.in 2003-09-06 03:00:27.000000000 -0700 @@ -147,6 +147,9 @@ if [ "$CONFIG_FB_ATY" != "n" ]; then bool ' Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX bool ' Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT + if [ "$ARCH" = "i386" -a "$CONFIG_FB_ATY_CT" != "n" ]; then + bool ' Mach64 generic LCD monitor support (EXPERIMENTAL)' CONFIG_FB_ATY_GENERIC_LCD + fi fi tristate ' ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON tristate ' ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128 diff -urN linux-2.4.22-bk11/drivers/video/aty/atyfb.h linux-2.4.22-bk12/drivers/video/aty/atyfb.h --- linux-2.4.22-bk11/drivers/video/aty/atyfb.h 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.22-bk12/drivers/video/aty/atyfb.h 2003-09-06 03:00:27.000000000 -0700 @@ -4,7 +4,8 @@ */ #include - +#include +#include /* * Elements of the hardware specific atyfb_par structure @@ -15,7 +16,6 @@ u32 vyres; u32 xoffset; u32 yoffset; - u32 bpp; u32 h_tot_disp; u32 h_sync_strt_wid; u32 v_tot_disp; @@ -24,6 +24,17 @@ u32 gen_cntl; u32 dp_pix_width; /* acceleration */ u32 dp_chain_mask; /* acceleration */ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 monitors_enabled; /* LCD monitor support */ + u16 h_stretching; /* LCD monitor support */ + u16 v_stretching; /* LCD monitor support */ +#endif + u8 bpp; + u8 h_blank_start; + u8 h_blank_end; + u16 v_blank_start; + u8 v_blank_end; + u8 genmo; }; struct pll_514 { @@ -40,16 +51,17 @@ }; struct pll_ct { - u8 pll_ref_div; - u8 pll_gen_cntl; - u8 mclk_fb_div; +// u8 pll_ref_div; +// u8 pll_gen_cntl; +// u8 mclk_fb_div; u8 pll_vclk_cntl; u8 vclk_post_div; u8 vclk_fb_div; - u8 pll_ext_cntl; +// u8 alt_post_div; +// u8 pll_ext_cntl; u32 dsp_config; /* Mach64 GTB DSP */ u32 dsp_on_off; /* Mach64 GTB DSP */ - u8 mclk_post_div_real; +// u8 mclk_post_div_real; u8 vclk_post_div_real; }; @@ -89,11 +101,42 @@ struct fb_info_aty { struct fb_info fb_info; struct fb_info_aty *next; + u32* ati_regaddr[256]; unsigned long ati_regbase_phys; unsigned long ati_regbase; unsigned long frame_buffer_phys; unsigned long frame_buffer; unsigned long clk_wr_offset; +#ifdef CONFIG_FB_ATY_CT + u8 pll_ref_div; + u8 xclk_post_div_real; + u16 mclk_fb_div; + u8 fifo_size; + u8 dsp_loop_latency; +// u8 page_size; + u8 xclkpagefaultdelay,xclkmaxrasdelay; +#endif +#ifdef CONFIG_FB_ATY_GENERIC_LCD + unsigned long bios_base_phys; + unsigned long bios_base; + unsigned long lcd_table; + u16 lcd_width; + u16 lcd_height; + u32 lcd_pixclock; + u16 lcd_htotal; + u16 lcd_hdisp; + u16 lcd_hsync_start; + u16 lcd_hsync_delay; + u16 lcd_hsync_width; + u16 lcd_vtotal; + u16 lcd_vdisp; + u16 lcd_vsync_start; + u16 lcd_vsync_width; + u16 lcd_right; + u16 lcd_lower; + u16 lcd_hblank_width; + u16 lcd_vblank_width; +#endif struct pci_mmap_map *mmap_map; struct aty_cursor *cursor; struct aty_cmap_regs *aty_cmap_regs; @@ -105,6 +148,7 @@ u32 ref_clk_per; u32 pll_per; u32 mclk_per; + u32 xclk_per; u8 bus_type; u8 ram_type; u8 mem_refresh_rate; @@ -124,6 +168,7 @@ #endif } fbcon_cmap; u8 blitter_may_be_busy; + u8 font_loaded; #ifdef __sparc__ u8 mmaped; int open; @@ -164,6 +209,12 @@ #define M64F_LT_SLEEP 0x00040000 #define M64F_XL_DLL 0x00080000 +#ifdef __i386__ +# define stdcall __attribute__ ((stdcall)) +#else +# define stdcall +#endif +#define packed __attribute__ ((packed)) /* * Register access @@ -172,70 +223,72 @@ static inline u32 aty_ld_le32(int regindex, const struct fb_info_aty *info) { - /* Hack for bloc 1, should be cleanly optimized by compiler */ - if (regindex >= 0x400) - regindex -= 0x800; + if (regindex >= 0x400) { + regindex -= 0x800; +#if defined(__mc68000__) + return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex))); +#else + return readl (info->ati_regbase + regindex); +#endif + } else { +#if defined(__mc68000__) + return le32_to_cpu(*((volatile u32 *)(info->ati_regaddr[regindex/4]))); +#else + return readl (info->ati_regaddr[regindex/4]); +#endif + }; +} -#ifdef CONFIG_ATARI - return in_le32((volatile u32 *)(info->ati_regbase+regindex)); +static inline void aty_st_le32_sr(int regindex, u32 val, + const struct fb_info_aty *info) +{ +#if defined(__mc68000__) + *((volatile u32 *)(info->ati_regaddr[regindex/4])) = cpu_to_le32(val); #else - return readl (info->ati_regbase + regindex); + writel (val,info->ati_regaddr[regindex/4]); #endif } static inline void aty_st_le32(int regindex, u32 val, const struct fb_info_aty *info) { - /* Hack for bloc 1, should be cleanly optimized by compiler */ - if (regindex >= 0x400) - regindex -= 0x800; - -#ifdef CONFIG_ATARI - out_le32 (info->ati_regbase+regindex, val); + if (regindex >= 0x400) { + regindex -= 0x800; +#if defined(__mc68000__) + *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val); +#else + writel (val,info->ati_regbase + regindex); +#endif + } else { +#if defined(__mc68000__) + *((volatile u32 *)(info->ati_regaddr[regindex/4])) = cpu_to_le32(val); #else - writel (val, info->ati_regbase + regindex); + writel (val,info->ati_regaddr[regindex/4]); #endif + }; } static inline u8 aty_ld_8(int regindex, const struct fb_info_aty *info) { - /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >= 0x400) - regindex -= 0x800; - -#ifdef CONFIG_ATARI - return in_8 (info->ati_regbase + regindex); -#else + regindex -= 0x800; return readb (info->ati_regbase + regindex); -#endif } static inline void aty_st_8(int regindex, u8 val, const struct fb_info_aty *info) { - /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >= 0x400) - regindex -= 0x800; - -#ifdef CONFIG_ATARI - out_8 (info->ati_regbase + regindex, val); -#else - writeb (val, info->ati_regbase + regindex); -#endif + regindex -= 0x800; + writeb (val,info->ati_regbase + regindex); } -static inline u8 aty_ld_pll(int offset, const struct fb_info_aty *info) -{ - u8 res; - - /* write addr byte */ - aty_st_8(CLOCK_CNTL + 1, (offset << 2), info); - /* read the register value */ - res = aty_ld_8(CLOCK_CNTL + 2, info); - return res; -} + /* + * Mach64 CT PLL operations + */ +extern u8 aty_ld_pll(int offset, const struct fb_info_aty *info) stdcall; /* * DAC operations @@ -259,10 +312,11 @@ struct aty_pll_ops { int (*var_to_pll)(const struct fb_info_aty *info, u32 vclk_per, u8 bpp, - union aty_pll *pll); + u32 xres, union aty_pll *pll); u32 (*pll_to_var)(const struct fb_info_aty *info, const union aty_pll *pll); void (*set_pll)(const struct fb_info_aty *info, const union aty_pll *pll); + void (*init_pll)(struct fb_info_aty *info); }; extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */ @@ -276,8 +330,8 @@ extern void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll); -extern void aty_calc_pll_ct(const struct fb_info_aty *info, - struct pll_ct *pll); +//extern void aty_calc_pll_ct(const struct fb_info_aty *info, +// struct pll_ct *pll); /* @@ -297,7 +351,7 @@ static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info) { - while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) > + while (__builtin_expect((aty_ld_le32(FIFO_STAT, info) & 0xffff), 0) > ((u32)(0x8000 >> entries))); } @@ -305,20 +359,21 @@ { wait_for_fifo(16, info); while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0); - info->blitter_may_be_busy = 0; + info->blitter_may_be_busy = 0; } extern void aty_reset_engine(const struct fb_info_aty *info); extern void aty_init_engine(const struct atyfb_par *par, struct fb_info_aty *info); extern void aty_rectfill(int dstx, int dsty, u_int width, u_int height, - u_int color, struct fb_info_aty *info); + u_int color, struct fb_info_aty *info); /* * Text console acceleration */ +extern const struct display_switch fbcon_aty0; extern const struct display_switch fbcon_aty8; extern const struct display_switch fbcon_aty16; extern const struct display_switch fbcon_aty24; diff -urN linux-2.4.22-bk11/drivers/video/aty/atyfb_base.c linux-2.4.22-bk12/drivers/video/aty/atyfb_base.c --- linux-2.4.22-bk11/drivers/video/aty/atyfb_base.c 2002-11-28 15:53:15.000000000 -0800 +++ linux-2.4.22-bk12/drivers/video/aty/atyfb_base.c 2003-09-06 03:00:27.000000000 -0700 @@ -1,10 +1,9 @@ - /* * ATI Frame Buffer Device Driver Core * - * Copyright (C) 1997-2001 Geert Uytterhoeven - * Copyright (C) 1998 Bernd Harries - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997-2001 Geert Uytterhoeven + * Copyright (C) 1998 Bernd Harries + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * * This driver supports the following ATI graphics chips: * - ATI Mach64 @@ -15,15 +14,17 @@ * * This driver is partly based on the PowerMac console driver: * - * Copyright (C) 1996 Paul Mackerras + * Copyright (C) 1996 Paul Mackerras * * and on the PowerMac ATI/mach64 display driver: * - * Copyright (C) 1997 Michael AK Tesch + * Copyright (C) 1997 Michael AK Tesch + * + * with work by Jon Howell + * Harry AC Eaton + * Anthony Tong * - * with work by Jon Howell - * Harry AC Eaton - * Anthony Tong + * Generic LCD support written by Daniel Mantione * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -41,7 +42,7 @@ - guess PLL and MCLK based on the original PLL register values initialized by the BIOS or Open Firmware (if they are initialized). - (Anyone to help with this?) + (Anyone to help with this?) ******************************************************************************/ @@ -110,13 +111,12 @@ /* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */ /* - must be large enough to catch all GUI-Regs */ /* - must be aligned to a PAGE boundary */ -#define GUI_RESERVE (1 * PAGE_SIZE) +#define GUI_RESERVE (1 * PAGE_SIZE) /* FIXME: remove the FAIL definition */ #define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) - /* * The Hardware parameters for each card */ @@ -145,22 +145,22 @@ static int atyfb_open(struct fb_info *info, int user); static int atyfb_release(struct fb_info *info, int user); static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *fb); + struct fb_info *fb); static int atyfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb); + struct fb_info *fb); static int atyfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb); + struct fb_info *fb); static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *fb); + struct fb_info *fb); static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); + struct fb_info *info); static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info); + struct fb_info *info); static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info); + u_long arg, int con, struct fb_info *info); #ifdef __sparc__ static int atyfb_mmap(struct fb_info *info, struct file *file, - struct vm_area_struct *vma); + struct vm_area_struct *vma); #endif static int atyfb_rasterimg(struct fb_info *info, int start); @@ -185,32 +185,33 @@ #endif static void aty_set_crtc(const struct fb_info_aty *info, - const struct crtc *crtc); + const struct crtc *crtc); static int aty_var_to_crtc(const struct fb_info_aty *info, - const struct fb_var_screeninfo *var, - struct crtc *crtc); + const struct fb_var_screeninfo *var, + struct crtc *crtc, u32 *monitors_enabled); static int aty_crtc_to_var(const struct crtc *crtc, - struct fb_var_screeninfo *var); + struct fb_var_screeninfo *var); static void atyfb_set_par(const struct atyfb_par *par, - struct fb_info_aty *info); + struct fb_info_aty *info); static int atyfb_decode_var(const struct fb_var_screeninfo *var, - struct atyfb_par *par, - const struct fb_info_aty *info); + struct atyfb_par *par, + const struct fb_info_aty *info, + u32 monitors_enabled); static int atyfb_encode_var(struct fb_var_screeninfo *var, - const struct atyfb_par *par, - const struct fb_info_aty *info); + const struct atyfb_par *par, + const struct fb_info_aty *info); static void set_off_pitch(struct atyfb_par *par, - const struct fb_info_aty *info); + const struct fb_info_aty *info); static int encode_fix(struct fb_fix_screeninfo *fix, - const struct atyfb_par *par, - const struct fb_info_aty *info); + const struct atyfb_par *par, + const struct fb_info_aty *info); static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, - int bpp, int accel); + int bpp, int accel); static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *fb); + u_int *transp, struct fb_info *fb); static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *fb); + u_int transp, struct fb_info *fb); static void do_install_cmap(int con, struct fb_info *info); #ifdef CONFIG_PPC static int read_aty_sense(const struct fb_info_aty *info); @@ -229,20 +230,20 @@ static int currcon = 0; static struct fb_ops atyfb_ops = { - owner: THIS_MODULE, - fb_open: atyfb_open, - fb_release: atyfb_release, - fb_get_fix: atyfb_get_fix, - fb_get_var: atyfb_get_var, - fb_set_var: atyfb_set_var, - fb_get_cmap: atyfb_get_cmap, - fb_set_cmap: atyfb_set_cmap, - fb_pan_display: atyfb_pan_display, - fb_ioctl: atyfb_ioctl, + owner: THIS_MODULE, + fb_open: atyfb_open, + fb_release: atyfb_release, + fb_get_fix: atyfb_get_fix, + fb_get_var: atyfb_get_var, + fb_set_var: atyfb_set_var, + fb_get_cmap: atyfb_get_cmap, + fb_set_cmap: atyfb_set_cmap, + fb_pan_display: atyfb_pan_display, + fb_ioctl: atyfb_ioctl, #ifdef __sparc__ - fb_mmap: atyfb_mmap, + fb_mmap: atyfb_mmap, #endif - fb_rasterimg: atyfb_rasterimg, + fb_rasterimg: atyfb_rasterimg, }; static char atyfb_name[16] = "ATY Mach64"; @@ -252,6 +253,7 @@ static u32 default_vram __initdata = 0; static int default_pll __initdata = 0; static int default_mclk __initdata = 0; +static int default_xclk __initdata = 0; #ifndef MODULE static char *mode_option __initdata = NULL; @@ -308,65 +310,78 @@ u16 pci_id, chip_type; u8 rev_mask, rev_val; const char *name; - int pll, mclk; + int pll, mclk, xclk; u32 features; } aty_chips[] __initdata = { + /* Note to kernel maintainers: Please resfuse any patch to change a clock rate, + unless someone proves that a value is incorrect for him with a dump of + the driver information table in the BIOS. Patches accepted in the past have + caused chips to be overclocked by as much as 50%! + + Even in the case the table appear to be wrong, do not simply change the value + in the table. Ask about the chip revision the person uses and *add* an entry. + It's also often a good idea to contact ATi. + + Lastly, third party board vendors might use different memory clocks + than ATi. No examples of this have been found yet, but it is possible. + + (Daniel Mantione, 26 June 2003) + */ #ifdef CONFIG_FB_ATY_GX /* Mach64 GX */ - { 0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, M64F_GX }, - { 0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, M64F_GX }, + { 0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, 50, M64F_GX }, + { 0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, 50, M64F_GX }, #endif /* CONFIG_FB_ATY_GX */ #ifdef CONFIG_FB_ATY_CT /* Mach64 CT */ - { 0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO }, - { 0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO }, + { 0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO }, + { 0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO }, /* Mach64 VT */ - { 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 }, - { 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV }, - { 0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 }, - { 0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL }, - { 0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83, M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP }, + { 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 }, + { 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV }, + { 0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 }, + { 0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL }, + { 0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83, 83, M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP }, /* Mach64 GT (3D RAGE) */ - { 0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63, M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_EXTRA_BRIGHT }, - { 0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63, 63, M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_EXTRA_BRIGHT }, + { 0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, /* Mach64 LT */ - { 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP }, - { 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_LT_SLEEP | M64F_G3_PB_1024x768 }, + { 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP }, + { 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_LT_SLEEP | M64F_G3_PB_1024x768 }, /* Mach64 GTC (3D RAGE PRO) */ - { 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE }, - { 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, - { 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE }, + { 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, + { 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT }, /* 3D RAGE XL */ - { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL }, + { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 235, 83, 63, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL }, /* Mach64 LT PRO */ - { 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP }, - { 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP }, - { 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, - { 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP }, + { 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 236, 75, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT}, + { 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT}, + { 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, + { 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT}, /* 3D RAGE Mobility */ - { 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS }, - { 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS }, + { 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 83, 125, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS | M64F_EXTRA_BRIGHT}, + { 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 83, 125, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS | M64F_EXTRA_BRIGHT}, #endif /* CONFIG_FB_ATY_CT */ }; #if defined(CONFIG_FB_ATY_GX) || defined(CONFIG_FB_ATY_CT) static char ram_dram[] __initdata = "DRAM"; -static char ram_resv[] __initdata = "RESV"; #endif /* CONFIG_FB_ATY_GX || CONFIG_FB_ATY_CT */ #ifdef CONFIG_FB_ATY_GX @@ -379,6 +394,7 @@ static char ram_sgram[] __initdata = "SGRAM"; static char ram_wram[] __initdata = "WRAM"; static char ram_off[] __initdata = "OFF"; +static char ram_resv[] __initdata = "RESV"; #endif /* CONFIG_FB_ATY_CT */ #ifdef CONFIG_FB_ATY_GX @@ -406,39 +422,39 @@ { int sense, i; - aty_st_le32(GP_IO, 0x31003100, info); /* drive outputs high */ + aty_st_le32(GP_IO, 0x31003100, info); /* drive outputs high */ __delay(200); - aty_st_le32(GP_IO, 0, info); /* turn off outputs */ + aty_st_le32(GP_IO, 0, info); /* turn off outputs */ __delay(2000); - i = aty_ld_le32(GP_IO, info); /* get primary sense value */ + i = aty_ld_le32(GP_IO, info); /* get primary sense value */ sense = ((i & 0x3000) >> 3) | (i & 0x100); /* drive each sense line low in turn and collect the other 2 */ - aty_st_le32(GP_IO, 0x20000000, info); /* drive A low */ + aty_st_le32(GP_IO, 0x20000000, info); /* drive A low */ __delay(2000); i = aty_ld_le32(GP_IO, info); sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); - aty_st_le32(GP_IO, 0x20002000, info); /* drive A high again */ + aty_st_le32(GP_IO, 0x20002000, info); /* drive A high again */ __delay(200); - aty_st_le32(GP_IO, 0x10000000, info); /* drive B low */ + aty_st_le32(GP_IO, 0x10000000, info); /* drive B low */ __delay(2000); i = aty_ld_le32(GP_IO, info); sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); - aty_st_le32(GP_IO, 0x10001000, info); /* drive B high again */ + aty_st_le32(GP_IO, 0x10001000, info); /* drive B high again */ __delay(200); - aty_st_le32(GP_IO, 0x01000000, info); /* drive C low */ + aty_st_le32(GP_IO, 0x01000000, info); /* drive C low */ __delay(2000); sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12; - aty_st_le32(GP_IO, 0, info); /* turn off outputs */ + aty_st_le32(GP_IO, 0, info); /* turn off outputs */ return sense; } #endif /* defined(CONFIG_PPC) */ -#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) +#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info) { unsigned long temp; @@ -460,7 +476,7 @@ /* read the register value */ return aty_ld_le32(LCD_DATA, info); } -#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */ +#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT || CONFIG_FB_ATY_GENERIC_LCD*/ /* ------------------------------------------------------------------------- */ @@ -469,30 +485,103 @@ */ static void aty_set_crtc(const struct fb_info_aty *info, - const struct crtc *crtc) + const struct crtc *crtc) { + u32 v; + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info); aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info); +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* HACK: + * I don't want to do this, but Geert Uytterhoeven's laptop seems to + * have some shadowing enabled that I don't know yet how to switch + * off. It is a Rage Mobility M1, but doesn't happen on these chips + * in general. (Daniel Mantione, 26 june 2003) + */ + aty_st_lcd(aty_ld_lcd(LCD_GEN_CTRL, info) | SHADOW_RW_EN, info); + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info); + aty_st_lcd(aty_ld_lcd(LCD_GEN_CTRL, info) & ~SHADOW_RW_EN, info); + /* End hack */ +#endif + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info); aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info); aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info); aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info); aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info); +/* printk(KERN_INFO "CRTC_GEN_CNTL: %x\n",crtc->gen_cntl); + printk(KERN_INFO "CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp); + printk(KERN_INFO "CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid); + printk(KERN_INFO "CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp); + printk(KERN_INFO "CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid);*/ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* After setting the CRTC registers we should set the LCD + registers. + */ + if (info->lcd_table != 0) { + /* Enable/disable horizontal stretching */ + v = aty_ld_lcd(HORZ_STRETCHING, info); + v = v & ~(HORZ_STRETCH_RATIO | HORZ_STRETCH_EN | AUTO_HORZ_RATIO | + HORZ_STRETCH_LOOP); + v = v | HORZ_STRETCH_MODE; /* Use interpolation instead of duplication. */ + if (crtc->h_stretching != 0) + v = v | HORZ_STRETCH_EN | crtc->h_stretching; + aty_st_lcd(HORZ_STRETCHING, v, info); + /*printk(KERN_INFO "HORZ_STRETCHING: %x\n", v);*/ + + /* Enable/disable vertital stretching */ + v = aty_ld_lcd(VERT_STRETCHING, info); + v = v & ~(VERT_STRETCH_RATIO0 | VERT_STRETCH_EN); + v = v | VERT_STRETCH_USE0; /* Use VERT_STRETCH_RATIO0. */ + if (crtc->v_stretching != 0) + v = v | VERT_STRETCH_EN | crtc->v_stretching; + aty_st_lcd(VERT_STRETCHING, v, info); + /*printk(KERN_INFO "VERT_STRETCHING: %x\n", v);*/ + v = aty_ld_lcd(EXT_VERT_STRETCH, info); + v = v & ~AUTO_VERT_RATIO; /* Forbit the chip to guess the vertical + expansion (used for vga compatibility) */ + v = v | VERT_STRETCH_MODE; /* Use interpolation instead of duplication. */ + aty_st_lcd(EXT_VERT_STRETCH, v, info); + /*printk(KERN_INFO "EXT_VERT_STRETCH: %x\n", v);*/ + + /* Don't use shadowing. Don't divide the horizontal paramters. + (VGA compatibility junk that might be enabled.) + Enable only the monitors that were enabled before we switched the + video mode. + */ + v = aty_ld_lcd(LCD_GEN_CTRL, info); + v = v & ~(HORZ_DIVBY2_EN | DISABLE_PCLK_RESET | SCLK_SEL | + DIS_HOR_CRT_DIVBY2 | VCLK_DAC_PM_EN | XTALIN_PM_EN | + CRTC_RW_SELECT | USE_SHADOWED_ROWCUR | + USE_SHADOWED_VEND | SHADOW_EN | SHADOW_RW_EN | + LCD_ON | CRT_ON); + v = v | DONT_SHADOW_VPAR | crtc->monitors_enabled; + aty_st_lcd(LCD_GEN_CTRL, v, info); + /*printk(KERN_INFO "LCD_GEN_CTRL: %x\n", v);*/ + aty_st_lcd(CONFIG_PANEL, aty_ld_lcd(CONFIG_PANEL, info) | + DONT_SHADOW_HEND, info); + }; +#endif } static int aty_var_to_crtc(const struct fb_info_aty *info, - const struct fb_var_screeninfo *var, - struct crtc *crtc) + const struct fb_var_screeninfo *var, + struct crtc *crtc, u32 *monitors_enabled) { - u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 xres, yres, ryres, vxres, vyres, xoffset, yoffset, bpp; u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width, dp_pix_width, dp_chain_mask; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 lcd_hsync_start,lcd_htotal,lcd_vsync_start,lcd_vtotal; +#endif /* input */ xres = var->xres; yres = var->yres; + ryres = yres; vxres = var->xres_virtual; vyres = var->yres_virtual; xoffset = var->xoffset; @@ -501,6 +590,7 @@ left = var->left_margin; right = var->right_margin; upper = var->upper_margin; + lower = var->lower_margin; hslen = var->hsync_len; vslen = var->vsync_len; @@ -512,70 +602,82 @@ xoffset = (xoffset+7) & ~7; vxres = (vxres+7) & ~7; if (vxres < xres+xoffset) - vxres = xres+xoffset; + vxres = xres+xoffset; h_disp = xres/8-1; if (h_disp > 0xff) - FAIL("h_disp too large"); + FAIL("h_disp too large"); h_sync_strt = h_disp+(right/8); if (h_sync_strt > 0x1ff) - FAIL("h_sync_start too large"); + FAIL("h_sync_start too large"); h_sync_dly = right & 7; h_sync_wid = (hslen+7)/8; if (h_sync_wid > 0x1f) - FAIL("h_sync_wid too large"); + FAIL("h_sync_wid too large"); h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8; if (h_total > 0x1ff) - FAIL("h_total too large"); + FAIL("h_total too large"); h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; if (vyres < yres+yoffset) - vyres = yres+yoffset; + vyres = yres+yoffset; v_disp = yres-1; if (v_disp > 0x7ff) - FAIL("v_disp too large"); + FAIL("v_disp too large"); v_sync_strt = v_disp+lower; if (v_sync_strt > 0x7ff) - FAIL("v_sync_strt too large"); + FAIL("v_sync_strt too large"); v_sync_wid = vslen; if (v_sync_wid > 0x1f) - FAIL("v_sync_wid too large"); + FAIL("v_sync_wid too large"); v_total = v_sync_strt+v_sync_wid+upper; if (v_total > 0x7ff) - FAIL("v_total too large"); + FAIL("v_total too large"); v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; - + /* In double scan mode, the vertical parameters need to be doubled. + But in interlaced mode, there is no need to half the vertical parameters. + Code has been tested in 1024x768, 43 Hz interlaced and 640x480, 60 Hz + double scan. + */ + if ((vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) { + ryres <<= 1; + v_total <<= 1; + v_disp <<= 1; + v_sync_strt <<= 1; + v_sync_wid <<= 1; + }; + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; if (bpp <= 8) { - bpp = 8; - pix_width = CRTC_PIX_WIDTH_8BPP; - dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; + bpp = 8; + pix_width = CRTC_PIX_WIDTH_8BPP; + dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; } else if (bpp <= 16) { - bpp = 16; - pix_width = CRTC_PIX_WIDTH_15BPP; - dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | - BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x4210; + bpp = 16; + pix_width = CRTC_PIX_WIDTH_15BPP; + dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x4210; } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { - bpp = 24; - pix_width = CRTC_PIX_WIDTH_24BPP; - dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; + bpp = 24; + pix_width = CRTC_PIX_WIDTH_24BPP; + dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; } else if (bpp <= 32) { - bpp = 32; - pix_width = CRTC_PIX_WIDTH_32BPP; - dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | - BYTE_ORDER_LSB_TO_MSB; - dp_chain_mask = 0x8080; + bpp = 32; + pix_width = CRTC_PIX_WIDTH_32BPP; + dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask = 0x8080; } else - FAIL("invalid bpp"); + FAIL("invalid bpp"); if (vxres*vyres*bpp/8 > info->total_vram) - FAIL("not enough video RAM"); + FAIL("not enough video RAM"); - if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - FAIL("invalid vmode"); +// if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) +// FAIL("invalid vmode"); /* output */ crtc->vxres = vxres; @@ -583,18 +685,97 @@ crtc->xoffset = xoffset; crtc->yoffset = yoffset; crtc->bpp = bpp; - crtc->h_tot_disp = h_total | (h_disp<<16); - crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | - ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | - (h_sync_pol<<21); - crtc->v_tot_disp = v_total | (v_disp<<16); - crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE; + /* Enable doublescan mode if requested */ + if ((vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) + crtc->gen_cntl|=CRTC_DBL_SCAN_EN; + /* Enable interlaced mode if requested */ + if ((vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) + crtc->gen_cntl|=CRTC_INTERLACE_EN; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* We can only program the real mode parameters to the CRTC + if the LCD monitor is switched off. Otherwise we will have to + use the parameters the LCD monitor prefers, effectively setting + a completely different mode which simulates the requested + video mode. + */ + if ((info->lcd_table != 0) && ((*monitors_enabled & LCD_ON) != 0) && + ((xres > info->lcd_width) || (ryres > info->lcd_height)) + ) { + /* We cannot display the mode on the LCD. If the CRT is enabled + we can turn off the LCD. + If the CRT is off, it isn't a good idea to switch it on; we don't + know if one is connected. So it's better to fail then. + */ + if (*monitors_enabled & CRT_ON) { + printk(KERN_INFO "Disabling lcd monitor because video mode does not fit.\n"); + *monitors_enabled = *monitors_enabled & (~LCD_ON); + } else + FAIL("Video mode exceeds size of lcd monitor.\nConnect this computer to a conventional monitor if you really need this mode."); + }; + if ((info->lcd_table == 0) || ((*monitors_enabled & LCD_ON) == 0)) { +#endif + crtc->h_tot_disp = h_total | (h_disp<<16); + crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | + ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | + (h_sync_pol<<21); + crtc->v_tot_disp = v_total | (v_disp<<16); + crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* No hardware stretching please! */ + crtc->h_stretching = 0; + crtc->v_stretching = 0; + } else { + /* This is horror! When we simulate, say 640x480 on an 800x600 + lcd monitor, the CRTC should be programmed 800x600 values for + the non visible part, but 640x480 for the visible part. + This code has been tested on a laptop with it's 800x600 lcd + monitor and a conventional monitor both switched on. + Tested modes: 640x400, 720x400, 800x600, 320x200-doublescan, + 800x600-interlaced + */ + lcd_htotal = h_disp + info->lcd_hblank_width; + lcd_hsync_start = h_disp + info->lcd_right; + lcd_vtotal = v_disp + info->lcd_vblank_width; + lcd_vsync_start = v_disp + info->lcd_lower; + + crtc->h_tot_disp = (lcd_htotal) | (h_disp<<16); + crtc->h_sync_strt_wid = (lcd_hsync_start & 0xff) | + (info->lcd_hsync_delay<<8) | + ((lcd_hsync_start & 0x100)<<4) | + (info->lcd_hsync_width<<16); + crtc->v_tot_disp = lcd_vtotal | (v_disp<<16); + crtc->v_sync_strt_wid = lcd_vsync_start | + (info->lcd_vsync_width<<16); + /* To simulate the requested video mode, we use the hardware stretcher, + which zooms the image to the dimensions of the LCD screen. It has + two modes; replication and blending. Replication duplicates some + pixels, blending interpolates between pixels. We use blending. + The formula for blending is: + h_stretching=(source_with/dest_width)*4096 + v_stretching=(source_lines/dest_lines)*1024 + */ + if (xres != info->lcd_width) + crtc->h_stretching = (xres*4096)/info->lcd_width; + else + crtc->h_stretching = 0; + if (ryres != info->lcd_height) + crtc->v_stretching = (ryres*1024)/info->lcd_height; + else + crtc->v_stretching = 0; + /* The prefered mode for the lcd is not interlaced, so disable it if + it was enabled. For doublescan there is no problem, because we can + compensate for it in the hardware stretching (we stretch half as much) + */ + crtc->gen_cntl&=~CRTC_INTERLACE_EN; + }; + crtc->monitors_enabled = *monitors_enabled; +#endif if (M64_HAS(MAGIC_FIFO)) { - /* Not VTB/GTB */ - /* FIXME: magic FIFO values */ - crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; + /* Not VTB/GTB */ + /* FIXME: magic FIFO values */ + crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; } crtc->dp_pix_width = dp_pix_width; crtc->dp_chain_mask = dp_chain_mask; @@ -604,18 +785,19 @@ static int aty_crtc_to_var(const struct crtc *crtc, - struct fb_var_screeninfo *var) + struct fb_var_screeninfo *var) { u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; - + u32 double_scan, interlace; + /* input */ h_total = crtc->h_tot_disp & 0x1ff; h_disp = (crtc->h_tot_disp>>16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | - ((crtc->h_sync_strt_wid>>4) & 0x100); + ((crtc->h_sync_strt_wid>>4) & 0x100); h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7; h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f; h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1; @@ -626,7 +808,9 @@ v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; - + double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN; + interlace = crtc->gen_cntl & CRTC_INTERLACE_EN; + /* convert */ xres = (h_disp+1)*8; yres = v_disp+1; @@ -637,82 +821,82 @@ lower = v_sync_strt-v_disp; vslen = v_sync_wid; sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | - (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | - (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); switch (pix_width) { #if 0 - case CRTC_PIX_WIDTH_4BPP: - bpp = 4; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; -#endif - case CRTC_PIX_WIDTH_8BPP: - bpp = 8; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ - bpp = 16; - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; + case CRTC_PIX_WIDTH_4BPP: + bpp = 4; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; +#endif + case CRTC_PIX_WIDTH_8BPP: + bpp = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ + bpp = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; #if 0 - case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ - bpp = 16; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; -#endif - case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ - bpp = 24; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ - bpp = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - default: - FAIL("Invalid pixel width"); + case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ + bpp = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; +#endif + case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ + bpp = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ + bpp = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + default: + FAIL("Invalid pixel width"); } /* output */ @@ -731,14 +915,30 @@ var->vsync_len = vslen; var->sync = sync; var->vmode = FB_VMODE_NONINTERLACED; - + /* In double scan mode, the vertical parameters are doubled, so we need to + half them to get the right values. + In interlaced mode the values are already correct, so no correction is + necessary. + Code has been tested in 1024x768, 43 Hz interlaced and 640x480, 60 Hz + doublesscan. + */ + if (interlace) + var->vmode = FB_VMODE_INTERLACED; + if (double_scan) { + var->vmode = FB_VMODE_DOUBLE; + var->yres>>=1; + var->upper_margin>>=1; + var->lower_margin>>=1; + var->vsync_len>>=1; + }; + return 0; } /* ------------------------------------------------------------------------- */ static void atyfb_set_par(const struct atyfb_par *par, - struct fb_info_aty *info) + struct fb_info_aty *info) { u32 i; int accelmode; @@ -749,134 +949,157 @@ info->current_par = *par; if (info->blitter_may_be_busy) - wait_for_idle(info); + wait_for_idle(info); tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_set_crtc(info, &par->crtc); + +#if 0 aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); - /* better call aty_StrobeClock ?? */ + /* better call aty_StrobeClock ?? */ aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info); +#endif + aty_st_8(CLOCK_CNTL, 0, info); + aty_st_8(CLOCK_CNTL, CLOCK_STROBE | CLOCK_DIV, info); info->dac_ops->set_dac(info, &par->pll, par->crtc.bpp, accelmode); info->pll_ops->set_pll(info, &par->pll); if (!M64_HAS(INTEGRATED)) { - /* Don't forget MEM_CNTL */ - i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; - switch (par->crtc.bpp) { - case 8: - i |= 0x02000000; - break; - case 16: - i |= 0x03000000; - break; - case 32: - i |= 0x06000000; - break; - } - aty_st_le32(MEM_CNTL, i, info); + /* Don't forget MEM_CNTL */ + i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; + switch (par->crtc.bpp) { + case 8: + i |= 0x02000000; + break; + case 16: + i |= 0x03000000; + break; + case 32: + i |= 0x06000000; + break; + } + aty_st_le32(MEM_CNTL, i, info); } else { - i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; - if (!M64_HAS(MAGIC_POSTDIV)) - i |= info->mem_refresh_rate << 20; - switch (par->crtc.bpp) { - case 8: - case 24: - i |= 0x00000000; - break; - case 16: - i |= 0x04000000; - break; - case 32: - i |= 0x08000000; - break; - } - if (M64_HAS(CT_BUS)) { - aty_st_le32(DAC_CNTL, 0x87010184, info); - aty_st_le32(BUS_CNTL, 0x680000f9, info); - } else if (M64_HAS(VT_BUS)) { - aty_st_le32(DAC_CNTL, 0x87010184, info); - aty_st_le32(BUS_CNTL, 0x680000f9, info); - } else if (M64_HAS(MOBIL_BUS)) { - aty_st_le32(DAC_CNTL, 0x80010102, info); - aty_st_le32(BUS_CNTL, 0x7b33a040, info); - } else { - /* GT */ - aty_st_le32(DAC_CNTL, 0x86010102, info); - aty_st_le32(BUS_CNTL, 0x7b23a040, info); - aty_st_le32(EXT_MEM_CNTL, - aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); - } - aty_st_le32(MEM_CNTL, i, info); + i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; + if (!M64_HAS(MAGIC_POSTDIV)) + i |= info->mem_refresh_rate << 20; + switch (par->crtc.bpp) { + case 8: + case 24: + i |= 0x00000000; + break; + case 16: + i |= 0x04000000; + break; + case 32: + i |= 0x08000000; + break; + } + if (M64_HAS(CT_BUS)) { + aty_st_le32(DAC_CNTL, 0x87010184, info); + aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if (M64_HAS(VT_BUS)) { + aty_st_le32(DAC_CNTL, 0x87010184, info); + aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if (M64_HAS(MOBIL_BUS)) { + aty_st_le32(DAC_CNTL, 0x80010102, info); + aty_st_le32(BUS_CNTL, 0x7b33a040, info); + } else { + /* GT */ + aty_st_le32(DAC_CNTL, 0x86010102, info); + aty_st_le32(BUS_CNTL, 0x7b23a040, info); + aty_st_le32(EXT_MEM_CNTL, + aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); + } + aty_st_le32(MEM_CNTL, i, info); } aty_st_8(DAC_MASK, 0xff, info); /* Initialize the graphics engine */ if (par->accel_flags & FB_ACCELF_TEXT) - aty_init_engine(par, info); + aty_init_engine(par, info); #ifdef CONFIG_FB_COMPAT_XPMAC if (!console_fb_info || console_fb_info == &info->fb_info) { - struct fb_var_screeninfo var; - int vmode, cmode; - display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; - display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; - display_info.depth = par->crtc.bpp; - display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; - atyfb_encode_var(&var, par, info); - if (mac_var_to_vmode(&var, &vmode, &cmode)) - display_info.mode = 0; - else - display_info.mode = vmode; - strcpy(display_info.name, atyfb_name); - display_info.fb_address = info->frame_buffer_phys; - display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; - display_info.cmap_data_address = info->ati_regbase_phys+0xc1; - display_info.disp_reg_address = info->ati_regbase_phys; + struct fb_var_screeninfo var; + int vmode, cmode; + display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; + display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; + display_info.depth = par->crtc.bpp; + display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; + atyfb_encode_var(&var, par, info); + if (mac_var_to_vmode(&var, &vmode, &cmode)) + display_info.mode = 0; + else + display_info.mode = vmode; + strcpy(display_info.name, atyfb_name); + display_info.fb_address = info->frame_buffer_phys; + display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; + display_info.cmap_data_address = info->ati_regbase_phys+0xc1; + display_info.disp_reg_address = info->ati_regbase_phys; } #endif /* CONFIG_FB_COMPAT_XPMAC */ #ifdef CONFIG_BOOTX_TEXT btext_update_display(info->frame_buffer_phys, - (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, - ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, - par->crtc.bpp, - par->crtc.vxres*par->crtc.bpp/8); + (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, + ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); #endif /* CONFIG_BOOTX_TEXT */ } static int atyfb_decode_var(const struct fb_var_screeninfo *var, - struct atyfb_par *par, - const struct fb_info_aty *info) + struct atyfb_par *par, + const struct fb_info_aty *info, + u32 monitors_enabled) { int err; + u32 pixclock,xres; - if ((err = aty_var_to_crtc(info, var, &par->crtc)) || - (err = info->pll_ops->var_to_pll(info, var->pixclock, par->crtc.bpp, - &par->pll))) - return err; + err = aty_var_to_crtc(info, var, &par->crtc, &monitors_enabled); + if (err == 0) { + /* Alert! aty_var_to_crtc can modify monitors_enabled which is + important for the pixclock decision */ + pixclock = var->pixclock; + xres = 0; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if ((info->lcd_table != 0) && ((monitors_enabled & LCD_ON) != 0)) { + pixclock = info->lcd_pixclock; + xres = var->xres; + }; +#endif + if (pixclock == 0) { + FAIL("Invalid pixclock"); + } else + err = info->pll_ops->var_to_pll(info, pixclock, par->crtc.bpp, xres, + &par->pll); + }; + if (err != 0) + return err; if (var->accel_flags & FB_ACCELF_TEXT) - par->accel_flags = FB_ACCELF_TEXT; + par->accel_flags = FB_ACCELF_TEXT; else - par->accel_flags = 0; + par->accel_flags = 0; #if 0 /* fbmon is not done. uncomment for 2.5.x -brad */ - if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info)) - return -EINVAL; + if (!fbmon_valid_timings(pixclock, htotal, vtotal, info)) + return -EINVAL; #endif return 0; } static int atyfb_encode_var(struct fb_var_screeninfo *var, - const struct atyfb_par *par, - const struct fb_info_aty *info) + const struct atyfb_par *par, + const struct fb_info_aty *info) { int err; memset(var, 0, sizeof(struct fb_var_screeninfo)); if ((err = aty_crtc_to_var(&par->crtc, var))) - return err; + return err; var->pixclock = info->pll_ops->pll_to_var(info, &par->pll); var->height = -1; @@ -889,7 +1112,7 @@ static void set_off_pitch(struct atyfb_par *par, - const struct fb_info_aty *info) + const struct fb_info_aty *info) { u32 xoffset = par->crtc.xoffset; u32 yoffset = par->crtc.yoffset; @@ -912,11 +1135,11 @@ struct fb_info_aty *fb = (struct fb_info_aty *)info; if (user) { - fb->open++; - fb->mmaped = 0; - fb->vtconsole = -1; + fb->open++; + fb->mmaped = 0; + fb->vtconsole = -1; } else { - fb->consolecnt++; + fb->consolecnt++; } #endif return(0); @@ -936,42 +1159,42 @@ struct fb_info_aty *fb = (struct fb_info_aty *)info; if (user) { - fb->open--; - mdelay(1); - wait_for_idle(fb); - if (!fb->open) { - int was_mmaped = fb->mmaped; - - fb->mmaped = 0; - if (fb->vtconsole != -1) - vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; - fb->vtconsole = -1; - - if (was_mmaped) { - struct fb_var_screeninfo var; - - /* Now reset the default display config, we have no - * idea what the program(s) which mmap'd the chip did - * to the configuration, nor whether it restored it - * correctly. - */ - var = default_var; - if (noaccel) - var.accel_flags &= ~FB_ACCELF_TEXT; - else - var.accel_flags |= FB_ACCELF_TEXT; - if (var.yres == var.yres_virtual) { - u32 vram = (fb->total_vram - (PAGE_SIZE << 2)); - var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / - var.xres_virtual; - if (var.yres_virtual < var.yres) - var.yres_virtual = var.yres; - } - atyfb_set_var(&var, -1, &fb->fb_info); - } - } + fb->open--; + mdelay(1); + wait_for_idle(fb); + if (!fb->open) { + int was_mmaped = fb->mmaped; + + fb->mmaped = 0; + if (fb->vtconsole != -1) + vt_cons[fb->vtconsole]->vc_mode = KD_TEXT; + fb->vtconsole = -1; + + if (was_mmaped) { + struct fb_var_screeninfo var; + + /* Now reset the default display config, we have no + * idea what the program(s) which mmap'd the chip did + * to the configuration, nor whether it restored it + * correctly. + */ + var = default_var; + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + if (var.yres == var.yres_virtual) { + u32 vram = (fb->total_vram - (PAGE_SIZE << 2)); + var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / + var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; + } + atyfb_set_var(&var, -1, &fb->fb_info); + } + } } else { - fb->consolecnt--; + fb->consolecnt--; } #endif return(0); @@ -979,8 +1202,8 @@ static int encode_fix(struct fb_fix_screeninfo *fix, - const struct atyfb_par *par, - const struct fb_info_aty *info) + const struct atyfb_par *par, + const struct fb_info_aty *info) { memset(fix, 0, sizeof(struct fb_fix_screeninfo)); @@ -993,27 +1216,27 @@ * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400 */ if (M64_HAS(GX)) { - fix->mmio_start = info->ati_regbase_phys; - fix->mmio_len = 0x400; - fix->accel = FB_ACCEL_ATI_MACH64GX; + fix->mmio_start = info->ati_regbase_phys; + fix->mmio_len = 0x400; + fix->accel = FB_ACCEL_ATI_MACH64GX; } else if (M64_HAS(CT)) { - fix->mmio_start = info->ati_regbase_phys; - fix->mmio_len = 0x400; - fix->accel = FB_ACCEL_ATI_MACH64CT; + fix->mmio_start = info->ati_regbase_phys; + fix->mmio_len = 0x400; + fix->accel = FB_ACCEL_ATI_MACH64CT; } else if (M64_HAS(VT)) { - fix->mmio_start = info->ati_regbase_phys-0x400; - fix->mmio_len = 0x800; - fix->accel = FB_ACCEL_ATI_MACH64VT; + fix->mmio_start = info->ati_regbase_phys-0x400; + fix->mmio_len = 0x800; + fix->accel = FB_ACCEL_ATI_MACH64VT; } else /* if (M64_HAS(GT)) */ { - fix->mmio_start = info->ati_regbase_phys-0x400; - fix->mmio_len = 0x800; - fix->accel = FB_ACCEL_ATI_MACH64GT; + fix->mmio_start = info->ati_regbase_phys-0x400; + fix->mmio_len = 0x800; + fix->accel = FB_ACCEL_ATI_MACH64GT; } fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->line_length = par->crtc.vxres*par->crtc.bpp/8; fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR - : FB_VISUAL_DIRECTCOLOR; + : FB_VISUAL_DIRECTCOLOR; fix->ywrapstep = 0; fix->xpanstep = 8; fix->ypanstep = 1; @@ -1027,15 +1250,18 @@ */ static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con, - struct fb_info *fb) + struct fb_info *fb) { const struct fb_info_aty *info = (struct fb_info_aty *)fb; struct atyfb_par par; if (con == -1) - par = info->default_par; + par = info->default_par; else - atyfb_decode_var(&fb_display[con].var, &par, info); + /* The monitors_enabled information is not important for + the calculation of the information in par that encode_fix + needs, so we pass a 0. */ + atyfb_decode_var(&fb_display[con].var, &par, info, 0); encode_fix(fix, &par, info); return 0; } @@ -1046,125 +1272,185 @@ */ static int atyfb_get_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb) + struct fb_info *fb) { const struct fb_info_aty *info = (struct fb_info_aty *)fb; if (con == -1) - atyfb_encode_var(var, &info->default_par, info); + atyfb_encode_var(var, &info->default_par, info); else - *var = fb_display[con].var; + *var = fb_display[con].var; return 0; } static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info, - int bpp, int accel) + int bpp, int accel) { - switch (bpp) { + switch (bpp) { #ifdef FBCON_HAS_CFB8 - case 8: - info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; - disp->dispsw = &info->dispsw; - break; + case 8: + info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8; + disp->dispsw = &info->dispsw; + break; #endif #ifdef FBCON_HAS_CFB16 - case 16: - info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; - disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb16; - break; + case 16: + info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb16; + break; #endif #ifdef FBCON_HAS_CFB24 - case 24: - info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; - disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb24; - break; + case 24: + info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb24; + break; #endif #ifdef FBCON_HAS_CFB32 - case 32: - info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; - disp->dispsw = &info->dispsw; - disp->dispsw_data = info->fbcon_cmap.cfb32; - break; -#endif - default: - disp->dispsw = &fbcon_dummy; - } + case 32: + info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32; + disp->dispsw = &info->dispsw; + disp->dispsw_data = info->fbcon_cmap.cfb32; + break; +#endif + default: + disp->dispsw = &fbcon_dummy; + } #ifdef CONFIG_FB_ATY_CT - if (info->cursor) { - info->dispsw.cursor = atyfb_cursor; - info->dispsw.set_font = atyfb_set_font; - } + if (info->cursor) { + info->dispsw.cursor = atyfb_cursor; + info->dispsw.set_font = atyfb_set_font; + } #endif /* CONFIG_FB_ATY_CT */ } + /* + * In the display mode set code we need to make desisions depending on + * wether the LCD or CRT monitor is enabled. + * This is going to give problems in the unlikely case that someone + * for example turns on the LCD monitor just after we tested what + * monitors are enabled. Since the consequences are very serious + * (the graphic card crashes and sends the wrong signals to the lcd + * monitor which gets brighter and brighter; to prevent it from + * damage the computer must be switched off as soon as possible) + * we need to prevent this. + * + * As far as I know there is no way to prevent people switching on the + * LCD monitor while we are programming the video card. So the best way + * to do it, is detect what monitors are enabled before programming the + * video chip. After programming the video chip, we write this information + * back to the video chip, switching the LCD off again if someone enabled + * it. But isn't the card already crashed before we have the chance to + * turn the display back off? I don't think so because the CRTC is disabled + * while we program it. + */ + +#ifdef CONFIG_FB_ATY_GENERIC_LCD +static u32 atyfb_monitors_enabled(struct fb_info_aty *info) { + if (info->lcd_table != 0) { + return aty_ld_lcd(LCD_GEN_CTRL, info) & 3; + }; + return 0; +}; +#else +#define atyfb_monitors_enabled(info) 0 +#endif /* * Set the User Defined Part of the Display */ static int atyfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *fb) + struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; struct atyfb_par par; struct display *display; int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err; int activate = var->activate; + u32 monitors_enabled; if (con >= 0) - display = &fb_display[con]; + display = &fb_display[con]; else - display = fb->disp; /* used during initialization */ + display = fb->disp; /* used during initialization */ - if ((err = atyfb_decode_var(var, &par, info))) - return err; + monitors_enabled = atyfb_monitors_enabled(info); + + /* + * We have to be very carefull with encode_var for LCD_panels. Fbdev + * applications do not know about LCD monitors. We have to make them + * think they are using a CRT. That means that alltough the video + * chip is programmed for the resolution of the LCD monitor (say 800x600), + * the applications expect the mode they asked for, say 640x480 + * + * So when a program asks for 640x480, atyfb_decode_var sets the crtc + * registers for 800x600. Then atyfb_encode_var calculates the crtc + * registers back into the var variable, but now the var variable + * will contain wrong values for 800x600! Result: wrong information is + * returned to the program! + * + * To counter this, we call atyfb_decode_var first like if there is no + * lcd monitor switched on. Then we call atyfb_decode_var. Now + * the correct information is returned to the program, but the values + * for the crtc registers are not suited for the LCD monitor. We call + * atyfb_decode_var again to calculate the registers again, this time + * with the right monitors_enabled. + */ + + if ((err = atyfb_decode_var(var, &par, info, CRT_ON))) + return err; atyfb_encode_var(var, &par, (struct fb_info_aty *)info); +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if ((err = atyfb_decode_var(var, &par, info, monitors_enabled))) + return err; +#endif + if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldxres = display->var.xres; - oldyres = display->var.yres; - oldvxres = display->var.xres_virtual; - oldvyres = display->var.yres_virtual; - oldbpp = display->var.bits_per_pixel; - oldaccel = display->var.accel_flags; - display->var = *var; - accel = var->accel_flags & FB_ACCELF_TEXT; - if (oldxres != var->xres || oldyres != var->yres || - oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || - oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { - struct fb_fix_screeninfo fix; - - encode_fix(&fix, &par, info); - display->screen_base = (char *)info->frame_buffer; - display->visual = fix.visual; - display->type = fix.type; - display->type_aux = fix.type_aux; - display->ypanstep = fix.ypanstep; - display->ywrapstep = fix.ywrapstep; - display->line_length = fix.line_length; - display->can_soft_blank = 1; - display->inverse = 0; - if (accel) - display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; - else - display->scrollmode = SCROLL_YREDRAW; - if (info->fb_info.changevar) - (*info->fb_info.changevar)(con); - } - if (!info->fb_info.display_fg || - info->fb_info.display_fg->vc_num == con) { - atyfb_set_par(&par, info); - atyfb_set_dispsw(display, info, par.crtc.bpp, accel); - } - if (oldbpp != var->bits_per_pixel) { - if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) - return err; - do_install_cmap(con, &info->fb_info); - } + oldxres = display->var.xres; + oldyres = display->var.yres; + oldvxres = display->var.xres_virtual; + oldvyres = display->var.yres_virtual; + oldbpp = display->var.bits_per_pixel; + oldaccel = display->var.accel_flags; + display->var = *var; + accel = var->accel_flags & FB_ACCELF_TEXT; + if (oldxres != var->xres || oldyres != var->yres || + oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || + oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { + struct fb_fix_screeninfo fix; + + encode_fix(&fix, &par, info); + display->screen_base = (char *)info->frame_buffer; + display->visual = fix.visual; + display->type = fix.type; + display->type_aux = fix.type_aux; + display->ypanstep = fix.ypanstep; + display->ywrapstep = fix.ywrapstep; + display->line_length = fix.line_length; + display->can_soft_blank = 1; + display->inverse = 0; + if (accel) + display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0; + else + display->scrollmode = SCROLL_YREDRAW; + if (info->fb_info.changevar) + (*info->fb_info.changevar)(con); + } + if (!info->fb_info.display_fg || + info->fb_info.display_fg->vc_num == con) { + atyfb_set_par(&par, info); + atyfb_set_dispsw(display, info, par.crtc.bpp, accel); + } + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, &info->fb_info); + } } return 0; @@ -1178,7 +1464,7 @@ */ static int atyfb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *fb) + struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; u32 xres, yres, xoffset, yoffset; @@ -1189,7 +1475,7 @@ xoffset = (var->xoffset+7) & ~7; yoffset = var->yoffset; if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) - return -EINVAL; + return -EINVAL; par->crtc.xoffset = xoffset; par->crtc.yoffset = yoffset; set_off_pitch(par, info); @@ -1201,15 +1487,15 @@ */ static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) + struct fb_info *info) { if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info); + return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info); else if (fb_display[con].cmap.len) /* non default colormap? */ - fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); + fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2); } return 0; } @@ -1219,54 +1505,32 @@ */ static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) + struct fb_info *info) { int err; struct display *disp; if (con >= 0) - disp = &fb_display[con]; + disp = &fb_display[con]; else disp = info->disp; - if (!disp->cmap.len) { /* no colormap allocated? */ - int size = disp->var.bits_per_pixel == 16 ? 32 : 256; - if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) - return err; + if (!disp->cmap.len) { /* no colormap allocated? */ + int size = disp->var.bits_per_pixel == 16 ? 32 : 256; + if ((err = fb_alloc_cmap(&disp->cmap, size, 0))) + return err; } - if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ - return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); + if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */ + return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info); else - fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); + fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1); return 0; } -#ifdef DEBUG -#define ATYIO_CLKR 0x41545900 /* ATY\00 */ -#define ATYIO_CLKW 0x41545901 /* ATY\01 */ - -struct atyclk { - u32 ref_clk_per; - u8 pll_ref_div; - u8 mclk_fb_div; - u8 mclk_post_div; /* 1,2,3,4,8 */ - u8 vclk_fb_div; - u8 vclk_post_div; /* 1,2,3,4,6,8,12 */ - u32 dsp_xclks_per_row; /* 0-16383 */ - u32 dsp_loop_latency; /* 0-15 */ - u32 dsp_precision; /* 0-7 */ - u32 dsp_on; /* 0-2047 */ - u32 dsp_off; /* 0-2047 */ -}; - -#define ATYIO_FEATR 0x41545902 /* ATY\02 */ -#define ATYIO_FEATW 0x41545903 /* ATY\03 */ -#endif - static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, - u_long arg, int con, struct fb_info *info2) + u_long arg, int con, struct fb_info *info2) { -#if defined(__sparc__) || (defined(DEBUG) && defined(CONFIG_FB_ATY_CT)) +#if defined(__sparc__) struct fb_info_aty *info = (struct fb_info_aty *)info2; #endif /* __sparc__ || DEBUG */ #ifdef __sparc__ @@ -1274,7 +1538,7 @@ struct display *disp; if (con >= 0) - disp = &fb_display[con]; + disp = &fb_display[con]; else disp = info2->disp; #endif @@ -1282,72 +1546,18 @@ switch (cmd) { #ifdef __sparc__ case FBIOGTYPE: - fbtyp.fb_type = FBTYPE_PCI_GENERIC; - fbtyp.fb_width = info->current_par.crtc.vxres; - fbtyp.fb_height = info->current_par.crtc.vyres; - fbtyp.fb_depth = info->current_par.crtc.bpp; - fbtyp.fb_cmsize = disp->cmap.len; - fbtyp.fb_size = info->total_vram; - if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp))) - return -EFAULT; - break; + fbtyp.fb_type = FBTYPE_PCI_GENERIC; + fbtyp.fb_width = info->current_par.crtc.vxres; + fbtyp.fb_height = info->current_par.crtc.vyres; + fbtyp.fb_depth = info->current_par.crtc.bpp; + fbtyp.fb_cmsize = disp->cmap.len; + fbtyp.fb_size = info->total_vram; + if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp))) + return -EFAULT; + break; #endif /* __sparc__ */ -#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT) - case ATYIO_CLKR: - if (M64_HAS(INTEGRATED)) { - struct atyclk clk; - union aty_pll *pll = &info->current_par.pll; - u32 dsp_config = pll->ct.dsp_config; - u32 dsp_on_off = pll->ct.dsp_on_off; - clk.ref_clk_per = info->ref_clk_per; - clk.pll_ref_div = pll->ct.pll_ref_div; - clk.mclk_fb_div = pll->ct.mclk_fb_div; - clk.mclk_post_div = pll->ct.mclk_post_div_real; - clk.vclk_fb_div = pll->ct.vclk_fb_div; - clk.vclk_post_div = pll->ct.vclk_post_div_real; - clk.dsp_xclks_per_row = dsp_config & 0x3fff; - clk.dsp_loop_latency = (dsp_config>>16) & 0xf; - clk.dsp_precision = (dsp_config>>20) & 7; - clk.dsp_on = dsp_on_off & 0x7ff; - clk.dsp_off = (dsp_on_off>>16) & 0x7ff; - if (copy_to_user((struct atyclk *)arg, &clk, sizeof(clk))) - return -EFAULT; - } else - return -EINVAL; - break; - case ATYIO_CLKW: - if (M64_HAS(INTEGRATED)) { - struct atyclk clk; - union aty_pll *pll = &info->current_par.pll; - if (copy_from_user(&clk, (struct atyclk *)arg, sizeof(clk))) - return -EFAULT; - info->ref_clk_per = clk.ref_clk_per; - pll->ct.pll_ref_div = clk.pll_ref_div; - pll->ct.mclk_fb_div = clk.mclk_fb_div; - pll->ct.mclk_post_div_real = clk.mclk_post_div; - pll->ct.vclk_fb_div = clk.vclk_fb_div; - pll->ct.vclk_post_div_real = clk.vclk_post_div; - pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) | - ((clk.dsp_loop_latency & 0xf)<<16) | - ((clk.dsp_precision & 7)<<20); - pll->ct.dsp_on_off = (clk.dsp_on & 0x7ff) | - ((clk.dsp_off & 0x7ff)<<16); - aty_calc_pll_ct(info, &pll->ct); - aty_set_pll_ct(info, pll); - } else - return -EINVAL; - break; - case ATYIO_FEATR: - if (get_user(info->features, (u32 *)arg)) - return -EFAULT; - break; - case ATYIO_FEATW: - if (put_user(info->features, (u32 *)arg)) - return -EFAULT; - break; -#endif /* DEBUG && CONFIG_FB_ATY_CT */ default: - return -EINVAL; + return -EINVAL; } return 0; } @@ -1357,148 +1567,148 @@ struct fb_info_aty *fb = (struct fb_info_aty *)info; if (fb->blitter_may_be_busy) - wait_for_idle(fb); + wait_for_idle(fb); return 0; } #ifdef __sparc__ static int atyfb_mmap(struct fb_info *info, struct file *file, - struct vm_area_struct *vma) + struct vm_area_struct *vma) { - struct fb_info_aty *fb = (struct fb_info_aty *)info; - unsigned int size, page, map_size = 0; - unsigned long map_offset = 0; - unsigned long off; - int i; - - if (!fb->mmap_map) - return -ENXIO; - - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) - return -EINVAL; - - off = vma->vm_pgoff << PAGE_SHIFT; - size = vma->vm_end - vma->vm_start; - - /* To stop the swapper from even considering these pages. */ - vma->vm_flags |= (VM_SHM | VM_LOCKED); - - if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) || - ((off == fb->total_vram) && (size == PAGE_SIZE))) - off += 0x8000000000000000UL; - - vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ - - /* Each page, see which map applies */ - for (page = 0; page < size; ) { - map_size = 0; - for (i = 0; fb->mmap_map[i].size; i++) { - unsigned long start = fb->mmap_map[i].voff; - unsigned long end = start + fb->mmap_map[i].size; - unsigned long offset = off + page; - - if (start > offset) - continue; - if (offset >= end) - continue; - - map_size = fb->mmap_map[i].size - (offset - start); - map_offset = fb->mmap_map[i].poff + (offset - start); - break; - } - if (!map_size) { - page += PAGE_SIZE; - continue; - } - if (page + map_size > size) - map_size = size - page; - - pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask); - pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag; - - if (remap_page_range(vma->vm_start + page, map_offset, - map_size, vma->vm_page_prot)) - return -EAGAIN; - - page += map_size; - } - - if (!map_size) - return -EINVAL; - - vma->vm_flags |= VM_IO; - - if (!fb->mmaped) { - int lastconsole = 0; - - if (info->display_fg) - lastconsole = info->display_fg->vc_num; - fb->mmaped = 1; - if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { - fb->vtconsole = lastconsole; - vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; - } - } - return 0; + struct fb_info_aty *fb = (struct fb_info_aty *)info; + unsigned int size, page, map_size = 0; + unsigned long map_offset = 0; + unsigned long off; + int i; + + if (!fb->mmap_map) + return -ENXIO; + + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + off = vma->vm_pgoff << PAGE_SHIFT; + size = vma->vm_end - vma->vm_start; + + /* To stop the swapper from even considering these pages. */ + vma->vm_flags |= (VM_SHM | VM_LOCKED); + + if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) || + ((off == fb->total_vram) && (size == PAGE_SIZE))) + off += 0x8000000000000000UL; + + vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */ + + /* Each page, see which map applies */ + for (page = 0; page < size; ) { + map_size = 0; + for (i = 0; fb->mmap_map[i].size; i++) { + unsigned long start = fb->mmap_map[i].voff; + unsigned long end = start + fb->mmap_map[i].size; + unsigned long offset = off + page; + + if (start > offset) + continue; + if (offset >= end) + continue; + + map_size = fb->mmap_map[i].size - (offset - start); + map_offset = fb->mmap_map[i].poff + (offset - start); + break; + } + if (!map_size) { + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + + pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask); + pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag; + + if (remap_page_range(vma->vm_start + page, map_offset, + map_size, vma->vm_page_prot)) + return -EAGAIN; + + page += map_size; + } + + if (!map_size) + return -EINVAL; + + vma->vm_flags |= VM_IO; + + if (!fb->mmaped) { + int lastconsole = 0; + + if (info->display_fg) + lastconsole = info->display_fg->vc_num; + fb->mmaped = 1; + if (fb->consolecnt && fb_display[lastconsole].fb_info == info) { + fb->vtconsole = lastconsole; + vt_cons[lastconsole]->vc_mode = KD_GRAPHICS; + } + } + return 0; } static struct { - u32 yoffset; - u8 r[2][256]; - u8 g[2][256]; - u8 b[2][256]; + u32 yoffset; + u8 r[2][256]; + u8 g[2][256]; + u8 b[2][256]; } atyfb_save; static void atyfb_save_palette(struct fb_info *fb, int enter) { - struct fb_info_aty *info = (struct fb_info_aty *)fb; - int i, tmp; + struct fb_info_aty *info = (struct fb_info_aty *)fb; + int i, tmp; - for (i = 0; i < 256; i++) { - tmp = aty_ld_8(DAC_CNTL, info) & 0xfc; - if (M64_HAS(EXTRA_BRIGHT)) - tmp |= 0x2; - aty_st_8(DAC_CNTL, tmp, info); - aty_st_8(DAC_MASK, 0xff, info); - - writeb(i, &info->aty_cmap_regs->rindex); - atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); - atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); - atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); - writeb(i, &info->aty_cmap_regs->windex); - writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); - writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); - writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); - } + for (i = 0; i < 256; i++) { + tmp = aty_ld_8(DAC_CNTL, info) & 0xfc; + if (M64_HAS(EXTRA_BRIGHT)) + tmp |= 0x2; + aty_st_8(DAC_CNTL, tmp, info); + aty_st_8(DAC_MASK, 0xff, info); + + writeb(i, &info->aty_cmap_regs->rindex); + atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut); + atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut); + atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut); + writeb(i, &info->aty_cmap_regs->windex); + writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut); + writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut); + writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut); + } } static void atyfb_palette(int enter) { - struct fb_info_aty *info; - struct atyfb_par *par; - struct display *d; - int i; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - d = &fb_display[i]; - if (d->fb_info && - d->fb_info->fbops == &atyfb_ops && - d->fb_info->display_fg && - d->fb_info->display_fg->vc_num == i) { - atyfb_save_palette(d->fb_info, enter); - info = (struct fb_info_aty *)d->fb_info; - par = &info->current_par; - if (enter) { - atyfb_save.yoffset = par->crtc.yoffset; - par->crtc.yoffset = 0; - set_off_pitch(par, info); - } else { - par->crtc.yoffset = atyfb_save.yoffset; - set_off_pitch(par, info); - } - break; - } - } + struct fb_info_aty *info; + struct atyfb_par *par; + struct display *d; + int i; + + for (i = 0; i < MAX_NR_CONSOLES; i++) { + d = &fb_display[i]; + if (d->fb_info && + d->fb_info->fbops == &atyfb_ops && + d->fb_info->display_fg && + d->fb_info->display_fg->vc_num == i) { + atyfb_save_palette(d->fb_info, enter); + info = (struct fb_info_aty *)d->fb_info; + par = &info->current_par; + if (enter) { + atyfb_save.yoffset = par->crtc.yoffset; + par->crtc.yoffset = 0; + set_off_pitch(par, info); + } else { + par->crtc.yoffset = atyfb_save.yoffset; + set_off_pitch(par, info); + } + break; + } + } } #endif /* __sparc__ */ @@ -1516,117 +1726,117 @@ */ static int aty_power_mgmt_LT(int sleep, struct fb_info_aty *info) { - unsigned int pm; - int timeout; - - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - - timeout = 200000; - if (sleep) { - /* Sleep */ - pm &= ~PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm &= ~(PWR_BLON | AUTO_PWR_UP); - pm |= SUSPEND_NOW; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - do { - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); - } else { - /* Wakeup */ - pm &= ~PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm |= (PWR_BLON | AUTO_PWR_UP); - pm &= ~SUSPEND_NOW; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_le32(POWER_MANAGEMENT_LG, pm, info); - do { - pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); - udelay(10); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != 0); - } - mdelay(500); + unsigned int pm; + int timeout; + + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + + timeout = 200000; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + do { + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= (PWR_BLON | AUTO_PWR_UP); + pm &= ~SUSPEND_NOW; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_le32(POWER_MANAGEMENT_LG, pm, info); + do { + pm = aty_ld_le32(POWER_MANAGEMENT_LG, info); + udelay(10); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } + mdelay(500); - return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; + return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; } static int aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info) { - unsigned int pm; - int timeout; - - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; - aty_st_lcd(POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - - timeout = 200; - if (sleep) { - /* Sleep */ - pm &= ~PWR_MGT_ON; - aty_st_lcd(POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - udelay(10); - pm &= ~(PWR_BLON | AUTO_PWR_UP); - pm |= SUSPEND_NOW; - aty_st_lcd(POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_lcd(POWER_MANAGEMENT, pm, info); - do { - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - mdelay(1); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); - } else { - /* Wakeup */ - pm &= ~PWR_MGT_ON; - aty_st_lcd(POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - udelay(10); - pm &= ~SUSPEND_NOW; - pm |= (PWR_BLON | AUTO_PWR_UP); - aty_st_lcd(POWER_MANAGEMENT, pm, info); - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - udelay(10); - pm |= PWR_MGT_ON; - aty_st_lcd(POWER_MANAGEMENT, pm, info); - do { - pm = aty_ld_lcd(POWER_MANAGEMENT, info); - mdelay(1); - if ((--timeout) == 0) - break; - } while ((pm & PWR_MGT_STATUS_MASK) != 0); - } + unsigned int pm; + int timeout; + + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + + timeout = 200; + if (sleep) { + /* Sleep */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + udelay(10); + pm &= ~(PWR_BLON | AUTO_PWR_UP); + pm |= SUSPEND_NOW; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + do { + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + mdelay(1); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND); + } else { + /* Wakeup */ + pm &= ~PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + udelay(10); + pm &= ~SUSPEND_NOW; + pm |= (PWR_BLON | AUTO_PWR_UP); + aty_st_lcd(POWER_MANAGEMENT, pm, info); + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + udelay(10); + pm |= PWR_MGT_ON; + aty_st_lcd(POWER_MANAGEMENT, pm, info); + do { + pm = aty_ld_lcd(POWER_MANAGEMENT, info); + mdelay(1); + if ((--timeout) == 0) + break; + } while ((pm & PWR_MGT_STATUS_MASK) != 0); + } - return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; + return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE; } static int aty_power_mgmt(int sleep, struct fb_info_aty *info) { return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, info) - : aty_power_mgmt_LTPro(sleep, info); + : aty_power_mgmt_LTPro(sleep, info); } /* @@ -1635,72 +1845,72 @@ */ static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when) { - struct fb_info_aty *info; - int result; + struct fb_info_aty *info; + int result; - result = PBOOK_SLEEP_OK; + result = PBOOK_SLEEP_OK; - for (info = first_display; info != NULL; info = info->next) { - struct fb_fix_screeninfo fix; - int nb; - - atyfb_get_fix(&fix, fg_console, (struct fb_info *)info); - nb = fb_display[fg_console].var.yres * fix.line_length; - - switch (when) { - case PBOOK_SLEEP_REQUEST: - info->save_framebuffer = vmalloc(nb); - if (info->save_framebuffer == NULL) - return PBOOK_SLEEP_REFUSE; - break; - case PBOOK_SLEEP_REJECT: - if (info->save_framebuffer) { - vfree(info->save_framebuffer); - info->save_framebuffer = 0; - } - break; - case PBOOK_SLEEP_NOW: - if (currcon >= 0) - fb_display[currcon].dispsw = &fbcon_dummy; - if (info->blitter_may_be_busy) - wait_for_idle(info); - /* Stop accel engine (stop bus mastering) */ - if (info->current_par.accel_flags & FB_ACCELF_TEXT) - aty_reset_engine(info); - - /* Backup fb content */ - if (info->save_framebuffer) - memcpy_fromio(info->save_framebuffer, - (void *)info->frame_buffer, nb); - - /* Blank display and LCD */ - atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); - - /* Set chip to "suspend" mode */ - result = aty_power_mgmt(1, info); - break; - case PBOOK_WAKE: - /* Wakeup chip */ - result = aty_power_mgmt(0, info); - - /* Restore fb content */ - if (info->save_framebuffer) { - memcpy_toio((void *)info->frame_buffer, - info->save_framebuffer, nb); - vfree(info->save_framebuffer); - info->save_framebuffer = 0; - } - /* Restore display */ - if (currcon >= 0) { - atyfb_set_dispsw(&fb_display[currcon], - info, info->current_par.crtc.bpp, - info->current_par.accel_flags & FB_ACCELF_TEXT); - } - atyfbcon_blank(0, (struct fb_info *)info); - break; - } - } - return result; + for (info = first_display; info != NULL; info = info->next) { + struct fb_fix_screeninfo fix; + int nb; + + atyfb_get_fix(&fix, fg_console, (struct fb_info *)info); + nb = fb_display[fg_console].var.yres * fix.line_length; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + info->save_framebuffer = vmalloc(nb); + if (info->save_framebuffer == NULL) + return PBOOK_SLEEP_REFUSE; + break; + case PBOOK_SLEEP_REJECT: + if (info->save_framebuffer) { + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + break; + case PBOOK_SLEEP_NOW: + if (currcon >= 0) + fb_display[currcon].dispsw = &fbcon_dummy; + if (info->blitter_may_be_busy) + wait_for_idle(info); + /* Stop accel engine (stop bus mastering) */ + if (info->current_par.accel_flags & FB_ACCELF_TEXT) + aty_reset_engine(info); + + /* Backup fb content */ + if (info->save_framebuffer) + memcpy_fromio(info->save_framebuffer, + (void *)info->frame_buffer, nb); + + /* Blank display and LCD */ + atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info); + + /* Set chip to "suspend" mode */ + result = aty_power_mgmt(1, info); + break; + case PBOOK_WAKE: + /* Wakeup chip */ + result = aty_power_mgmt(0, info); + + /* Restore fb content */ + if (info->save_framebuffer) { + memcpy_toio((void *)info->frame_buffer, + info->save_framebuffer, nb); + vfree(info->save_framebuffer); + info->save_framebuffer = 0; + } + /* Restore display */ + if (currcon >= 0) { + atyfb_set_dispsw(&fb_display[currcon], + info, info->current_par.crtc.bpp, + info->current_par.accel_flags & FB_ACCELF_TEXT); + } + atyfbcon_blank(0, (struct fb_info *)info); + break; + } + } + return result; } static struct pmu_sleep_notifier aty_sleep_notifier = { @@ -1715,38 +1925,38 @@ */ static int backlight_conv[] = { - 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, - 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff + 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, + 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff }; static int aty_set_backlight_enable(int on, int level, void* data) { - struct fb_info_aty *info = (struct fb_info_aty *)data; - unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); - - reg |= (BLMOD_EN | BIASMOD_EN); - if (on && level > BACKLIGHT_OFF) { - reg &= ~BIAS_MOD_LEVEL_MASK; - reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); - } else { - reg &= ~BIAS_MOD_LEVEL_MASK; - reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); - } - aty_st_lcd(LCD_MISC_CNTL, reg, info); + struct fb_info_aty *info = (struct fb_info_aty *)data; + unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); + + reg |= (BLMOD_EN | BIASMOD_EN); + if (on && level > BACKLIGHT_OFF) { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); + } else { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); + } + aty_st_lcd(LCD_MISC_CNTL, reg, info); - return 0; + return 0; } static int aty_set_backlight_level(int level, void* data) { - return aty_set_backlight_enable(1, level, data); + return aty_set_backlight_enable(1, level, data); } static struct backlight_controller aty_backlight_controller = { - aty_set_backlight_enable, - aty_set_backlight_level + aty_set_backlight_enable, + aty_set_backlight_level }; #endif /* CONFIG_PMAC_BACKLIGHT */ @@ -1768,25 +1978,27 @@ u16 type; u8 rev; const char *chipname = NULL, *ramname = NULL, *xtal; - int pll, mclk, gtb_memsize; + int pll, mclk, xclk, gtb_memsize; #if defined(CONFIG_PPC) int sense; #endif u8 pll_ref_div; + u32 monitors_enabled; info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0); chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); type = chip_id & CFG_CHIP_TYPE; rev = (chip_id & CFG_CHIP_REV)>>24; for (j = 0; j < (sizeof(aty_chips)/sizeof(*aty_chips)); j++) - if (type == aty_chips[j].chip_type && - (rev & aty_chips[j].rev_mask) == aty_chips[j].rev_val) { - chipname = aty_chips[j].name; - pll = aty_chips[j].pll; - mclk = aty_chips[j].mclk; - info->features = aty_chips[j].features; - goto found; - } + if (type == aty_chips[j].chip_type && + (rev & aty_chips[j].rev_mask) == aty_chips[j].rev_val) { + chipname = aty_chips[j].name; + pll = aty_chips[j].pll; + mclk = aty_chips[j].mclk; + xclk = aty_chips[j].xclk; + info->features = aty_chips[j].features; + goto found; + } printk("atyfb: Unknown mach64 0x%04x rev 0x%04x\n", type, rev); return 0; @@ -1794,208 +2006,245 @@ printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, type, rev); #ifdef CONFIG_FB_ATY_GX if (!M64_HAS(INTEGRATED)) { - u32 stat0; - u8 dac_type, dac_subtype, clk_type; - stat0 = aty_ld_le32(CONFIG_STAT0, info); - info->bus_type = (stat0 >> 0) & 0x07; - info->ram_type = (stat0 >> 3) & 0x07; - ramname = aty_gx_ram[info->ram_type]; - /* FIXME: clockchip/RAMDAC probing? */ - dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07; + u32 stat0; + u8 dac_type, dac_subtype, clk_type; + stat0 = aty_ld_le32(CONFIG_STAT0, info); + info->bus_type = (stat0 >> 0) & 0x07; + info->ram_type = (stat0 >> 3) & 0x07; + ramname = aty_gx_ram[info->ram_type]; + /* FIXME: clockchip/RAMDAC probing? */ + dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07; #ifdef CONFIG_ATARI - clk_type = CLK_ATI18818_1; - dac_type = (stat0 >> 9) & 0x07; - if (dac_type == 0x07) - dac_subtype = DAC_ATT20C408; - else - dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) | dac_type; + clk_type = CLK_ATI18818_1; + dac_type = (stat0 >> 9) & 0x07; + if (dac_type == 0x07) + dac_subtype = DAC_ATT20C408; + else + dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) | dac_type; #else - dac_type = DAC_IBMRGB514; - dac_subtype = DAC_IBMRGB514; - clk_type = CLK_IBMRGB514; -#endif - switch (dac_subtype) { - case DAC_IBMRGB514: - info->dac_ops = &aty_dac_ibm514; - break; - case DAC_ATI68860_B: - case DAC_ATI68860_C: - info->dac_ops = &aty_dac_ati68860b; - break; - case DAC_ATT20C408: - case DAC_ATT21C498: - info->dac_ops = &aty_dac_att21c498; - break; - default: - printk(" atyfb_set_par: DAC type not implemented yet!\n"); - info->dac_ops = &aty_dac_unsupported; - break; - } - switch (clk_type) { - case CLK_ATI18818_1: - info->pll_ops = &aty_pll_ati18818_1; - break; - case CLK_STG1703: - info->pll_ops = &aty_pll_stg1703; - break; - case CLK_CH8398: - info->pll_ops = &aty_pll_ch8398; - break; - case CLK_ATT20C408: - info->pll_ops = &aty_pll_att20c408; - break; - case CLK_IBMRGB514: - info->pll_ops = &aty_pll_ibm514; - break; - default: - printk(" atyfb_set_par: CLK type not implemented yet!"); - info->pll_ops = &aty_pll_unsupported; - break; - } + dac_type = DAC_IBMRGB514; + dac_subtype = DAC_IBMRGB514; + clk_type = CLK_IBMRGB514; +#endif + switch (dac_subtype) { + case DAC_IBMRGB514: + info->dac_ops = &aty_dac_ibm514; + break; + case DAC_ATI68860_B: + case DAC_ATI68860_C: + info->dac_ops = &aty_dac_ati68860b; + break; + case DAC_ATT20C408: + case DAC_ATT21C498: + info->dac_ops = &aty_dac_att21c498; + break; + default: + printk(" atyfb_set_par: DAC type not implemented yet!\n"); + info->dac_ops = &aty_dac_unsupported; + break; + } + switch (clk_type) { + case CLK_ATI18818_1: + info->pll_ops = &aty_pll_ati18818_1; + break; + case CLK_STG1703: + info->pll_ops = &aty_pll_stg1703; + break; + case CLK_CH8398: + info->pll_ops = &aty_pll_ch8398; + break; + case CLK_ATT20C408: + info->pll_ops = &aty_pll_att20c408; + break; + case CLK_IBMRGB514: + info->pll_ops = &aty_pll_ibm514; + break; + default: + printk(" atyfb_set_par: CLK type not implemented yet!"); + info->pll_ops = &aty_pll_unsupported; + break; + } } #endif /* CONFIG_FB_ATY_GX */ #ifdef CONFIG_FB_ATY_CT if (M64_HAS(INTEGRATED)) { - info->bus_type = PCI; - info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); - ramname = aty_ct_ram[info->ram_type]; - info->dac_ops = &aty_dac_ct; - info->pll_ops = &aty_pll_ct; - /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ - if (mclk == 67 && info->ram_type < SDRAM) - mclk = 63; + info->bus_type = PCI; + info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07); + ramname = aty_ct_ram[info->ram_type]; + info->dac_ops = &aty_dac_ct; + info->pll_ops = &aty_pll_ct; + /* + * I disable the hack below because it is completely unreliable. + * DRAM at 67 is very well imaginable. If a chip is indeed clocked + * below it's official clock rate because it is equiped with + * too slow memory the driver information table + * in the BIOS will contain the right value. So if you need it + * write code to scan the driver information table, it will work + * in any case the chip is clocked lower than the official rate + * instead of just cases where the mclk is 67 MHz. + * (Daniel Mantione, 25 may 2003) + */ + /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */ +/* if (xclk == 67 && info->ram_type < SDRAM) + xclk = 63;*/ } #endif /* CONFIG_FB_ATY_CT */ info->ref_clk_per = 1000000000000ULL/14318180; xtal = "14.31818"; if (M64_HAS(GTB_DSP) && (pll_ref_div = aty_ld_pll(PLL_REF_DIV, info))) { - int diff1, diff2; - diff1 = 510*14/pll_ref_div-pll; - diff2 = 510*29/pll_ref_div-pll; - if (diff1 < 0) - diff1 = -diff1; - if (diff2 < 0) - diff2 = -diff2; - if (diff2 < diff1) { - info->ref_clk_per = 1000000000000ULL/29498928; - xtal = "29.498928"; - } + int diff1, diff2; + diff1 = 510*14/pll_ref_div-pll; + diff2 = 510*29/pll_ref_div-pll; + if (diff1 < 0) + diff1 = -diff1; + if (diff2 < 0) + diff2 = -diff2; + if (diff2 < diff1) { + info->ref_clk_per = 1000000000000ULL/29498928; + xtal = "29.498928"; + } } i = aty_ld_le32(MEM_CNTL, info); gtb_memsize = M64_HAS(GTB_DSP); if (gtb_memsize) - switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ - case MEM_SIZE_512K: - info->total_vram = 0x80000; - break; - case MEM_SIZE_1M: - info->total_vram = 0x100000; - break; - case MEM_SIZE_2M_GTB: - info->total_vram = 0x200000; - break; - case MEM_SIZE_4M_GTB: - info->total_vram = 0x400000; - break; - case MEM_SIZE_6M_GTB: - info->total_vram = 0x600000; - break; - case MEM_SIZE_8M_GTB: - info->total_vram = 0x800000; - break; - default: - info->total_vram = 0x80000; - } + switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */ + case MEM_SIZE_512K: + info->total_vram = 0x80000; + break; + case MEM_SIZE_1M: + info->total_vram = 0x100000; + break; + case MEM_SIZE_2M_GTB: + info->total_vram = 0x200000; + break; + case MEM_SIZE_4M_GTB: + info->total_vram = 0x400000; + break; + case MEM_SIZE_6M_GTB: + info->total_vram = 0x600000; + break; + case MEM_SIZE_8M_GTB: + info->total_vram = 0x800000; + break; + default: + info->total_vram = 0x80000; + } else - switch (i & MEM_SIZE_ALIAS) { - case MEM_SIZE_512K: - info->total_vram = 0x80000; - break; - case MEM_SIZE_1M: - info->total_vram = 0x100000; - break; - case MEM_SIZE_2M: - info->total_vram = 0x200000; - break; - case MEM_SIZE_4M: - info->total_vram = 0x400000; - break; - case MEM_SIZE_6M: - info->total_vram = 0x600000; - break; - case MEM_SIZE_8M: - info->total_vram = 0x800000; - break; - default: - info->total_vram = 0x80000; - } + switch (i & MEM_SIZE_ALIAS) { + case MEM_SIZE_512K: + info->total_vram = 0x80000; + break; + case MEM_SIZE_1M: + info->total_vram = 0x100000; + break; + case MEM_SIZE_2M: + info->total_vram = 0x200000; + break; + case MEM_SIZE_4M: + info->total_vram = 0x400000; + break; + case MEM_SIZE_6M: + info->total_vram = 0x600000; + break; + case MEM_SIZE_8M: + info->total_vram = 0x800000; + break; + default: + info->total_vram = 0x80000; + } if (M64_HAS(MAGIC_VRAM_SIZE)) { - if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000) - info->total_vram += 0x400000; + if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000) + info->total_vram += 0x400000; } if (default_vram) { - info->total_vram = default_vram*1024; - i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); - if (info->total_vram <= 0x80000) - i |= MEM_SIZE_512K; - else if (info->total_vram <= 0x100000) - i |= MEM_SIZE_1M; - else if (info->total_vram <= 0x200000) - i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; - else if (info->total_vram <= 0x400000) - i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; - else if (info->total_vram <= 0x600000) - i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; - else - i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; - aty_st_le32(MEM_CNTL, i, info); + info->total_vram = default_vram*1024; + i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS); + if (info->total_vram <= 0x80000) + i |= MEM_SIZE_512K; + else if (info->total_vram <= 0x100000) + i |= MEM_SIZE_1M; + else if (info->total_vram <= 0x200000) + i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M; + else if (info->total_vram <= 0x400000) + i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M; + else if (info->total_vram <= 0x600000) + i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M; + else + i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M; + aty_st_le32(MEM_CNTL, i, info); } if (default_pll) - pll = default_pll; + pll = default_pll; if (default_mclk) - mclk = default_mclk; - - printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n", - info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), - info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk); - - if (mclk < 44) - info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ - else if (mclk < 50) - info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ - else if (mclk < 55) - info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ - else if (mclk < 66) - info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ - else if (mclk < 75) - info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ - else if (mclk < 80) - info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ - else if (mclk < 100) - info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ + mclk = default_mclk; + if (default_xclk) + xclk = default_xclk; + + printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d Mhz XCLK\n", + info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20), + info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk, + xclk); + + if (xclk < 44) + info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */ + else if (xclk < 50) + info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */ + else if (xclk < 55) + info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */ + else if (xclk < 66) + info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */ + else if (xclk < 75) + info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */ + else if (xclk < 80) + info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */ + else if (xclk < 100) + info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */ else - info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ + info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */ info->pll_per = 1000000/pll; - info->mclk_per = 1000000/mclk; + if ((mclk < 0) || (xclk < 0)) { + info->mclk_per = 0; + info->xclk_per = 0; + } else { + info->mclk_per = 1000000/mclk; + info->xclk_per = 1000000/xclk; + }; #ifdef DEBUG if (M64_HAS(INTEGRATED)) { - int i; - printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " - "DSP_CONFIG DSP_ON_OFF\n" - "%08x %08x %08x %08x %08x %08x %08x\n" - "PLL", - aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info), - aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info), - aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info), - aty_ld_le32(DSP_ON_OFF, info)); - for (i = 0; i < 16; i++) - printk(" %02x", aty_ld_pll(i, info)); - printk("\n"); + int i; + printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " + "DSP_CONFIG DSP_ON_OFF CLOCK_CNTL\n" + "%08x %08x %08x %08x %08x %08x %08x %08x\n" + "PLL", + aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info), + aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info), + aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info), + aty_ld_le32(DSP_ON_OFF, info), aty_ld_le32(CLOCK_CNTL ,info)); + for (i = 0; i < 40; i++) + printk(" %02x", aty_ld_pll(i, info)); + printk("\n"); + } +#endif + info->pll_ops->init_pll(info); +#ifdef DEBUG + if (M64_HAS(INTEGRATED)) { + int i; + printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL " + "DSP_CONFIG DSP_ON_OFF\n" + "%08x %08x %08x %08x %08x %08x %08x\n" + "PLL", + aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info), + aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info), + aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info), + aty_ld_le32(DSP_ON_OFF, info)); + for (i = 0; i < 40; i++) + printk(" %02x", aty_ld_pll(i, info)); + printk("\n"); } #endif @@ -2005,8 +2254,8 @@ * the full 8 MB of video RAM on 8 MB boards */ if (info->total_vram == 0x800000 || - (info->bus_type == ISA && info->total_vram == 0x400000)) - info->total_vram -= GUI_RESERVE; + (info->bus_type == ISA && info->total_vram == 0x400000)) + info->total_vram -= GUI_RESERVE; /* Clear the video memory */ fb_memset((void *)info->frame_buffer, 0, info->total_vram); @@ -2026,12 +2275,12 @@ #ifdef CONFIG_PMAC_BACKLIGHT if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) { - /* these bits let the 101 powerbook wake up from sleep -- paulus */ - aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, info) - | (USE_F32KHZ | TRISTATE_MEM_EN), info); + /* these bits let the 101 powerbook wake up from sleep -- paulus */ + aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, info) + | (USE_F32KHZ | TRISTATE_MEM_EN), info); } if (M64_HAS(MOBIL_BUS)) - register_backlight_controller(&aty_backlight_controller, info, "ati"); + register_backlight_controller(&aty_backlight_controller, info, "ati"); #endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef MODULE @@ -2040,53 +2289,53 @@ memset(&var, 0, sizeof(var)); #ifdef CONFIG_PPC if (_machine == _MACH_Pmac) { - /* - * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it - * applies to all Mac video cards - */ - if (mode_option) { - if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) - var = default_var; - } else { - if (default_vmode == VMODE_CHOOSE) { - if (M64_HAS(G3_PB_1024x768)) - /* G3 PowerBook with 1024x768 LCD */ - default_vmode = VMODE_1024_768_60; - else if (machine_is_compatible("iMac")) - default_vmode = VMODE_1024_768_75; - else if (machine_is_compatible("PowerBook2,1")) - /* iBook with 800x600 LCD */ - default_vmode = VMODE_800_600_60; - else - default_vmode = VMODE_640_480_67; - sense = read_aty_sense(info); - printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n", - sense, mac_map_monitor_sense(sense)); - } - if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_640_480_60; + /* + * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it + * applies to all Mac video cards + */ + if (mode_option) { + if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) + var = default_var; + } else { + if (default_vmode == VMODE_CHOOSE) { + if (M64_HAS(G3_PB_1024x768)) + /* G3 PowerBook with 1024x768 LCD */ + default_vmode = VMODE_1024_768_60; + else if (machine_is_compatible("iMac")) + default_vmode = VMODE_1024_768_75; + else if (machine_is_compatible("PowerBook2,1")) + /* iBook with 800x600 LCD */ + default_vmode = VMODE_800_600_60; + else + default_vmode = VMODE_640_480_67; + sense = read_aty_sense(info); + printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n", + sense, mac_map_monitor_sense(sense)); + } + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_640_480_60; #ifdef CONFIG_NVRAM - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); + if (default_cmode == CMODE_NVRAM) + default_cmode = nvram_read_byte(NV_CMODE); #endif - if (default_cmode < CMODE_8 || default_cmode > CMODE_32) - default_cmode = CMODE_8; - if (mac_vmode_to_var(default_vmode, default_cmode, &var)) - var = default_var; - } + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; + } } else if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) - var = default_var; + var = default_var; #else /* !CONFIG_PPC */ #ifdef __sparc__ if (mode_option) { - if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) - var = default_var; + if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) + var = default_var; } else - var = default_var; + var = default_var; #else if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8)) - var = default_var; + var = default_var; #endif /* !__sparc__ */ #endif /* !CONFIG_PPC */ #endif /* !MODULE */ @@ -2096,49 +2345,66 @@ var.accel_flags |= FB_ACCELF_TEXT; if (var.yres == var.yres_virtual) { - u32 vram = (info->total_vram - (PAGE_SIZE << 2)); - var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual; - if (var.yres_virtual < var.yres) - var.yres_virtual = var.yres; + u32 vram = (info->total_vram - (PAGE_SIZE << 2)); + var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual; + if (var.yres_virtual < var.yres) + var.yres_virtual = var.yres; } - if (atyfb_decode_var(&var, &info->default_par, info)) { - printk("atyfb: can't set default video mode\n"); - return 0; + monitors_enabled = atyfb_monitors_enabled(info); + + if (atyfb_decode_var(&var, &info->default_par, info, monitors_enabled)) { + printk("atyfb: can't set default video mode\n"); + return 0; } #ifdef __sparc__ atyfb_save_palette(&info->fb_info, 0); #endif for (j = 0; j < 16; j++) { - k = color_table[j]; - info->palette[j].red = default_red[k]; - info->palette[j].green = default_grn[k]; - info->palette[j].blue = default_blu[k]; + k = color_table[j]; + info->palette[j].red = default_red[k]; + info->palette[j].green = default_grn[k]; + info->palette[j].blue = default_blu[k]; } #ifdef CONFIG_FB_ATY_CT if (curblink && M64_HAS(INTEGRATED)) { - info->cursor = aty_init_cursor(info); - if (info->cursor) { - info->dispsw.cursor = atyfb_cursor; - info->dispsw.set_font = atyfb_set_font; - } + info->cursor = aty_init_cursor(info); + if (info->cursor) { + info->dispsw.cursor = atyfb_cursor; + info->dispsw.set_font = atyfb_set_font; + } } #endif /* CONFIG_FB_ATY_CT */ atyfb_set_var(&var, -1, &info->fb_info); if (register_framebuffer(&info->fb_info) < 0) - return 0; + return 0; info->next = fb_list; fb_list = info; printk("fb%d: %s frame buffer device on %s\n", - GET_FB_IDX(info->fb_info.node), atyfb_name, name); + GET_FB_IDX(info->fb_info.node), atyfb_name, name); return 1; } + +void __init aty_init_register_array(struct fb_info_aty *info) +{ + u32 **p, **q; + u32 *i; + + i = (u32 *) info->ati_regbase; + p = (u32 **) info->ati_regaddr; + q = p + 256; + do { + *p = i; + i++; + p++; + } while (p != q); +}; int __init atyfb_init(void) { @@ -2157,339 +2423,544 @@ /* Do not attach when we have a serial console. */ if (!con_is_present()) - return -ENXIO; + return -ENXIO; #else u16 tmp; int aux_app; unsigned long raddr; #endif +#if defined(CONFIG_FB_ATY_GENERIC_LCD) + u16 lcd_ofs; + u32 driv_inf_tab,sig,rom_addr; +#endif while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) { - if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { - struct resource *rp; + if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + struct resource *rp; #ifndef __sparc__ - struct resource *rrp; + struct resource *rrp; #endif - for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--) - if (pdev->device == aty_chips[i].pci_id) - break; - if (i < 0) - continue; - - info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); - if (!info) { - printk("atyfb_init: can't alloc fb_info_aty\n"); - return -ENXIO; - } - memset(info, 0, sizeof(struct fb_info_aty)); - - rp = &pdev->resource[0]; - if (rp->flags & IORESOURCE_IO) - rp = &pdev->resource[1]; - addr = rp->start; - if (!addr) - continue; - - res_start = rp->start; - res_size = rp->end-rp->start+1; - if (!request_mem_region(res_start, res_size, "atyfb")) - continue; + for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--) + if (pdev->device == aty_chips[i].pci_id) + break; + if (i < 0) + continue; + + info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + if (!info) { + printk("atyfb_init: can't alloc fb_info_aty\n"); + return -ENXIO; + } + memset(info, 0, sizeof(struct fb_info_aty)); + + rp = &pdev->resource[0]; + if (rp->flags & IORESOURCE_IO) + rp = &pdev->resource[1]; + addr = rp->start; + if (!addr) + continue; + + res_start = rp->start; + res_size = rp->end-rp->start+1; + if (!request_mem_region(res_start, res_size, "atyfb")) + continue; #ifdef __sparc__ - /* - * Map memory-mapped registers. - */ - info->ati_regbase = addr + 0x7ffc00UL; - info->ati_regbase_phys = addr + 0x7ffc00UL; - - /* - * Map in big-endian aperture. - */ - info->frame_buffer = (unsigned long) addr + 0x800000UL; - info->frame_buffer_phys = addr + 0x800000UL; - - /* - * Figure mmap addresses from PCI config space. - * Split Framebuffer in big- and little-endian halfs. - */ - for (i = 0; i < 6 && pdev->resource[i].start; i++) - /* nothing */; - j = i + 4; - - info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); - if (!info->mmap_map) { - printk("atyfb_init: can't alloc mmap_map\n"); - kfree(info); - release_mem_region(res_start, res_size); - return -ENXIO; - } - memset(info->mmap_map, 0, j * sizeof(*info->mmap_map)); - - for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { - struct resource *rp = &pdev->resource[i]; - int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); - unsigned long base; - u32 size, pbase; - - base = rp->start; - - io = (rp->flags & IORESOURCE_IO); - - size = rp->end - base + 1; - - pci_read_config_dword(pdev, breg, &pbase); - - if (io) - size &= ~1; - - /* - * Map the framebuffer a second time, this time without - * the braindead _PAGE_IE setting. This is used by the - * fixed Xserver, but we need to maintain the old mapping - * to stay compatible with older ones... - */ - if (base == addr) { - info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK; - info->mmap_map[j].poff = base & PAGE_MASK; - info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; - info->mmap_map[j].prot_mask = _PAGE_CACHE; - info->mmap_map[j].prot_flag = _PAGE_E; - j++; - } - - /* - * Here comes the old framebuffer mapping with _PAGE_IE - * set for the big endian half of the framebuffer... - */ - if (base == addr) { - info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; - info->mmap_map[j].poff = (base+0x800000) & PAGE_MASK; - info->mmap_map[j].size = 0x800000; - info->mmap_map[j].prot_mask = _PAGE_CACHE; - info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE; - size -= 0x800000; - j++; - } - - info->mmap_map[j].voff = pbase & PAGE_MASK; - info->mmap_map[j].poff = base & PAGE_MASK; - info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; - info->mmap_map[j].prot_mask = _PAGE_CACHE; - info->mmap_map[j].prot_flag = _PAGE_E; - j++; - } - - if (pdev->device != XL_CHIP_ID) { - /* - * Fix PROMs idea of MEM_CNTL settings... - */ - mem = aty_ld_le32(MEM_CNTL, info); - chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); - if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && - !((chip_id >> 24) & 1)) { - switch (mem & 0x0f) { - case 3: - mem = (mem & ~(0x0f)) | 2; - break; - case 7: - mem = (mem & ~(0x0f)) | 3; - break; - case 9: - mem = (mem & ~(0x0f)) | 4; - break; - case 11: - mem = (mem & ~(0x0f)) | 5; - break; - default: - break; - } - if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) - mem &= ~(0x00700000); - } - mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ - aty_st_le32(MEM_CNTL, mem, info); - } - - /* - * If this is the console device, we will set default video - * settings to what the PROM left us with. - */ - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "aliases"); - if (node) { - len = prom_getproperty(node, "screen", prop, sizeof(prop)); - if (len > 0) { - prop[len] = '\0'; - node = prom_finddevice(prop); - } else { - node = 0; - } - } - - pcp = pdev->sysdata; - if (node == pcp->prom_node) { - - struct fb_var_screeninfo *var = &default_var; - unsigned int N, P, Q, M, T, R; - u32 v_total, h_total; - struct crtc crtc; - u8 pll_regs[16]; - u8 clock_cntl; - - crtc.vxres = prom_getintdefault(node, "width", 1024); - crtc.vyres = prom_getintdefault(node, "height", 768); - crtc.bpp = prom_getintdefault(node, "depth", 8); - crtc.xoffset = crtc.yoffset = 0; - crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info); - crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info); - crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info); - crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info); - crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info); - aty_crtc_to_var(&crtc, var); - - h_total = var->xres + var->right_margin + - var->hsync_len + var->left_margin; - v_total = var->yres + var->lower_margin + - var->vsync_len + var->upper_margin; - - /* - * Read the PLL to figure actual Refresh Rate. - */ - clock_cntl = aty_ld_8(CLOCK_CNTL, info); - /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */ - for (i = 0; i < 16; i++) - pll_regs[i] = aty_ld_pll(i, info); - - /* - * PLL Reference Divider M: - */ - M = pll_regs[2]; - - /* - * PLL Feedback Divider N (Dependant on CLOCK_CNTL): - */ - N = pll_regs[7 + (clock_cntl & 3)]; - - /* - * PLL Post Divider P (Dependant on CLOCK_CNTL): - */ - P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); - - /* - * PLL Divider Q: - */ - Q = N / P; - - /* - * Target Frequency: - * - * T * M - * Q = ------- - * 2 * R - * - * where R is XTALIN (= 14318 or 29498 kHz). - */ - if (pdev->device == XL_CHIP_ID) - R = 29498; - else - R = 14318; + /* + * Map memory-mapped registers. + */ + info->ati_regbase = addr + 0x7ffc00UL; + info->ati_regbase_phys = addr + 0x7ffc00UL; + + /* + * Map in big-endian aperture. + */ + info->frame_buffer = (unsigned long) addr + 0x800000UL; + info->frame_buffer_phys = addr + 0x800000UL; + + /* + * Figure mmap addresses from PCI config space. + * Split Framebuffer in big- and little-endian halfs. + */ + for (i = 0; i < 6 && pdev->resource[i].start; i++) + /* nothing */; + j = i + 4; + + info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC); + if (!info->mmap_map) { + printk("atyfb_init: can't alloc mmap_map\n"); + kfree(info); + release_mem_region(res_start, res_size); + return -ENXIO; + } + memset(info->mmap_map, 0, j * sizeof(*info->mmap_map)); + + for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) { + struct resource *rp = &pdev->resource[i]; + int io, breg = PCI_BASE_ADDRESS_0 + (i << 2); + unsigned long base; + u32 size, pbase; + + base = rp->start; + + io = (rp->flags & IORESOURCE_IO); + + size = rp->end - base + 1; + + pci_read_config_dword(pdev, breg, &pbase); + + if (io) + size &= ~1; + + /* + * Map the framebuffer a second time, this time without + * the braindead _PAGE_IE setting. This is used by the + * fixed Xserver, but we need to maintain the old mapping + * to stay compatible with older ones... + */ + if (base == addr) { + info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK; + info->mmap_map[j].poff = base & PAGE_MASK; + info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; + info->mmap_map[j].prot_mask = _PAGE_CACHE; + info->mmap_map[j].prot_flag = _PAGE_E; + j++; + } + + /* + * Here comes the old framebuffer mapping with _PAGE_IE + * set for the big endian half of the framebuffer... + */ + if (base == addr) { + info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK; + info->mmap_map[j].poff = (base+0x800000) & PAGE_MASK; + info->mmap_map[j].size = 0x800000; + info->mmap_map[j].prot_mask = _PAGE_CACHE; + info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE; + size -= 0x800000; + j++; + } + + info->mmap_map[j].voff = pbase & PAGE_MASK; + info->mmap_map[j].poff = base & PAGE_MASK; + info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK; + info->mmap_map[j].prot_mask = _PAGE_CACHE; + info->mmap_map[j].prot_flag = _PAGE_E; + j++; + } + + if (pdev->device != XL_CHIP_ID) { + /* + * Fix PROMs idea of MEM_CNTL settings... + */ + mem = aty_ld_le32(MEM_CNTL, info); + chip_id = aty_ld_le32(CONFIG_CHIP_ID, info); + if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && + !((chip_id >> 24) & 1)) { + switch (mem & 0x0f) { + case 3: + mem = (mem & ~(0x0f)) | 2; + break; + case 7: + mem = (mem & ~(0x0f)) | 3; + break; + case 9: + mem = (mem & ~(0x0f)) | 4; + break; + case 11: + mem = (mem & ~(0x0f)) | 5; + break; + default: + break; + } + if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM) + mem &= ~(0x00700000); + } + mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */ + aty_st_le32(MEM_CNTL, mem, info); + } + + /* + * If this is the console device, we will set default video + * settings to what the PROM left us with. + */ + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "aliases"); + if (node) { + len = prom_getproperty(node, "screen", prop, sizeof(prop)); + if (len > 0) { + prop[len] = '\0'; + node = prom_finddevice(prop); + } else { + node = 0; + } + } + + pcp = pdev->sysdata; + if (node == pcp->prom_node) { + + struct fb_var_screeninfo *var = &default_var; + unsigned int N, P, Q, M, T, R; + u32 v_total, h_total; + struct crtc crtc; + u8 pll_regs[16]; + u8 clock_cntl; + + crtc.vxres = prom_getintdefault(node, "width", 1024); + crtc.vyres = prom_getintdefault(node, "height", 768); + crtc.bpp = prom_getintdefault(node, "depth", 8); + crtc.xoffset = crtc.yoffset = 0; + crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info); + crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info); + crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info); + crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info); + crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info); + aty_crtc_to_var(&crtc, var); + + h_total = var->xres + var->right_margin + + var->hsync_len + var->left_margin; + v_total = var->yres + var->lower_margin + + var->vsync_len + var->upper_margin; + + /* + * Read the PLL to figure actual Refresh Rate. + */ + clock_cntl = aty_ld_8(CLOCK_CNTL, info); + /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */ + for (i = 0; i < 16; i++) + pll_regs[i] = aty_ld_pll(i, info); + + /* + * PLL Reference Divider M: + */ + M = pll_regs[2]; + + /* + * PLL Feedback Divider N (Dependant on CLOCK_CNTL): + */ + N = pll_regs[7 + (clock_cntl & 3)]; + + /* + * PLL Post Divider P (Dependant on CLOCK_CNTL): + */ + P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); + + /* + * PLL Divider Q: + */ + Q = N / P; + + /* + * Target Frequency: + * + * T * M + * Q = ------- + * 2 * R + * + * where R is XTALIN (= 14318 or 29498 kHz). + */ + if (pdev->device == XL_CHIP_ID) + R = 29498; + else + R = 14318; - T = 2 * Q * R / M; + T = 2 * Q * R / M; - default_var.pixclock = 1000000000 / T; - } + default_var.pixclock = 1000000000 / T; + } #else /* __sparc__ */ - aux_app = 0; - raddr = addr + 0x7ff000UL; - rrp = &pdev->resource[2]; - if ((rrp->flags & IORESOURCE_MEM) - && request_mem_region(rrp->start, rrp->end - rrp->start + 1, - "atyfb")) { - aux_app = 1; - raddr = rrp->start; - printk(KERN_INFO "atyfb: using auxiliary register aperture\n"); - } - - info->ati_regbase_phys = raddr; - info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000); - - if(!info->ati_regbase) { - kfree(info); - release_mem_region(res_start, res_size); - return -ENOMEM; - } - - info->ati_regbase_phys += aux_app? 0x400: 0xc00; - info->ati_regbase += aux_app? 0x400: 0xc00; - - /* - * Enable memory-space accesses using config-space - * command register. - */ - pci_read_config_word(pdev, PCI_COMMAND, &tmp); - if (!(tmp & PCI_COMMAND_MEMORY)) { - tmp |= PCI_COMMAND_MEMORY; - pci_write_config_word(pdev, PCI_COMMAND, tmp); - } + aux_app = 0; + raddr = addr + 0x7ff000UL; + rrp = &pdev->resource[2]; + if ((rrp->flags & IORESOURCE_MEM) + && request_mem_region(rrp->start, rrp->end - rrp->start + 1, + "atyfb")) { + aux_app = 1; + raddr = rrp->start; + printk(KERN_INFO "atyfb: using auxiliary register aperture\n"); + } + + info->ati_regbase_phys = raddr; + info->ati_regbase = (unsigned long) ioremap(raddr, 0x1000); + + if(!info->ati_regbase) { + kfree(info); + release_mem_region(res_start, res_size); + return -ENOMEM; + } + + info->ati_regbase_phys += aux_app? 0x400: 0xc00; + info->ati_regbase += aux_app? 0x400: 0xc00; + + /* + * Enable memory-space accesses using config-space + * command register. + */ + pci_read_config_word(pdev, PCI_COMMAND, &tmp); + if (!(tmp & PCI_COMMAND_MEMORY)) { + tmp |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, tmp); + } #ifdef __BIG_ENDIAN - /* Use the big-endian aperture */ - addr += 0x800000; + /* Use the big-endian aperture */ + addr += 0x800000; #endif - /* Map in frame buffer */ - info->frame_buffer_phys = addr; - info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); - - if(!info->frame_buffer) { - kfree(info); - release_mem_region(res_start, res_size); - return -ENXIO; - } + /* Map in frame buffer */ + info->frame_buffer_phys = addr; + info->frame_buffer = (unsigned long)ioremap(addr, 0x800000); + + aty_init_register_array(info); + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* To support an LCD panel, we should know it's dimensions and + it's desired pixel clock. + There are two ways to do it: + - Check the startup video mode and calculate the panel + size from it. This is unreliable. + - Read it from the driver information table in the video BIOS. + + So, we try to find a BIOS and get access to it. + */ + rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1,info) & 0x7f) << 11); + info->bios_base_phys = rom_addr; + info->bios_base = (unsigned long)ioremap(rom_addr,0x10000); + + /* The BIOS starts with 0xaa55. */ + if (*((u16 *)info->bios_base) == 0xaa55) { + printk(KERN_INFO "atyfb: Mach64 BIOS is located at %x, mapped at %x.\n", + (u32)info->bios_base_phys,(u32)info->bios_base); + + /* Address of driver information table is at offset 0x78. */ + driv_inf_tab=info->bios_base + *((u16 *)(info->bios_base+0x78)); + + /* Check for the driver information table signature. */ + sig = (*(u32 *)driv_inf_tab); + if ((sig == 0x54504c24) || /* Rage LT pro */ + (sig == 0x544d5224) || /* Rage mobility */ + (sig == 0x54435824) || /* Rage XC */ + (sig == 0x544c5824)) { /* Rage XL */ + printk(KERN_INFO "atyfb: BIOS contains driver information table.\n"); + lcd_ofs = (*(u16 *)(driv_inf_tab + 10)); + info->lcd_table = 0; + if (lcd_ofs != 0) { + info->lcd_table = info->bios_base + lcd_ofs; + }; + }; + }; + if (info->lcd_table != 0) { + char model[24]; + char strbuf[16]; + char refresh_rates_buf[100]; + int id,tech,f,i,m,default_refresh_rate; + char *txtcolour; + char *txtmonitor; + char *txtdual; + char *txtformat; + u16 width,height,panel_type,refresh_rates; + u16 *lcdmodeptr; + u32 format; + u8 lcd_refresh_rates[16] = {50,56,60,67,70,72,75,76,85,90,100,120,140,150,160,200}; + /* The most important information is the panel size at + offset 25 and 27, but there's some other nice information + which we print to the screen. + */ + id = *(u8 *)info->lcd_table; + strncpy(model,(char *)info->lcd_table+1,24); + model[23]=0; + + width = info->lcd_width = *(u16 *)(info->lcd_table+25); + height = info->lcd_height = *(u16 *)(info->lcd_table+27); + panel_type = *(u16 *)(info->lcd_table+29); + if (panel_type & 1) + txtcolour = "colour"; + else + txtcolour = "monochrome"; + if (panel_type & 2) + txtdual = "dual (split) "; + else + txtdual = ""; + tech = (panel_type>>2) & 63; + switch (tech) { + case 0: + txtmonitor = "passive matrix"; + break; + case 1: + txtmonitor = "active matrix"; + break; + case 2: + txtmonitor = "active addressed STN"; + break; + case 3: + txtmonitor = "EL"; + break; + case 4: + txtmonitor = "plasma"; + break; + default: + txtmonitor = "unknown"; + }; + format = *(u32 *)(info->lcd_table+57); + if (tech == 0 || tech == 2) { + switch (format & 7) { + case 0: + txtformat = "12 bit interface"; + break; + case 1: + txtformat = "16 bit interface"; + break; + case 2: + txtformat = "24 bit interface"; + break; + default: + txtformat = "unkown format"; + }; + } else { + switch (format & 7) { + case 0: + txtformat = "8 colours"; + break; + case 1: + txtformat = "512 colours"; + break; + case 2: + txtformat = "4096 colours"; + break; + case 4: + txtformat = "262144 colours (LT mode)"; + break; + case 5: + txtformat = "16777216 colours"; + break; + case 6: + txtformat = "262144 colours (FDPI-2 mode)"; + break; + default: + txtformat = "unkown format"; + }; + }; + printk(KERN_INFO "atyfb: %s%s %s monitor detected: %s\n id=%d, %dx%d pixels, %s\n", + txtdual,txtcolour,txtmonitor,model,id,width,height,txtformat); + refresh_rates_buf[0] = 0; + refresh_rates = *(u16 *)(info->lcd_table+62); + m = 1; + f = 0; + for (i=0;i<16;i++) { + if (refresh_rates & m) { + if (f == 0) { + sprintf(strbuf,"%d",lcd_refresh_rates[i]); + f++; + } else + sprintf(strbuf,",%d",lcd_refresh_rates[i]); + strcat(refresh_rates_buf,strbuf); + }; + m = m << 1; + }; + default_refresh_rate = (*(u8 *)(info->lcd_table+61) & 0xf0) >> 4; + printk(KERN_INFO " supports %s Hz refresh rates, default %d Hz\n", + refresh_rates_buf,lcd_refresh_rates[default_refresh_rate]); + /* We now need to determine the crtc parameters for the + lcd monitor. This is tricky, because they are not stored + individually in the BIOS. Instead, the BIOS contains a + table of display modes that work for this monitor. + + The idea is that we search for a mode of the same dimensions + as the dimensions of the lcd monitor. Say our lcd monitor + is 800x600 pixels, we search for a 800x600 monitor. + The CRTC parameters we find here are the ones that we need + to use to simulate other resolutions on the lcd screen. + */ + lcdmodeptr = (u16 *)(info->lcd_table + 64); + while (*lcdmodeptr != 0) { + u32 modeptr; + u16 mwidth,mheight; + modeptr = info->bios_base + *lcdmodeptr; + + mwidth = *((u16 *)(modeptr+0)); + mheight = *((u16 *)(modeptr+2)); + + if (mwidth == width && mheight == height) { + info->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9)); + info->lcd_htotal = *((u16 *)(modeptr+17)) & 511; + info->lcd_hdisp = *((u16 *)(modeptr+19)) & 511; + info->lcd_hsync_start = *((u16 *)(modeptr+21)) & 511; + info->lcd_hsync_delay = (*((u16 *)(modeptr+21)) >> 9) & 7; + info->lcd_hsync_width = *((u8 *)(modeptr+23)) & 63; + info->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047; + info->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047; + info->lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047; + info->lcd_vsync_width = (*((u16 *)(modeptr+28)) >> 11) & 31; + info->lcd_right = info->lcd_hsync_start - info->lcd_hdisp; + info->lcd_lower = info->lcd_vsync_start - info->lcd_vdisp; + info->lcd_hblank_width = info->lcd_htotal - info->lcd_hdisp; + info->lcd_vblank_width = info->lcd_vtotal - info->lcd_vdisp; + break; + }; + + lcdmodeptr++; + }; + if (*lcdmodeptr == 0) { + printk(KERN_WARNING "atyfb: LCD monitor CRTC parameters not found!!!\n"); + /* To do: Switch to CRT if possible. */ + } else { + printk(KERN_INFO " LCD CRTC parameters: %d %d %d %d %d %d %d %d %d %d\n", + info->lcd_pixclock,info->lcd_htotal,info->lcd_hdisp,info->lcd_hsync_start, + info->lcd_hsync_delay,info->lcd_hsync_width,info->lcd_vtotal,info->lcd_vdisp, + info->lcd_vsync_start,info->lcd_vsync_width); + }; + }; +#endif + + if(!info->frame_buffer) { + kfree(info); + release_mem_region(res_start, res_size); + return -ENXIO; + } #endif /* __sparc__ */ - if (!aty_init(info, "PCI")) { - if (info->mmap_map) - kfree(info->mmap_map); - kfree(info); - release_mem_region(res_start, res_size); - return -ENXIO; - } + if (!aty_init(info, "PCI")) { + if (info->mmap_map) + kfree(info->mmap_map); + kfree(info); + release_mem_region(res_start, res_size); + return -ENXIO; + } #ifdef __sparc__ - if (!prom_palette) - prom_palette = atyfb_palette; + if (!prom_palette) + prom_palette = atyfb_palette; - /* - * Add /dev/fb mmap values. - */ - info->mmap_map[0].voff = 0x8000000000000000UL; - info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; - info->mmap_map[0].size = info->total_vram; - info->mmap_map[0].prot_mask = _PAGE_CACHE; - info->mmap_map[0].prot_flag = _PAGE_E; - info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram; - info->mmap_map[1].poff = info->ati_regbase & PAGE_MASK; - info->mmap_map[1].size = PAGE_SIZE; - info->mmap_map[1].prot_mask = _PAGE_CACHE; - info->mmap_map[1].prot_flag = _PAGE_E; + /* + * Add /dev/fb mmap values. + */ + info->mmap_map[0].voff = 0x8000000000000000UL; + info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK; + info->mmap_map[0].size = info->total_vram; + info->mmap_map[0].prot_mask = _PAGE_CACHE; + info->mmap_map[0].prot_flag = _PAGE_E; + info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram; + info->mmap_map[1].poff = info->ati_regbase & PAGE_MASK; + info->mmap_map[1].size = PAGE_SIZE; + info->mmap_map[1].prot_mask = _PAGE_CACHE; + info->mmap_map[1].prot_flag = _PAGE_E; #endif /* __sparc__ */ #ifdef CONFIG_PMAC_PBOOK - if (first_display == NULL) - pmu_register_sleep_notifier(&aty_sleep_notifier); - info->next = first_display; - first_display = info; + if (first_display == NULL) + pmu_register_sleep_notifier(&aty_sleep_notifier); + info->next = first_display; + first_display = info; #endif #ifdef CONFIG_FB_COMPAT_XPMAC - if (!console_fb_info) - console_fb_info = &info->fb_info; + if (!console_fb_info) + console_fb_info = &info->fb_info; #endif /* CONFIG_FB_COMPAT_XPMAC */ - } + } } #elif defined(CONFIG_ATARI) @@ -2498,54 +2969,52 @@ struct fb_info_aty *info; for (m64_num = 0; m64_num < mach64_count; m64_num++) { - if (!phys_vmembase[m64_num] || !phys_size[m64_num] || - !phys_guiregbase[m64_num]) { - printk(" phys_*[%d] parameters not set => returning early. \n", - m64_num); - continue; - } - - info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); - if (!info) { - printk("atyfb_init: can't alloc fb_info_aty\n"); - return -ENOMEM; - } - memset(info, 0, sizeof(struct fb_info_aty)); - - /* - * Map the video memory (physical address given) to somewhere in the - * kernel address space. - */ - info->frame_buffer = (unsigned long)ioremap(phys_vmembase[m64_num], - phys_size[m64_num]); - info->frame_buffer_phys = info->frame_buffer; /* Fake! */ - info->ati_regbase = (unsigned long)ioremap(phys_guiregbase[m64_num], - 0x10000)+0xFC00ul; - info->ati_regbase_phys = info->ati_regbase; /* Fake! */ - - aty_st_le32(CLOCK_CNTL, 0x12345678, info); - clock_r = aty_ld_le32(CLOCK_CNTL, info); - - switch (clock_r & 0x003F) { - case 0x12: - info->clk_wr_offset = 3; /* */ - break; - case 0x34: - info->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ - break; - case 0x16: - info->clk_wr_offset = 1; /* */ - break; - case 0x38: - info->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ - break; - } - - if (!aty_init(info, "ISA bus")) { - kfree(info); - /* This is insufficient! kernel_map has added two large chunks!! */ - return -ENXIO; - } + if (!phys_vmembase[m64_num] || !phys_size[m64_num] || + !phys_guiregbase[m64_num]) { + printk(" phys_*[%d] parameters not set => returning early. \n", + m64_num); + continue; + } + + info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC); + if (!info) { + printk("atyfb_init: can't alloc fb_info_aty\n"); + return -ENOMEM; + } + memset(info, 0, sizeof(struct fb_info_aty)); + + /* + * Map the video memory (physical address given) to somewhere in the + * kernel address space. + */ + info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->frame_buffer_phys = info->frame_buffer; /* Fake! */ + info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul; + info->ati_regbase_phys = info->ati_regbase; /* Fake! */ + + aty_st_le32(CLOCK_CNTL, 0x12345678, info); + clock_r = aty_ld_le32(CLOCK_CNTL, info); + + switch (clock_r & 0x003F) { + case 0x12: + info->clk_wr_offset = 3; /* */ + break; + case 0x34: + info->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */ + break; + case 0x16: + info->clk_wr_offset = 1; /* */ + break; + case 0x38: + info->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */ + break; + } + + if (!aty_init(info, "ISA bus")) { + kfree(info); + /* This is insufficient! kernel_map has added two large chunks!! */ + return -ENXIO; + } } #endif /* CONFIG_ATARI */ return 0; @@ -2557,69 +3026,71 @@ char *this_opt; if (!options || !*options) - return 0; + return 0; while ((this_opt = strsep(&options, ",")) != NULL) { - if (!strncmp(this_opt, "font:", 5)) { - char *p; - int i; - - p = this_opt + 5; - for (i = 0; i < sizeof(fontname) - 1; i++) - if (!*p || *p == ' ' || *p == ',') - break; - memcpy(fontname, this_opt + 5, i); - fontname[i] = 0; - } else if (!strncmp(this_opt, "noblink", 7)) { - curblink = 0; - } else if (!strncmp(this_opt, "noaccel", 7)) { - noaccel = 1; - } else if (!strncmp(this_opt, "vram:", 5)) - default_vram = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "pll:", 4)) - default_pll = simple_strtoul(this_opt+4, NULL, 0); - else if (!strncmp(this_opt, "mclk:", 5)) - default_mclk = simple_strtoul(this_opt+5, NULL, 0); + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt + 5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } else if (!strncmp(this_opt, "noblink", 7)) { + curblink = 0; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else if (!strncmp(this_opt, "vram:", 5)) + default_vram = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "pll:", 4)) + default_pll = simple_strtoul(this_opt+4, NULL, 0); + else if (!strncmp(this_opt, "mclk:", 5)) + default_mclk = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "xclk:", 5)) + default_xclk = simple_strtoul(this_opt+5, NULL, 0); #ifdef CONFIG_PPC - else if (!strncmp(this_opt, "vmode:", 6)) { - unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); - if (vmode > 0 && vmode <= VMODE_MAX) - default_vmode = vmode; - } else if (!strncmp(this_opt, "cmode:", 6)) { - unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); - switch (cmode) { - case 0: - case 8: - default_cmode = CMODE_8; - break; - case 15: - case 16: - default_cmode = CMODE_16; - break; - case 24: - case 32: - default_cmode = CMODE_32; - break; - } - } + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } #endif #ifdef CONFIG_ATARI - /* - * Why do we need this silly Mach64 argument? - * We are already here because of mach64= so its redundant. - */ - else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { - static unsigned char m64_num; - static char mach64_str[80]; - strncpy(mach64_str, this_opt+7, 80); - if (!store_video_par(mach64_str, m64_num)) { - m64_num++; - mach64_count = m64_num; - } - } + /* + * Why do we need this silly Mach64 argument? + * We are already here because of mach64= so its redundant. + */ + else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) { + static unsigned char m64_num; + static char mach64_str[80]; + strncpy(mach64_str, this_opt+7, 80); + if (!store_video_par(mach64_str, m64_num)) { + m64_num++; + mach64_count = m64_num; + } + } #endif - else - mode_option = this_opt; + else + mode_option = this_opt; } return 0; } @@ -2634,20 +3105,20 @@ printk("store_video_par() '%s' \n", video_str); if (!(p = strtoke(video_str, ";")) || !*p) - goto mach64_invalid; + goto mach64_invalid; vmembase = simple_strtoul(p, NULL, 0); if (!(p = strtoke(NULL, ";")) || !*p) - goto mach64_invalid; + goto mach64_invalid; size = simple_strtoul(p, NULL, 0); if (!(p = strtoke(NULL, ";")) || !*p) - goto mach64_invalid; + goto mach64_invalid; guiregbase = simple_strtoul(p, NULL, 0); phys_vmembase[m64_num] = vmembase; phys_size[m64_num] = size; phys_guiregbase[m64_num] = guiregbase; printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size, - guiregbase); + guiregbase); return 0; mach64_invalid: @@ -2662,14 +3133,14 @@ sbegin = s ? s : ssave; if (!sbegin) - return NULL; + return NULL; if (*sbegin == '\0') { - ssave = NULL; - return NULL; + ssave = NULL; + return NULL; } send = strpbrk(sbegin, ct); if (send && *send != '\0') - *send++ = '\0'; + *send++ = '\0'; ssave = send; return sbegin; } @@ -2679,24 +3150,27 @@ { struct fb_info_aty *info = (struct fb_info_aty *)fb; struct atyfb_par par; + u32 monitors_enabled; /* Do we have to save the colormap? */ if (fb_display[currcon].cmap.len) - fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb); + fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb); #ifdef CONFIG_FB_ATY_CT /* Erase HW Cursor */ if (info->cursor) - atyfb_cursor(&fb_display[currcon], CM_ERASE, - info->cursor->pos.x, info->cursor->pos.y); + atyfb_cursor(&fb_display[currcon], CM_ERASE, + info->cursor->pos.x, info->cursor->pos.y); #endif /* CONFIG_FB_ATY_CT */ currcon = con; - atyfb_decode_var(&fb_display[con].var, &par, info); + monitors_enabled = atyfb_monitors_enabled(info); + + atyfb_decode_var(&fb_display[con].var, &par, info, monitors_enabled); atyfb_set_par(&par, info); atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp, - par.accel_flags & FB_ACCELF_TEXT); + par.accel_flags & FB_ACCELF_TEXT); /* Install new colormap */ do_install_cmap(con, fb); @@ -2704,8 +3178,8 @@ #ifdef CONFIG_FB_ATY_CT /* Install hw cursor */ if (info->cursor) { - aty_set_cursor_color(info); - aty_set_cursor_shape(info); + aty_set_cursor_color(info); + aty_set_cursor_shape(info); } #endif /* CONFIG_FB_ATY_CT */ return 1; @@ -2722,32 +3196,32 @@ #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) - set_backlight_enable(0); + set_backlight_enable(0); #endif /* CONFIG_PMAC_BACKLIGHT */ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); if (blank > 0) - switch (blank-1) { - case VESA_NO_BLANKING: - gen_cntl |= 0x40; - break; - case VESA_VSYNC_SUSPEND: - gen_cntl |= 0x8; - break; - case VESA_HSYNC_SUSPEND: - gen_cntl |= 0x4; - break; - case VESA_POWERDOWN: - gen_cntl |= 0x4c; - break; - } + switch (blank-1) { + case VESA_NO_BLANKING: + gen_cntl |= 0x40; + break; + case VESA_VSYNC_SUSPEND: + gen_cntl |= 0x8; + break; + case VESA_HSYNC_SUSPEND: + gen_cntl |= 0x4; + break; + case VESA_POWERDOWN: + gen_cntl |= 0x4c; + break; + } else - gen_cntl &= ~(0x4c); + gen_cntl &= ~(0x4c); aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); #ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) - set_backlight_enable(1); + set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ } @@ -2758,12 +3232,12 @@ */ static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, - u_int *transp, struct fb_info *fb) + u_int *transp, struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; if (regno > 255) - return 1; + return 1; *red = (info->palette[regno].red<<8) | info->palette[regno].red; *green = (info->palette[regno].green<<8) | info->palette[regno].green; *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue; @@ -2779,13 +3253,13 @@ */ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *fb) + u_int transp, struct fb_info *fb) { struct fb_info_aty *info = (struct fb_info_aty *)fb; int i, scale; if (regno > 255) - return 1; + return 1; red >>= 8; green >>= 8; blue >>= 8; @@ -2794,42 +3268,35 @@ info->palette[regno].blue = blue; i = aty_ld_8(DAC_CNTL, info) & 0xfc; if (M64_HAS(EXTRA_BRIGHT)) - i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ + i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/ aty_st_8(DAC_CNTL, i, info); aty_st_8(DAC_MASK, 0xff, info); scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0; -#ifdef CONFIG_ATARI - out_8(&info->aty_cmap_regs->windex, regno << scale); - out_8(&info->aty_cmap_regs->lut, red); - out_8(&info->aty_cmap_regs->lut, green); - out_8(&info->aty_cmap_regs->lut, blue); -#else writeb(regno << scale, &info->aty_cmap_regs->windex); writeb(red, &info->aty_cmap_regs->lut); writeb(green, &info->aty_cmap_regs->lut); writeb(blue, &info->aty_cmap_regs->lut); -#endif if (regno < 16) - switch (info->current_par.crtc.bpp) { + switch (info->current_par.crtc.bpp) { #ifdef FBCON_HAS_CFB16 - case 16: - info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | - regno; - break; + case 16: + info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | + regno; + break; #endif #ifdef FBCON_HAS_CFB24 - case 24: - info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | - regno; - break; + case 24: + info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | + regno; + break; #endif #ifdef FBCON_HAS_CFB32 - case 32: - i = (regno << 8) | regno; - info->fbcon_cmap.cfb32[regno] = (i << 16) | i; - break; + case 32: + i = (regno << 8) | regno; + info->fbcon_cmap.cfb32[regno] = (i << 16) | i; + break; #endif - } + } return 0; } @@ -2837,12 +3304,12 @@ static void do_install_cmap(int con, struct fb_info *info) { if (con != currcon) - return; + return; if (fb_display[con].cmap.len) - fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); + fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info); else { - int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; - fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info); + int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; + fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info); } } @@ -2866,27 +3333,27 @@ height = yres - conp->vc_rows * fontheight(p); if (height && (yoffset + yres > sy)) { - u32 xres, xoffset; - u32 bgx; + u32 xres, xoffset; + u32 bgx; - xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; - xoffset = fb_display[con].var.xoffset; + xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8; + xoffset = fb_display[con].var.xoffset; - bgx = attr_bgcol_ec(p, conp); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - - if (sy + height > par->crtc.vyres) { - wait_for_fifo(1, info); - aty_st_le32(SC_BOTTOM, sy + height - 1, info); - } - aty_rectfill(xoffset, sy, xres, height, bgx, info); + bgx = attr_bgcol_ec(p, conp); + bgx |= (bgx << 8); + bgx |= (bgx << 16); + + if (sy + height > par->crtc.vyres) { + wait_for_fifo(1, info); + aty_st_le32(SC_BOTTOM, sy + height - 1, info); + } + aty_rectfill(xoffset, sy, xres, height, bgx, info); } #ifdef CONFIG_FB_ATY_CT if (info->cursor && (yoffset + yres <= sy)) - atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); + atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y); #endif /* CONFIG_FB_ATY_CT */ info->current_par.crtc.yoffset = yoffset; @@ -2906,34 +3373,50 @@ void cleanup_module(void) { while (fb_list) { - struct fb_info_aty *info = fb_list; - fb_list = info->next; + struct fb_info_aty *info = fb_list; + fb_list = info->next; - unregister_framebuffer(&info->fb_info); + unregister_framebuffer(&info->fb_info); #ifndef __sparc__ - if (info->ati_regbase) - iounmap((void *)info->ati_regbase); - if (info->frame_buffer) - iounmap((void *)info->frame_buffer); + if (info->ati_regbase) + iounmap((void *)info->ati_regbase); + if (info->frame_buffer) + iounmap((void *)info->frame_buffer); #ifdef __BIG_ENDIAN - if (info->cursor && info->cursor->ram) - iounmap(info->cursor->ram); + if (info->cursor && info->cursor->ram) + iounmap(info->cursor->ram); #endif #endif - if (info->cursor) { - if (info->cursor->timer) - kfree(info->cursor->timer); - kfree(info->cursor); - } + if (info->cursor) { + if (info->cursor->timer) + kfree(info->cursor->timer); + kfree(info->cursor); + } #ifdef __sparc__ - if (info->mmap_map) - kfree(info->mmap_map); + if (info->mmap_map) + kfree(info->mmap_map); #endif - kfree(info); + kfree(info); } } #endif MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Geert Uytterhoeven, Bernd Harries, Eddie C. Dost, Daniel Mantione"); +MODULE_DESCRIPTION("Accelerated FBDev driver for ATI Mach64 and derivates"); + +MODULE_PARM(curblink, "i"); +MODULE_PARM_DESC(noblink, "Enable(1) or disable(0) cursor blinking"); +MODULE_PARM(noaccel, "i"); +MODULE_PARM_DESC(noaccel, "Disable(1) or enable(0) 2d acceleration"); +MODULE_PARM(default_vram, "i"); +MODULE_PARM_DESC(default_vram, "Specify the amount of available video memory"); +MODULE_PARM(default_pll, "i"); +MODULE_PARM_DESC(default_pll, "Specify the maximum PLL rate"); +MODULE_PARM(default_mclk, "i"); +MODULE_PARM_DESC(default_mclk, "Program the chip clock frequency (in MHz)"); +MODULE_PARM(default_xclk, "i"); +MODULE_PARM_DESC(default_xclk, "Program the memory clock frequency (in MHz)"); + diff -urN linux-2.4.22-bk11/drivers/video/aty/mach64.h linux-2.4.22-bk12/drivers/video/aty/mach64.h --- linux-2.4.22-bk11/drivers/video/aty/mach64.h 2001-07-31 14:43:29.000000000 -0700 +++ linux-2.4.22-bk12/drivers/video/aty/mach64.h 2003-09-06 03:00:27.000000000 -0700 @@ -726,6 +726,10 @@ #define VCLK2_POST 0x30 #define VCLK3_POST 0xC0 +#define EXT_VPLL_EN 0x04 +#define EXT_VPLL_VGA_EN 0x08 +#define EXT_VPLL_INSYNC 0x10 + /* CONFIG_CNTL register constants */ #define APERTURE_4M_ENABLE 1 #define APERTURE_8M_ENABLE 2 @@ -946,6 +950,7 @@ #define SRC_15BPP 0x300 #define SRC_16BPP 0x400 #define SRC_32BPP 0x600 +#define HOST_TRIPLE_EN 0x2000 #define HOST_1BPP 0 #define HOST_4BPP 0x10000 #define HOST_8BPP 0x20000 @@ -1148,6 +1153,69 @@ #define APC_LUT_MN 0x39 #define APC_LUT_OP 0x3A +/* Values in CONFIG_PANEL */ + +#define DONT_SHADOW_HEND 0x00004000ul + +/* Values in LCD_GEN_CTRL */ +#define CRT_ON 0x00000001ul +#define LCD_ON 0x00000002ul +#define HORZ_DIVBY2_EN 0x00000004ul +#define DONT_DS_ICON 0x00000008ul +#define LOCK_8DOT 0x00000010ul +#define ICON_ENABLE 0x00000020ul +#define DONT_SHADOW_VPAR 0x00000040ul +#define V2CLK_PM_EN 0x00000080ul +#define RST_FM 0x00000100ul +#define DISABLE_PCLK_RESET 0x00000200ul /* XC/XL */ +#define DIS_HOR_CRT_DIVBY2 0x00000400ul +#define SCLK_SEL 0x00000800ul +#define SCLK_DELAY 0x0000f000ul +#define TVCLK_PM_EN 0x00010000ul +#define VCLK_DAC_PM_EN 0x00020000ul +#define VCLK_LCD_OFF 0x00040000ul +#define SELECT_WAIT_4MS 0x00080000ul +#define XTALIN_PM_EN 0x00080000ul /* XC/XL */ +#define V2CLK_DAC_PM_EN 0x00100000ul +#define LVDS_EN 0x00200000ul +#define LVDS_PLL_EN 0x00400000ul +#define LVDS_PLL_RESET 0x00800000ul +#define LVDS_RESERVED_BITS 0x07000000ul +#define CRTC_RW_SELECT 0x08000000ul /* LTPro */ +#define USE_SHADOWED_VEND 0x10000000ul +#define USE_SHADOWED_ROWCUR 0x20000000ul +#define SHADOW_EN 0x40000000ul +#define SHADOW_RW_EN 0x80000000ul + +/* Values in HORZ_STRETCHING */ +#define HORZ_STRETCH_BLEND 0x00000ffful +#define HORZ_STRETCH_RATIO 0x0000fffful +#define HORZ_STRETCH_LOOP 0x00070000ul +#define HORZ_STRETCH_LOOP09 0x00000000ul +#define HORZ_STRETCH_LOOP11 0x00010000ul +#define HORZ_STRETCH_LOOP12 0x00020000ul +#define HORZ_STRETCH_LOOP14 0x00030000ul +#define HORZ_STRETCH_LOOP15 0x00040000ul +/* ? 0x00050000ul */ +/* ? 0x00060000ul */ +/* ? 0x00070000ul */ +/* ? 0x00080000ul */ +#define HORZ_PANEL_SIZE 0x0ff00000ul /* XC/XL */ +/* ? 0x10000000ul */ +#define AUTO_HORZ_RATIO 0x20000000ul /* XC/XL */ +#define HORZ_STRETCH_MODE 0x40000000ul +#define HORZ_STRETCH_EN 0x80000000ul + +/* Values in VERT_STRETCHING */ +#define VERT_STRETCH_RATIO0 0x000003fful +#define VERT_STRETCH_RATIO1 0x000ffc00ul +#define VERT_STRETCH_RATIO2 0x3ff00000ul +#define VERT_STRETCH_USE0 0x40000000ul +#define VERT_STRETCH_EN 0x80000000ul + +/* Values in EXT_VERT_STRETCH */ +#define AUTO_VERT_RATIO 0x00400000ul +#define VERT_STRETCH_MODE 0x00000400ul /* Values in LCD_MISC_CNTL */ #define BIAS_MOD_LEVEL_MASK 0x0000ff00 diff -urN linux-2.4.22-bk11/drivers/video/aty/mach64_ct.c linux-2.4.22-bk12/drivers/video/aty/mach64_ct.c --- linux-2.4.22-bk11/drivers/video/aty/mach64_ct.c 2001-07-31 14:43:29.000000000 -0700 +++ linux-2.4.22-bk12/drivers/video/aty/mach64_ct.c 2003-09-06 03:00:27.000000000 -0700 @@ -16,28 +16,99 @@ /* FIXME: remove the FAIL definition */ #define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) -static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info); +static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) stdcall; static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, struct pll_ct *pll); -static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, +static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, u32 stretch, struct pll_ct *pll); static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, - u8 bpp, union aty_pll *pll); + u8 bpp, u32 stretch, union aty_pll *pll); static u32 aty_pll_ct_to_var(const struct fb_info_aty *info, const union aty_pll *pll); +/* + * ATI Mach64 CT clock synthesis description. + * + * All clocks on the Mach64 can be calculated using the same principle: + * + * XTALIN * x * FB_DIV + * CLK = ---------------------- + * PLL_REF_DIV * POST_DIV + * + * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz. + * PLL_REF_DIV can be set by the user, but is the same for all clocks. + * FB_DIV can be set by the user for each clock individually, it should be set + * between 128 and 255, the chip will generate a bad clock signal for too low + * values. + * x depends on the type of clock; usually it is 2, but for the MCLK it can also + * be set to 4. + * POST_DIV can be set by the user for each clock individually, Possible values + * are 1,2,4,8 and for some clocks other values are available too. + * CLK is of course the clock speed that is generated. + * + * The Mach64 has these clocks: + * + * MCLK The clock rate of the chip + * XCLK The clock rate of the on-chip memory + * VCLK0 First pixel clock of first CRT controller + * VCLK1 Second pixel clock of first CRT controller + * VCLK2 Third pixel clock of first CRT controller + * VCLK3 Fourth pixel clock of first CRT controller + * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3 + * V2CLK Pixel clock of the second CRT controller. + * SCLK Multi-purpose clock + * + * - MCLK and XCLK use the same FB_DIV + * - VCLK0 .. VCLK3 use the same FB_DIV + * - V2CLK is needed when the second CRTC is used (can be used for dualhead); + * i.e. CRT monitor connected to laptop has different resolution than built + * in LCD monitor. + * - SCLK is not available on all cards; it is known to exist on the Rage LT-PRO, + * Rage XL and Rage Mobility. It is known not to exist on the Mach64 VT. + * - V2CLK is not available on all cards, most likely only the Rage LT-PRO, + * the Rage XL and the Rage Mobility + * + * SCLK can be used to: + * - Clock the chip instead of MCLK + * - Replace XTALIN with a user defined frequency + * - Generate the pixel clock for the LCD monitor (instead of VCLK) + */ + + /* + * It can be quite hard to calculate XCLK and MCLK if they don't run at the + * same frequency. Luckily, until now all cards that need asynchrone clock + * speeds seem to have SCLK. + * So this driver uses SCLK to clock the chip and XCLK to clock the memory. + */ +static u8 postdividers[] = {1,2,4,8,3}; -static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) +u8 stdcall aty_ld_pll(int offset, const struct fb_info_aty *info) { + u32 addr; + + addr = info->ati_regbase + CLOCK_CNTL + 1; /* write addr byte */ - aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info); - /* write the register value */ - aty_st_8(CLOCK_CNTL + 2, val, info); - aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info); + writeb((offset << 2) | PLL_WR_EN,addr); + addr++; + /* read the register value */ + return readb(addr); } +static void stdcall aty_st_pll(int offset, u8 val, const struct fb_info_aty *info) +{ + u32 addr; + addr = info->ati_regbase + CLOCK_CNTL + 1; + /* write addr byte */ + writeb((offset << 2) | PLL_WR_EN,addr); + addr++; + /* write the register value */ + writeb(val,addr); + addr--; + /* Disable write access */ + writeb(offset << 2,addr); +} /* ------------------------------------------------------------------------- */ @@ -45,179 +116,135 @@ * PLL programming (Mach64 CT family) */ +/* + * This procedure sets the display fifo. The display fifo is a buffer that + * contains data read from the video memory that waits to be processed by + * the CRT controller. + * + * On the more modern Mach64 variants, the chip doesn't calculate the + * interval after which the display fifo has to be reloaded from memory + * automatically, the driver has to do it instead. + */ + + +#define Maximum_DSP_PRECISION 7 + static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp, - struct pll_ct *pll) -{ - u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on; - u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size; + u32 width, struct pll_ct *pll) { - /* xclocks_per_row<<11 */ - xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/ - (pll->vclk_fb_div*pll->mclk_post_div_real*bpp); - if (xclks_per_row < (1<<11)) - FAIL("Dotclock to high"); - if (M64_HAS(FIFO_24)) { - fifo_size = 24; - dsp_loop_latency = 0; - } else { - fifo_size = 32; - dsp_loop_latency = 2; - } - dsp_precision = 0; - y = (xclks_per_row*fifo_size)>>11; - while (y) { - y >>= 1; - dsp_precision++; - } - dsp_precision -= 5; - /* fifo_off<<6 */ - fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6); - - if (info->total_vram > 1*1024*1024) { - if (info->ram_type >= SDRAM) { - /* >1 MB SDRAM */ - dsp_loop_latency += 8; - page_size = 8; - } else { - /* >1 MB DRAM */ - dsp_loop_latency += 6; - page_size = 9; - } - } else { - if (info->ram_type >= SDRAM) { - /* <2 MB SDRAM */ - dsp_loop_latency += 9; - page_size = 10; - } else { - /* <2 MB DRAM */ - dsp_loop_latency += 8; - page_size = 10; - } + u32 multiplier,divider,ras_multiplier,ras_divider,tmp; + u32 dsp_on,dsp_off,dsp_xclks; + u8 vshift,xshift; + s8 dsp_precision; + + multiplier = ((u32)info->mclk_fb_div)*pll->vclk_post_div_real; + divider = ((u32)pll->vclk_fb_div)*info->xclk_post_div_real; + + ras_multiplier = info->xclkmaxrasdelay; + ras_divider = 1; + + if (bpp>=8) + divider = divider * (bpp >> 2); + + vshift = (6 - 2); /* FIFO is 64 bits wide in accelerator mode ... */ + + if (bpp == 0) + vshift--; /* ... but only 32 bits in VGA mode. */ + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (width != 0) { + multiplier = multiplier * info->lcd_width; + divider = divider * width; + + ras_multiplier = ras_multiplier * info->lcd_width; + ras_divider = ras_divider * width; + }; +#endif + + /* If we don't do this, 32 bits for multiplier & divider won't be + enough in certain situations! */ + while (((multiplier | divider) & 1) == 0) { + multiplier = multiplier >> 1; + divider = divider >> 1; + }; + + /* Determine DSP precision first */ + tmp = ((multiplier * info->fifo_size) << vshift) / divider; + for (dsp_precision = -5; tmp; dsp_precision++) + tmp >>= 1; + if (dsp_precision < 0) + dsp_precision = 0; + else if (dsp_precision > Maximum_DSP_PRECISION) + dsp_precision = Maximum_DSP_PRECISION; + + xshift = 6 - dsp_precision; + vshift += xshift; + + /* Move on to dsp_off */ + dsp_off = ((multiplier * (info->fifo_size - 1)) << vshift) / divider - + (1 << (vshift - xshift)); + + /* Next is dsp_on */ +// if (bpp == 0) +// dsp_on = ((multiplier * 20 << vshift) + divider) / divider; +// else { + dsp_on = ((multiplier << vshift) + divider) / divider; + tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider; + if (dsp_on < tmp) + dsp_on = tmp; + dsp_on = dsp_on + (tmp * 2) + (info->xclkpagefaultdelay << xshift); +// }; + + /* Calculate rounding factor and apply it to dsp_on */ + tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1; + dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1); + + if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) + { + dsp_on = dsp_off - (multiplier << vshift) / divider; + dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1); } - /* fifo_on<<6 */ - if (xclks_per_row >= (page_size<<11)) - fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5); - else - fifo_on = (3*page_size+2)<<6; - dsp_xclks_per_row = xclks_per_row>>dsp_precision; - dsp_on = fifo_on>>dsp_precision; - dsp_off = fifo_off>>dsp_precision; - - pll->dsp_config = (dsp_xclks_per_row & 0x3fff) | - ((dsp_loop_latency & 0xf)<<16) | - ((dsp_precision & 7)<<20); - pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16); + /* Last but not least: dsp_xclks */ + dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider; + + /* Get register values. */ + pll->dsp_on_off = (dsp_on << 16) + dsp_off; + pll->dsp_config = (dsp_precision << 20) | (info->dsp_loop_latency << 16) | + dsp_xclks; return 0; -} +}; static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per, struct pll_ct *pll) { - u32 q, x; /* x is a workaround for sparc64-linux-gcc */ - x = x; /* x is a workaround for sparc64-linux-gcc */ - - pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per; - - /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ - q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per; /* actually 8*q */ - if (q < 16*8 || q > 255*8) - FAIL("mclk out of range"); - else if (q < 32*8) - pll->mclk_post_div_real = 8; - else if (q < 64*8) - pll->mclk_post_div_real = 4; - else if (q < 128*8) - pll->mclk_post_div_real = 2; - else - pll->mclk_post_div_real = 1; - pll->mclk_fb_div = q*pll->mclk_post_div_real/8; + u32 q; /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */ - q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per; /* actually 8*q */ + q = info->ref_clk_per*info->pll_ref_div*4/vclk_per; /* actually 8*q */ if (q < 16*8 || q > 255*8) - FAIL("vclk out of range"); - else if (q < 32*8) - pll->vclk_post_div_real = 8; - else if (q < 64*8) - pll->vclk_post_div_real = 4; - else if (q < 128*8) - pll->vclk_post_div_real = 2; - else - pll->vclk_post_div_real = 1; + FAIL("vclk out of range"); + else { + pll->vclk_post_div = (q < 128*8); + pll->vclk_post_div += (q < 64*8); + pll->vclk_post_div += (q < 32*8); + }; + pll->vclk_post_div_real = postdividers[pll->vclk_post_div]; +// pll->vclk_post_div <<= 6; pll->vclk_fb_div = q*pll->vclk_post_div_real/8; - return 0; -} - -void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll) -{ - u8 mpostdiv = 0; - u8 vpostdiv = 0; - - if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM)) - pll->pll_gen_cntl = 0x04; - else - pll->pll_gen_cntl = 0x84; - - switch (pll->mclk_post_div_real) { - case 1: - mpostdiv = 0; - break; - case 2: - mpostdiv = 1; - break; - case 3: - mpostdiv = 4; - break; - case 4: - mpostdiv = 2; - break; - case 8: - mpostdiv = 3; - break; - } - pll->pll_gen_cntl |= mpostdiv<<4; /* mclk */ - - if (M64_HAS(MAGIC_POSTDIV)) - pll->pll_ext_cntl = 0; - else - pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */ - - switch (pll->vclk_post_div_real) { - case 2: - vpostdiv = 1; - break; - case 3: - pll->pll_ext_cntl |= 0x10; - case 1: - vpostdiv = 0; - break; - case 6: - pll->pll_ext_cntl |= 0x10; - case 4: - vpostdiv = 2; - break; - case 12: - pll->pll_ext_cntl |= 0x10; - case 8: - vpostdiv = 3; - break; - } - pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */ - pll->vclk_post_div = vpostdiv; + return 0; } static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per, - u8 bpp, union aty_pll *pll) + u8 bpp, u32 width, union aty_pll *pll) { int err; if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct))) - return err; - if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct))) - return err; - aty_calc_pll_ct(info, &pll->ct); + return err; + if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, width, &pll->ct))) + return err; return 0; } @@ -225,7 +252,7 @@ const union aty_pll *pll) { u32 ref_clk_per = info->ref_clk_per; - u8 pll_ref_div = pll->ct.pll_ref_div; + u8 pll_ref_div = info->pll_ref_div; u8 vclk_fb_div = pll->ct.vclk_fb_div; u8 vclk_post_div = pll->ct.vclk_post_div_real; @@ -234,27 +261,187 @@ void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll) { - aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info); - aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info); - aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info); + u8 a; aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info); - aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info); + a = aty_ld_pll(VCLK_POST_DIV, info) & ~3; + aty_st_pll(VCLK_POST_DIV, a | pll->ct.vclk_post_div, info); aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info); - aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info); if (M64_HAS(GTB_DSP)) { - if (M64_HAS(XL_DLL)) - aty_st_pll(DLL_CNTL, 0x80, info); - else if (info->ram_type >= SDRAM) - aty_st_pll(DLL_CNTL, 0xa6, info); - else - aty_st_pll(DLL_CNTL, 0xa0, info); - aty_st_pll(VFC_CNTL, 0x1b, info); - aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info); - aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info); + aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info); + aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info); } } + +static void __init aty_init_pll_ct(struct fb_info_aty *info) { + u8 pll_ref_div,pll_gen_cntl,pll_ext_cntl; + u8 mpost_div,xpost_div; + u8 sclk_post_div_real,sclk_fb_div,spll_cntl2; + u32 q,i; + u32 mc,trp,trcd,tcrd,tras; + + mc = aty_ld_le32(MEM_CNTL, info); + trp = (mc & 0x300) >> 8; + trcd = (mc & 0xc00) >> 10; + tcrd = (mc & 0x1000) >> 12; tras = (mc & 0x70000) >> 16; + info->xclkpagefaultdelay = trcd + tcrd + trp + 2; + info->xclkmaxrasdelay = tras + trp + 2; + + if (M64_HAS(FIFO_24)) { + info->fifo_size = 24; + info->xclkpagefaultdelay += 2; + info->xclkmaxrasdelay += 3; + } else { + info->fifo_size = 32; + }; + + switch (info->ram_type) { + case DRAM: + if (info->total_vram<=1*1024*1024) { + info->dsp_loop_latency = 10; + } else { + info->dsp_loop_latency = 8; + info->xclkpagefaultdelay += 2; + }; + break; + case EDO: + case PSEUDO_EDO: + if (info->total_vram<=1*1024*1024) { + info->dsp_loop_latency = 9; + } else { + info->dsp_loop_latency = 8; + info->xclkpagefaultdelay += 1; + }; + break; + case SDRAM: + if (info->total_vram<=1*1024*1024) { + info->dsp_loop_latency = 11; + } else { + info->dsp_loop_latency = 10; + info->xclkpagefaultdelay += 1; + }; + break; + case SGRAM: + info->dsp_loop_latency = 8; + info->xclkpagefaultdelay += 3; + break; + default: + info->dsp_loop_latency = 11; + info->xclkpagefaultdelay += 3; + break; + }; + + if (info->xclkmaxrasdelay <= info->xclkpagefaultdelay) + info->xclkmaxrasdelay = info->xclkpagefaultdelay + 1; + + /* Exit if the user does not want us to tamper with the clock + rates of her chip. */ + if (info->mclk_per == 0) { + u16 mclk_fb_div; + u8 pll_ext_cntl; + + info->pll_ref_div = aty_ld_pll(PLL_REF_DIV, info); + pll_ext_cntl = aty_ld_pll(PLL_EXT_CNTL, info); + info->xclk_post_div_real = postdividers[pll_ext_cntl & 7]; + mclk_fb_div = aty_ld_pll(MCLK_FB_DIV, info); + if (pll_ext_cntl & 8) + mclk_fb_div <<= 1; + info->mclk_fb_div = mclk_fb_div; + return; + }; + + pll_ref_div = info->pll_per*2*255/info->ref_clk_per; + info->pll_ref_div = pll_ref_div; + + /* FIXME: use the VTB/GTB /3 post divider if it's better suited */ + q = info->ref_clk_per*pll_ref_div*4/info->xclk_per; /* actually 8*q */ + if (q < 16*8 || q > 255*8) { + printk(KERN_CRIT "xclk out of range\n"); + return; + } else { + xpost_div = (q < 128*8); + xpost_div += (q < 64*8); + xpost_div += (q < 32*8); + }; + info->xclk_post_div_real = postdividers[xpost_div]; + info->mclk_fb_div = q*info->xclk_post_div_real/8; + + if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM)) + pll_gen_cntl = 0x04; + else + /* The Rage Mobility M1 needs bit 3 set...*/ + /* original: pll_gen_cntl = 0x84 */ + pll_gen_cntl = 0x8C; + + if (M64_HAS(MAGIC_POSTDIV)) + pll_ext_cntl = 0; + else + pll_ext_cntl = xpost_div; + + if (info->mclk_per == info->xclk_per) + pll_gen_cntl |= xpost_div<<4; /* mclk == xclk */ + else { + /* + * The chip clock is not equal to the memory clock. + * Therefore we will use sclk to clock the chip. + */ + pll_gen_cntl |= 6<<4; /* mclk == sclk*/ + + q = info->ref_clk_per*pll_ref_div*4/info->mclk_per; /* actually 8*q */ + if (q < 16*8 || q > 255*8) { + printk(KERN_CRIT "mclk out of range\n"); + return; + } else { + mpost_div = (q < 128*8); + mpost_div += (q < 64*8); + mpost_div += (q < 32*8); + }; + sclk_post_div_real = postdividers[mpost_div]; + sclk_fb_div = q*sclk_post_div_real/8; + spll_cntl2 = mpost_div << 4; + /* + * This disables the sclk, crashes the computer as reported: + * aty_st_pll(SPLL_CNTL2, 3, info); + * + * So it seems the sclk must be enabled before it is used; + * so PLL_GEN_CNTL must be programmed *after* the sclk. + */ + aty_st_pll(SCLK_FB_DIV, sclk_fb_div, info); + aty_st_pll(SPLL_CNTL2, spll_cntl2, info); + /* + * The sclk has been started. However, I believe the first clock + * ticks it generates are not very stable. Hope this primitive loop + * helps for Rage Mobilities that sometimes crash when + * we switch to sclk. (Daniel Mantione, 13-05-2003) + */ + for (i=0;i<=0x1ffff;i++); + }; + + aty_st_pll(PLL_REF_DIV, pll_ref_div, info); + aty_st_pll(PLL_GEN_CNTL, pll_gen_cntl, info); + aty_st_pll(MCLK_FB_DIV, info->mclk_fb_div, info); + aty_st_pll(PLL_EXT_CNTL, pll_ext_cntl, info); + /* Disable the extra precision pixel clock controls since we do not + use them. */ + aty_st_pll(EXT_VPLL_CNTL, aty_ld_pll(EXT_VPLL_CNTL, info) & + ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | + EXT_VPLL_INSYNC), info); +#if 0 + /* This code causes problems on the Rage Mobility M1 + and seems unnecessary. Comments wanted! */ + if (M64_HAS(GTB_DSP)) { + if (M64_HAS(XL_DLL)) + aty_st_pll(DLL_CNTL, 0x80, info); + else if (info->ram_type >= SDRAM) + aty_st_pll(DLL_CNTL, 0xa6, info); + else + aty_st_pll(DLL_CNTL, 0xa0, info); + aty_st_pll(VFC_CNTL, 0x1b, info); + }; +#endif +}; + static int dummy(void) { return 0; @@ -268,5 +455,6 @@ var_to_pll: aty_var_to_pll_ct, pll_to_var: aty_pll_ct_to_var, set_pll: aty_set_pll_ct, + init_pll: aty_init_pll_ct }; diff -urN linux-2.4.22-bk11/drivers/video/aty/mach64_cursor.c linux-2.4.22-bk12/drivers/video/aty/mach64_cursor.c --- linux-2.4.22-bk11/drivers/video/aty/mach64_cursor.c 2001-10-25 13:53:52.000000000 -0700 +++ linux-2.4.22-bk12/drivers/video/aty/mach64_cursor.c 2003-09-06 03:00:27.000000000 -0700 @@ -144,6 +144,10 @@ yoff = 0; } + /* In doublescan mode, the cursor location also needs to be + doubled. */ + if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) + y<<=1; wait_for_fifo(4, fb); aty_st_le32(CUR_OFFSET, (c->offset >> 3) + (yoff << 1), fb); aty_st_le32(CUR_HORZ_VERT_OFF, diff -urN linux-2.4.22-bk11/drivers/video/aty/mach64_gx.c linux-2.4.22-bk12/drivers/video/aty/mach64_gx.c --- linux-2.4.22-bk11/drivers/video/aty/mach64_gx.c 2002-08-02 17:39:45.000000000 -0700 +++ linux-2.4.22-bk12/drivers/video/aty/mach64_gx.c 2003-09-06 03:00:27.000000000 -0700 @@ -5,7 +5,6 @@ #include #include -#include #include @@ -37,6 +36,11 @@ #define MIN_N 35 #define MAX_N 255-8 +static int dummy(void) +{ + return 0; +} + /* * Support Functions @@ -183,6 +187,7 @@ var_to_pll: aty_var_to_pll_514, pll_to_var: aty_pll_514_to_var, set_pll: aty_set_pll_514, + init_pll: (void *)dummy }; @@ -467,6 +472,7 @@ var_to_pll: aty_var_to_pll_18818, pll_to_var: aty_pll_18818_to_var, set_pll: aty_set_pll18818, + init_pll: (void *)dummy }; @@ -580,6 +586,7 @@ var_to_pll: aty_var_to_pll_1703, pll_to_var: aty_pll_1703_to_var, set_pll: aty_set_pll_1703, + init_pll: (void *)dummy }; @@ -707,6 +714,7 @@ var_to_pll: aty_var_to_pll_8398, pll_to_var: aty_pll_8398_to_var, set_pll: aty_set_pll_8398, + init_pll: (void *)dummy }; @@ -851,6 +859,7 @@ var_to_pll: aty_var_to_pll_408, pll_to_var: aty_pll_408_to_var, set_pll: aty_set_pll_408, + init_pll: (void *)dummy }; @@ -870,11 +879,6 @@ return 0; } -static int dummy(void) -{ - return 0; -} - const struct aty_dac_ops aty_dac_unsupported = { set_dac: aty_set_dac_unsupported, }; @@ -883,5 +887,6 @@ var_to_pll: (void *)dummy, pll_to_var: (void *)dummy, set_pll: (void *)dummy, + init_pll: (void *)dummy }; diff -urN linux-2.4.22-bk11/net/atm/addr.c linux-2.4.22-bk12/net/atm/addr.c --- linux-2.4.22-bk11/net/atm/addr.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.22-bk12/net/atm/addr.c 2003-09-06 03:00:28.000000000 -0700 @@ -118,23 +118,24 @@ { unsigned long flags; struct atm_dev_addr *walk; - int total; + int total = 0, error; + struct sockaddr_atmsvc *tmp_buf, *tmp_bufp; + spin_lock_irqsave(&dev->lock, flags); - total = 0; - for (walk = dev->local; walk; walk = walk->next) { + for (walk = dev->local; walk; walk = walk->next) total += sizeof(struct sockaddr_atmsvc); - if (total > size) { - spin_unlock_irqrestore(&dev->lock, flags); - return -E2BIG; - } - if (copy_to_user(u_buf,&walk->addr, - sizeof(struct sockaddr_atmsvc))) { - spin_unlock_irqrestore(&dev->lock, flags); - return -EFAULT; - } - u_buf++; + tmp_buf = tmp_bufp = kmalloc(total, GFP_ATOMIC); + if (!tmp_buf) { + spin_unlock_irqrestore(&dev->lock, flags); + return -ENOMEM; } + for (walk = dev->local; walk; walk = walk->next) + memcpy(tmp_bufp++, &walk->addr, sizeof(struct sockaddr_atmsvc)); spin_unlock_irqrestore(&dev->lock, flags); - return total; + error = total > size ? -E2BIG : total; + if (copy_to_user(u_buf, tmp_buf, total < size ? total : size)) + error = -EFAULT; + kfree(tmp_buf); + return error; } diff -urN linux-2.4.22-bk11/net/atm/common.c linux-2.4.22-bk12/net/atm/common.c --- linux-2.4.22-bk11/net/atm/common.c 2003-09-06 03:00:10.000000000 -0700 +++ linux-2.4.22-bk12/net/atm/common.c 2003-09-06 03:00:28.000000000 -0700 @@ -672,7 +672,8 @@ } if (try_atm_clip_ops()) { ret_val = atm_clip_ops->clip_create(arg); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); } else ret_val = -ENOSYS; goto done; @@ -687,7 +688,8 @@ #endif if (try_atm_clip_ops()) { error = atm_clip_ops->atm_init_atmarp(vcc); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); if (!error) sock->state = SS_CONNECTED; ret_val = error; @@ -701,7 +703,8 @@ } if (try_atm_clip_ops()) { ret_val = atm_clip_ops->clip_mkip(vcc, arg); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); } else ret_val = -ENOSYS; goto done; @@ -712,7 +715,8 @@ } if (try_atm_clip_ops()) { ret_val = atm_clip_ops->clip_setentry(vcc, arg); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); } else ret_val = -ENOSYS; goto done; @@ -723,7 +727,8 @@ } if (try_atm_clip_ops()) { ret_val = atm_clip_ops->clip_encap(vcc, arg); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); } else ret_val = -ENOSYS; goto done; diff -urN linux-2.4.22-bk11/net/atm/proc.c linux-2.4.22-bk12/net/atm/proc.c --- linux-2.4.22-bk11/net/atm/proc.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.22-bk12/net/atm/proc.c 2003-09-06 03:00:28.000000000 -0700 @@ -358,7 +358,7 @@ spin_unlock_irqrestore(&dev->lock, flags); spin_unlock(&atm_dev_lock); #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) - if (clip_info) + if (clip_info && atm_clip_ops->owner) __MOD_DEC_USE_COUNT(atm_clip_ops->owner); #endif return strlen(buf); @@ -367,8 +367,8 @@ } spin_unlock(&atm_dev_lock); #if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) - if (clip_info) - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (clip_info && atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); #endif return 0; } @@ -458,7 +458,8 @@ if (--count) continue; atmarp_info(n->dev,entry,NULL,buf); read_unlock_bh(&clip_tbl_hook->lock); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); return strlen(buf); } for (vcc = entry->vccs; vcc; @@ -466,12 +467,14 @@ if (--count) continue; atmarp_info(n->dev,entry,vcc,buf); read_unlock_bh(&clip_tbl_hook->lock); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); return strlen(buf); } } read_unlock_bh(&clip_tbl_hook->lock); - __MOD_DEC_USE_COUNT(atm_clip_ops->owner); + if (atm_clip_ops->owner) + __MOD_DEC_USE_COUNT(atm_clip_ops->owner); return 0; } #endif diff -urN linux-2.4.22-bk11/net/bridge/br_stp_bpdu.c linux-2.4.22-bk12/net/bridge/br_stp_bpdu.c --- linux-2.4.22-bk11/net/bridge/br_stp_bpdu.c 2003-08-25 04:44:44.000000000 -0700 +++ linux-2.4.22-bk12/net/bridge/br_stp_bpdu.c 2003-09-06 03:00:28.000000000 -0700 @@ -194,6 +194,6 @@ } err: - kfree(skb); + kfree_skb(skb); return 0; } diff -urN linux-2.4.22-bk11/net/ipv4/netfilter/ip_nat_core.c linux-2.4.22-bk12/net/ipv4/netfilter/ip_nat_core.c --- linux-2.4.22-bk11/net/ipv4/netfilter/ip_nat_core.c 2003-09-06 03:00:11.000000000 -0700 +++ linux-2.4.22-bk12/net/ipv4/netfilter/ip_nat_core.c 2003-09-06 03:00:28.000000000 -0700 @@ -157,8 +157,8 @@ continue; } - if ((mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED) - && proto->in_range(&newtuple, IP_NAT_MANIP_SRC, + if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED) + || proto->in_range(&newtuple, IP_NAT_MANIP_SRC, &mr->range[i].min, &mr->range[i].max)) return 1; }