]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Update aty128fb video driver
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Sun, 15 Feb 2004 01:32:46 +0000 (17:32 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Sun, 15 Feb 2004 01:32:46 +0000 (17:32 -0800)
This updates the aty128fb driver.  It adds more PCI IDs, uses the new
framebuffer alloc/release functions, make BIOS PLL data access more
reliable (using ROM whenever possible, with a fallback to RAM BIOS
image), cleanup the Power Management stuff (get rid of PowerMac specific
stuffs, use real PCI ones instead), along with some style cleanups

drivers/video/aty/aty128fb.c
include/linux/pci_ids.h
include/video/aty128.h

index 781c4613e9a4f2f738fc071c61514defe5a842ec..173a9ea800cbda54fd02ecfb5b5020d6c1f813d6 100644 (file)
@@ -13,6 +13,7 @@
  *
  *                Benjamin Herrenschmidt
  *                      - pmac-specific PM stuff
+ *                     - various fixes & cleanups
  *
  *                Andreas Hundt <andi@convergence.de>
  *                      - FB_ACTIVATE fixes
  *               Paul Mundt 
  *                     - PCI hotplug
  *
+ *               Jon Smirl <jonsmirl@yahoo.com>
+ *                     - PCI ID update
+ *                     - replace ROM BIOS search
+ *
  *  Based off of Geert's atyfb.c and vfb.c.
  *
  *  TODO:
@@ -43,6 +48,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -57,6 +63,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/console.h>
 #include <asm/io.h>
 
 #ifdef CONFIG_PPC_PMAC
 #include "../macmodes.h"
 #endif
 
-#ifdef CONFIG_ADB_PMU
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
-
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
@@ -136,8 +138,25 @@ static struct fb_videomode defaultmode __initdata = {
 /* Chip generations */
 enum {
        rage_128,
+       rage_128_pci,
        rage_128_pro,
-       rage_M3
+       rage_128_pro_pci,
+       rage_M3,
+       rage_M3_pci,
+       rage_M4,
+       rage_128_ultra,
+};
+
+/* Must match above enum */
+static const char *r128_family[] __devinitdata = {
+       "AGP",
+       "PCI",
+       "PRO AGP",
+       "PRO PCI",
+       "M3 AGP",
+       "M3 PCI",
+       "M4 AGP",
+       "Ultra AGP",
 };
 
 /*
@@ -146,35 +165,105 @@ enum {
 static int aty128_probe(struct pci_dev *pdev,
                                const struct pci_device_id *ent);
 static void aty128_remove(struct pci_dev *pdev);
+static int aty128_pci_suspend(struct pci_dev *pdev, u32 state);
+static int aty128_pci_resume(struct pci_dev *pdev);
 
 /* supported Rage128 chipsets */
 static struct pci_device_id aty128_pci_tbl[] = {
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RI,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_Rage128_PD,
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U3,
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U1,
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
-       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
        { 0, }
 };
 
@@ -185,6 +274,8 @@ static struct pci_driver aty128fb_driver = {
        .id_table       = aty128_pci_tbl,
        .probe          = aty128_probe,
        .remove         = __devexit_p(aty128_remove),
+       .suspend        = aty128_pci_suspend,
+       .resume         = aty128_pci_resume,
 };
 
 /* packed BIOS settings */
@@ -250,13 +341,6 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = {
        .accel          = FB_ACCEL_ATI_RAGE128,
 };
 
-#ifdef MODULE
-static char *mode __initdata = NULL;
-#ifdef CONFIG_MTRR
-static int  nomtrr __initdata = 0;
-#endif /* CONFIG_MTRR */
-#endif /* MODULE */
-
 static char *mode_option __initdata = NULL;
 
 #ifdef CONFIG_PPC_PMAC
@@ -275,7 +359,7 @@ static int mtrr = 1;
 
 /* PLL constants */
 struct aty128_constants {
-       u32 dotclock;
+       u32 ref_clk;
        u32 ppll_min;
        u32 ppll_max;
        u32 ref_divider;
@@ -322,26 +406,20 @@ struct aty128fb_par {
 #endif
        int blitter_may_be_busy;
        int fifo_slots;                 /* free slots in FIFO (64 max) */
-#ifdef CONFIG_PMAC_PBOOK
-       unsigned char *save_framebuffer;
+
        int     pm_reg;
        int crt_on, lcd_on;
        struct pci_dev *pdev;
        struct fb_info *next;
-#endif
+       int     asleep;
+       int     lock_blank;
+
        u8      red[32];                /* see aty128fb_setcolreg */
        u8      green[64];
        u8      blue[32];
        u32     pseudo_palette[16];     /* used for TRUECOLOR */
 };
 
-#ifdef CONFIG_PMAC_PBOOK
-int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier aty128_sleep_notifier = {
-       aty128_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-static struct fb_info *aty128_fb = NULL;
-#endif
 
 #define round_div(n, d) ((n+(d/2))/d)
 
@@ -349,7 +427,6 @@ static struct fb_info *aty128_fb = NULL;
      *  Interface used by the world
      */
 int aty128fb_init(void);
-int aty128fb_setup(char *options);
 
 static int aty128fb_check_var(struct fb_var_screeninfo *var,
                              struct fb_info *info);
@@ -371,10 +448,10 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
                              const struct aty128fb_par *par);
 static int aty128_decode_var(struct fb_var_screeninfo *var,
                              struct aty128fb_par *par);
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
+#if 0
 static void __init aty128_get_pllinfo(struct aty128fb_par *par,
                                      void *bios);
-static void __init *aty128_map_ROM(struct pci_dev *pdev);
+static void __init *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
 static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom);
 #endif
 static void aty128_timings(struct aty128fb_par *par);
@@ -386,6 +463,15 @@ static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
 static void wait_for_idle(struct aty128fb_par *par);
 static u32 depth_to_dst(u32 depth);
 
+#define BIOS_IN8(v)    (readb(bios + (v)))
+#define BIOS_IN16(v)   (readb(bios + (v)) | \
+                         (readb(bios + (v) + 1) << 8))
+#define BIOS_IN32(v)   (readb(bios + (v)) | \
+                         (readb(bios + (v) + 1) << 8) | \
+                         (readb(bios + (v) + 2) << 16) | \
+                         (readb(bios + (v) + 3) << 24))
+
+
 static struct fb_ops aty128fb_ops = {
        .owner          = THIS_MODULE,
        .fb_check_var   = aty128fb_check_var,
@@ -395,15 +481,9 @@ static struct fb_ops aty128fb_ops = {
        .fb_blank       = aty128fb_blank,
        .fb_ioctl       = aty128fb_ioctl,
        .fb_sync        = aty128fb_sync,
-#if 0
-       .fb_fillrect    = aty128fb_fillrect,
-       .fb_copyarea    = aty128fb_copyarea,
-       .fb_imageblit   = aty128fb_imageblit,
-#else
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
-#endif
        .fb_cursor      = soft_cursor,
 };
 
@@ -422,40 +502,26 @@ static struct backlight_controller aty128_backlight_controller = {
      * - endian conversions may possibly be avoided by
      *    using the other register aperture. TODO.
      */
-static inline u32
-_aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par)
+static inline u32 _aty_ld_le32(volatile unsigned int regindex, 
+                              const struct aty128fb_par *par)
 {
-       u32 val;
-
-#if defined(__powerpc__)
-       asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(par->regbase));
-#else
-       val = readl (par->regbase + regindex);
-#endif
-
-       return val;
+       return readl (par->regbase + regindex);
 }
 
-static inline void
-_aty_st_le32(volatile unsigned int regindex, u32 val, 
-                               const struct aty128fb_par *par)
+static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, 
+                               const struct aty128fb_par *par)
 {
-#if defined(__powerpc__)
-       asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex),
-           "r"(par->regbase) : "memory");
-#else
        writel (val, par->regbase + regindex);
-#endif
 }
 
-static inline u8
-_aty_ld_8(unsigned int regindex, const struct aty128fb_par *par)
+static inline u8 _aty_ld_8(unsigned int regindex,
+                          const struct aty128fb_par *par)
 {
        return readb (par->regbase + regindex);
 }
 
-static inline void
-_aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par)
+static inline void _aty_st_8(unsigned int regindex, u8 val,
+                            const struct aty128fb_par *par)
 {
        writeb (val, par->regbase + regindex);
 }
@@ -473,17 +539,15 @@ _aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par)
 #define aty_st_pll(pll_index, val)     _aty_st_pll(pll_index, val, par)
 
 
-static u32
-_aty_ld_pll(unsigned int pll_index,
-                       const struct aty128fb_par *par)
+static u32 _aty_ld_pll(unsigned int pll_index,
+                      const struct aty128fb_par *par)
 {       
        aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
        return aty_ld_le32(CLOCK_CNTL_DATA);
 }
 
     
-static void
-_aty_st_pll(unsigned int pll_index, u32 val,
+static void _aty_st_pll(unsigned int pll_index, u32 val,
                        const struct aty128fb_par *par)
 {
        aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN);
@@ -492,15 +556,13 @@ _aty_st_pll(unsigned int pll_index, u32 val,
 
 
 /* return true when the PLL has completed an atomic update */
-static int
-aty_pll_readupdate(const struct aty128fb_par *par)
+static int aty_pll_readupdate(const struct aty128fb_par *par)
 {
        return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
 }
 
 
-static void
-aty_pll_wait_readupdate(const struct aty128fb_par *par)
+static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
 {
        unsigned long timeout = jiffies + HZ/100; // should be more than enough
        int reset = 1;
@@ -517,8 +579,7 @@ aty_pll_wait_readupdate(const struct aty128fb_par *par)
 
 
 /* tell PLL to update */
-static void
-aty_pll_writeupdate(const struct aty128fb_par *par)
+static void aty_pll_writeupdate(const struct aty128fb_par *par)
 {
        aty_pll_wait_readupdate(par);
 
@@ -528,8 +589,7 @@ aty_pll_writeupdate(const struct aty128fb_par *par)
 
 
 /* write to the scratch register to test r/w functionality */
-static int __init
-register_test(const struct aty128fb_par *par)
+static int __init register_test(const struct aty128fb_par *par)
 {
        u32 val;
        int flag = 0;
@@ -552,8 +612,7 @@ register_test(const struct aty128fb_par *par)
 /*
  * Accelerator engine functions
  */
-static void
-do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
+static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
 {
        int i;
 
@@ -568,8 +627,7 @@ do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
 }
 
 
-static void
-wait_for_idle(struct aty128fb_par *par)
+static void wait_for_idle(struct aty128fb_par *par)
 {
        int i;
 
@@ -588,8 +646,7 @@ wait_for_idle(struct aty128fb_par *par)
 }
 
 
-static void
-wait_for_fifo(u16 entries, struct aty128fb_par *par)
+static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
 {
        if (par->fifo_slots < entries)
                do_wait_for_fifo(64, par);
@@ -597,8 +654,7 @@ wait_for_fifo(u16 entries, struct aty128fb_par *par)
 }
 
 
-static void
-aty128_flush_pixel_cache(const struct aty128fb_par *par)
+static void aty128_flush_pixel_cache(const struct aty128fb_par *par)
 {
        int i;
        u32 tmp;
@@ -614,8 +670,7 @@ aty128_flush_pixel_cache(const struct aty128fb_par *par)
 }
 
 
-static void
-aty128_reset_engine(const struct aty128fb_par *par)
+static void aty128_reset_engine(const struct aty128fb_par *par)
 {
        u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
 
@@ -643,8 +698,7 @@ aty128_reset_engine(const struct aty128fb_par *par)
 }
 
 
-static void
-aty128_init_engine(struct aty128fb_par *par)
+static void aty128_init_engine(struct aty128fb_par *par)
 {
        u32 pitch_value;
 
@@ -712,8 +766,7 @@ aty128_init_engine(struct aty128fb_par *par)
 
 
 /* convert depth values to their register representation */
-static u32
-depth_to_dst(u32 depth)
+static u32 depth_to_dst(u32 depth)
 {
        if (depth <= 8)
                return DST_8BPP;
@@ -729,15 +782,247 @@ depth_to_dst(u32 depth)
        return -EINVAL;
 }
 
+/*
+ * PLL informations retreival
+ */
+
+
+#ifndef __sparc__
+static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
+{
+       struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
+       
+       iounmap(rom);
+       
+       /* Release the ROM resource if we used it in the first place */
+       if (r->parent && r->flags & PCI_ROM_ADDRESS_ENABLE) {
+               release_resource(r);
+               r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+               r->end -= r->start;
+               r->start = 0;
+       }
+       /* This will disable and set address to unassigned */
+       pci_write_config_dword(dev, dev->rom_base_reg, 0);
+}
+
+
+static void * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+{
+       struct resource *r;
+       u16 dptr;
+       u8 rom_type;
+       void *bios;
+
+       /* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */
+       unsigned int temp;
+       temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
+       temp &= 0x00ffffffu;
+       temp |= 0x04 << 24;
+       aty_st_le32(RAGE128_MPP_TB_CONFIG, temp);
+       temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
+
+       /* no need to search for the ROM, just ask the card where it is. */
+       r = &dev->resource[PCI_ROM_RESOURCE];
+
+       /* assign the ROM an address if it doesn't have one */
+       if (r->parent == NULL)
+               pci_assign_resource(dev, PCI_ROM_RESOURCE);
+       
+       /* enable if needed */
+       if (!(r->flags & PCI_ROM_ADDRESS_ENABLE)) {
+               pci_write_config_dword(dev, dev->rom_base_reg,
+                                      r->start | PCI_ROM_ADDRESS_ENABLE);
+               r->flags |= PCI_ROM_ADDRESS_ENABLE;
+       }
+       
+       bios = ioremap(r->start, r->end - r->start + 1);
+       if (!bios) {
+               printk(KERN_ERR "aty128fb: ROM failed to map\n");
+               return NULL;
+       }
+       
+       /* Very simple test to make sure it appeared */
+       if (BIOS_IN16(0) != 0xaa55) {
+               printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n",
+                      BIOS_IN16(0));
+               goto failed;
+       }
+
+       /* Look for the PCI data to check the ROM type */
+       dptr = BIOS_IN16(0x18);
+
+       /* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
+        * for now, until I've verified this works everywhere. The goal here is more
+        * to phase out Open Firmware images.
+        *
+        * Currently, we only look at the first PCI data, we could iteratre and deal with
+        * them all, and we should use fb_bios_start relative to start of image and not
+        * relative start of ROM, but so far, I never found a dual-image ATI card
+        *
+        * typedef struct {
+        *      u32     signature;      + 0x00
+        *      u16     vendor;         + 0x04
+        *      u16     device;         + 0x06
+        *      u16     reserved_1;     + 0x08
+        *      u16     dlen;           + 0x0a
+        *      u8      drevision;      + 0x0c
+        *      u8      class_hi;       + 0x0d
+        *      u16     class_lo;       + 0x0e
+        *      u16     ilen;           + 0x10
+        *      u16     irevision;      + 0x12
+        *      u8      type;           + 0x14
+        *      u8      indicator;      + 0x15
+        *      u16     reserved_2;     + 0x16
+        * } pci_data_t;
+        */
+       if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
+               printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n",
+                      BIOS_IN32(dptr));
+               goto anyway;
+       }
+       rom_type = BIOS_IN8(dptr + 0x14);
+       switch(rom_type) {
+       case 0:
+               printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n");
+               break;
+       case 1:
+               printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n");
+               goto failed;
+       case 2:
+               printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");
+               goto failed;
+       default:
+               printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type);
+               goto failed;
+       }
+ anyway:
+       return bios;
+
+ failed:
+       aty128_unmap_ROM(dev, bios);
+       return NULL;
+}
+
+static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char *bios)
+{
+       unsigned int bios_hdr;
+       unsigned int bios_pll;
+
+       bios_hdr = BIOS_IN16(0x48);
+       bios_pll = BIOS_IN16(bios_hdr + 0x30);
+       
+       par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16);
+       par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12);
+       par->constants.xclk = BIOS_IN16(bios_pll + 0x08);
+       par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10);
+       par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e);
+
+       DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n",
+                       par->constants.ppll_max, par->constants.ppll_min,
+                       par->constants.xclk, par->constants.ref_divider,
+                       par->constants.ref_clk);
+
+}           
+
+#ifdef __i386__
+static void *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
+{
+       /* I simplified this code as we used to miss the signatures in
+        * a lot of case. It's now closer to XFree, we just don't check
+        * for signatures at all... Something better will have to be done
+        * if we end up having conflicts
+        */
+        u32  segstart;
+        unsigned char *rom_base = NULL;
+                                                
+        for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
+                rom_base = (char *)ioremap(segstart, 0x10000);
+               if (rom_base == NULL)
+                       return NULL;
+                if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
+                       break;
+                iounmap(rom_base);
+               rom_base = NULL;
+        }
+       return rom_base;
+}
+#endif /* __i386__ */
+#endif /* ndef(__sparc__) */
+
+/* fill in known card constants if pll_block is not available */
+static void __init aty128_timings(struct aty128fb_par *par)
+{
+#ifdef CONFIG_PPC_OF
+       /* instead of a table lookup, assume OF has properly
+        * setup the PLL registers and use their values
+        * to set the XCLK values and reference divider values */
+
+       u32 x_mpll_ref_fb_div;
+       u32 xclk_cntl;
+       u32 Nx, M;
+       unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
+#endif
+
+       if (!par->constants.ref_clk)
+               par->constants.ref_clk = 2950;
+
+#ifdef CONFIG_PPC_OF
+       x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
+       xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
+       Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
+       M  = x_mpll_ref_fb_div & 0x0000ff;
+
+       par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk),
+                                       (M * PostDivSet[xclk_cntl]));
+
+       par->constants.ref_divider =
+               aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
+#endif
+
+       if (!par->constants.ref_divider) {
+               par->constants.ref_divider = 0x3b;
+
+               aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
+               aty_pll_writeupdate(par);
+       }
+       aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
+       aty_pll_writeupdate(par);
+
+       /* from documentation */
+       if (!par->constants.ppll_min)
+               par->constants.ppll_min = 12500;
+       if (!par->constants.ppll_max)
+               par->constants.ppll_max = 25000;    /* 23000 on some cards? */
+       if (!par->constants.xclk)
+               par->constants.xclk = 0x1d4d;        /* same as mclk */
+
+       par->constants.fifo_width = 128;
+       par->constants.fifo_depth = 32;
+
+       switch (aty_ld_le32(MEM_CNTL) & 0x3) {
+       case 0:
+               par->mem = &sdr_128;
+               break;
+       case 1:
+               par->mem = &sdr_sgram;
+               break;
+       case 2:
+               par->mem = &ddr_sgram;
+               break;
+       default:
+               par->mem = &sdr_sgram;
+       }
+}
+
+
 
 /*
-     * CRTC programming
-     */
+ * CRTC programming
+ */
 
 /* Program the CRTC registers */
-static void
-aty128_set_crtc(const struct aty128_crtc *crtc,
-               const struct aty128fb_par *par)
+static void aty128_set_crtc(const struct aty128_crtc *crtc,
+                           const struct aty128fb_par *par)
 {
        aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
        aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
@@ -752,10 +1037,9 @@ aty128_set_crtc(const struct aty128_crtc *crtc,
 }
 
 
-static int
-aty128_var_to_crtc(const struct fb_var_screeninfo *var,
-                  struct aty128_crtc *crtc,
-                  const struct aty128fb_par *par)
+static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
+                             struct aty128_crtc *crtc,
+                             const struct aty128fb_par *par)
 {
        u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst;
        u32 left, right, upper, lower, hslen, vslen, sync, vmode;
@@ -881,8 +1165,7 @@ aty128_var_to_crtc(const struct fb_var_screeninfo *var,
 }
 
 
-static int
-aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
+static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
 {
 
        /* fill in pixel info */
@@ -945,9 +1228,8 @@ aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
 }
 
 
-static int
-aty128_crtc_to_var(const struct aty128_crtc *crtc,
-                  struct fb_var_screeninfo *var)
+static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
+                             struct fb_var_screeninfo *var)
 {
        u32 xres, yres, left, right, upper, lower, hslen, vslen, sync;
        u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
@@ -1003,8 +1285,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
 }
 
 #ifdef CONFIG_PMAC_PBOOK
-static void
-aty128_set_crt_enable(struct aty128fb_par *par, int on)
+static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
 {
        if (on) {
                aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON);
@@ -1013,8 +1294,7 @@ aty128_set_crt_enable(struct aty128fb_par *par, int on)
                aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);
 }
 
-static void
-aty128_set_lcd_enable(struct aty128fb_par *par, int on)
+static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
 {
        u32 reg;
 
@@ -1039,10 +1319,9 @@ aty128_set_lcd_enable(struct aty128fb_par *par, int on)
                aty_st_le32(LVDS_GEN_CNTL, reg);
        }
 }
-#endif
+#endif /* CONFIG_PMAC_PBOOK */
 
-static void
-aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
+static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
 {
        u32 div3;
 
@@ -1081,9 +1360,8 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
 }
 
 
-static int
-aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
-                 const struct aty128fb_par *par)
+static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
+                            const struct aty128fb_par *par)
 {
        const struct aty128_constants c = par->constants;
        unsigned char post_dividers[] = {1,2,4,8,3,6,12};
@@ -1109,7 +1387,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
 
        /* calculate feedback divider */
        n = c.ref_divider * output_freq;
-       d = c.dotclock;
+       d = c.ref_clk;
 
        pll->post_divider = post_dividers[i];
        pll->feedback_divider = round_div(n, d);
@@ -1124,8 +1402,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
 }
 
 
-static int
-aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
+static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
 {
        var->pixclock = 100000000 / pll->vclk;
 
@@ -1133,20 +1410,18 @@ aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
 }
 
 
-static void
-aty128_set_fifo(const struct aty128_ddafifo *dsp,
-               const struct aty128fb_par *par)
+static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
+                           const struct aty128fb_par *par)
 {
        aty_st_le32(DDA_CONFIG, dsp->dda_config);
        aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
 }
 
 
