Commit b6c81047 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Linus Torvalds

[PATCH] Update aty128fb video driver

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
parent 7b377012
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* *
* Benjamin Herrenschmidt * Benjamin Herrenschmidt
* - pmac-specific PM stuff * - pmac-specific PM stuff
* - various fixes & cleanups
* *
* Andreas Hundt <andi@convergence.de> * Andreas Hundt <andi@convergence.de>
* - FB_ACTIVATE fixes * - FB_ACTIVATE fixes
...@@ -24,6 +25,10 @@ ...@@ -24,6 +25,10 @@
* Paul Mundt * Paul Mundt
* - PCI hotplug * - PCI hotplug
* *
* Jon Smirl <jonsmirl@yahoo.com>
* - PCI ID update
* - replace ROM BIOS search
*
* Based off of Geert's atyfb.c and vfb.c. * Based off of Geert's atyfb.c and vfb.c.
* *
* TODO: * TODO:
...@@ -43,6 +48,7 @@ ...@@ -43,6 +48,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -57,6 +63,7 @@ ...@@ -57,6 +63,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/console.h>
#include <asm/io.h> #include <asm/io.h>
#ifdef CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PMAC
...@@ -65,11 +72,6 @@ ...@@ -65,11 +72,6 @@
#include "../macmodes.h" #include "../macmodes.h"
#endif #endif
#ifdef CONFIG_ADB_PMU
#include <linux/adb.h>
#include <linux/pmu.h>
#endif
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h> #include <asm/backlight.h>
#endif #endif
...@@ -136,8 +138,25 @@ static struct fb_videomode defaultmode __initdata = { ...@@ -136,8 +138,25 @@ static struct fb_videomode defaultmode __initdata = {
/* Chip generations */ /* Chip generations */
enum { enum {
rage_128, rage_128,
rage_128_pci,
rage_128_pro, 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 { ...@@ -146,35 +165,105 @@ enum {
static int aty128_probe(struct pci_dev *pdev, static int aty128_probe(struct pci_dev *pdev,
const struct pci_device_id *ent); const struct pci_device_id *ent);
static void aty128_remove(struct pci_dev *pdev); 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 */ /* supported Rage128 chipsets */
static struct pci_device_id aty128_pci_tbl[] = { static struct pci_device_id aty128_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RI, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_Rage128_PD, { 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_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro }, 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_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP, { 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_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_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_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 }, 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, } { 0, }
}; };
...@@ -185,6 +274,8 @@ static struct pci_driver aty128fb_driver = { ...@@ -185,6 +274,8 @@ static struct pci_driver aty128fb_driver = {
.id_table = aty128_pci_tbl, .id_table = aty128_pci_tbl,
.probe = aty128_probe, .probe = aty128_probe,
.remove = __devexit_p(aty128_remove), .remove = __devexit_p(aty128_remove),
.suspend = aty128_pci_suspend,
.resume = aty128_pci_resume,
}; };
/* packed BIOS settings */ /* packed BIOS settings */
...@@ -250,13 +341,6 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = { ...@@ -250,13 +341,6 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = {
.accel = FB_ACCEL_ATI_RAGE128, .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; static char *mode_option __initdata = NULL;
#ifdef CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PMAC
...@@ -275,7 +359,7 @@ static int mtrr = 1; ...@@ -275,7 +359,7 @@ static int mtrr = 1;
/* PLL constants */ /* PLL constants */
struct aty128_constants { struct aty128_constants {
u32 dotclock; u32 ref_clk;
u32 ppll_min; u32 ppll_min;
u32 ppll_max; u32 ppll_max;
u32 ref_divider; u32 ref_divider;
...@@ -322,26 +406,20 @@ struct aty128fb_par { ...@@ -322,26 +406,20 @@ struct aty128fb_par {
#endif #endif
int blitter_may_be_busy; int blitter_may_be_busy;
int fifo_slots; /* free slots in FIFO (64 max) */ int fifo_slots; /* free slots in FIFO (64 max) */
#ifdef CONFIG_PMAC_PBOOK
unsigned char *save_framebuffer;
int pm_reg; int pm_reg;
int crt_on, lcd_on; int crt_on, lcd_on;
struct pci_dev *pdev; struct pci_dev *pdev;
struct fb_info *next; struct fb_info *next;
#endif int asleep;
int lock_blank;
u8 red[32]; /* see aty128fb_setcolreg */ u8 red[32]; /* see aty128fb_setcolreg */
u8 green[64]; u8 green[64];
u8 blue[32]; u8 blue[32];
u32 pseudo_palette[16]; /* used for TRUECOLOR */ 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) #define round_div(n, d) ((n+(d/2))/d)
...@@ -349,7 +427,6 @@ static struct fb_info *aty128_fb = NULL; ...@@ -349,7 +427,6 @@ static struct fb_info *aty128_fb = NULL;
* Interface used by the world * Interface used by the world
*/ */
int aty128fb_init(void); int aty128fb_init(void);
int aty128fb_setup(char *options);
static int aty128fb_check_var(struct fb_var_screeninfo *var, static int aty128fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info); struct fb_info *info);
...@@ -371,10 +448,10 @@ static int aty128_encode_var(struct fb_var_screeninfo *var, ...@@ -371,10 +448,10 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
const struct aty128fb_par *par); const struct aty128fb_par *par);
static int aty128_decode_var(struct fb_var_screeninfo *var, static int aty128_decode_var(struct fb_var_screeninfo *var,
struct aty128fb_par *par); struct aty128fb_par *par);
#if !defined(CONFIG_PPC) && !defined(__sparc__) #if 0
static void __init aty128_get_pllinfo(struct aty128fb_par *par, static void __init aty128_get_pllinfo(struct aty128fb_par *par,
void *bios); 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); static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom);
#endif #endif
static void aty128_timings(struct aty128fb_par *par); static void aty128_timings(struct aty128fb_par *par);
...@@ -386,6 +463,15 @@ static void wait_for_fifo(u16 entries, 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 void wait_for_idle(struct aty128fb_par *par);
static u32 depth_to_dst(u32 depth); 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 = { static struct fb_ops aty128fb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fb_check_var = aty128fb_check_var, .fb_check_var = aty128fb_check_var,
...@@ -395,15 +481,9 @@ static struct fb_ops aty128fb_ops = { ...@@ -395,15 +481,9 @@ static struct fb_ops aty128fb_ops = {
.fb_blank = aty128fb_blank, .fb_blank = aty128fb_blank,
.fb_ioctl = aty128fb_ioctl, .fb_ioctl = aty128fb_ioctl,
.fb_sync = aty128fb_sync, .fb_sync = aty128fb_sync,
#if 0
.fb_fillrect = aty128fb_fillrect,
.fb_copyarea = aty128fb_copyarea,
.fb_imageblit = aty128fb_imageblit,
#else
.fb_fillrect = cfb_fillrect, .fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea, .fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit, .fb_imageblit = cfb_imageblit,
#endif
.fb_cursor = soft_cursor, .fb_cursor = soft_cursor,
}; };
...@@ -422,40 +502,26 @@ static struct backlight_controller aty128_backlight_controller = { ...@@ -422,40 +502,26 @@ static struct backlight_controller aty128_backlight_controller = {
* - endian conversions may possibly be avoided by * - endian conversions may possibly be avoided by
* using the other register aperture. TODO. * using the other register aperture. TODO.
*/ */
static inline u32 static inline u32 _aty_ld_le32(volatile unsigned int regindex,
_aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par) const struct aty128fb_par *par)
{ {
u32 val; return readl (par->regbase + regindex);
#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;
} }
static inline void static inline void _aty_st_le32(volatile unsigned int regindex, u32 val,
_aty_st_le32(volatile unsigned int regindex, u32 val, const struct aty128fb_par *par)
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); writel (val, par->regbase + regindex);
#endif
} }
static inline u8 static inline u8 _aty_ld_8(unsigned int regindex,
_aty_ld_8(unsigned int regindex, const struct aty128fb_par *par) const struct aty128fb_par *par)
{ {
return readb (par->regbase + regindex); return readb (par->regbase + regindex);
} }
static inline void static inline void _aty_st_8(unsigned int regindex, u8 val,
_aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par) const struct aty128fb_par *par)
{ {
writeb (val, par->regbase + regindex); writeb (val, par->regbase + regindex);
} }
...@@ -473,17 +539,15 @@ _aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par) ...@@ -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) #define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, par)
static u32 static u32 _aty_ld_pll(unsigned int pll_index,
_aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F); aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
return aty_ld_le32(CLOCK_CNTL_DATA); return aty_ld_le32(CLOCK_CNTL_DATA);
} }
static void static void _aty_st_pll(unsigned int pll_index, u32 val,
_aty_st_pll(unsigned int pll_index, u32 val,
const struct aty128fb_par *par) const struct aty128fb_par *par)
{ {
aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN); 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, ...@@ -492,15 +556,13 @@ _aty_st_pll(unsigned int pll_index, u32 val,
/* return true when the PLL has completed an atomic update */ /* return true when the PLL has completed an atomic update */
static int static int aty_pll_readupdate(const struct aty128fb_par *par)
aty_pll_readupdate(const struct aty128fb_par *par)
{ {
return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
} }
static void static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
aty_pll_wait_readupdate(const struct aty128fb_par *par)
{ {
unsigned long timeout = jiffies + HZ/100; // should be more than enough unsigned long timeout = jiffies + HZ/100; // should be more than enough
int reset = 1; int reset = 1;
...@@ -517,8 +579,7 @@ aty_pll_wait_readupdate(const struct aty128fb_par *par) ...@@ -517,8 +579,7 @@ aty_pll_wait_readupdate(const struct aty128fb_par *par)
/* tell PLL to update */ /* tell PLL to update */
static void static void aty_pll_writeupdate(const struct aty128fb_par *par)
aty_pll_writeupdate(const struct aty128fb_par *par)
{ {
aty_pll_wait_readupdate(par); aty_pll_wait_readupdate(par);
...@@ -528,8 +589,7 @@ aty_pll_writeupdate(const struct aty128fb_par *par) ...@@ -528,8 +589,7 @@ aty_pll_writeupdate(const struct aty128fb_par *par)
/* write to the scratch register to test r/w functionality */ /* write to the scratch register to test r/w functionality */
static int __init static int __init register_test(const struct aty128fb_par *par)
register_test(const struct aty128fb_par *par)
{ {
u32 val; u32 val;
int flag = 0; int flag = 0;
...@@ -552,8 +612,7 @@ register_test(const struct aty128fb_par *par) ...@@ -552,8 +612,7 @@ register_test(const struct aty128fb_par *par)
/* /*
* Accelerator engine functions * Accelerator engine functions
*/ */
static void static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
{ {
int i; int i;
...@@ -568,8 +627,7 @@ do_wait_for_fifo(u16 entries, struct aty128fb_par *par) ...@@ -568,8 +627,7 @@ do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
} }
static void static void wait_for_idle(struct aty128fb_par *par)
wait_for_idle(struct aty128fb_par *par)
{ {
int i; int i;
...@@ -588,8 +646,7 @@ wait_for_idle(struct aty128fb_par *par) ...@@ -588,8 +646,7 @@ wait_for_idle(struct aty128fb_par *par)
} }
static void static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
wait_for_fifo(u16 entries, struct aty128fb_par *par)
{ {
if (par->fifo_slots < entries) if (par->fifo_slots < entries)
do_wait_for_fifo(64, par); do_wait_for_fifo(64, par);
...@@ -597,8 +654,7 @@ wait_for_fifo(u16 entries, struct aty128fb_par *par) ...@@ -597,8 +654,7 @@ wait_for_fifo(u16 entries, struct aty128fb_par *par)
} }
static void static void aty128_flush_pixel_cache(const struct aty128fb_par *par)
aty128_flush_pixel_cache(const struct aty128fb_par *par)
{ {
int i; int i;
u32 tmp; u32 tmp;
...@@ -614,8 +670,7 @@ aty128_flush_pixel_cache(const struct aty128fb_par *par) ...@@ -614,8 +670,7 @@ aty128_flush_pixel_cache(const struct aty128fb_par *par)
} }
static void static void aty128_reset_engine(const struct aty128fb_par *par)
aty128_reset_engine(const struct aty128fb_par *par)
{ {
u32 gen_reset_cntl, clock_cntl_index, mclk_cntl; u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
...@@ -643,8 +698,7 @@ aty128_reset_engine(const struct aty128fb_par *par) ...@@ -643,8 +698,7 @@ aty128_reset_engine(const struct aty128fb_par *par)
} }
static void static void aty128_init_engine(struct aty128fb_par *par)
aty128_init_engine(struct aty128fb_par *par)
{ {
u32 pitch_value; u32 pitch_value;
...@@ -712,8 +766,7 @@ aty128_init_engine(struct aty128fb_par *par) ...@@ -712,8 +766,7 @@ aty128_init_engine(struct aty128fb_par *par)
/* convert depth values to their register representation */ /* convert depth values to their register representation */
static u32 static u32 depth_to_dst(u32 depth)
depth_to_dst(u32 depth)
{ {
if (depth <= 8) if (depth <= 8)
return DST_8BPP; return DST_8BPP;
...@@ -729,15 +782,247 @@ depth_to_dst(u32 depth) ...@@ -729,15 +782,247 @@ depth_to_dst(u32 depth)
return -EINVAL; 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 */ /* Program the CRTC registers */
static void static void aty128_set_crtc(const struct aty128_crtc *crtc,
aty128_set_crtc(const struct aty128_crtc *crtc, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl); aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total); aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
...@@ -752,10 +1037,9 @@ aty128_set_crtc(const struct aty128_crtc *crtc, ...@@ -752,10 +1037,9 @@ aty128_set_crtc(const struct aty128_crtc *crtc,
} }
static int static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
aty128_var_to_crtc(const struct fb_var_screeninfo *var, struct aty128_crtc *crtc,
struct aty128_crtc *crtc, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst; u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst;
u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 left, right, upper, lower, hslen, vslen, sync, vmode;
...@@ -881,8 +1165,7 @@ aty128_var_to_crtc(const struct fb_var_screeninfo *var, ...@@ -881,8 +1165,7 @@ aty128_var_to_crtc(const struct fb_var_screeninfo *var,
} }
static int static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
{ {
/* fill in pixel info */ /* fill in pixel info */
...@@ -945,9 +1228,8 @@ aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var) ...@@ -945,9 +1228,8 @@ aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
} }
static int static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
aty128_crtc_to_var(const struct aty128_crtc *crtc, struct fb_var_screeninfo *var)
struct fb_var_screeninfo *var)
{ {
u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; 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; 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, ...@@ -1003,8 +1285,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
} }
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
static void static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
aty128_set_crt_enable(struct aty128fb_par *par, int on)
{ {
if (on) { if (on) {
aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_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) ...@@ -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); aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);
} }
static void static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
aty128_set_lcd_enable(struct aty128fb_par *par, int on)
{ {
u32 reg; u32 reg;
...@@ -1039,10 +1319,9 @@ aty128_set_lcd_enable(struct aty128fb_par *par, int on) ...@@ -1039,10 +1319,9 @@ aty128_set_lcd_enable(struct aty128fb_par *par, int on)
aty_st_le32(LVDS_GEN_CNTL, reg); aty_st_le32(LVDS_GEN_CNTL, reg);
} }
} }
#endif #endif /* CONFIG_PMAC_PBOOK */
static void static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
{ {
u32 div3; u32 div3;
...@@ -1081,9 +1360,8 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) ...@@ -1081,9 +1360,8 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
} }
static int static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
const struct aty128_constants c = par->constants; const struct aty128_constants c = par->constants;
unsigned char post_dividers[] = {1,2,4,8,3,6,12}; 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, ...@@ -1109,7 +1387,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
/* calculate feedback divider */ /* calculate feedback divider */
n = c.ref_divider * output_freq; n = c.ref_divider * output_freq;
d = c.dotclock; d = c.ref_clk;
pll->post_divider = post_dividers[i]; pll->post_divider = post_dividers[i];
pll->feedback_divider = round_div(n, d); pll->feedback_divider = round_div(n, d);
...@@ -1124,8 +1402,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, ...@@ -1124,8 +1402,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
} }
static int static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
{ {
var->pixclock = 100000000 / pll->vclk; var->pixclock = 100000000 / pll->vclk;
...@@ -1133,20 +1410,18 @@ aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var) ...@@ -1133,20 +1410,18 @@ aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
} }
static void static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
aty128_set_fifo(const struct aty128_ddafifo *dsp, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
aty_st_le32(DDA_CONFIG, dsp->dda_config); aty_st_le32(DDA_CONFIG, dsp->dda_config);
aty_st_le32(DDA_ON_OFF, dsp->dda_on_off); aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
} }
static int static int aty128_ddafifo(struct aty128_ddafifo *dsp,
aty128_ddafifo(struct aty128_ddafifo *dsp, const struct aty128_pll *pll,
const struct aty128_pll *pll, u32 depth,
u32 depth, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
const struct aty128_meminfo *m = par->mem; const struct aty128_meminfo *m = par->mem;
u32 xclk = par->constants.xclk; u32 xclk = par->constants.xclk;
...@@ -1203,8 +1478,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, ...@@ -1203,8 +1478,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
/* /*
* This actually sets the video mode. * This actually sets the video mode.
*/ */
static int static int aty128fb_set_par(struct fb_info *info)
aty128fb_set_par(struct fb_info *info)
{ {
struct aty128fb_par *par = info->par; struct aty128fb_par *par = info->par;
u32 config; u32 config;
...@@ -1276,8 +1550,7 @@ aty128fb_set_par(struct fb_info *info) ...@@ -1276,8 +1550,7 @@ aty128fb_set_par(struct fb_info *info)
* encode/decode the User Defined Part of the Display * encode/decode the User Defined Part of the Display
*/ */
static int static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
{ {
int err; int err;
struct aty128_crtc crtc; struct aty128_crtc crtc;
...@@ -1302,9 +1575,8 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par) ...@@ -1302,9 +1575,8 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
} }
static int static int aty128_encode_var(struct fb_var_screeninfo *var,
aty128_encode_var(struct fb_var_screeninfo *var, const struct aty128fb_par *par)
const struct aty128fb_par *par)
{ {
int err; int err;
...@@ -1325,8 +1597,7 @@ aty128_encode_var(struct fb_var_screeninfo *var, ...@@ -1325,8 +1597,7 @@ aty128_encode_var(struct fb_var_screeninfo *var,
} }
static int static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ {
struct aty128fb_par par; struct aty128fb_par par;
int err; int err;
...@@ -1342,8 +1613,7 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -1342,8 +1613,7 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
/* /*
* Pan or Wrap the Display * Pan or Wrap the Display
*/ */
static int static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
{ {
struct aty128fb_par *par = fb->par; struct aty128fb_par *par = fb->par;
u32 xoffset, yoffset; u32 xoffset, yoffset;
...@@ -1376,9 +1646,8 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) ...@@ -1376,9 +1646,8 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
/* /*
* Helper function to store a single palette register * Helper function to store a single palette register
*/ */
static void static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, struct aty128fb_par *par)
struct aty128fb_par *par)
{ {
if (par->chip_gen == rage_M3) { if (par->chip_gen == rage_M3) {
#if 0 #if 0
...@@ -1400,8 +1669,7 @@ aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue, ...@@ -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); aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
} }
static int static int aty128fb_sync(struct fb_info *info)
aty128fb_sync(struct fb_info *info)
{ {
struct aty128fb_par *par = info->par; struct aty128fb_par *par = info->par;
...@@ -1410,8 +1678,7 @@ aty128fb_sync(struct fb_info *info) ...@@ -1410,8 +1678,7 @@ aty128fb_sync(struct fb_info *info)
return 0; return 0;
} }
int __init int __init aty128fb_setup(char *options)
aty128fb_setup(char *options)
{ {
char *this_opt; char *this_opt;
...@@ -1470,13 +1737,12 @@ aty128fb_setup(char *options) ...@@ -1470,13 +1737,12 @@ aty128fb_setup(char *options)
* Initialisation * Initialisation
*/ */
static int __init static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
struct fb_info *info = pci_get_drvdata(pdev); struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par; struct aty128fb_par *par = info->par;
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
char video_card[25]; char video_card[DEVICE_NAME_SIZE];
u8 chip_rev; u8 chip_rev;
u32 dac; u32 dac;
...@@ -1486,43 +1752,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1486,43 +1752,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get the chip revision */ /* Get the chip revision */
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
switch (pdev->device) { strcpy(video_card, "Rage128 XX ");
case PCI_DEVICE_ID_ATI_RAGE128_RE: video_card[8] = ent->device >> 8;
strcpy(video_card, "Rage128 RE (PCI)"); video_card[9] = ent->device & 0xFF;
break;
case PCI_DEVICE_ID_ATI_RAGE128_RF: /* range check to make sure */
strcpy(video_card, "Rage128 RF (AGP)"); if (ent->driver_data < (sizeof(r128_family)/sizeof(char *)))
break; strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
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;
}
printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); 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) ...@@ -1575,8 +1811,12 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
if (machine_is_compatible("PowerBook3,2")) if (machine_is_compatible("PowerBook3,2"))
default_vmode = VMODE_1152_768_60; default_vmode = VMODE_1152_768_60;
if (default_cmode < CMODE_8 || default_cmode > CMODE_32) if (default_cmode > 16)
default_cmode = CMODE_8; 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)) if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var; var = default_var;
...@@ -1584,9 +1824,10 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1584,9 +1824,10 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
} else } else
#endif /* CONFIG_PPC_PMAC */ #endif /* CONFIG_PPC_PMAC */
{ {
if (fb_find_mode(&var, info, mode_option, NULL, 0, if (mode_option)
&defaultmode, 8) == 0) if (fb_find_mode(&var, info, mode_option, NULL,
var = default_var; 0, &defaultmode, 8) == 0)
var = default_var;
} }
var.accel_flags &= ~FB_ACCELF_TEXT; var.accel_flags &= ~FB_ACCELF_TEXT;
...@@ -1623,16 +1864,12 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1623,16 +1864,12 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
if (par->chip_gen == rage_M3) if (par->chip_gen == rage_M3)
register_backlight_controller(&aty128_backlight_controller, par, "ati"); register_backlight_controller(&aty128_backlight_controller, par, "ati");
#endif /* CONFIG_PMAC_BACKLIGHT */ #endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PMAC_PBOOK
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); 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; par->pdev = pdev;
#endif par->asleep = 0;
par->lock_blank = 0;
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, video_card); info->node, info->fix.id, video_card);
...@@ -1641,14 +1878,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1641,14 +1878,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* register a card ++ajoshi */ /* register a card ++ajoshi */
static int __init static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
unsigned long fb_addr, reg_addr; unsigned long fb_addr, reg_addr;
struct aty128fb_par *par; struct aty128fb_par *par;
struct fb_info *info; struct fb_info *info;
int err, size; int err;
#if !defined(CONFIG_PPC) && !defined(__sparc__) #ifndef __sparc__
void *bios = NULL; void *bios = NULL;
#endif #endif
...@@ -1675,17 +1911,14 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1675,17 +1911,14 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
/* We have the resources. Now virtualize them */ /* We have the resources. Now virtualize them */
size = sizeof(struct fb_info) + sizeof(struct aty128fb_par); info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
if (!(info = kmalloc(size, GFP_ATOMIC))) { if (info == NULL) {
printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
goto err_free_mmio; goto err_free_mmio;
} }
memset(info, 0, size); par = info->par;
par = (struct aty128fb_par *)(info + 1);
info->pseudo_palette = par->pseudo_palette; info->pseudo_palette = par->pseudo_palette;
info->par = par;
info->fix = aty128fb_fix; info->fix = aty128fb_fix;
/* Virtualize mmio region */ /* Virtualize mmio region */
...@@ -1715,16 +1948,21 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1715,16 +1948,21 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out; goto err_out;
} }
#if !defined(CONFIG_PPC) && !defined(__sparc__) #ifndef __sparc__
if (!(bios = aty128_map_ROM(pdev))) 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"); printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");
else { else {
printk(KERN_INFO "aty128fb: Rage128 BIOS located at %lx\n", printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");
pdev->resource[PCI_ROM_RESOURCE].start);
aty128_get_pllinfo(par, bios); aty128_get_pllinfo(par, bios);
aty128_unmap_ROM(pdev, bios); aty128_unmap_ROM(pdev, bios);
} }
#endif #endif /* __sparc__ */
aty128_timings(par); aty128_timings(par);
pci_set_drvdata(pdev, info); pci_set_drvdata(pdev, info);
...@@ -1747,7 +1985,7 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1747,7 +1985,7 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_unmap_out: err_unmap_out:
iounmap(par->regbase); iounmap(par->regbase);
err_free_info: err_free_info:
kfree(info); framebuffer_release(info);
err_free_mmio: err_free_mmio:
release_mem_region(pci_resource_start(pdev, 2), release_mem_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2)); pci_resource_len(pdev, 2));
...@@ -1780,170 +2018,23 @@ static void __devexit aty128_remove(struct pci_dev *pdev) ...@@ -1780,170 +2018,23 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
pci_resource_len(pdev, 1)); pci_resource_len(pdev, 1));
release_mem_region(pci_resource_start(pdev, 2), release_mem_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2)); pci_resource_len(pdev, 2));
#ifdef CONFIG_PMAC_PBOOK framebuffer_release(info);
if (info == aty128_fb)
aty128_fb = NULL;
#endif
kfree(info);
} }
#endif /* CONFIG_PCI */ #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. * Blank the display.
*/ */
static int static int aty128fb_blank(int blank, struct fb_info *fb)
aty128fb_blank(int blank, struct fb_info *fb)
{ {
struct aty128fb_par *par = fb->par; struct aty128fb_par *par = fb->par;
u8 state = 0; u8 state = 0;
if (par->lock_blank || par->asleep)
return 0;
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
if ((_machine == _MACH_Pmac) && blank) if ((_machine == _MACH_Pmac) && blank)
set_backlight_enable(0); set_backlight_enable(0);
...@@ -1976,9 +2067,8 @@ aty128fb_blank(int blank, struct fb_info *fb) ...@@ -1976,9 +2067,8 @@ aty128fb_blank(int blank, struct fb_info *fb)
* rounded down to the hardware's capabilities (according to the * rounded down to the hardware's capabilities (according to the
* entries in the var structure). Return != 0 for invalid regno. * entries in the var structure). Return != 0 for invalid regno.
*/ */
static int static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info)
u_int transp, struct fb_info *info)
{ {
struct aty128fb_par *par = info->par; struct aty128fb_par *par = info->par;
...@@ -2041,9 +2131,9 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -2041,9 +2131,9 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
#define ATY_MIRROR_CRT_ON 0x00000002 #define ATY_MIRROR_CRT_ON 0x00000002
/* out param: u32* backlight value: 0 to 15 */ /* 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 */ /* 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, static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, struct fb_info *info) u_long arg, struct fb_info *info)
...@@ -2091,8 +2181,7 @@ static int backlight_conv[] = { ...@@ -2091,8 +2181,7 @@ static int backlight_conv[] = {
/* That one prevents proper CRT output with LCD off */ /* That one prevents proper CRT output with LCD off */
#undef BACKLIGHT_DAC_OFF #undef BACKLIGHT_DAC_OFF
static int static int aty128_set_backlight_enable(int on, int level, void *data)
aty128_set_backlight_enable(int on, int level, void *data)
{ {
struct aty128fb_par *par = data; struct aty128fb_par *par = data;
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
...@@ -2139,8 +2228,7 @@ aty128_set_backlight_enable(int on, int level, void *data) ...@@ -2139,8 +2228,7 @@ aty128_set_backlight_enable(int on, int level, void *data)
return 0; return 0;
} }
static int static int aty128_set_backlight_level(int level, void* data)
aty128_set_backlight_level(int level, void* data)
{ {
return aty128_set_backlight_enable(1, level, data); return aty128_set_backlight_enable(1, level, data);
} }
...@@ -2151,10 +2239,9 @@ aty128_set_backlight_level(int level, void* data) ...@@ -2151,10 +2239,9 @@ aty128_set_backlight_level(int level, void* data)
* Accelerated functions * Accelerated functions
*/ */
static inline void static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width, u_int height,
u_int width, u_int height, struct fb_info_aty128 *par)
struct fb_info_aty128 *par)
{ {
u32 save_dp_datatype, save_dp_cntl, dstval; u32 save_dp_datatype, save_dp_cntl, dstval;
...@@ -2196,8 +2283,7 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, ...@@ -2196,8 +2283,7 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
* Text mode accelerated functions * Text mode accelerated functions
*/ */
static void static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width) int height, int width)
{ {
sx *= fontwidth(p); sx *= fontwidth(p);
...@@ -2212,9 +2298,7 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, ...@@ -2212,9 +2298,7 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
} }
#endif /* 0 */ #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; u32 pmgt;
u16 pwr_command; u16 pwr_command;
...@@ -2257,95 +2341,122 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend) ...@@ -2257,95 +2341,122 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend)
} }
} }
/* static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
* 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)
{ {
int nb; struct fb_info *info = pci_get_drvdata(pdev);
struct fb_info *info = aty128_fb; struct aty128fb_par *par = info->par;
struct aty128fb_par *par;
if (info == NULL) /* We don't do anything but D2, for now we return 0, but
return PBOOK_SLEEP_OK; * we may want to change that. How do we know if the BIOS
par = info->par; * can properly take care of D3 ? Also, with swsusp, we
nb = info->var.yres * info->fix.line_length; * 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) { printk(KERN_DEBUG "aty128fb: suspending...\n");
case PBOOK_SLEEP_REQUEST:
par->save_framebuffer = vmalloc(nb); acquire_console_sem();
if (par->save_framebuffer == NULL)
return PBOOK_SLEEP_REFUSE; fb_set_suspend(info, 1);
break;
case PBOOK_SLEEP_REJECT: /* Make sure engine is reset */
if (par->save_framebuffer) { wait_for_idle(par);
vfree(par->save_framebuffer); aty128_reset_engine(par);
par->save_framebuffer = 0; wait_for_idle(par);
}
break;
case PBOOK_SLEEP_NOW:
wait_for_idle(par);
aty128_reset_engine(par);
wait_for_idle(par);
/* Backup fb content */ /* Blank display and LCD */
if (par->save_framebuffer) aty128fb_blank(VESA_POWERDOWN, info);
memcpy_fromio(par->save_framebuffer,
info->screen_base, nb);
/* Blank display and LCD */ /* Sleep */
aty128fb_blank(VESA_POWERDOWN, info); par->asleep = 1;
par->lock_blank = 1;
/* Sleep the chip */
/* 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); aty128_set_suspend(par, 1);
break; release_console_sem();
case PBOOK_WAKE:
/* Wake the chip */ 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_set_suspend(par, 0);
par->asleep = 0;
aty128_reset_engine(par);
wait_for_idle(par);
/* Restore fb content */ /* Restore display & engine */
if (par->save_framebuffer) { aty128_reset_engine(par);
memcpy_toio(info->screen_base, wait_for_idle(par);
par->save_framebuffer, nb); aty128fb_set_par(info);
vfree(par->save_framebuffer); fb_pan_display(info, &info->var);
par->save_framebuffer = 0; fb_set_cmap(&info->cmap, 1, info);
}
aty128fb_blank(0, info); /* Refresh */
break; fb_set_suspend(info, 0);
}
return PBOOK_SLEEP_OK; /* 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) int __init aty128fb_init(void)
{ {
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&aty128_sleep_notifier);
#endif
return pci_module_init(&aty128fb_driver); return pci_module_init(&aty128fb_driver);
} }
static void __exit aty128fb_exit(void) static void __exit aty128fb_exit(void)
{ {
#ifdef CONFIG_PMAC_PBOOK
pmu_unregister_sleep_notifier(&aty128_sleep_notifier);
#endif
pci_unregister_driver(&aty128fb_driver); 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_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
MODULE_LICENSE("GPL"); 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>]\" "); MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i"); module_param_named(nomtrr, mtrr, invbool, 0);
MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); MODULE_PARM_DESC(mtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
#endif
#endif #endif
...@@ -216,28 +216,37 @@ ...@@ -216,28 +216,37 @@
/* Rage128 GL */ /* Rage128 GL */
#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245 #define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245
#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 #define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246
#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x534b #define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247
#define PCI_DEVICE_ID_ATI_RAGE128_RH 0x534c
#define PCI_DEVICE_ID_ATI_RAGE128_RI 0x534d
/* Rage128 VR */ /* Rage128 VR */
#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b #define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b
#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c #define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c
#define PCI_DEVICE_ID_ATI_RAGE128_RM 0x5345 #define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345
#define PCI_DEVICE_ID_ATI_RAGE128_RN 0x5346 #define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346
#define PCI_DEVICE_ID_ATI_RAGE128_RO 0x5347 #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 */ /* Rage128 M3 */
#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45 #define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45
#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46 #define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46
/* Rage128 Pro Ultra */ /* Rage128 M4 */
#define PCI_DEVICE_ID_ATI_RAGE128_U1 0x5446 #define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46
#define PCI_DEVICE_ID_ATI_RAGE128_U2 0x544C #define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c
#define PCI_DEVICE_ID_ATI_RAGE128_U3 0x5452
/* Rage128 Pro GL */ /* Rage128 Pro GL */
#define PCI_DEVICE_ID_ATI_Rage128_PA 0x5041 #define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041
#define PCI_DEVICE_ID_ATI_Rage128_PB 0x5042 #define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042
#define PCI_DEVICE_ID_ATI_Rage128_PC 0x5043 #define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043
#define PCI_DEVICE_ID_ATI_Rage128_PD 0x5044 #define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044
#define PCI_DEVICE_ID_ATI_Rage128_PE 0x5045 #define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045
#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 #define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046
/* Rage128 Pro VR */ /* Rage128 Pro VR */
#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047 #define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047
......
...@@ -415,5 +415,8 @@ ...@@ -415,5 +415,8 @@
#define PWR_MGT_SLOWDOWN_MCLK 0x00002000 #define PWR_MGT_SLOWDOWN_MCLK 0x00002000
#define PMI_PMSCR_REG 0x60 #define PMI_PMSCR_REG 0x60
/* used by ATI bug fix for hardware ROM */
#define RAGE128_MPP_TB_CONFIG 0x01c0
#endif /* REG_RAGE128_H */ #endif /* REG_RAGE128_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment