From: Antonino A. D. <ad...@ho...> - 2004-10-20 00:10:17
|
Alexander Kern <ale...@gm...> [PATCH] port Daniel Mantione 2.4 driver to 2.6 [PATCH] add more pci_id number [PATCH] add accelerated imgblit [PATCH] revert SDRAM_MAGIC_PLL to old behaviour [PATCH] do a "from BIOS" initialisation only by __i386__ Arnaud FONTAINE <arn...@fr...> [PATCH atyfb] correction for 3D Rage Mobility L Geert Uytterhoeven <ge...@li...> [PATCH atyfb] Atari Atyfb fixes [PATCH atyfb] Atyfb on Mach64 GX or Atari [PATCH 468] m68k sparse floating point James Simmons <jsi...@in...> [PATCH add] port to framebuffer_alloc api Nicolas Souchu <ns...@fr...> [PATCH] I do not found a copy, but it was incorporated too Ville Syrj=E4l=E4 <sy...@sc...> [PATCH] fix pan with doublescan [PATCH] another double scan fix [PATCH] disable linear aperture register access [PATCH] Memory type correction [PATCH] atyfb (2.6): Fix mmio_start [PATCH] atyfb (2.6): Fix mem_refresh_rate for Mobility [PATCH] atyfb (2.6): Add RGB565 support [PATCH] atyfb: Blank LCD by turning off backlight voltage [PATCH] atyfb: Rage LT LCD register access [PATCH] atyfb: vblank irq support [PATCH] atyfb: MTRR support Signed-off-by: Antonino Daplas <ad...@po...> =2D-- drivers/video/Kconfig | 19 drivers/video/aty/ati_ids.h | 1 drivers/video/aty/atyfb.h | 207 +- drivers/video/aty/atyfb_base.c | 3576 ++++++++++++++++++++++++---------= =2D---- drivers/video/aty/mach64_accel.c | 212 ++ drivers/video/aty/mach64_ct.c | 731 +++++-- drivers/video/aty/mach64_cursor.c | 309 +-- drivers/video/aty/mach64_gx.c | 20 drivers/video/aty/xlinit.c | 68 include/video/mach64.h | 351 +++ 10 files changed, 3680 insertions(+), 1814 deletions(-) diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig =2D-- a/drivers/video/Kconfig 2004-10-17 14:02:58 +08:00 +++ b/drivers/video/Kconfig 2004-10-07 06:18:18 +08:00 @@ -750,6 +750,19 @@ framebuffer device. The ATI product support page for these boards is at <http://support.ati.com/products/pc/mach64/>. =20 +config FB_ATY_GENERIC_LCD + bool "Mach64 generic LCD support (EXPERIMENTAL)" + depends on FB_ATY_CT + help + Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility, + Rage XC, or Rage XL chipset. + +config FB_ATY_XL_INIT + bool "Rage XL No-BIOS Init support" + depends on FB_ATY_CT + help + Say Y here to support booting a Rage XL without BIOS support. + config FB_ATY_GX bool "Mach64 GX support" if PCI depends on FB_ATY @@ -760,12 +773,6 @@ framebuffer device. The ATI product support page for these boards is at <http://support.ati.com/products/pc/mach64/graphics_xpression.html>. =2D =2Dconfig FB_ATY_XL_INIT =2D bool " Rage XL No-BIOS Init support" if FB_ATY_CT =2D depends on FB_ATY =2D help =2D Say Y here to support booting a Rage XL without BIOS support. =20 config FB_SIS tristate "SiS acceleration" diff -Nru a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h =2D-- a/drivers/video/aty/ati_ids.h 2004-10-19 20:22:38 +08:00 +++ b/drivers/video/aty/ati_ids.h 2004-10-07 06:18:18 +08:00 @@ -64,6 +64,7 @@ #define PCI_CHIP_MACH64LQ 0x4C51 #define PCI_CHIP_MACH64LR 0x4C52 #define PCI_CHIP_MACH64LS 0x4C53 +#define PCI_CHIP_MACH64LT 0x4C54 #define PCI_CHIP_RADEON_LW 0x4C57 #define PCI_CHIP_RADEON_LX 0x4C58 #define PCI_CHIP_RADEON_LY 0x4C59 diff -Nru a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h =2D-- a/drivers/video/aty/atyfb.h 2004-10-19 20:22:40 +08:00 +++ b/drivers/video/aty/atyfb.h 2004-10-11 03:43:16 +08:00 @@ -3,6 +3,8 @@ */ =20 #include <linux/config.h> +#include <linux/spinlock.h> +#include <linux/wait.h> /* * Elements of the hardware specific atyfb_par structure */ @@ -10,16 +12,60 @@ struct crtc { u32 vxres; u32 vyres; + u32 xoffset; + u32 yoffset; + u32 bpp; u32 h_tot_disp; u32 h_sync_strt_wid; u32 v_tot_disp; u32 v_sync_strt_wid; + u32 vline_crnt_vline; u32 off_pitch; u32 gen_cntl; u32 dp_pix_width; /* acceleration */ u32 dp_chain_mask; /* acceleration */ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 horz_stretching; + u32 vert_stretching; + u32 ext_vert_stretch; + u32 shadow_h_tot_disp; + u32 shadow_h_sync_strt_wid; + u32 shadow_v_tot_disp; + u32 shadow_v_sync_strt_wid; + u32 lcd_gen_cntl; + u32 lcd_config_panel; + u32 lcd_index; +#endif +}; + +struct aty_interrupt { + wait_queue_head_t wait; + unsigned int count; + int pan_display; +}; + +struct pll_info { + int pll_max; + int pll_min; + int sclk, mclk, mclk_pm, xclk; + int ref_div; + int ref_clk; }; =20 +typedef struct { + u16 unknown1; + u16 PCLK_min_freq; + u16 PCLK_max_freq; + u16 unknown2; + u16 ref_freq; + u16 ref_divider; + u16 unknown3; + u16 MCLK_pwd; + u16 MCLK_max_freq; + u16 XCLK_max_freq; + u16 SCLK_freq; +} __attribute__ ((packed)) PLL_BLOCK_MACH64; + struct pll_514 { u8 m; u8 n; @@ -36,16 +82,39 @@ u8 pll_ref_div; u8 pll_gen_cntl; u8 mclk_fb_div; + u8 mclk_fb_mult; /* 2 ro 4 */ +/* u8 sclk_fb_div;*/ u8 pll_vclk_cntl; u8 vclk_post_div; u8 vclk_fb_div; u8 pll_ext_cntl; =2D u32 dsp_config; /* Mach64 GTB DSP */ =2D u32 dsp_on_off; /* Mach64 GTB DSP */ +/* u8 ext_vpll_cntl; + u8 spll_cntl2;*/ + u32 dsp_config; /* Mach64 GTB DSP */ + u32 dsp_on_off; /* Mach64 GTB DSP */ + u32 dsp_loop_latency; + u32 fifo_size; + u32 xclkpagefaultdelay; + u32 xclkmaxrasdelay; + u8 xclk_ref_div; + u8 xclk_post_div; u8 mclk_post_div_real; + u8 xclk_post_div_real; u8 vclk_post_div_real; + u8 features; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 xres; /* use for LCD stretching/scaling */ +#endif }; =20 +/* + for pll_ct.features +*/ +#define DONT_USE_SPLL 0x1 +#define DONT_USE_XDLL 0x2 +#define USE_CPUCLK 0x4 +#define POWERDOWN_PLL 0x8 + union aty_pll { struct pll_ct ct; struct pll_514 ibm514; @@ -56,42 +125,68 @@ * The hardware parameters for each card */ =20 =2Dstruct aty_cursor { =2D u8 bits[8][64]; =2D u8 mask[8][64]; =2D u8 *ram; =2D}; =2D struct atyfb_par { struct aty_cmap_regs *aty_cmap_regs; + struct { u8 red, green, blue; } palette[256]; const struct aty_dac_ops *dac_ops; const struct aty_pll_ops *pll_ops; =2D struct aty_cursor *cursor; =2D unsigned long ati_regbase; =2D unsigned long clk_wr_offset; + void *ati_regbase; + unsigned long clk_wr_offset; /* meaning overloaded, clock id by CT */ struct crtc crtc; union aty_pll pll; + struct pll_info pll_limits; u32 features; u32 ref_clk_per; u32 pll_per; u32 mclk_per; + u32 xclk_per; u8 bus_type; u8 ram_type; u8 mem_refresh_rate; =2D u8 blitter_may_be_busy; + u16 pci_id; u32 accel_flags; + int blitter_may_be_busy; + int asleep; + int lock_blank; + unsigned long res_start; + unsigned long res_size; #ifdef __sparc__ struct pci_mmap_map *mmap_map; u8 mmaped; +#endif int open; +#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_refreshrate; + u16 lcd_htotal; + u16 lcd_hdisp; + u16 lcd_hsync_dly; + u16 lcd_hsync_len; + u16 lcd_vtotal; + u16 lcd_vdisp; + u16 lcd_vsync_len; + u16 lcd_right_margin; + u16 lcd_lower_margin; + u16 lcd_hblank_len; + u16 lcd_vblank_len; #endif =2D#ifdef CONFIG_PMAC_PBOOK =2D struct fb_info *next; =2D unsigned char *save_framebuffer; =2D unsigned long save_pll[64]; + unsigned long aux_start; /* auxiliary aperture */ + unsigned long aux_size; + struct aty_interrupt vblank; + unsigned long irq_flags; + unsigned int irq; + spinlock_t int_lock; +#ifdef CONFIG_MTRR + int mtrr_aper; + int mtrr_reg; #endif }; =2D =20 + /* * ATI Mach64 features */ @@ -101,7 +196,7 @@ #define M64F_RESET_3D 0x00000001 #define M64F_MAGIC_FIFO 0x00000002 #define M64F_GTB_DSP 0x00000004 =2D#define M64F_FIFO_24 0x00000008 +#define M64F_FIFO_32 0x00000008 #define M64F_SDRAM_MAGIC_PLL 0x00000010 #define M64F_MAGIC_POSTDIV 0x00000020 #define M64F_INTEGRATED 0x00000040 @@ -116,9 +211,10 @@ #define M64F_G3_PB_1_1 0x00008000 #define M64F_G3_PB_1024x768 0x00010000 #define M64F_EXTRA_BRIGHT 0x00020000 =2D#define M64F_LT_SLEEP 0x00040000 +#define M64F_LT_LCD_REGS 0x00040000 #define M64F_XL_DLL 0x00080000 =2D +#define M64F_MFB_FORCE_4 0x00100000 +#define M64F_HW_TRIPLE 0x00200000 =20 /* * Register access @@ -137,8 +233,7 @@ #endif } =20 =2Dstatic inline void aty_st_le32(int regindex, u32 val, =2D const struct atyfb_par *par) +static inline void aty_st_le32(int regindex, u32 val, const struct atyfb_p= ar *par) { /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >=3D 0x400) @@ -163,8 +258,7 @@ #endif } =20 =2Dstatic inline void aty_st_8(int regindex, u8 val, =2D const struct atyfb_par *par) +static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *= par) { /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >=3D 0x400) @@ -177,17 +271,10 @@ #endif } =20 =2Dstatic inline u8 aty_ld_pll(int offset, const struct atyfb_par *par) =2D{ =2D u8 res; =2D =2D /* write addr byte */ =2D aty_st_8(CLOCK_CNTL + 1, (offset << 2), par); =2D /* read the register value */ =2D res =3D aty_ld_8(CLOCK_CNTL + 2, par); =2D return res; =2D} =2D +#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFI= G_FB_ATY_GENERIC_LCD) +extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par); +extern u32 aty_ld_lcd(int index, const struct atyfb_par *par); +#endif =20 /* * DAC operations @@ -195,14 +282,14 @@ =20 struct aty_dac_ops { int (*set_dac) (const struct fb_info * info, =2D const union aty_pll * pll, u32 bpp, u32 accel); + const union aty_pll * pll, u32 bpp, u32 accel); }; =20 =2Dextern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */ =2Dextern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */ =2Dextern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */ =2Dextern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */ =2Dextern const struct aty_dac_ops aty_dac_ct; /* Integrated */ +extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */ +extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */ +extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */ +extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */ +extern const struct aty_dac_ops aty_dac_ct; /* Integrated */ =20 =20 /* @@ -210,37 +297,32 @@ */ =20 struct aty_pll_ops { =2D int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, =2D u8 bpp, union aty_pll * pll); =2D u32(*pll_to_var) (const struct fb_info * info, =2D const union aty_pll * pll); =2D void (*set_pll) (const struct fb_info * info, =2D const union aty_pll * pll); + int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, u32 bpp, un= ion aty_pll * pll); + u32 (*pll_to_var) (const struct fb_info * info, const union aty_pll * pll= ); + void (*set_pll) (const struct fb_info * info, const union aty_pll * pll= ); + void (*get_pll) (const struct fb_info *info, union aty_pll * pll); + int (*init_pll) (const struct fb_info * info, union aty_pll * pll); }; =20 =2Dextern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */ =2Dextern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */ =2Dextern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */ =2Dextern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */ =2Dextern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */ =2Dextern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */ =2Dextern const struct aty_pll_ops aty_pll_ct; /* Integrated */ +extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */ +extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */ +extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */ +extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */ +extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */ +extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */ +extern const struct aty_pll_ops aty_pll_ct; /* Integrated */ =20 =20 =2Dextern void aty_set_pll_ct(const struct fb_info *info, =2D const union aty_pll *pll); =2Dextern void aty_calc_pll_ct(const struct fb_info *info, =2D struct pll_ct *pll); +extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll= *pll); +extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par); =20 =20 /* * Hardware cursor support */ =20 =2Dextern struct aty_cursor *aty_init_cursor(struct fb_info *info); +extern int aty_init_cursor(struct fb_info *info); extern int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor); =2Dextern void aty_set_cursor_color(struct fb_info *info); =2Dextern void aty_set_cursor_shape(struct fb_info *info); =20 /* * Hardware acceleration @@ -260,6 +342,5 @@ } =20 extern void aty_reset_engine(const struct atyfb_par *par); =2Dextern void aty_init_engine(struct atyfb_par *par, =2D struct fb_info *info); +extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info); =20 diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c =2D-- a/drivers/video/aty/atyfb_base.c 2004-10-19 20:22:41 +08:00 +++ b/drivers/video/aty/atyfb_base.c 2004-10-11 04:38:39 +08:00 @@ -1,6 +1,7 @@ /* * ATI Frame Buffer Device Driver Core * + * Copyright (C) 2004 Alex Kern <ale...@gm...> * Copyright (C) 1997-2001 Geert Uytterhoeven * Copyright (C) 1998 Bernd Harries * Copyright (C) 1998 Eddie C. Dost (ec...@sk...) @@ -24,10 +25,13 @@ * Harry AC Eaton * Anthony Tong <at...@ui...> * + * Generic LCD support written by Daniel Mantione, ported from 2.4.20 by = Alex Kern + * Many Thanks to Ville Syrj=E4l=E4 for patches and fixing nasting 16 bit= color bug. + * * This file is subject to the terms and conditions of the GNU General Pu= blic * License. See the file COPYING in the main directory of this archive for * more details. =2D * =20 + * * Many thanks to Nitya from ATI devrel for support and patience ! */ =20 @@ -38,15 +42,16 @@ - cursor support on all cards and all ramdacs. - cursor parameters controlable via ioctl()s. - guess PLL and MCLK based on the original PLL register values initial= ized =2D by the BIOS or Open Firmware (if they are initialized). + by Open Firmware (if they are initialized). BIOS is done =20 =2D (Anyone to help with this?) + (Anyone with Mac to help with this?) =20 **************************************************************************= ****/ =20 =20 #include <linux/config.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> @@ -54,19 +59,20 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/delay.h> =2D#include <linux/selection.h> #include <linux/console.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> =2D#include <linux/vt_kern.h> =2D#include <linux/kd.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/wait.h> =20 #include <asm/io.h> #include <asm/uaccess.h> =20 #include <video/mach64.h> #include "atyfb.h" +#include "ati_ids.h" =20 #ifdef __powerpc__ #include <asm/prom.h> @@ -87,23 +93,102 @@ #ifdef CONFIG_PMAC_BACKLIGHT #include <asm/backlight.h> #endif =2D +#ifdef CONFIG_MTRR +#include <asm/mtrr.h> +#endif =20 /* * Debug flags. */ =2D#undef DEBUG +/*#undef DEBUG*/ +#define DEBUG =20 /* 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) =20 =2D /* FIXME: remove the FAIL definition */ =2D#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0) +#define FAIL(msg) do { printk(KERN_CRIT "atyfb: " msg "\n"); return -EINVA= L; } while (0) +#define FAIL_MAX(msg, x, _max_) do { if(x > _max_) { printk(KERN_CRIT "aty= fb: " msg " %x(%x)\n", x, _max_); return -EINVAL; } } while (0) + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "atyfb: " fmt, ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args) +#define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args) + +#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFI= G_FB_ATY_GENERIC_LCD) +static const u32 lt_lcd_regs[] =3D { + CONFIG_PANEL_LG, + LCD_GEN_CNTL_LG, + DSTN_CONTROL_LG, + HFB_PITCH_ADDR_LG, + HORZ_STRETCHING_LG, + VERT_STRETCHING_LG, + 0, /* EXT_VERT_STRETCH */ + LT_GIO_LG, + POWER_MANAGEMENT_LG +}; + +void aty_st_lcd(int index, u32 val, const struct atyfb_par *par) +{ + if (M64_HAS(LT_LCD_REGS)) { + aty_st_le32(lt_lcd_regs[index], val, par); + } else { + unsigned long temp; + + /* write addr byte */ + temp =3D aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); + /* write the register value */ + aty_st_le32(LCD_DATA, val, par); + } +} + +u32 aty_ld_lcd(int index, const struct atyfb_par *par) +{ + if (M64_HAS(LT_LCD_REGS)) { + return aty_ld_le32(lt_lcd_regs[index], par); + } else { + unsigned long temp; + + /* write addr byte */ + temp =3D aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); + /* read the register value */ + return aty_ld_le32(LCD_DATA, par); + } +} +#endif /* defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined = (CONFIG_FB_ATY_GENERIC_LCD) */ + +#ifdef CONFIG_FB_ATY_GENERIC_LCD +/* + * ATIReduceRatio -- + * + * Reduce a fraction by factoring out the largest common divider of the + * fraction's numerator and denominator. + */ +static void ATIReduceRatio(int *Numerator, int *Denominator) +{ + int Multiplier, Divider, Remainder; =20 + Multiplier =3D *Numerator; + Divider =3D *Denominator; =20 + while ((Remainder =3D Multiplier % Divider)) + { + Multiplier =3D Divider; + Divider =3D Remainder; + } + + *Numerator /=3D Divider; + *Denominator /=3D Divider; +} +#endif /* * The Hardware parameters for each card */ @@ -138,22 +223,19 @@ =20 static int atyfb_open(struct fb_info *info, int user); static int atyfb_release(struct fb_info *info, int user); =2Dstatic int atyfb_check_var(struct fb_var_screeninfo *var, =2D struct fb_info *info); =2Dstatic int atyfb_set_par(struct fb_info *info);=20 +static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *= info); +static int atyfb_set_par(struct fb_info *info); static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, =2D u_int transp, struct fb_info *info); =2Dstatic int atyfb_pan_display(struct fb_var_screeninfo *var, =2D struct fb_info *info); + u_int transp, struct fb_info *info); +static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info= *info); static int atyfb_blank(int blank, struct fb_info *info); static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd, =2D u_long arg, struct fb_info *info); + u_long arg, struct fb_info *info); extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect = *rect); extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea = *area); extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *i= mage); #ifdef __sparc__ =2Dstatic int atyfb_mmap(struct fb_info *info, struct file *file, =2D struct vm_area_struct *vma); +static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_a= rea_struct *vma); #endif static int atyfb_sync(struct fb_info *info); =20 @@ -166,15 +248,14 @@ static int store_video_par(char *videopar, unsigned char m64_num); #endif =20 =2Dstatic void aty_set_crtc(const struct atyfb_par *par, =2D const struct crtc *crtc); =2Dstatic int aty_var_to_crtc(const struct fb_info *info, =2D const struct fb_var_screeninfo *var, =2D struct crtc *crtc); =2Dstatic int aty_crtc_to_var(const struct crtc *crtc, =2D struct fb_var_screeninfo *var); =2Dstatic void set_off_pitch(struct atyfb_par *par, =2D const struct fb_info *info); +static struct crtc saved_crtc; +static union aty_pll saved_pll; +static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc); + +static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *c= rtc); +static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var= _screeninfo *var, struct crtc *crtc); +static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screenin= fo *var); +static void set_off_pitch(struct atyfb_par *par, const struct fb_info *inf= o); #ifdef CONFIG_PPC static int read_aty_sense(const struct atyfb_par *par); #endif @@ -184,10 +265,19 @@ * Interface used by the world */ =20 =2Dint atyfb_init(void); =2D#ifndef MODULE =2Dint atyfb_setup(char *); =2D#endif +struct fb_var_screeninfo default_var =3D { + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; + +static struct fb_videomode defmode =3D { + /* 640x480 @ 60 Hz, 31.5 kHz hsync */ + NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED +}; =20 static struct fb_ops atyfb_ops =3D { .owner =3D THIS_MODULE, @@ -202,22 +292,22 @@ .fb_fillrect =3D atyfb_fillrect, .fb_copyarea =3D atyfb_copyarea, .fb_imageblit =3D atyfb_imageblit, =2D .fb_cursor =3D soft_cursor, + .fb_cursor =3D atyfb_cursor, #ifdef __sparc__ .fb_mmap =3D atyfb_mmap, #endif .fb_sync =3D atyfb_sync, }; =20 =2Dstatic char curblink __initdata =3D 1; =2Dstatic char noaccel __initdata =3D 0; =2Dstatic u32 default_vram __initdata =3D 0; =2Dstatic int default_pll __initdata =3D 0; =2Dstatic int default_mclk __initdata =3D 0; =2D =2D#ifndef MODULE =2Dstatic char *mode_option __initdata =3D NULL; =2D#endif +static int noaccel; +#ifdef CONFIG_MTRR +static int nomtrr; +#endif +static int vram; +static int pll; +static int mclk; +static int xclk; +static char *mode; =20 #ifdef CONFIG_PPC static int default_vmode __initdata =3D VMODE_CHOOSE; @@ -231,177 +321,185 @@ static unsigned long phys_guiregbase[FB_MAX] __initdata =3D { 0, }; #endif =20 =2D#ifdef CONFIG_FB_ATY_GX =2Dstatic char m64n_gx[] __initdata =3D "mach64GX (ATI888GX00)"; =2Dstatic char m64n_cx[] __initdata =3D "mach64CX (ATI888CX00)"; =2D#endif /* CONFIG_FB_ATY_GX */ =2D#ifdef CONFIG_FB_ATY_CT =2Dstatic char m64n_ct[] __initdata =3D "mach64CT (ATI264CT)"; =2Dstatic char m64n_et[] __initdata =3D "mach64ET (ATI264ET)"; =2Dstatic char m64n_vta3[] __initdata =3D "mach64VTA3 (ATI264VT)"; =2Dstatic char m64n_vta4[] __initdata =3D "mach64VTA4 (ATI264VT)"; =2Dstatic char m64n_vtb[] __initdata =3D "mach64VTB (ATI264VTB)"; =2Dstatic char m64n_vt4[] __initdata =3D "mach64VT4 (ATI264VT4)"; =2Dstatic char m64n_gt[] __initdata =3D "3D RAGE (GT)"; =2Dstatic char m64n_gtb[] __initdata =3D "3D RAGE II+ (GTB)"; =2Dstatic char m64n_iic_p[] __initdata =3D "3D RAGE IIC (PCI)"; =2Dstatic char m64n_iic_a[] __initdata =3D "3D RAGE IIC (AGP)"; =2Dstatic char m64n_lt[] __initdata =3D "3D RAGE LT"; =2Dstatic char m64n_ltg[] __initdata =3D "3D RAGE LT-G"; =2Dstatic char m64n_gtc_ba[] __initdata =3D "3D RAGE PRO (BGA, AGP)"; =2Dstatic char m64n_gtc_ba1[] __initdata =3D "3D RAGE PRO (BGA, AGP, 1x onl= y)"; =2Dstatic char m64n_gtc_bp[] __initdata =3D "3D RAGE PRO (BGA, PCI)"; =2Dstatic char m64n_gtc_pp[] __initdata =3D "3D RAGE PRO (PQFP, PCI)"; =2Dstatic char m64n_gtc_ppl[] __initdata =3D =2D "3D RAGE PRO (PQFP, PCI, limited 3D)"; =2Dstatic char m64n_xl[] __initdata =3D "3D RAGE (XL)"; =2Dstatic char m64n_ltp_a[] __initdata =3D "3D RAGE LT PRO (AGP)"; =2Dstatic char m64n_ltp_p[] __initdata =3D "3D RAGE LT PRO (PCI)"; =2Dstatic char m64n_mob_p[] __initdata =3D "3D RAGE Mobility (PCI)"; =2Dstatic char m64n_mob_a[] __initdata =3D "3D RAGE Mobility (AGP)"; =2D#endif /* CONFIG_FB_ATY_CT */ +/* top -> down is an evolution of mach64 chipset, any corrections? */ +#define ATI_CHIP_88800GX (M64F_GX) +#define ATI_CHIP_88800CX (M64F_GX) + +#define ATI_CHIP_264CT (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F= _MAGIC_FIFO) +#define ATI_CHIP_264ET (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F= _MAGIC_FIFO) + +#define ATI_CHIP_264VT (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F= _MAGIC_FIFO) +#define ATI_CHIP_264GT (M64F_GT | M64F_INTEGRATED | M64F= _MAGIC_FIFO | M64F_EXTRA_BRIGHT) + +#define ATI_CHIP_264VTB (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F= _GTB_DSP) +#define ATI_CHIP_264VT3 (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F= _GTB_DSP | M64F_SDRAM_MAGIC_PLL) +#define ATI_CHIP_264VT4 (M64F_VT | M64F_INTEGRATED | M64F= _GTB_DSP) + +#define ATI_CHIP_264LT (M64F_GT | M64F_INTEGRATED | M64F= _GTB_DSP) + +/* make sets shorter */ +#define ATI_MODERN_SET (M64F_GT | M64F_INTEGRATED | M64F= _GTB_DSP | M64F_EXTRA_BRIGHT) + +#define ATI_CHIP_264GTB (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) +/*#define ATI_CHIP_264GTDVD ?*/ +#define ATI_CHIP_264LTG (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL) + +#define ATI_CHIP_264GT2C (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_H= W_TRIPLE) +#define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_H= W_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D) +#define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32= | M64F_RESET_3D) + +#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32= | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4) +#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32= | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS) =20 static struct { =2D u16 pci_id, chip_type; =2D u8 rev_mask, rev_val; + u16 pci_id; const char *name; =2D int pll, mclk; + int pll, mclk, xclk; u32 features; } aty_chips[] __initdata =3D { #ifdef CONFIG_FB_ATY_GX /* Mach64 GX */ =2D { =2D 0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, M64F_GX}, { =2D 0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, M64F_GX}, =2D#endif /* CONFIG_FB_ATY_GX */ + { PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, ATI_CHIP_8880= 0GX }, + { PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, ATI_CHIP_8880= 0CX }, +#endif /* CONFIG_FB_ATY_GX */ + #ifdef CONFIG_FB_ATY_CT =2D /* Mach64 CT */ =2D { =2D 0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60, =2D M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | =2D M64F_MAGIC_FIFO}, { =2D 0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60, =2D M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | =2D M64F_MAGIC_FIFO}, =2D /* Mach64 VT */ =2D { =2D 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67, =2D M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | =2D M64F_MAGIC_FIFO | M64F_FIFO_24}, { =2D 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67, =2D M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | =2D M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV}, { =2D 0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67, =2D M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | =2D M64F_GTB_DSP | M64F_FIFO_24}, { =2D 0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67, =2D M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | =2D M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL}, { =2D 0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83, =2D M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP}, =2D /* Mach64 GT (3D RAGE) */ =2D { =2D 0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63, =2D M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | =2D M64F_FIFO_24 | M64F_EXTRA_BRIGHT}, { =2D 0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, =2D /* Mach64 LT */ =2D { =2D 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP}, { =2D 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63, =2D M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | =2D M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | =2D M64F_LT_SLEEP | M64F_G3_PB_1024x768}, =2D /* Mach64 GTC (3D RAGE PRO) */ =2D { =2D 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE}, { =2D 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, { =2D 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT}, =2D /* 3D RAGE XL */ =2D { =2D 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | =2D M64F_EXTRA_BRIGHT | M64F_XL_DLL}, =2D /* Mach64 LT PRO */ =2D { =2D 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP}, { =2D 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP}, { =2D 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_EXTRA_BRIGHT | =2D M64F_G3_PB_1_1 | M64F_G3_PB_1024x768}, { =2D 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP}, =2D /* 3D RAGE Mobility */ =2D { =2D 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_MOBIL_BUS}, { =2D 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50, =2D M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | =2D M64F_GTB_DSP | M64F_MOBIL_BUS}, =2D#endif /* CONFIG_FB_ATY_CT */ + { PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, ATI_CHIP_264CT = }, + { PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, ATI_CHIP_264ET = }, + { PCI_CHIP_MACH64VT, "ATI264VT? (Mach64 VT)", 170, 67, 67, ATI_CHIP_264VT= }, + { PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, ATI_CHIP_264GT }, + /* FIXME { ...ATI_264GU, maybe ATI_CHIP_264GTDVD }, */ + { PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GTB)", 200, 67, 67, ATI_CHIP_26= 4GTB }, + { PCI_CHIP_MACH64VU, "ATI264VTB (Mach64 VU)", 200, 67, 67, ATI_CHIP_264VT= 3 }, + + { PCI_CHIP_MACH64LT, "3D RAGE LT (Mach64 LT)", 135, 63, 63, ATI_CHIP_264L= T }, + /* FIXME chipset maybe ATI_CHIP_264LTPRO ? */ + { PCI_CHIP_MACH64LG, "3D RAGE LT-G (Mach64 LG)", 230, 63, 63, ATI_CHIP_26= 4LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 }, + + { PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, ATI_CHIP_264VT= 4 }, + + { PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, ATI_CHI= P_264GT2C }, + { PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, ATI_CHI= P_264GT2C }, + { PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, ATI_CHI= P_264GT2C }, + { PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, ATI_CHI= P_264GT2C }, + + { PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, = ATI_CHIP_264GTPRO }, + { PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 10= 0, ATI_CHIP_264GTPRO }, + { PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, = ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE }, + { PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100,= ATI_CHIP_264GTPRO }, + { PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 23= 0, 100, 100, ATI_CHIP_264GTPRO }, + + { PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, ATI= _CHIP_264LTPRO }, + { PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, AT= I_CHIP_264LTPRO }, + { PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, AT= I_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 }, + { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, AT= I_CHIP_264LTPRO }, + { PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, AT= I_CHIP_264LTPRO }, + + { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP= _264XL }, + { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP= _264XL }, + { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, A= TI_CHIP_264XL }, + { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 230, 83, 63, AT= I_CHIP_264XL }, + { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP= _264XL }, + { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP= _264XL }, + + { PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83,= 125, ATI_CHIP_MOBILITY }, + { PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 1= 25, ATI_CHIP_MOBILITY }, + { PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 12= 5, ATI_CHIP_MOBILITY }, + { PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125,= ATI_CHIP_MOBILITY }, +#endif /* CONFIG_FB_ATY_CT */ }; =20 +/* can not fail */ +static int __devinit correct_chipset(struct atyfb_par *par) +{ + u8 rev; + u16 type; + u32 chip_id; + const char *name; + int i; + + for (i =3D sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >=3D 0; i--) + if (par->pci_id =3D=3D aty_chips[i].pci_id) + break; + + name =3D aty_chips[i].name; + par->pll_limits.pll_max =3D aty_chips[i].pll; + par->pll_limits.mclk =3D aty_chips[i].mclk; + par->pll_limits.xclk =3D aty_chips[i].xclk; + par->features =3D aty_chips[i].features; + + chip_id =3D aty_ld_le32(CONFIG_CHIP_ID, par); + type =3D chip_id & CFG_CHIP_TYPE; + rev =3D (chip_id & CFG_CHIP_REV) >> 24; + + switch(par->pci_id) { +#ifdef CONFIG_FB_ATY_GX + case PCI_CHIP_MACH64GX: + if(type !=3D 0x00d7); + return -ENODEV; + break; + case PCI_CHIP_MACH64CX: + if(type !=3D 0x0057); + return -ENODEV; + break; +#endif +#ifdef CONFIG_FB_ATY_CT + case PCI_CHIP_MACH64VT: + rev &=3D 0xc7; + if(rev =3D=3D 0x00) { + name =3D "ATI264VTA3 (Mach64 VT)"; + par->pll_limits.pll_max =3D 170; + par->pll_limits.mclk =3D 67; + par->pll_limits.xclk =3D 67; + par->features =3D ATI_CHIP_264VT; + } else if(rev =3D=3D 0x40) { + name =3D "ATI264VTA4 (Mach64 VT)"; + par->pll_limits.pll_max =3D 200; + par->pll_limits.mclk =3D 67; + par->pll_limits.xclk =3D 67; + par->features =3D ATI_CHIP_264VT | M64F_MAGIC_POSTDIV; + } else { + name =3D "ATI264VTB (Mach64 VT)"; + par->pll_limits.pll_max =3D 200; + par->pll_limits.mclk =3D 67; + par->pll_limits.xclk =3D 67; + par->features =3D ATI_CHIP_264VTB; + } + break; + case PCI_CHIP_MACH64GT: + rev &=3D 0x07; + if(rev =3D=3D 0x01) { + par->pll_limits.pll_max =3D 170; + par->pll_limits.mclk =3D 67; + par->pll_limits.xclk =3D 67; + par->features =3D ATI_CHIP_264GTB; + } else if(rev =3D=3D 0x02) { + par->pll_limits.pll_max =3D 200; + par->pll_limits.mclk =3D 67; + par->pll_limits.xclk =3D 67; + par->features =3D ATI_CHIP_264GTB; + } + break; +#endif + } + + PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev); + return 0; +} + static char ram_dram[] __initdata =3D "DRAM"; +static char ram_resv[] __initdata =3D "RESV"; #ifdef CONFIG_FB_ATY_GX static char ram_vram[] __initdata =3D "VRAM"; #endif /* CONFIG_FB_ATY_GX */ #ifdef CONFIG_FB_ATY_CT static char ram_edo[] __initdata =3D "EDO"; =2Dstatic char ram_sdram[] __initdata =3D "SDRAM"; =2Dstatic char ram_sgram[] __initdata =3D "SGRAM"; =2Dstatic char ram_wram[] __initdata =3D "WRAM"; +static char ram_sdram[] __initdata =3D "SDRAM (1:1)"; +static char ram_sgram[] __initdata =3D "SGRAM (1:1)"; +static char ram_sdram32[] __initdata =3D "SDRAM (2:1) (32-bit)"; static char ram_off[] __initdata =3D "OFF"; #endif /* CONFIG_FB_ATY_CT */ =2Dstatic char ram_resv[] __initdata =3D "RESV"; + =20 static u32 pseudo_palette[17]; =20 @@ -410,109 +508,226 @@ ram_dram, ram_vram, ram_vram, ram_dram, ram_dram, ram_vram, ram_vram, ram_resv }; =2D#endif /* CONFIG_FB_ATY_GX */ +#endif /* CONFIG_FB_ATY_GX */ =20 #ifdef CONFIG_FB_ATY_CT static char *aty_ct_ram[8] __initdata =3D { ram_off, ram_dram, ram_edo, ram_edo, =2D ram_sdram, ram_sgram, ram_wram, ram_resv + ram_sdram, ram_sgram, ram_sdram32, ram_resv }; =2D#endif /* CONFIG_FB_ATY_CT */ +#endif /* CONFIG_FB_ATY_CT */ =20 +static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_= par *par) +{ + u32 pixclock =3D var->pixclock; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + u32 lcd_on_off; + par->pll.ct.xres =3D 0; + if (par->lcd_table !=3D 0) { + lcd_on_off =3D aty_ld_lcd(LCD_GEN_CNTL, par); + if(lcd_on_off & LCD_ON) { + par->pll.ct.xres =3D var->xres; + pixclock =3D par->lcd_pixclock; + } + } +#endif + return pixclock; +} =20 #if defined(CONFIG_PPC) =20 =2D /* =2D * Apple monitor sense =2D */ +/* + * Apple monitor sense + */ =20 static int __init read_aty_sense(const struct atyfb_par *par) { int sense, i; =20 =2D aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */ + aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */ __delay(200); =2D aty_st_le32(GP_IO, 0, par); /* turn off outputs */ + aty_st_le32(GP_IO, 0, par); /* turn off outputs */ __delay(2000); =2D i =3D aty_ld_le32(GP_IO, par); /* get primary sense value */ + i =3D aty_ld_le32(GP_IO, par); /* get primary sense value */ sense =3D ((i & 0x3000) >> 3) | (i & 0x100); =20 /* drive each sense line low in turn and collect the other 2 */ =2D aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */ + aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */ __delay(2000); i =3D aty_ld_le32(GP_IO, par); sense |=3D ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); =2D aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */ + aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */ __delay(200); =20 =2D aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */ + aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */ __delay(2000); i =3D aty_ld_le32(GP_IO, par); sense |=3D ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); =2D aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */ + aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */ __delay(200); =20 =2D aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */ + aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */ __delay(2000); sense |=3D (aty_ld_le32(GP_IO, par) & 0x3000) >> 12; =2D aty_st_le32(GP_IO, 0, par); /* turn off outputs */ + aty_st_le32(GP_IO, 0, par); /* turn off outputs */ return sense; } =20 =2D#endif /* defined(CONFIG_PPC) */ =2D =2D#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) =2Dstatic void aty_st_lcd(int index, u32 val, const struct atyfb_par *par) =2D{ =2D unsigned long temp; =2D =2D /* write addr byte */ =2D temp =3D aty_ld_le32(LCD_INDEX, par); =2D aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); =2D /* write the register value */ =2D aty_st_le32(LCD_DATA, val, par); =2D} =2D =2Dstatic u32 aty_ld_lcd(int index, const struct atyfb_par *par) =2D{ =2D unsigned long temp; =2D =2D /* write addr byte */ =2D temp =3D aty_ld_le32(LCD_INDEX, par); =2D aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par); =2D /* read the register value */ =2D return aty_ld_le32(LCD_DATA, par); =2D} =2D#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */ +#endif /* defined(CONFIG_PPC) */ =20 /* -----------------------------------------------------------------------= =2D- */ =20 =2D /* =2D * CRTC programming =2D */ +/* + * CRTC programming + */ =20 =2Dstatic void aty_set_crtc(const struct atyfb_par *par, =2D const struct crtc *crtc) +static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc) { +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table !=3D 0) { + if(!M64_HAS(LT_LCD_REGS)) { + crtc->lcd_index =3D aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, crtc->lcd_index, par); + } + crtc->lcd_config_panel =3D aty_ld_lcd(CONFIG_PANEL, par); + crtc->lcd_gen_cntl =3D aty_ld_lcd(LCD_GEN_CNTL, par); + + + /* switch to non shadow registers */ + aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & + ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); + + /* save stretching */ + crtc->horz_stretching =3D aty_ld_lcd(HORZ_STRETCHING, par); + crtc->vert_stretching =3D aty_ld_lcd(VERT_STRETCHING, par); + if (!M64_HAS(LT_LCD_REGS)) + crtc->ext_vert_stretch =3D aty_ld_lcd(EXT_VERT_STRETCH, par); + } +#endif + crtc->h_tot_disp =3D aty_ld_le32(CRTC_H_TOTAL_DISP, par); + crtc->h_sync_strt_wid =3D aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); + crtc->v_tot_disp =3D aty_ld_le32(CRTC_V_TOTAL_DISP, par); + crtc->v_sync_strt_wid =3D aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); + crtc->vline_crnt_vline =3D aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par); + crtc->off_pitch =3D aty_ld_le32(CRTC_OFF_PITCH, par); + crtc->gen_cntl =3D aty_ld_le32(CRTC_GEN_CNTL, par); + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table !=3D 0) { + /* switch to shadow registers */ + aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | + SHADOW_EN | SHADOW_RW_EN, par); + + crtc->shadow_h_tot_disp =3D aty_ld_le32(CRTC_H_TOTAL_DISP, par); + crtc->shadow_h_sync_strt_wid =3D aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); + crtc->shadow_v_tot_disp =3D aty_ld_le32(CRTC_V_TOTAL_DISP, par); + crtc->shadow_v_sync_strt_wid =3D aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); + + aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ +} + +static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *c= rtc) +{ +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table !=3D 0) { + /* stop CRTC */ + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN= ), par); + + /* update non-shadow registers first */ + aty_st_lcd(CONFIG_PANEL, crtc->lcd_config_panel, par); + aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & + ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); + + /* temporarily disable stretching */ + aty_st_lcd(HORZ_STRETCHING, + crtc->horz_stretching & + ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par); + aty_st_lcd(VERT_STRETCHING, + crtc->vert_stretching & + ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 | + VERT_STRETCH_USE0 | VERT_STRETCH_EN), par); + } +#endif + /* turn off CRT */ + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par); + + DPRINTK("setting up CRTC\n"); + PRINTKI("set primary CRT to %ix%i %c%c composite %c\n", + ((((crtc->h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->v_tot_disp>>16) = & 0x7ff) + 1), + (crtc->h_sync_strt_wid & 0x200000)?'N':'P', (crtc->v_sync_strt_wid & = 0x200000)?'N':'P', + (crtc->gen_cntl & CRTC_CSYNC_EN)?'P':'N'); + + DPRINTK("CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp); + DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid); + DPRINTK("CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp); + DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid); + DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch); + DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline); + DPRINTK("CRTC_GEN_CNTL: %x\n",crtc->gen_cntl); + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par); aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par); aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par); aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par); =2D aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, par); aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par); + aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par); + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par); +#if 0 + FIXME + if (par->accel_flags & FB_ACCELF_TEXT) + aty_init_engine(par, info); +#endif +#ifdef CONFIG_FB_ATY_GENERIC_LCD + /* after setting the CRTC registers we should set the LCD registers. */ + if (par->lcd_table !=3D 0) { + /* switch to shadow registers */ + aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | + (SHADOW_EN | SHADOW_RW_EN), par); + + PRINTKI("set secondary CRT to %ix%i %c%c\n", + ((((crtc->shadow_h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->shadow_v= _tot_disp>>16) & 0x7ff) + 1), + (crtc->shadow_h_sync_strt_wid & 0x200000)?'N':'P', (crtc->shadow_v_s= ync_strt_wid & 0x200000)?'N':'P'); + + DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", crtc->shadow_h_tot_disp); + DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", crtc->shadow_h_sync_strt_wi= d); + DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", crtc->shadow_v_tot_disp); + DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", crtc->shadow_v_sync_strt_wi= d); + + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par); + + /* restore CRTC selection & shadow state and enable stretching */ + DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl); + DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching); + DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching); + if(!M64_HAS(LT_LCD_REGS)) + DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch); + + aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); + aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par); + aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par); + if(!M64_HAS(LT_LCD_REGS)) { + aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par); + aty_ld_le32(LCD_INDEX, par); + aty_st_le32(LCD_INDEX, crtc->lcd_index, par); + } + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ } =20 static int aty_var_to_crtc(const struct fb_info *info, =2D const struct fb_var_screeninfo *var, =2D struct crtc *crtc) + const struct fb_var_screeninfo *var, struct crtc *crtc) { struct atyfb_par *par =3D (struct atyfb_par *) info->par; u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; =2D u32 left, right, upper, lower, hslen, vslen, sync, vmode; =2D u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, =2D h_sync_pol; =2D u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 sync, vmode, vdisplay; + u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_s= ync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_s= ync; u32 pix_width, dp_pix_width, dp_chain_mask; =20 /* input */ @@ -523,53 +738,19 @@ xoffset =3D var->xoffset; yoffset =3D var->yoffset; bpp =3D var->bits_per_pixel; =2D left =3D var->left_margin; =2D right =3D var->right_margin; =2D upper =3D var->upper_margin; =2D lower =3D var->lower_margin; =2D hslen =3D var->hsync_len; =2D vslen =3D var->vsync_len; + if (bpp =3D=3D 16) + bpp =3D (var->green.length =3D=3D 5) ? 15 : 16; sync =3D var->sync; vmode =3D var->vmode; =20 /* convert (and round up) and validate */ =2D xres =3D (xres + 7) & ~7; =2D xoffset =3D (xoffset + 7) & ~7; =2D vxres =3D (vxres + 7) & ~7; if (vxres < xres + xoffset) vxres =3D xres + xoffset; =2D h_disp =3D xres / 8 - 1; =2D if (h_disp > 0xff) =2D FAIL("h_disp too large"); =2D h_sync_strt =3D h_disp + (right / 8); =2D if (h_sync_strt > 0x1ff) =2D FAIL("h_sync_start too large"); =2D h_sync_dly =3D right & 7; =2D h_sync_wid =3D (hslen + 7) / 8; =2D if (h_sync_wid > 0x1f) =2D FAIL("h_sync_wid too large"); =2D h_total =3D h_sync_strt + h_sync_wid + (h_sync_dly + left + 7) / 8; =2D if (h_total > 0x1ff) =2D FAIL("h_total too large"); =2D h_sync_pol =3D sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + h_disp =3D xres; =20 if (vyres < yres + yoffset) vyres =3D yres + yoffset; =2D v_disp =3D yres - 1; =2D if (v_disp > 0x7ff) =2D FAIL("v_disp too large"); =2D v_sync_strt =3D v_disp + lower; =2D if (v_sync_strt > 0x7ff) =2D FAIL("v_sync_strt too large"); =2D v_sync_wid =3D vslen; =2D if (v_sync_wid > 0x1f) =2D FAIL("v_sync_wid too large"); =2D v_total =3D v_sync_strt + v_sync_wid + upper; =2D if (v_total > 0x7ff) =2D FAIL("v_total too large"); =2D v_sync_pol =3D sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; =2D =2D c_sync =3D sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; + v_disp =3D yres; =20 if (bpp <=3D 8) { bpp =3D 8; @@ -577,54 +758,325 @@ dp_pix_width =3D HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; =2D dp_chain_mask =3D 0x8080; =2D } else if (bpp <=3D 16) { + dp_chain_mask =3D DP_CHAIN_8BPP; + } else if (bpp <=3D 15) { bpp =3D 16; pix_width =3D CRTC_PIX_WIDTH_15BPP; dp_pix_width =3D HOST_15BPP | SRC_15BPP | DST_15BPP | BYTE_ORDER_LSB_TO_MSB; =2D dp_chain_mask =3D 0x4210; + dp_chain_mask =3D DP_CHAIN_15BPP; + } else if (bpp <=3D 16) { + bpp =3D 16; + pix_width =3D CRTC_PIX_WIDTH_16BPP; + dp_pix_width =3D HOST_16BPP | SRC_16BPP | DST_16BPP | + BYTE_ORDER_LSB_TO_MSB; + dp_chain_mask =3D DP_CHAIN_16BPP; } else if (bpp <=3D 24 && M64_HAS(INTEGRATED)) { bpp =3D 24; pix_width =3D CRTC_PIX_WIDTH_24BPP; dp_pix_width =3D HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; =2D dp_chain_mask =3D 0x8080; + dp_chain_mask =3D DP_CHAIN_24BPP; } else if (bpp <=3D 32) { bpp =3D 32; pix_width =3D CRTC_PIX_WIDTH_32BPP; dp_pix_width =3D HOST_32BPP | SRC_32BPP | DST_32BPP | BYTE_ORDER_LSB_TO_MSB; =2D dp_chain_mask =3D 0x8080; + dp_chain_mask =3D DP_CHAIN_32BPP; } else FAIL("invalid bpp"); =20 if (vxres * vyres * bpp / 8 > info->fix.smem_len) FAIL("not enough video RAM"); =20 =2D if ((vmode & FB_VMODE_MASK) !=3D FB_VMODE_NONINTERLACED) =2D FAIL("invalid vmode"); + h_sync_pol =3D sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol =3D sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + if((xres > 1600) || (yres > 1200)) { + FAIL("MACH64 chips are designed for max 1600x1200\n" + "select anoter resolution."); + } + h_sync_strt =3D h_disp + var->right_margin; + h_sync_end =3D h_sync_strt + var->hsync_len; + h_sync_dly =3D var->right_margin & 7; + h_total =3D h_sync_end + h_sync_dly + var->left_margin; + + v_sync_strt =3D v_disp + var->lower_margin; + v_sync_end =3D v_sync_strt + var->vsync_len; + v_total =3D v_sync_end + var->upper_margin; + +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table !=3D 0) { + if(!M64_HAS(LT_LCD_REGS)) { + u32 lcd_index =3D aty_ld_le32(LCD_INDEX, par); + crtc->lcd_index =3D lcd_index & + ~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | LCD_SRC_SEL | CRTC2_DISPLAY_DIS); + aty_st_le32(LCD_INDEX, lcd_index, par); + } + + if (!M64_HAS(MOBIL_BUS)) + crtc->lcd_index |=3D CRTC2_DISPLAY_DIS; + + crtc->lcd_config_panel =3D aty_ld_lcd(CONFIG_PANEL, par) | 0x4000; + crtc->lcd_gen_cntl =3D aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT; + + crtc->lcd_gen_cntl &=3D + ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN | + /*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/ + USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); + crtc->lcd_gen_cntl |=3D DONT_SHADOW_VPAR | LOCK_8DOT; + + if((crtc->lcd_gen_cntl & LCD_ON) && + ((xres > par->lcd_width) || (yres > par->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 (crtc->lcd_gen_cntl & CRT_ON) { + PRINTKI("Disable lcd panel, because video mode does not fit.\n"); + crtc->lcd_gen_cntl &=3D ~LCD_ON; + /*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/ + } else { + FAIL("Video mode exceeds size of lcd panel.\nConnect this computer to = a conventional monitor if you really need this mode."); + } + } + } + + if ((par->lcd_table !=3D 0) && (crtc->lcd_gen_cntl & LCD_ON)) { + int VScan =3D 1; + /* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5 + const u8 DFP_h_sync_dly_LT[] =3D { 0, 2, 1, 6, 5 }; + const u8 ADD_to_strt_wid_and_dly_LT_DAC[] =3D { 0, 5, 6, 9, 9, 12, 12 };= */ + + vmode &=3D ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED); + + /* 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 1400x1050 lcd + monitor and a conventional monitor both switched on. + Tested modes: 1280x1024, 1152x864, 1024x768, 800x600, + works with little glitches also with DOUBLESCAN modes + */ + if (yres < par->lcd_height) { + VScan =3D par->lcd_height / yres; + if(VScan > 1) { + VScan =3D 2; + vmode |=3D FB_VMODE_DOUBLE; + } + } + + h_sync_strt =3D h_disp + par->lcd_right_margin; + h_sync_end =3D h_sync_strt + par->lcd_hsync_len; + h_sync_dly =3D /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly; + h_total =3D h_disp + par->lcd_hblank_len; + + v_sync_strt =3D v_disp + par->lcd_lower_margin / VScan; + v_sync_end =3D v_sync_strt + par->lcd_vsync_len / VScan; + v_total =3D v_disp + par->lcd_vblank_len / VScan; + } +#endif /* CONFIG_FB_ATY_GENERIC_LCD */ + + h_disp =3D (h_disp >> 3) - 1; + h_sync_strt =3D (h_sync_strt >> 3) - 1; + h_sync_end =3D (h_sync_end >> 3) - 1; + h_total =3D (h_total >> 3) - 1; + h_sync_wid =3D h_sync_end - h_sync_strt; + + FAIL_MAX("h_disp too large", h_disp, 0xff); + FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff); + /*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/ + if(h_sync_wid > 0x1f) + h_sync_wid =3D 0x1f; + FAIL_MAX("h_total too large", h_total, 0x1ff); + + if (vmode & FB_VMODE_DOUBLE) { + v_disp <<=3D 1; + v_sync_strt <<=3D 1; + v_sync_end <<=3D 1; + v_total <<=3D 1; + } + + vdisplay =3D yres; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if ((par->lcd_table !=3D 0) && (crtc->lcd_gen_cntl & LCD_ON)) + vdisplay =3D par->lcd_height; +#endif + + if(vdisplay < 400) { + h_sync_pol =3D 1; + v_sync_pol =3D 0; + } else if(vdisplay < 480) { + h_sync_pol =3D 0; + v_sync_pol =3D 1; + } else if(vdisplay < 768) { + h_sync_pol =3D 0; + v_sync_pol =3D 0; + } else { + h_sync_pol =3D 1; + v_sync_pol =3D 1; + } + + v_disp--; + v_sync_strt--; + v_sync_end--; + v_total--; + v_sync_wid =3D v_sync_end - v_sync_strt; + + FAIL_MAX("v_disp too large", v_disp, 0x7ff); + FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff); + /*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/ + if(v_sync_wid > 0x1f) + v_sync_wid =3D 0x1f; + FAIL_MAX("v_total too large", v_total, 0x7ff); + + c_sync =3D sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; =20 /* output */ crtc->vxres =3D vxres; crtc->vyres =3D vyres; =2D crtc->h_tot_disp =3D h_total | (h_disp << 16); =2D crtc->h_sync_strt_wid =3D (h_sync_strt & 0xff) | (h_sync_dly << 8) | =2D ((h_sync_strt & 0x100) << 4) | (h_sync_wid << 16) | =2D (h_sync_pol << 21); =2D crtc->v_tot_disp =3D v_total | (v_disp << 16); =2D crtc->v_sync_strt_wid =3D =2D v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 21); =2D crtc->off_pitch =3D =2D ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19); =2D crtc->gen_cntl =3D =2D pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE; + crtc->xoffset =3D xoffset; + crtc->yoffset =3D yoffset; + crtc->bpp =3D bpp; + crtc->off_pitch =3D ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); + crtc->vline_crnt_vline =3D 0; + + crtc->h_tot_disp =3D h_total | (h_disp<<16); + crtc->h_sync_strt_wid =3D (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 =3D v_total | (v_disp<<16); + crtc->v_sync_strt_wid =3D v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<2= 1); + + /* crtc->gen_cntl =3D aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MA= SK; */ + crtc->gen_cntl =3D CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync; + crtc->gen_cntl |=3D CRTC_VGA_LINEAR; + + /* Enable doublescan mode if requested */ + if (vmode & FB_VMODE_DOUBLE) + crtc->gen_cntl |=3D CRTC_DBL_SCAN_EN; + /* Enable interlaced mode if requested */ + if (vmode & FB_VMODE_INTERLACED) + crtc->gen_cntl |=3D CRTC_INTERLACE_EN; +#ifdef CONFIG_FB_ATY_GENERIC_LCD + if (par->lcd_table !=3D 0) { + vdisplay =3D yres; + if(vmode & FB_VMODE_DOUBLE) + vdisplay <<=3D 1; + if(vmode & FB_VMODE_INTERLACED) { + vdisplay >>=3D 1; + + /* 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 muc= h) + */ + vmode &=3D ~FB_VMODE_INTERLACED; + /*crtc->gen_cntl &=3D ~CRTC_INTERLACE_EN;*/ + } + crtc->gen_cntl &=3D ~(CRTC2_EN | CRTC2_PIX_WIDTH); + crtc->lcd_gen_cntl &=3D ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | + /*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/ + USE_SHADOWED_VEND | USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); + crtc->lcd_gen_cntl |=3D (DONT_SHADOW_VPAR/* | LOCK_8DOT*/); + + /* MOBILITY M1 tested, FIXME: LT */ + crtc->horz_stretching =3D aty_ld_lcd(HORZ_STRETCHING, par); + if (!M64_HAS(LT_LCD_REGS)) + crtc->ext_vert_stretch =3D aty_ld_lcd(EXT_VERT_STRETCH, par) & + ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3); + + crtc->horz_stretching &=3D + ~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO | + HORZ_STRETCH_MODE | HORZ_STRETCH_EN); + if (xres < par->lcd_width) { + do { + /* + * The horizontal blender misbehaves when HDisplay is less than a + * a certain threshold (440 for a 1024-wide panel). It doesn't + * stretch such modes enough. Use pixel replication instead of + * blending to stretch modes that can be made to exactly fit the + * panel width. The undocumented "NoLCDBlend" option allows the + * pixel-replicated mode to be slightly wider or narrower than the + * panel width. It also causes a mode that is exactly half as wide + * as the panel to be pixel-replicated, rather than blended. + */ + int HDisplay =3D xres & ~7; + int nStretch =3D par->lcd_width / HDisplay; + int Remainder =3D par->lcd_width % HDisplay; + + if ((!Remainder && ((nStretch > 2))) || + (((HDisplay * 16) / par->lcd_width) < 7)) { + static const char StretchLoops[] =3D {10, 12, 13, 15, 16}; + int horz_stretch_loop =3D -1, BestRemainder; + int Numerator =3D HDisplay, Denominator =3D par->lcd_width; + int Index =3D 5; + ATIReduceRatio(&Numerator, &Denominator); + + BestRemainder =3D (Numerator * 16) / Denominator; + while (--Index >=3D 0) { + Remainder =3D ((Denominator - Numerator) * StretchLoops[Index]) % + Denominator; + if (Remainder < BestRemainder) { + horz_stretch_loop =3D Index; + if (!(BestRemainder =3D Remainder)) + break; + } + } + + if ((horz_stretch_loop >=3D 0) && !BestRemainder) { + int horz_stretch_ratio =3D 0, Accumulator =3D 0; + int reuse_previous =3D 1; + + Index =3D StretchLoops[horz_stretch_loop]; + + while (--Index >=3D 0) { + if (Accumulator > 0) + horz_stretch_ratio |=3D reuse_previous; + else + ... [truncated message content] |