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 @@
*
* Benjamin Herrenschmidt
* - pmac-specific PM stuff
* - various fixes & cleanups
*
* Andreas Hundt <andi@convergence.de>
* - FB_ACTIVATE fixes
......@@ -24,6 +25,10 @@
* 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
......@@ -65,11 +72,6 @@
#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_U3,
{ 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_U1,
{ 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_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_PU,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ 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,
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,8 +539,7 @@ _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,
static u32 _aty_ld_pll(unsigned int pll_index,
const struct aty128fb_par *par)
{
aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
......@@ -482,8 +547,7 @@ _aty_ld_pll(unsigned int pll_index,
}
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,14 +782,246 @@ 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
*/
/* Program the CRTC registers */
static void
aty128_set_crtc(const struct aty128_crtc *crtc,
static void aty128_set_crtc(const struct aty128_crtc *crtc,
const struct aty128fb_par *par)
{
aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
......@@ -752,8 +1037,7 @@ aty128_set_crtc(const struct aty128_crtc *crtc,
}
static int
aty128_var_to_crtc(const struct fb_var_screeninfo *var,
static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
struct aty128_crtc *crtc,
const struct aty128fb_par *par)
{
......@@ -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,8 +1228,7 @@ aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
}
static int
aty128_crtc_to_var(const struct aty128_crtc *crtc,
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;
......@@ -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,8 +1360,7 @@ 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,
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;
......@@ -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,8 +1410,7 @@ aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
}
static void
aty128_set_fifo(const struct aty128_ddafifo *dsp,
static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
const struct aty128fb_par *par)
{
aty_st_le32(DDA_CONFIG, dsp->dda_config);
......@@ -1142,8 +1418,7 @@ aty128_set_fifo(const struct aty128_ddafifo *dsp,
}
static int
aty128_ddafifo(struct aty128_ddafifo *dsp,
static int aty128_ddafifo(struct aty128_ddafifo *dsp,
const struct aty128_pll *pll,
u32 depth,
const struct aty128fb_par *par)
......@@ -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,8 +1575,7 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
}
static int
aty128_encode_var(struct fb_var_screeninfo *var,
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,8 +1646,7 @@ 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,
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) {
......@@ -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,7 +1811,11 @@ 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)
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))
......@@ -1584,8 +1824,9 @@ 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)
if (mode_option)
if (fb_find_mode(&var, info, mode_option, NULL,
0, &defaultmode, 8) == 0)
var = default_var;
}
......@@ -1623,15 +1864,11 @@ 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 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
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,8 +2067,7 @@ 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,
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,8 +2239,7 @@ aty128_set_backlight_level(int level, void* data)
* Accelerated functions
*/
static inline void
aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height,
struct fb_info_aty128 *par)
{
......@@ -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 */
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:
if (state != 2 || state == pdev->dev.power_state)
return 0;
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);
/* 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);
par->asleep = 0;
/* 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);
/* Restore fb content */
if (par->save_framebuffer) {
memcpy_toio(info->screen_base,
par->save_framebuffer, nb);
vfree(par->save_framebuffer);
par->save_framebuffer = 0;
}
/* Refresh */
fb_set_suspend(info, 0);
/* Unblank */
par->lock_blank = 0;
aty128fb_blank(0, info);
break;
}
return PBOOK_SLEEP_OK;
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
......@@ -216,28 +216,37 @@
/* 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
......
......@@ -416,4 +416,7 @@
#define PMI_PMSCR_REG 0x60
/* used by ATI bug fix for hardware ROM */
#define RAGE128_MPP_TB_CONFIG 0x01c0
#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