-static int
-aty128_ddafifo(struct aty128_ddafifo *dsp,
-              const struct aty128_pll *pll,
-              u32 depth,
-              const struct aty128fb_par *par)
+static int aty128_ddafifo(struct aty128_ddafifo *dsp,
+                         const struct aty128_pll *pll,
+                         u32 depth,
+                         const struct aty128fb_par *par)
 {
        const struct aty128_meminfo *m = par->mem;
        u32 xclk = par->constants.xclk;
@@ -1203,8 +1478,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
 /*
  * This actually sets the video mode.
  */
-static int
-aty128fb_set_par(struct fb_info *info)
+static int aty128fb_set_par(struct fb_info *info)
 { 
        struct aty128fb_par *par = info->par;
        u32 config;
@@ -1276,8 +1550,7 @@ aty128fb_set_par(struct fb_info *info)
  *  encode/decode the User Defined Part of the Display
  */
 
-static int
-aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
+static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
 {
        int err;
        struct aty128_crtc crtc;
@@ -1302,9 +1575,8 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
 }
 
 
-static int
-aty128_encode_var(struct fb_var_screeninfo *var,
-                 const struct aty128fb_par *par)
+static int aty128_encode_var(struct fb_var_screeninfo *var,
+                            const struct aty128fb_par *par)
 {
        int err;
 
@@ -1325,8 +1597,7 @@ aty128_encode_var(struct fb_var_screeninfo *var,
 }           
 
 
-static int
-aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
        struct aty128fb_par par;
        int err;
@@ -1342,8 +1613,7 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 /*
  *  Pan or Wrap the Display
  */
-static int
-aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) 
+static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) 
 {
        struct aty128fb_par *par = fb->par;
        u32 xoffset, yoffset;
@@ -1376,9 +1646,8 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
 /*
  *  Helper function to store a single palette register
  */
-static void
-aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
-             struct aty128fb_par *par)
+static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
+                         struct aty128fb_par *par)
 {
        if (par->chip_gen == rage_M3) {
 #if 0
@@ -1400,8 +1669,7 @@ aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
        aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
 }
 
-static int
-aty128fb_sync(struct fb_info *info)
+static int aty128fb_sync(struct fb_info *info)
 {
        struct aty128fb_par *par = info->par;
 
@@ -1410,8 +1678,7 @@ aty128fb_sync(struct fb_info *info)
        return 0;
 }
 
-int __init
-aty128fb_setup(char *options)
+int __init aty128fb_setup(char *options)
 {
        char *this_opt;
 
@@ -1470,13 +1737,12 @@ aty128fb_setup(char *options)
  *  Initialisation
  */
 
-static int __init
-aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct aty128fb_par *par = info->par;
        struct fb_var_screeninfo var;
-       char video_card[25];
+       char video_card[DEVICE_NAME_SIZE];
        u8 chip_rev;
        u32 dac;
 
@@ -1486,43 +1752,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Get the chip revision */
        chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
 
-       switch (pdev->device) {
-               case PCI_DEVICE_ID_ATI_RAGE128_RE:
-                       strcpy(video_card, "Rage128 RE (PCI)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_RF:
-                       strcpy(video_card, "Rage128 RF (AGP)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_RK:
-                       strcpy(video_card, "Rage128 RK (PCI)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_RL:
-                       strcpy(video_card, "Rage128 RL (AGP)");
-                       break;
-               case PCI_DEVICE_ID_ATI_Rage128_PD:
-                       strcpy(video_card, "Rage128 Pro PD (PCI)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_PF:
-                       strcpy(video_card, "Rage128 Pro PF (AGP)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_PR:
-                       strcpy(video_card, "Rage128 Pro PR (PCI)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_U3:
-                       strcpy(video_card, "Rage128 Pro TR (AGP)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_U1:
-                       strcpy(video_card, "Rage128 Pro TF (AGP)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_LE:
-                       strcpy(video_card, "Rage Mobility M3 (PCI)");
-                       break;
-               case PCI_DEVICE_ID_ATI_RAGE128_LF:
-                       strcpy(video_card, "Rage Mobility M3 (AGP)");
-                       break;
-               default:
-                       return -ENODEV;
-       }
+       strcpy(video_card, "Rage128 XX ");
+       video_card[8] = ent->device >> 8;
+       video_card[9] = ent->device & 0xFF;
+           
+       /* range check to make sure */
+       if (ent->driver_data < (sizeof(r128_family)/sizeof(char *)))
+           strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
 
        printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
 
@@ -1575,8 +1811,12 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
                        if (machine_is_compatible("PowerBook3,2"))
                                default_vmode = VMODE_1152_768_60;
        
-                       if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
-                               default_cmode = CMODE_8;
+                       if (default_cmode > 16) 
+                           default_cmode = CMODE_32;
+                       else if (default_cmode > 8) 
+                           default_cmode = CMODE_16;
+                       else 
+                           default_cmode = CMODE_8;
 
                        if (mac_vmode_to_var(default_vmode, default_cmode, &var))
                                var = default_var;
@@ -1584,9 +1824,10 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        } else
 #endif /* CONFIG_PPC_PMAC */
        {
-               if (fb_find_mode(&var, info, mode_option, NULL, 0,
-                                &defaultmode, 8) == 0)
-                       var = default_var;
+               if (mode_option)
+                       if (fb_find_mode(&var, info, mode_option, NULL, 
+                                        0, &defaultmode, 8) == 0)
+                               var = default_var;
        }
 
        var.accel_flags &= ~FB_ACCELF_TEXT;
@@ -1623,16 +1864,12 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (par->chip_gen == rage_M3)
                register_backlight_controller(&aty128_backlight_controller, par, "ati");
 #endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
+
        par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (aty128_fb == NULL) {
-               /* XXX can only put one chip to sleep */
-               aty128_fb = info;
-       } else
-               printk(KERN_WARNING "aty128fb: can only sleep one Rage 128\n");
        par->pdev = pdev;
-#endif
-
+       par->asleep = 0;
+       par->lock_blank = 0;
+       
        printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
               info->node, info->fix.id, video_card);
 
@@ -1641,14 +1878,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
 
 #ifdef CONFIG_PCI
 /* register a card    ++ajoshi */
-static int __init
-aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned long fb_addr, reg_addr;
        struct aty128fb_par *par;
        struct fb_info *info;
-       int err, size;
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
+       int err;
+#ifndef __sparc__
        void *bios = NULL;
 #endif
 
@@ -1675,17 +1911,14 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* We have the resources. Now virtualize them */
-       size = sizeof(struct fb_info) + sizeof(struct aty128fb_par);
-       if (!(info = kmalloc(size, GFP_ATOMIC))) {
+       info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
+       if (info == NULL) {
                printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
                goto err_free_mmio;
        }
-       memset(info, 0, size);
+       par = info->par;
 
-       par = (struct aty128fb_par *)(info + 1);
        info->pseudo_palette = par->pseudo_palette;
-
-       info->par = par;
        info->fix = aty128fb_fix;
 
        /* Virtualize mmio region */
@@ -1715,16 +1948,21 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out;
        }
 
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
-       if (!(bios = aty128_map_ROM(pdev)))
+#ifndef __sparc__
+       bios = aty128_map_ROM(par, pdev);
+#ifdef __i386__
+       if (bios == NULL)
+               bios = aty128_find_mem_vbios(par, pdev);
+#endif
+       if (bios == NULL)
                printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");
        else {
-               printk(KERN_INFO "aty128fb: Rage128 BIOS located at %lx\n",
-                               pdev->resource[PCI_ROM_RESOURCE].start);
+               printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");
                aty128_get_pllinfo(par, bios);
                aty128_unmap_ROM(pdev, bios);
        }
-#endif
+#endif /* __sparc__ */
+
        aty128_timings(par);
        pci_set_drvdata(pdev, info);
 
@@ -1747,7 +1985,7 @@ err_out:
 err_unmap_out:
        iounmap(par->regbase);
 err_free_info:
-       kfree(info);
+       framebuffer_release(info);
 err_free_mmio:
        release_mem_region(pci_resource_start(pdev, 2),
                        pci_resource_len(pdev, 2));
@@ -1780,170 +2018,23 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
                           pci_resource_len(pdev, 1));
        release_mem_region(pci_resource_start(pdev, 2),
                           pci_resource_len(pdev, 2));
-#ifdef CONFIG_PMAC_PBOOK
-       if (info == aty128_fb)
-               aty128_fb = NULL;
-#endif
-       kfree(info);
+       framebuffer_release(info);
 }
 #endif /* CONFIG_PCI */
 
-/* PPC and Sparc cannot read video ROM */
-#if !defined(CONFIG_PPC) && !defined(__sparc__)
-static void * __init aty128_map_ROM(struct pci_dev *dev)
-{
-       // If this is a primary card, there is a shadow copy of the
-       // ROM somewhere in the first meg. We will just ignore the copy
-       // and use the ROM directly.
-       
-       // no need to search for the ROM, just ask the card where it is.
-       struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
-       unsigned char *addr;
-       
-       // assign the ROM an address if it doesn't have one
-       if (r->start == 0)
-               pci_assign_resource(dev, PCI_ROM_RESOURCE);
-       
-       // enable if needed
-       if (!(r->flags & PCI_ROM_ADDRESS_ENABLE))
-               pci_write_config_dword(dev, dev->rom_base_reg, r->start | PCI_ROM_ADDRESS_ENABLE);
-       
-       addr = ioremap(r->start, r->end - r->start + 1);
-       
-       // Very simple test to make sure it appeared
-       if (addr && (*addr != 0x55)) {
-               printk("aty128fb: Invalid ROM signature %x\n", *addr);
-               iounmap(addr);
-               return NULL;
-       }
-       return (void *)addr;
-}
-
-static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
-{
-       // leave it disabled and unassigned
-       struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
-       
-       iounmap(rom);
-       
-       r->flags &= !PCI_ROM_ADDRESS_ENABLE;
-       r->end -= r->start;
-       r->start = 0;
-       pci_write_config_dword(dev, dev->rom_base_reg, 0);
-}
-
-static void __init
-aty128_get_pllinfo(struct aty128fb_par *par, void *bios)
-{
-       void *bios_header;
-       void *header_ptr;
-       u16 bios_header_offset, pll_info_offset;
-       PLL_BLOCK pll;
-
-       bios_header = (char *)bios + 0x48L;
-       header_ptr  = bios_header;
-
-       bios_header_offset = readw(header_ptr);
-       bios_header = (char *)bios + bios_header_offset;
-       bios_header += 0x30;
-
-       header_ptr = bios_header;
-       pll_info_offset = readw(header_ptr);
-       header_ptr = (char *)bios + pll_info_offset;
-
-       memcpy_fromio(&pll, header_ptr, 50);
-
-       par->constants.ppll_max = pll.PCLK_max_freq;
-       par->constants.ppll_min = pll.PCLK_min_freq;
-       par->constants.xclk = (u32)pll.XCLK;
-       par->constants.ref_divider = (u32)pll.PCLK_ref_divider;
-       par->constants.dotclock = (u32)pll.PCLK_ref_freq;
-
-       DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n",
-                       par->constants.ppll_max, par->constants.ppll_min,
-                       par->constants.xclk, par->constants.ref_divider,
-                       par->constants.dotclock);
-
-}           
-#endif /* !CONFIG_PPC */
-
-
-/* fill in known card constants if pll_block is not available */
-static void __init
-aty128_timings(struct aty128fb_par *par)
-{
-#ifdef CONFIG_PPC_OF
-       /* instead of a table lookup, assume OF has properly
-        * setup the PLL registers and use their values
-        * to set the XCLK values and reference divider values */
-
-       u32 x_mpll_ref_fb_div;
-       u32 xclk_cntl;
-       u32 Nx, M;
-       unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
-#endif
-
-       if (!par->constants.dotclock)
-               par->constants.dotclock = 2950;
-
-#ifdef CONFIG_PPC_OF
-       x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
-       xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
-       Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
-       M  = x_mpll_ref_fb_div & 0x0000ff;
-
-       par->constants.xclk = round_div((2 * Nx * par->constants.dotclock),
-                                       (M * PostDivSet[xclk_cntl]));
-
-       par->constants.ref_divider =
-               aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
-#endif
-
-       if (!par->constants.ref_divider) {
-               par->constants.ref_divider = 0x3b;
-
-               aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
-               aty_pll_writeupdate(par);
-       }
-       aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
-       aty_pll_writeupdate(par);
-
-       /* from documentation */
-       if (!par->constants.ppll_min)
-               par->constants.ppll_min = 12500;
-       if (!par->constants.ppll_max)
-               par->constants.ppll_max = 25000;    /* 23000 on some cards? */
-       if (!par->constants.xclk)
-               par->constants.xclk = 0x1d4d;        /* same as mclk */
-
-       par->constants.fifo_width = 128;
-       par->constants.fifo_depth = 32;
-
-       switch (aty_ld_le32(MEM_CNTL) & 0x3) {
-       case 0:
-               par->mem = &sdr_128;
-               break;
-       case 1:
-               par->mem = &sdr_sgram;
-               break;
-       case 2:
-               par->mem = &ddr_sgram;
-               break;
-       default:
-               par->mem = &sdr_sgram;
-       }
-}
 
 
     /*
      *  Blank the display.
      */
-static int
-aty128fb_blank(int blank, struct fb_info *fb)
+static int aty128fb_blank(int blank, struct fb_info *fb)
 {
        struct aty128fb_par *par = fb->par;
        u8 state = 0;
 
+       if (par->lock_blank || par->asleep)
+               return 0;
+
 #ifdef CONFIG_PMAC_BACKLIGHT
        if ((_machine == _MACH_Pmac) && blank)
                set_backlight_enable(0);
@@ -1976,9 +2067,8 @@ aty128fb_blank(int blank, struct fb_info *fb)
  *  rounded down to the hardware's capabilities (according to the
  *  entries in the var structure). Return != 0 for invalid regno.
  */
-static int
-aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                         u_int transp, struct fb_info *info)
+static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                             u_int transp, struct fb_info *info)
 {
        struct aty128fb_par *par = info->par;
 
@@ -2041,9 +2131,9 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 #define ATY_MIRROR_CRT_ON      0x00000002
 
 /* out param: u32*     backlight value: 0 to 15 */
-#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32*)
+#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32)
 /* in param: u32*      backlight value: 0 to 15 */
-#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32*)
+#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32)
 
 static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
                          u_long arg, struct fb_info *info)
@@ -2091,8 +2181,7 @@ static int backlight_conv[] = {
 /* That one prevents proper CRT output with LCD off */
 #undef BACKLIGHT_DAC_OFF
 
-static int
-aty128_set_backlight_enable(int on, int level, void *data)
+static int aty128_set_backlight_enable(int on, int level, void *data)
 {
        struct aty128fb_par *par = data;
        unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
@@ -2139,8 +2228,7 @@ aty128_set_backlight_enable(int on, int level, void *data)
        return 0;
 }
 
-static int
-aty128_set_backlight_level(int level, void* data)
+static int aty128_set_backlight_level(int level, void* data)
 {
        return aty128_set_backlight_enable(1, level, data);
 }
@@ -2151,10 +2239,9 @@ aty128_set_backlight_level(int level, void* data)
      *  Accelerated functions
      */
 
-static inline void
-aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
-               u_int width, u_int height,
-               struct fb_info_aty128 *par)
+static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
+                                  u_int width, u_int height,
+                                  struct fb_info_aty128 *par)
 {
     u32 save_dp_datatype, save_dp_cntl, dstval;
 
@@ -2196,8 +2283,7 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
      * Text mode accelerated functions
      */
 
-static void
-fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
+static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
                        int height, int width)
 {
     sx     *= fontwidth(p);
@@ -2212,9 +2298,7 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
 }
 #endif /* 0 */
 
-#ifdef CONFIG_PMAC_PBOOK
-static void
-aty128_set_suspend(struct aty128fb_par *par, int suspend)
+static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
 {
        u32     pmgt;
        u16     pwr_command;
@@ -2257,95 +2341,122 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend)
        }
 }
 
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-aty128_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
 {
-       int nb;
-       struct fb_info *info = aty128_fb;
-       struct aty128fb_par *par;
+       struct fb_info *info = pci_get_drvdata(pdev);
+       struct aty128fb_par *par = info->par;
 
-       if (info == NULL)
-               return PBOOK_SLEEP_OK;
-       par = info->par;
-       nb = info->var.yres * info->fix.line_length;
+       /* We don't do anything but D2, for now we return 0, but
+        * we may want to change that. How do we know if the BIOS
+        * can properly take care of D3 ? Also, with swsusp, we
+        * know we'll be rebooted, ...
+        */
+#ifdef CONFIG_PPC_PMAC
+       /* HACK ALERT ! Once I find a proper way to say to each driver
+        * individually what will happen with it's PCI slot, I'll change
+        * that. On laptops, the AGP slot is just unclocked, so D2 is
+        * expected, while on desktops, the card is powered off
+        */
+       if (state >= 3)
+               state = 2;
+#endif /* CONFIG_PPC_PMAC */
+        
+       if (state != 2 || state == pdev->dev.power_state)
+               return 0;
 
-       switch (when) {
-       case PBOOK_SLEEP_REQUEST:
-               par->save_framebuffer = vmalloc(nb);
-               if (par->save_framebuffer == NULL)
-                       return PBOOK_SLEEP_REFUSE;
-               break;
-       case PBOOK_SLEEP_REJECT:
-               if (par->save_framebuffer) {
-                       vfree(par->save_framebuffer);
-                       par->save_framebuffer = 0;
-               }
-               break;
-       case PBOOK_SLEEP_NOW:
-               wait_for_idle(par);
-               aty128_reset_engine(par);
-               wait_for_idle(par);
+       printk(KERN_DEBUG "aty128fb: suspending...\n");
+       
+       acquire_console_sem();
+
+       fb_set_suspend(info, 1);
+
+       /* Make sure engine is reset */
+       wait_for_idle(par);
+       aty128_reset_engine(par);
+       wait_for_idle(par);
 
-               /* Backup fb content */ 
-               if (par->save_framebuffer)
-                       memcpy_fromio(par->save_framebuffer,
-                              info->screen_base, nb);
+       /* Blank display and LCD */
+       aty128fb_blank(VESA_POWERDOWN, info);
 
-               /* Blank display and LCD */
-               aty128fb_blank(VESA_POWERDOWN, info);
-                       
-               /* Sleep the chip */
+       /* Sleep */
+       par->asleep = 1;
+       par->lock_blank = 1;
+
+       /* We need a way to make sure the fbdev layer will _not_ touch the
+        * framebuffer before we put the chip to suspend state. On 2.4, I
+        * used dummy fb ops, 2.5 need proper support for this at the
+        * fbdev level
+        */
+       if (state == 2)
                aty128_set_suspend(par, 1);
 
-               break;
-       case PBOOK_WAKE:
-               /* Wake the chip */
+       release_console_sem();
+
+       pdev->dev.power_state = state;
+
+       return 0;
+}
+
+static int aty128_pci_resume(struct pci_dev *pdev)
+{
+       struct fb_info *info = pci_get_drvdata(pdev);
+       struct aty128fb_par *par = info->par;
+
+       if (pdev->dev.power_state == 0)
+               return 0;
+
+       acquire_console_sem();
+
+       /* Wakeup chip */
+       if (pdev->dev.power_state == 2)
                aty128_set_suspend(par, 0);
-               
-               aty128_reset_engine(par);
-               wait_for_idle(par);
+       par->asleep = 0;
 
-               /* Restore fb content */                        
-               if (par->save_framebuffer) {
-                       memcpy_toio(info->screen_base,
-                              par->save_framebuffer, nb);
-                       vfree(par->save_framebuffer);
-                       par->save_framebuffer = 0;
-               }
-               aty128fb_blank(0, info);
-               break;
-       }
-       return PBOOK_SLEEP_OK;
+       /* Restore display & engine */
+       aty128_reset_engine(par);
+       wait_for_idle(par);
+       aty128fb_set_par(info);
+       fb_pan_display(info, &info->var);
+       fb_set_cmap(&info->cmap, 1, info);
+
+       /* Refresh */
+       fb_set_suspend(info, 0);
+
+       /* Unblank */
+       par->lock_blank = 0;
+       aty128fb_blank(0, info);
+
+       release_console_sem();
+
+       pdev->dev.power_state = 0;
+
+       printk(KERN_DEBUG "aty128fb: resumed !\n");
+
+       return 0;
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
 int __init aty128fb_init(void)
 {
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_register_sleep_notifier(&aty128_sleep_notifier);
-#endif
        return pci_module_init(&aty128fb_driver);
 }
 
 static void __exit aty128fb_exit(void)
 {
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_unregister_sleep_notifier(&aty128_sleep_notifier);
-#endif
        pci_unregister_driver(&aty128fb_driver);
 }
 
+#ifdef MODULE
+module_init(aty128fb_init);
+module_exit(aty128fb_exit);
+
 MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
 MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
 MODULE_LICENSE("GPL");
-MODULE_PARM(mode, "s");
+module_param(mode_option, charp, 0);
 MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
 #ifdef CONFIG_MTRR
-MODULE_PARM(nomtrr, "i");
-MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
+module_param_named(nomtrr, mtrr, invbool, 0);
+MODULE_PARM_DESC(mtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
+#endif
 #endif
 
index 79a90610f3024caa55dbfac05bb77777a4214a0b..a96b2fbdc51116030c71599fed5abc751afeab03 100644 (file)
 /* Rage128 GL */
 #define PCI_DEVICE_ID_ATI_RAGE128_RE   0x5245
 #define PCI_DEVICE_ID_ATI_RAGE128_RF   0x5246
-#define PCI_DEVICE_ID_ATI_RAGE128_RG   0x534b
-#define PCI_DEVICE_ID_ATI_RAGE128_RH   0x534c
-#define PCI_DEVICE_ID_ATI_RAGE128_RI   0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_RG   0x5247
 /* Rage128 VR */
 #define PCI_DEVICE_ID_ATI_RAGE128_RK   0x524b
 #define PCI_DEVICE_ID_ATI_RAGE128_RL   0x524c
-#define PCI_DEVICE_ID_ATI_RAGE128_RM   0x5345
-#define PCI_DEVICE_ID_ATI_RAGE128_RN   0x5346
-#define PCI_DEVICE_ID_ATI_RAGE128_RO   0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SE   0x5345
+#define PCI_DEVICE_ID_ATI_RAGE128_SF   0x5346
+#define PCI_DEVICE_ID_ATI_RAGE128_SG   0x5347
+#define PCI_DEVICE_ID_ATI_RAGE128_SH   0x5348
+#define PCI_DEVICE_ID_ATI_RAGE128_SK   0x534b
+#define PCI_DEVICE_ID_ATI_RAGE128_SL   0x534c
+#define PCI_DEVICE_ID_ATI_RAGE128_SM   0x534d
+#define PCI_DEVICE_ID_ATI_RAGE128_SN   0x534e
+/* Rage128 Ultra */
+#define PCI_DEVICE_ID_ATI_RAGE128_TF   0x5446
+#define PCI_DEVICE_ID_ATI_RAGE128_TL   0x544c
+#define PCI_DEVICE_ID_ATI_RAGE128_TR   0x5452
+#define PCI_DEVICE_ID_ATI_RAGE128_TS   0x5453
+#define PCI_DEVICE_ID_ATI_RAGE128_TT   0x5454
+#define PCI_DEVICE_ID_ATI_RAGE128_TU   0x5455
 /* Rage128 M3 */
 #define PCI_DEVICE_ID_ATI_RAGE128_LE   0x4c45
 #define PCI_DEVICE_ID_ATI_RAGE128_LF   0x4c46
-/* Rage128 Pro Ultra */
-#define PCI_DEVICE_ID_ATI_RAGE128_U1   0x5446
-#define PCI_DEVICE_ID_ATI_RAGE128_U2   0x544C
-#define PCI_DEVICE_ID_ATI_RAGE128_U3   0x5452
+/* Rage128 M4 */
+#define PCI_DEVICE_ID_ATI_RAGE128_MF    0x4d46
+#define PCI_DEVICE_ID_ATI_RAGE128_ML    0x4d4c
 /* Rage128 Pro GL */
-#define PCI_DEVICE_ID_ATI_Rage128_PA   0x5041
-#define PCI_DEVICE_ID_ATI_Rage128_PB   0x5042
-#define PCI_DEVICE_ID_ATI_Rage128_PC   0x5043
-#define PCI_DEVICE_ID_ATI_Rage128_PD   0x5044
-#define PCI_DEVICE_ID_ATI_Rage128_PE   0x5045
+#define PCI_DEVICE_ID_ATI_RAGE128_PA   0x5041
+#define PCI_DEVICE_ID_ATI_RAGE128_PB   0x5042
+#define PCI_DEVICE_ID_ATI_RAGE128_PC   0x5043
+#define PCI_DEVICE_ID_ATI_RAGE128_PD   0x5044
+#define PCI_DEVICE_ID_ATI_RAGE128_PE   0x5045
 #define PCI_DEVICE_ID_ATI_RAGE128_PF   0x5046
 /* Rage128 Pro VR */
 #define PCI_DEVICE_ID_ATI_RAGE128_PG   0x5047
index 7892a02665ff1f7044215c817c88e47dc8155c1e..7079beb005e812a9daad7aca630f6da9b05f26e2 100644 (file)
 #define PWR_MGT_SLOWDOWN_MCLK                  0x00002000
 
 #define PMI_PMSCR_REG                          0x60
+                                                                                
+/* used by ATI bug fix for hardware ROM */
+#define RAGE128_MPP_TB_CONFIG                   0x01c0
 
 #endif                         /* REG_RAGE128_H */