Commit 2eaf7c63 authored by James Simmons's avatar James Simmons

Port step some changes at authors request.

parent 8ef1bf6d
...@@ -109,36 +109,35 @@ static struct fb_var_screeninfo default_var = { ...@@ -109,36 +109,35 @@ static struct fb_var_screeninfo default_var = {
1024, 768, 1024, 768, 0, 0, 8, 0, 1024, 768, 1024, 768, 0, 0, 8, 0,
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
0, 0, -1, -1, 0, 12699, 160, 32, 28, 1, 96, 3, 0, 0, -1, -1, 0, 12699, 160, 32, 28, 1, 96, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
FB_VMODE_NONINTERLACED
}; };
#endif /* CONFIG_PPC */ #endif /* CONFIG_PPC */
/* default modedb mode */ /* default modedb mode */
/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
static struct fb_videomode defaultmode __initdata = { static struct fb_videomode defaultmode __initdata = {
refresh:60, refresh: 60,
xres:640, xres: 640,
yres:480, yres: 480,
pixclock:39722, pixclock: 39722,
left_margin:48, left_margin: 48,
right_margin:16, right_margin: 16,
upper_margin:33, upper_margin: 33,
lower_margin:10, lower_margin: 10,
hsync_len:96, hsync_len: 96,
vsync_len:2, vsync_len: 2,
sync:0, sync: 0,
vmode:FB_VMODE_NONINTERLACED vmode: FB_VMODE_NONINTERLACED
}; };
static struct fb_fix_screeninfo aty128fb_fix __initdata = { static struct fb_fix_screeninfo aty128fb_fix __initdata = {
id:"ATY Rage128", id: "ATY Rage128",
type:FB_TYPE_PACKED_PIXELS, type: FB_TYPE_PACKED_PIXELS,
visual:FB_VISUAL_PSEUDOCOLOR, visual: FB_VISUAL_PSEUDOCOLOR,
xpanstep:8, xpanstep: 8,
ypanstep:1, ypanstep: 1,
mmio_len:0x1fff, mmio_len: 0x1fff,
accel:FB_ACCEL_ATI_RAGE128 accel: FB_ACCEL_ATI_RAGE128
}; };
/* struct to hold chip description information */ /* struct to hold chip description information */
...@@ -156,21 +155,19 @@ enum { ...@@ -156,21 +155,19 @@ enum {
}; };
/* supported Rage128 chipsets */ /* supported Rage128 chipsets */
static struct aty128_chip_info aty128_pci_probe_list[] __initdata = { static struct aty128_chip_info aty128_pci_probe_list[] __initdata =
{
{"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, rage_128}, {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, rage_128},
{"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF, rage_128}, {"Rage128 RF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RF, rage_128},
{"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK, rage_128}, {"Rage128 RK (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RK, rage_128},
{"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128}, {"Rage128 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128},
{"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, rage_128_pro},
rage_128_pro}, {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, rage_128_pro},
{"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, {"Rage128 Pro TR (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U3, rage_128_pro},
rage_128_pro},
{"Rage128 Pro TR (AGP)", PCI_DEVICE_ID_ATI_RAGE128_U3,
rage_128_pro},
{"Rage Mobility M3 (PCI)", PCI_DEVICE_ID_ATI_RAGE128_LE, rage_M3}, {"Rage Mobility M3 (PCI)", PCI_DEVICE_ID_ATI_RAGE128_LE, rage_M3},
{"Rage Mobility M3 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3}, {"Rage Mobility M3 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3},
{NULL, 0, rage_128} {NULL, 0, rage_128}
}; };
/* packed BIOS settings */ /* packed BIOS settings */
#ifndef CONFIG_PPC #ifndef CONFIG_PPC
...@@ -227,6 +224,7 @@ static const struct aty128_meminfo ddr_sgram = ...@@ -227,6 +224,7 @@ static const struct aty128_meminfo ddr_sgram =
static char fontname[40] __initdata = { 0 }; static char fontname[40] __initdata = { 0 };
static int noaccel __initdata = 0;
#ifdef MODULE #ifdef MODULE
static char *font __initdata = NULL; static char *font __initdata = NULL;
static char *mode __initdata = NULL; static char *mode __initdata = NULL;
...@@ -265,7 +263,7 @@ struct aty128_crtc { ...@@ -265,7 +263,7 @@ struct aty128_crtc {
u32 pitch; u32 pitch;
u32 offset, offset_cntl; u32 offset, offset_cntl;
u32 xoffset, yoffset; u32 xoffset, yoffset;
u32 vyres; u32 vxres, vyres;
u32 bpp; u32 bpp;
}; };
...@@ -285,79 +283,136 @@ struct aty128fb_par { ...@@ -285,79 +283,136 @@ struct aty128fb_par {
struct aty128_crtc crtc; struct aty128_crtc crtc;
struct aty128_pll pll; struct aty128_pll pll;
struct aty128_ddafifo fifo_reg; struct aty128_ddafifo fifo_reg;
const struct aty128_meminfo *mem; /* onboard mem info */ u32 accel_flags;
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
#endif
};
struct fb_info_aty128 {
struct fb_info fb_info;
struct fb_info_aty128 *next;
struct aty128_constants constants; /* PLL and others */ struct aty128_constants constants; /* PLL and others */
void *regbase; /* remapped mmio */ void *regbase; /* remapped mmio */
int chip_gen;
const struct aty128_meminfo *mem; /* onboard mem info */
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) */
int chip_gen;
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
#endif
}; };
static struct fb_info_aty128 *board_list = NULL;
#define round_div(n, d) ((n+(d/2))/d) #define round_div(n, d) ((n+(d/2))/d)
/* /*
* Interface used by the world * Interface used by the world
*/ */
int aty128fb_init(void);
int aty128fb_setup(char *options); int aty128fb_setup(char *options);
static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); static int aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con,
static int aty128fb_set_par(struct fb_info *info); struct fb_info *info);
static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, static int aty128fb_get_var(struct fb_var_screeninfo *var, int con,
u_int blue, u_int transp,
struct fb_info *info); struct fb_info *info);
static int aty128fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con, static int aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *fb); struct fb_info *fb);
static int aty128fb_blank(int blank, struct fb_info *info); static int aty128fb_blank(int blank, struct fb_info *fb);
static int aty128fb_rasterimg(struct fb_info *info, int start); static int aty128fb_rasterimg(struct fb_info *info, int start);
/*
* Interface to the low level console driver
*/
int aty128fb_init(void);
static int aty128fbcon_switch(int con, struct fb_info *fb);
/* /*
* Internal routines * Internal routines
*/ */
static void aty128_encode_fix(struct fb_fix_screeninfo *fix,
struct aty128fb_par *par,
const struct fb_info_aty128 *info);
static void aty128_set_dispsw(struct display *disp,
struct fb_info_aty128 *info, int bpp, int accel);
static int aty128_encode_var(struct fb_var_screeninfo *var,
const struct aty128fb_par *par,
const struct fb_info_aty128 *info);
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,
const struct fb_info *info); const struct fb_info_aty128 *info);
static int aty128_pci_register(struct pci_dev *pdev, static int aty128_pci_register(struct pci_dev *pdev,
const struct aty128_chip_info *aci); const struct aty128_chip_info *aci);
static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128
*board_list, struct fb_info_aty128 *new_node);
#if !defined(CONFIG_PPC) && !defined(__sparc__) #if !defined(CONFIG_PPC) && !defined(__sparc__)
static void __init aty128_get_pllinfo(struct aty128fb_par *par, static void __init aty128_get_pllinfo(struct fb_info_aty128 *info,
char *bios_seg); char *bios_seg);
static char __init *aty128find_ROM(struct fb_info *info); static char __init *aty128find_ROM(struct fb_info_aty128 *info);
#endif #endif
static void aty128_timings(struct aty128fb_par *par); static void aty128_timings(struct fb_info_aty128 *info);
static void aty128_init_engine(struct aty128fb_par *par, static void aty128_init_engine(const struct aty128fb_par *par,
struct fb_info *info); struct fb_info_aty128 *info);
static void aty128_reset_engine(struct aty128fb_par *par); static void aty128_reset_engine(const struct fb_info_aty128 *info);
static void aty128_flush_pixel_cache(struct aty128fb_par *par); static void aty128_flush_pixel_cache(const struct fb_info_aty128 *info);
static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par); static void do_wait_for_fifo(u16 entries, struct fb_info_aty128 *info);
static void wait_for_fifo(u16 entries, struct aty128fb_par *par); static void wait_for_fifo(u16 entries, struct fb_info_aty128 *info);
static void wait_for_idle(struct aty128fb_par *par); static void wait_for_idle(struct fb_info_aty128 *info);
static u32 bpp_to_depth(u32 bpp); static u32 bpp_to_depth(u32 bpp);
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_aty128_8;
static void fbcon_aty8_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx);
static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx);
#endif
#ifdef FBCON_HAS_CFB16
static struct display_switch fbcon_aty128_16;
static void fbcon_aty16_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx);
static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx);
#endif
#ifdef FBCON_HAS_CFB24
static struct display_switch fbcon_aty128_24;
static void fbcon_aty24_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx);
static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx);
#endif
#ifdef FBCON_HAS_CFB32
static struct display_switch fbcon_aty128_32;
static void fbcon_aty32_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx);
static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx);
#endif
static struct fb_ops aty128fb_ops = { static struct fb_ops aty128fb_ops = {
owner: THIS_MODULE, owner: THIS_MODULE,
fb_get_fix: gen_get_fix, fb_get_fix: aty128fb_get_fix,
fb_get_var: gen_get_var, fb_get_var: aty128fb_get_var,
fb_set_var: gen_set_var, fb_set_var: aty128fb_set_var,
fb_get_cmap: gen_get_cmap, fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap, fb_set_cmap: gen_set_cmap,
fb_check_var: aty128fb_check_var,
fb_set_par: aty128fb_set_par,
fb_setcolreg: aty128fb_setcolreg, fb_setcolreg: aty128fb_setcolreg,
fb_pan_display: aty128fb_pan_display, fb_pan_display: aty128fb_pan_display,
fb_blank: aty128fb_blank, fb_blank: aty128fb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
fb_rasterimg: aty128fb_rasterimg, fb_rasterimg: aty128fb_rasterimg,
}; };
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
static int aty128_set_backlight_enable(int on, int level, void *data); static int aty128_set_backlight_enable(int on, int level, void* data);
static int aty128_set_backlight_level(int level, void *data); static int aty128_set_backlight_level(int level, void* data);
static struct backlight_controller aty128_backlight_controller = { static struct backlight_controller aty128_backlight_controller = {
aty128_set_backlight_enable, aty128_set_backlight_enable,
...@@ -371,55 +426,60 @@ static struct backlight_controller aty128_backlight_controller = { ...@@ -371,55 +426,60 @@ static struct backlight_controller aty128_backlight_controller = {
* 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, const struct aty128fb_par *par) _aty_ld_le32(volatile unsigned int regindex,
const struct fb_info_aty128 *info)
{ {
u32 val; u32 val;
#if defined(__powerpc__) #if defined(__powerpc__)
asm("lwbrx %0,%1,%2;eieio": "=r"(val):"b"(regindex),"r"(par->regbase)); asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(info->regbase));
#else #else
val = readl(par->regbase + regindex); val = readl (info->regbase + regindex);
#endif #endif
return val; return val;
} }
static inline void static inline void
_aty_st_le32(volatile unsigned int regindex, u32 val, const struct aty128fb_par *par) _aty_st_le32(volatile unsigned int regindex, u32 val,
const struct fb_info_aty128 *info)
{ {
#if defined(__powerpc__) #if defined(__powerpc__)
asm("stwbrx %0,%1,%2;eieio": : "r"(val), "b"(regindex), "r"(par->regbase):"memory"); asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex),
"r"(info->regbase) : "memory");
#else #else
writel(val, par->regbase + regindex); writel (val, info->regbase + regindex);
#endif #endif
} }
static inline u8 static inline u8
_aty_ld_8(unsigned int regindex, const struct aty128fb_par *par) _aty_ld_8(unsigned int regindex, const struct fb_info_aty128 *info)
{ {
return readb(par->regbase + regindex); return readb (info->regbase + regindex);
} }
static inline void static inline void
_aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par) _aty_st_8(unsigned int regindex, u8 val, const struct fb_info_aty128 *info)
{ {
writeb(val, par->regbase + regindex); writeb (val, info->regbase + regindex);
} }
#define aty_ld_le32(regindex) _aty_ld_le32(regindex, par) #define aty_ld_le32(regindex) _aty_ld_le32(regindex, info)
#define aty_st_le32(regindex, val) _aty_st_le32(regindex, val, par) #define aty_st_le32(regindex, val) _aty_st_le32(regindex, val, info)
#define aty_ld_8(regindex) _aty_ld_8(regindex, par) #define aty_ld_8(regindex) _aty_ld_8(regindex, info)
#define aty_st_8(regindex, val) _aty_st_8(regindex, val, par) #define aty_st_8(regindex, val) _aty_st_8(regindex, val, info)
/* /*
* Functions to read from/write to the pll registers * Functions to read from/write to the pll registers
*/ */
#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, par) #define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, info)
#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, info)
static u32 static u32
_aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par) _aty_ld_pll(unsigned int pll_index,
const struct fb_info_aty128 *info)
{ {
aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F); aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F);
return aty_ld_le32(CLOCK_CNTL_DATA); return aty_ld_le32(CLOCK_CNTL_DATA);
...@@ -427,7 +487,8 @@ _aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par) ...@@ -427,7 +487,8 @@ _aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par)
static void static void
_aty_st_pll(unsigned int pll_index, u32 val, const struct aty128fb_par *par) _aty_st_pll(unsigned int pll_index, u32 val,
const struct fb_info_aty128 *info)
{ {
aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN); aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN);
aty_st_le32(CLOCK_CNTL_DATA, val); aty_st_le32(CLOCK_CNTL_DATA, val);
...@@ -435,19 +496,21 @@ _aty_st_pll(unsigned int pll_index, u32 val, const struct aty128fb_par *par) ...@@ -435,19 +496,21 @@ _aty_st_pll(unsigned int pll_index, u32 val, const struct aty128fb_par *par)
/* return true when the PLL has completed an atomic update */ /* 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 fb_info_aty128 *info)
{ {
return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); 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 fb_info_aty128 *info)
{ {
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;
while (time_before(jiffies, timeout)) while (time_before(jiffies, timeout))
if (aty_pll_readupdate(par)) { if (aty_pll_readupdate(info)) {
reset = 0; reset = 0;
break; break;
} }
...@@ -458,9 +521,10 @@ static void aty_pll_wait_readupdate(const struct aty128fb_par *par) ...@@ -458,9 +521,10 @@ static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
/* tell PLL to update */ /* tell PLL to update */
static void aty_pll_writeupdate(const struct aty128fb_par *par) static void
aty_pll_writeupdate(const struct fb_info_aty128 *info)
{ {
aty_pll_wait_readupdate(par); aty_pll_wait_readupdate(info);
aty_st_pll(PPLL_REF_DIV, aty_st_pll(PPLL_REF_DIV,
aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W); aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);
...@@ -468,7 +532,8 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par) ...@@ -468,7 +532,8 @@ static void 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 register_test(const struct aty128fb_par *par) static int __init
register_test(const struct fb_info_aty128 *info)
{ {
u32 val; u32 val;
int flag = 0; int flag = 0;
...@@ -491,51 +556,56 @@ static int __init register_test(const struct aty128fb_par *par) ...@@ -491,51 +556,56 @@ static int __init register_test(const struct aty128fb_par *par)
/* /*
* Accelerator engine functions * Accelerator engine functions
*/ */
static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par) static void
do_wait_for_fifo(u16 entries, struct fb_info_aty128 *info)
{ {
int i; int i;
for (;;) { for (;;) {
for (i = 0; i < 2000000; i++) { for (i = 0; i < 2000000; i++) {
par->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff; info->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff;
if (par->fifo_slots >= entries) if (info->fifo_slots >= entries)
return; return;
} }
aty128_reset_engine(par); aty128_reset_engine(info);
} }
} }
static void wait_for_idle(struct aty128fb_par *par)
static void
wait_for_idle(struct fb_info_aty128 *info)
{ {
int i; int i;
do_wait_for_fifo(64, par); do_wait_for_fifo(64, info);
for (;;) { for (;;) {
for (i = 0; i < 2000000; i++) { for (i = 0; i < 2000000; i++) {
if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) { if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) {
aty128_flush_pixel_cache(par); aty128_flush_pixel_cache(info);
par->blitter_may_be_busy = 0; info->blitter_may_be_busy = 0;
return; return;
} }
} }
aty128_reset_engine(par); aty128_reset_engine(info);
} }
} }
static void wait_for_fifo(u16 entries, struct aty128fb_par *par) static void
wait_for_fifo(u16 entries, struct fb_info_aty128 *info)
{ {
if (par->fifo_slots < entries) if (info->fifo_slots < entries)
do_wait_for_fifo(64, par); do_wait_for_fifo(64, info);
par->fifo_slots -= entries; info->fifo_slots -= entries;
} }
static void aty128_flush_pixel_cache(struct aty128fb_par *par) static void
aty128_flush_pixel_cache(const struct fb_info_aty128 *info)
{ {
u32 tmp;
int i; int i;
u32 tmp;
tmp = aty_ld_le32(PC_NGUI_CTLSTAT); tmp = aty_ld_le32(PC_NGUI_CTLSTAT);
tmp &= ~(0x00ff); tmp &= ~(0x00ff);
...@@ -548,11 +618,12 @@ static void aty128_flush_pixel_cache(struct aty128fb_par *par) ...@@ -548,11 +618,12 @@ static void aty128_flush_pixel_cache(struct aty128fb_par *par)
} }
static void aty128_reset_engine(struct aty128fb_par *par) static void
aty128_reset_engine(const struct fb_info_aty128 *info)
{ {
u32 gen_reset_cntl, clock_cntl_index, mclk_cntl; u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
aty128_flush_pixel_cache(par); aty128_flush_pixel_cache(info);
clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX); clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX);
mclk_cntl = aty_ld_pll(MCLK_CNTL); mclk_cntl = aty_ld_pll(MCLK_CNTL);
...@@ -577,25 +648,25 @@ static void aty128_reset_engine(struct aty128fb_par *par) ...@@ -577,25 +648,25 @@ static void aty128_reset_engine(struct aty128fb_par *par)
static void static void
aty128_init_engine(struct aty128fb_par *par, aty128_init_engine(const struct aty128fb_par *par,
struct fb_info *info) struct fb_info_aty128 *info)
{ {
u32 pitch_value; u32 pitch_value;
wait_for_idle(par); wait_for_idle(info);
/* 3D scaler not spoken here */ /* 3D scaler not spoken here */
wait_for_fifo(1, par); wait_for_fifo(1, info);
aty_st_le32(SCALE_3D_CNTL, 0x00000000); aty_st_le32(SCALE_3D_CNTL, 0x00000000);
aty128_reset_engine(par); aty128_reset_engine(info);
pitch_value = par->crtc.pitch; pitch_value = par->crtc.pitch;
if (par->crtc.bpp == 24) { if (par->crtc.bpp == 24) {
pitch_value = pitch_value * 3; pitch_value = pitch_value * 3;
} }
wait_for_fifo(4, par); wait_for_fifo(4, info);
/* setup engine offset registers */ /* setup engine offset registers */
aty_st_le32(DEFAULT_OFFSET, 0x00000000); aty_st_le32(DEFAULT_OFFSET, 0x00000000);
...@@ -620,9 +691,10 @@ aty128_init_engine(struct aty128fb_par *par, ...@@ -620,9 +691,10 @@ aty128_init_engine(struct aty128fb_par *par,
GMC_DP_SRC_RECT | GMC_DP_SRC_RECT |
GMC_3D_FCN_EN_CLR | GMC_3D_FCN_EN_CLR |
GMC_DST_CLR_CMP_FCN_CLEAR | GMC_DST_CLR_CMP_FCN_CLEAR |
GMC_AUX_CLIP_CLEAR | GMC_WRITE_MASK_SET); GMC_AUX_CLIP_CLEAR |
GMC_WRITE_MASK_SET);
wait_for_fifo(8, par); wait_for_fifo(8, info);
/* clear the line drawing registers */ /* clear the line drawing registers */
aty_st_le32(DST_BRES_ERR, 0); aty_st_le32(DST_BRES_ERR, 0);
aty_st_le32(DST_BRES_INC, 0); aty_st_le32(DST_BRES_INC, 0);
...@@ -640,12 +712,13 @@ aty128_init_engine(struct aty128fb_par *par, ...@@ -640,12 +712,13 @@ aty128_init_engine(struct aty128fb_par *par,
aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF); aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);
/* Wait for all the writes to be completed before returning */ /* Wait for all the writes to be completed before returning */
wait_for_idle(par); wait_for_idle(info);
} }
/* convert bpp values to their register representation */ /* convert bpp values to their register representation */
static u32 bpp_to_depth(u32 bpp) static u32
bpp_to_depth(u32 bpp)
{ {
if (bpp <= 8) if (bpp <= 8)
return DST_8BPP; return DST_8BPP;
...@@ -667,7 +740,7 @@ static u32 bpp_to_depth(u32 bpp) ...@@ -667,7 +740,7 @@ static u32 bpp_to_depth(u32 bpp)
/* 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 fb_info_aty128 *info)
{ {
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);
...@@ -687,9 +760,9 @@ aty128_set_crtc(const struct aty128_crtc *crtc, ...@@ -687,9 +760,9 @@ aty128_set_crtc(const struct aty128_crtc *crtc,
static int static int
aty128_var_to_crtc(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 fb_info *info) const struct fb_info_aty128 *info)
{ {
u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 left, right, upper, lower, hslen, vslen, sync, vmode;
...@@ -744,7 +817,7 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var, ...@@ -744,7 +817,7 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
bytpp = mode_bytpp[depth]; bytpp = mode_bytpp[depth];
/* make sure there is enough video ram for the mode */ /* make sure there is enough video ram for the mode */
if ((u32) (vxres * vyres * bytpp) > info->fix.smem_len) { if ((u32)(vxres * vyres * bytpp) > info->fb_info.fix.smem_len) {
printk(KERN_ERR "aty128fb: Not enough memory for mode\n"); printk(KERN_ERR "aty128fb: Not enough memory for mode\n");
return -EINVAL; return -EINVAL;
} }
...@@ -787,11 +860,10 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var, ...@@ -787,11 +860,10 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
crtc->h_total = h_total | (h_disp << 16); crtc->h_total = h_total | (h_disp << 16);
crtc->v_total = v_total | (v_disp << 16); crtc->v_total = v_total | (v_disp << 16);
crtc->h_sync_strt_wid = crtc->h_sync_strt_wid = hsync_strt_pix[bytpp] | (h_sync_strt << 3) |
hsync_strt_pix[bytpp] | (h_sync_strt << 3) | (h_sync_wid << 16) (h_sync_wid << 16) | (h_sync_pol << 23);
| (h_sync_pol << 23); crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |
crtc->v_sync_strt_wid = (v_sync_pol << 23);
v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 23);
crtc->pitch = vxres >> 3; crtc->pitch = vxres >> 3;
...@@ -802,7 +874,7 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var, ...@@ -802,7 +874,7 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
else else
crtc->offset_cntl = 0; crtc->offset_cntl = 0;
var->xres_virtual = vxres; crtc->vxres = vxres;
crtc->vyres = vyres; crtc->vyres = vyres;
crtc->xoffset = xoffset; crtc->xoffset = xoffset;
crtc->yoffset = yoffset; crtc->yoffset = yoffset;
...@@ -812,7 +884,8 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var, ...@@ -812,7 +884,8 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
} }
static int aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var) static int
aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var)
{ {
/* fill in pixel info */ /* fill in pixel info */
...@@ -876,8 +949,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc, ...@@ -876,8 +949,7 @@ 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, u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
h_sync_pol;
u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
u32 pix_width; u32 pix_width;
...@@ -913,6 +985,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc, ...@@ -913,6 +985,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
var->xres = xres; var->xres = xres;
var->yres = yres; var->yres = yres;
var->xres_virtual = crtc->vxres;
var->yres_virtual = crtc->vyres; var->yres_virtual = crtc->vyres;
var->xoffset = crtc->xoffset; var->xoffset = crtc->xoffset;
var->yoffset = crtc->yoffset; var->yoffset = crtc->yoffset;
...@@ -929,7 +1002,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc, ...@@ -929,7 +1002,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
} }
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 fb_info_aty128 *info)
{ {
u32 div3; u32 div3;
...@@ -937,18 +1010,16 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) ...@@ -937,18 +1010,16 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
{ 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
/* select PPLL_DIV_3 */ /* select PPLL_DIV_3 */
aty_st_le32(CLOCK_CNTL_INDEX, aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
/* reset PLL */ /* reset PLL */
aty_st_pll(PPLL_CNTL, aty_st_pll(PPLL_CNTL,
aty_ld_pll(PPLL_CNTL) | PPLL_RESET | aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
PPLL_ATOMIC_UPDATE_EN);
/* write the reference divider */ /* write the reference divider */
aty_pll_wait_readupdate(par); aty_pll_wait_readupdate(info);
aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider & 0x3ff); aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff);
aty_pll_writeupdate(par); aty_pll_writeupdate(info);
div3 = aty_ld_pll(PPLL_DIV_3); div3 = aty_ld_pll(PPLL_DIV_3);
div3 &= ~PPLL_FB3_DIV_MASK; div3 &= ~PPLL_FB3_DIV_MASK;
...@@ -957,13 +1028,13 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) ...@@ -957,13 +1028,13 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
div3 |= post_conv[pll->post_divider] << 16; div3 |= post_conv[pll->post_divider] << 16;
/* write feedback and post dividers */ /* write feedback and post dividers */
aty_pll_wait_readupdate(par); aty_pll_wait_readupdate(info);
aty_st_pll(PPLL_DIV_3, div3); aty_st_pll(PPLL_DIV_3, div3);
aty_pll_writeupdate(par); aty_pll_writeupdate(info);
aty_pll_wait_readupdate(par); aty_pll_wait_readupdate(info);
aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */ aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */
aty_pll_writeupdate(par); aty_pll_writeupdate(info);
/* clear the reset, just in case */ /* clear the reset, just in case */
aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET); aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);
...@@ -972,10 +1043,10 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par) ...@@ -972,10 +1043,10 @@ 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 fb_info_aty128 *info)
{ {
const struct aty128_constants c = par->constants; const struct aty128_constants c = info->constants;
unsigned char post_dividers[] = { 1, 2, 4, 8, 3, 6, 12 }; unsigned char post_dividers[] = {1,2,4,8,3,6,12};
u32 output_freq; u32 output_freq;
u32 vclk; /* in .01 MHz */ u32 vclk; /* in .01 MHz */
int i; int i;
...@@ -987,7 +1058,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, ...@@ -987,7 +1058,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
if (vclk > c.ppll_max) if (vclk > c.ppll_max)
vclk = c.ppll_max; vclk = c.ppll_max;
if (vclk * 12 < c.ppll_min) if (vclk * 12 < c.ppll_min)
vclk = c.ppll_min / 12; vclk = c.ppll_min/12;
/* now, find an acceptable divider */ /* now, find an acceptable divider */
for (i = 0; i < sizeof(post_dividers); i++) { for (i = 0; i < sizeof(post_dividers); i++) {
...@@ -1014,9 +1085,8 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, ...@@ -1014,9 +1085,8 @@ 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, aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var,
struct fb_var_screeninfo *var, const struct fb_info_aty128 *info)
const struct fb_info *info)
{ {
var->pixclock = 100000000 / pll->vclk; var->pixclock = 100000000 / pll->vclk;
...@@ -1026,7 +1096,7 @@ aty128_pll_to_var(const struct aty128_pll *pll, ...@@ -1026,7 +1096,7 @@ aty128_pll_to_var(const struct aty128_pll *pll,
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 fb_info_aty128 *info)
{ {
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);
...@@ -1036,13 +1106,13 @@ aty128_set_fifo(const struct aty128_ddafifo *dsp, ...@@ -1036,13 +1106,13 @@ aty128_set_fifo(const struct aty128_ddafifo *dsp,
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 bpp, const struct fb_info *info) u32 bpp,
const struct fb_info_aty128 *info)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par; const struct aty128_meminfo *m = info->mem;
const struct aty128_meminfo *m = par->mem; u32 xclk = info->constants.xclk;
u32 xclk = par->constants.xclk; u32 fifo_width = info->constants.fifo_width;
u32 fifo_width = par->constants.fifo_width; u32 fifo_depth = info->constants.fifo_depth;
u32 fifo_depth = par->constants.fifo_depth;
s32 x, b, p, ron, roff; s32 x, b, p, ron, roff;
u32 n, d; u32 n, d;
...@@ -1056,7 +1126,11 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, ...@@ -1056,7 +1126,11 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
ron = 4 * m->MB + ron = 4 * m->MB +
3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) + 3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +
2 * m->Trp + m->Twr + m->CL + m->Tr2w + x; 2 * m->Trp +
m->Twr +
m->CL +
m->Tr2w +
x;
DBG("x %x\n", x); DBG("x %x\n", x);
...@@ -1091,14 +1165,16 @@ aty128_ddafifo(struct aty128_ddafifo *dsp, ...@@ -1091,14 +1165,16 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
/* /*
* This actually sets the video mode. * This actually sets the video mode.
*/ */
static int static void
aty128fb_set_par(struct fb_info *info) aty128_set_par(struct aty128fb_par *par,
struct fb_info_aty128 *info)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
u32 config; u32 config;
if (par->blitter_may_be_busy) info->fb_info.par = par;
wait_for_idle(par);
if (info->blitter_may_be_busy)
wait_for_idle(info);
/* clear all registers that may interfere with mode setting */ /* clear all registers that may interfere with mode setting */
aty_st_le32(OVR_CLR, 0); aty_st_le32(OVR_CLR, 0);
...@@ -1116,9 +1192,9 @@ aty128fb_set_par(struct fb_info *info) ...@@ -1116,9 +1192,9 @@ aty128fb_set_par(struct fb_info *info)
aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */ aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */
aty128_set_crtc(&par->crtc, par); aty128_set_crtc(&par->crtc, info);
aty128_set_pll(&par->pll, par); aty128_set_pll(&par->pll, info);
aty128_set_fifo(&par->fifo_reg, par); aty128_set_fifo(&par->fifo_reg, info);
config = aty_ld_le32(CONFIG_CNTL) & ~3; config = aty_ld_le32(CONFIG_CNTL) & ~3;
...@@ -1132,19 +1208,16 @@ aty128fb_set_par(struct fb_info *info) ...@@ -1132,19 +1208,16 @@ aty128fb_set_par(struct fb_info *info)
aty_st_le32(CONFIG_CNTL, config); aty_st_le32(CONFIG_CNTL, config);
aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */
if (info->var.accel_flags & FB_ACCELF_TEXT) if (par->accel_flags & FB_ACCELF_TEXT)
aty128_init_engine(par, info); aty128_init_engine(par, info);
#if defined(CONFIG_BOOTX_TEXT) #if defined(CONFIG_BOOTX_TEXT)
btext_update_display(info->fix.smem_start, btext_update_display(info->fb_info.fix.smem_start,
(((par->crtc.h_total >> 16) & 0xff) + 1) * 8, (((par->crtc.h_total>>16) & 0xff)+1)*8,
((par->crtc.v_total >> 16) & 0x7ff) + 1, ((par->crtc.v_total>>16) & 0x7ff)+1,
par->crtc.bpp, par->crtc.bpp,
par->crtc.vxres * par->crtc.bpp / 8); par->crtc.vxres*par->crtc.bpp/8);
#endif /* CONFIG_BOOTX_TEXT */ #endif /* CONFIG_BOOTX_TEXT */
info->fix.line_length = (info->var.xres_virtual * info->var.bits_per_pixel) >> 3;
info->fix.visual = info->var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
return 0;
} }
/* /*
...@@ -1153,29 +1226,90 @@ aty128fb_set_par(struct fb_info *info) ...@@ -1153,29 +1226,90 @@ aty128fb_set_par(struct fb_info *info)
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,
const struct fb_info *info) const struct fb_info_aty128 *info)
{ {
int err; int err;
if ((err = aty128_var_to_crtc(var, &par->crtc, info))) if ((err = aty128_var_to_crtc(var, &par->crtc, info)))
return err; return err;
if ((err = aty128_var_to_pll(var->pixclock, &par->pll, par))) if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info)))
return err; return err;
if ((err = if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info)))
aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp,
info)))
return err; return err;
if (var->accel_flags & FB_ACCELF_TEXT)
par->accel_flags = FB_ACCELF_TEXT;
else
par->accel_flags = 0;
return 0; return 0;
} }
static int static int
aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) aty128_encode_var(struct fb_var_screeninfo *var,
const struct aty128fb_par *par,
const struct fb_info_aty128 *info)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
int err; int err;
if ((err = aty128_crtc_to_var(&par->crtc, var)))
return err;
if ((err = aty128_pll_to_var(&par->pll, var, info)))
return err;
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
var->nonstd = 0;
var->activate = 0;
var->height = -1;
var->width = -1;
var->accel_flags = par->accel_flags;
return 0;
}
/*
* Get the User Defined Part of the Display
*/
static int
aty128fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
{
const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
if (con == -1)
aty128_encode_var(var, par, info);
else
*var = fb_display[con].var;
return 0;
}
/*
* Set the User Defined Part of the Display
*/
static int
aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
{
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par par;
struct display *display;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
int accel, err;
display = (con >= 0) ? &fb_display[con] : fb->disp;
/* basic (in)sanity checks */ /* basic (in)sanity checks */
if (!var->xres) if (!var->xres)
var->xres = 1; var->xres = 1;
...@@ -1203,28 +1337,141 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -1203,28 +1337,141 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL; return -EINVAL;
} }
var->red.msb_right = 0; if ((err = aty128_decode_var(var, &par, info)))
var->green.msb_right = 0; return err;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
var->nonstd = 0; aty128_encode_var(var, &par, info);
var->activate = 0;
var->height = -1; if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
var->width = -1; return 0;
if ((err = aty128_decode_var(var, par, info))) oldxres = display->var.xres;
return err; oldyres = display->var.yres;
oldvxres = display->var.xres_virtual;
oldvyres = display->var.yres_virtual;
oldbpp = display->var.bits_per_pixel;
oldaccel = display->var.accel_flags;
display->var = *var;
if (oldxres != var->xres || oldyres != var->yres ||
oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
struct fb_fix_screeninfo fix;
aty128_encode_fix(&fix, &par, info);
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
display->ypanstep = fix.ypanstep;
display->ywrapstep = fix.ywrapstep;
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = 0;
accel = var->accel_flags & FB_ACCELF_TEXT;
aty128_set_dispsw(display, info, par.crtc.bpp, accel);
if (accel)
display->scrollmode = SCROLL_YNOMOVE;
else
display->scrollmode = SCROLL_YREDRAW;
if ((err = aty128_crtc_to_var(&par->crtc, var))) if (info->fb_info.changevar)
return err; (*info->fb_info.changevar)(con);
}
if ((err = aty128_pll_to_var(&par->pll, var, info))) if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con)
aty128_set_par(&par, info);
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err; return err;
do_install_cmap(con, &info->fb_info);
}
return 0;
}
static void
aty128_set_dispsw(struct display *disp,
struct fb_info_aty128 *info, int bpp, int accel)
{
switch (bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 15:
case 16:
disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16;
disp->dispsw_data = info->fb_info.pseudo_palette;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24;
disp->dispsw_data = info->fb_info.pseudo_palette;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32;
disp->dispsw_data = info->fb_info.pseudo_palette;
break;
#endif
default:
disp->dispsw = &fbcon_dummy;
}
}
static void
aty128_encode_fix(struct fb_fix_screeninfo *fix,
struct aty128fb_par *par,
const struct fb_info_aty128 *info)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, info->fb_info.fix.id);
fix->smem_start = info->fb_info.fix.smem_start;
fix->mmio_start = info->fb_info.fix.mmio_start;
fix->smem_len = info->fb_info.fix.smem_len;
fix->mmio_len = info->fb_info.fix.mmio_len;
fix->type = info->fb_info.fix.type;
fix->type_aux = info->fb_info.fix.type_aux;
fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3;
fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR;
fix->ywrapstep = info->fb_info.fix.ywrapstep;
fix->xpanstep = info->fb_info.fix.xpanstep;
fix->ypanstep = info->fb_info.fix.ypanstep;
fix->accel = info->fb_info.fix.accel;
return;
}
/*
* Get the Fixed Part of the Display
*/
static int
aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
{
const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
aty128_decode_var(&fb_display[con].var, par, info);
aty128_encode_fix(fix, par, info);
return 0; return 0;
} }
/* /*
* Pan or Wrap the Display * Pan or Wrap the Display
* *
...@@ -1232,9 +1479,10 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -1232,9 +1479,10 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
*/ */
static int static int
aty128fb_pan_display(struct fb_var_screeninfo *var, int con, aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info) struct fb_info *fb)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par; struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
u32 xoffset, yoffset; u32 xoffset, yoffset;
u32 offset; u32 offset;
u32 xres, yres; u32 xres, yres;
...@@ -1242,79 +1490,36 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, int con, ...@@ -1242,79 +1490,36 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
xoffset = (var->xoffset + 7) & ~7; xoffset = (var->xoffset +7) & ~7;
yoffset = var->yoffset; yoffset = var->yoffset;
if (xoffset + xres > info->var.xres_virtual if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
|| yoffset + yres > par->crtc.vyres)
return -EINVAL; return -EINVAL;
par->crtc.xoffset = xoffset; par->crtc.xoffset = xoffset;
par->crtc.yoffset = yoffset; par->crtc.yoffset = yoffset;
offset = offset = ((yoffset * par->crtc.vxres + xoffset) * par->crtc.bpp) >> 6;
((yoffset * info->var.xres_virtual + xoffset) * par->crtc.bpp) >> 6;
aty_st_le32(CRTC_OFFSET, offset); aty_st_le32(CRTC_OFFSET, offset);
return 0; return 0;
} }
/* static int
* Accelerated functions aty128fb_rasterimg(struct fb_info *info, int start)
*/
static void
aty128fb_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height, struct fb_info *info)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par; struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info;
u32 save_dp_datatype, save_dp_cntl, bppval;
if (!width || !height)
return;
bppval = bpp_to_depth(par->crtc.bpp);
if (bppval == DST_24BPP) {
srcx *= 3;
dstx *= 3;
width *= 3;
} else if (bppval == -EINVAL) {
printk("aty128fb: invalid depth\n");
return;
}
wait_for_fifo(2, par);
save_dp_datatype = aty_ld_le32(DP_DATATYPE);
save_dp_cntl = aty_ld_le32(DP_CNTL);
wait_for_fifo(6, par);
aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR);
aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
par->blitter_may_be_busy = 1;
wait_for_fifo(2, par);
aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl);
}
static int aty128fb_rasterimg(struct fb_info *info, int start) if (fb->blitter_may_be_busy)
{ wait_for_idle(fb);
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
if (par->blitter_may_be_busy)
wait_for_idle(par);
return 0; return 0;
} }
int __init aty128fb_setup(char *options) int __init
aty128fb_setup(char *options)
{ {
char *this_opt; char *this_opt;
...@@ -1326,28 +1531,28 @@ int __init aty128fb_setup(char *options) ...@@ -1326,28 +1531,28 @@ int __init aty128fb_setup(char *options)
char *p; char *p;
int i; int i;
p = this_opt + 5; p = this_opt +5;
for (i = 0; i < sizeof(fontname) - 1; i++) for (i = 0; i < sizeof(fontname) - 1; i++)
if (!*p || *p == ' ' || *p == ',') if (!*p || *p == ' ' || *p == ',')
break; break;
memcpy(fontname, this_opt + 5, i); memcpy(fontname, this_opt + 5, i);
fontname[i] = 0; fontname[i] = 0;
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
} }
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
else if (!strncmp(this_opt, "nomtrr", 6)) { else if(!strncmp(this_opt, "nomtrr", 6)) {
mtrr = 0; mtrr = 0;
} }
#endif #endif
#ifdef CONFIG_PPC #ifdef CONFIG_PPC
/* vmode and cmode depreciated */ /* vmode and cmode depreciated */
else if (!strncmp(this_opt, "vmode:", 6)) { else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
simple_strtoul(this_opt + 6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX) if (vmode > 0 && vmode <= VMODE_MAX)
default_vmode = vmode; default_vmode = vmode;
} else if (!strncmp(this_opt, "cmode:", 6)) { } else if (!strncmp(this_opt, "cmode:", 6)) {
unsigned int cmode = unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
simple_strtoul(this_opt + 6, NULL, 0);
switch (cmode) { switch (cmode) {
case 0: case 0:
case 8: case 8:
...@@ -1376,8 +1581,7 @@ int __init aty128fb_setup(char *options) ...@@ -1376,8 +1581,7 @@ int __init aty128fb_setup(char *options)
*/ */
static int __init static int __init
aty128_init(struct fb_info *info, struct aty128fb_par *par, aty128_init(struct fb_info_aty128 *info, struct aty128fb_par *par, struct pci_dev *pdev, const char *name)
struct pci_dev *pdev, const char *name)
{ {
struct fb_var_screeninfo var; struct fb_var_screeninfo var;
u32 dac; u32 dac;
...@@ -1386,15 +1590,13 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par, ...@@ -1386,15 +1590,13 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
char *video_card = "Rage128"; char *video_card = "Rage128";
if (!info->fix.smem_len) /* may have already been probed */ if (!info->fb_info.fix.smem_len) /* may have already been probed */
info->fix.smem_len = info->fb_info.fix.smem_len = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
if (mtrr) { if (mtrr) {
par->mtrr.vram = mtrr_add(info->fix.smem_start, par->mtrr.vram = mtrr_add(info->fb_info.fix.smem_start,
info->fix.smem_len, info->fb_info.fix.smem_len, MTRR_TYPE_WRCOMB, 1);
MTRR_TYPE_WRCOMB, 1);
par->mtrr.vram_valid = 1; par->mtrr.vram_valid = 1;
/* let there be speed */ /* let there be speed */
printk(KERN_INFO "aty128fb: Rage128 MTRR set to ON\n"); printk(KERN_INFO "aty128fb: Rage128 MTRR set to ON\n");
...@@ -1405,43 +1607,35 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par, ...@@ -1405,43 +1607,35 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
/* put a name with the face */ /* put a name with the face */
while (aci->name && pdev->device != aci->device) { while (aci->name && pdev->device != aci->device) { aci++; }
aci++; video_card = (char *)aci->name;
} info->chip_gen = aci->chip_gen;
video_card = (char *) aci->name;
par->chip_gen = aci->chip_gen;
printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
chip_rev);
if (info->fix.smem_len % (1024 * 1024) == 0) if (info->fb_info.fix.smem_len % (1024 * 1024) == 0)
printk("%dM %s\n", printk("%dM %s\n", info->fb_info.fix.smem_len / (1024*1024), info->mem->name);
info->fix.smem_len / (1024 * 1024),
par->mem->name);
else else
printk("%dk %s\n", info->fix.smem_len / 1024, printk("%dk %s\n", info->fb_info.fix.smem_len / 1024, info->mem->name);
par->mem->name);
/* fill in info */ /* fill in info */
strcpy(info->modename, info->fix.id); strcpy(info->fb_info.modename, info->fb_info.fix.id);
info->node = NODEV; info->fb_info.node = NODEV;
info->fbops = &aty128fb_ops; info->fb_info.fbops = &aty128fb_ops;
strcpy(info->fontname, fontname); strcpy(info->fb_info.fontname, fontname);
info->changevar = NULL; info->fb_info.changevar = NULL;
info->switch_con = gen_switch; info->fb_info.switch_con = &aty128fbcon_switch;
info->updatevar = NULL; info->fb_info.updatevar = NULL;
info->flags = FBINFO_FLAG_DEFAULT; info->fb_info.flags = FBINFO_FLAG_DEFAULT;
var = default_var; var = default_var;
#ifdef CONFIG_PPC #ifdef CONFIG_PPC
if (_machine == _MACH_Pmac) { if (_machine == _MACH_Pmac) {
if (mode_option) { if (mode_option) {
if (!mac_find_mode if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
(&var, info, mode_option, 8))
var = default_var; var = default_var;
} else { } else {
if (default_vmode <= 0 if (default_vmode <= 0 || default_vmode > VMODE_MAX)
|| default_vmode > VMODE_MAX)
default_vmode = VMODE_1024_768_60; default_vmode = VMODE_1024_768_60;
/* iMacs need that resolution /* iMacs need that resolution
...@@ -1467,27 +1661,25 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par, ...@@ -1467,27 +1661,25 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
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 if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
|| default_cmode > CMODE_32)
default_cmode = CMODE_8; default_cmode = CMODE_8;
if (mac_vmode_to_var if (mac_vmode_to_var(default_vmode, default_cmode, &var))
(default_vmode, default_cmode, &var))
var = default_var; var = default_var;
} }
} else } else
#endif /* CONFIG_PPC */ #endif /* CONFIG_PPC */
{ {
if (fb_find_mode if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0,
(&var, info, mode_option, NULL, 0,
&defaultmode, 8) == 0) &defaultmode, 8) == 0)
var = default_var; var = default_var;
} }
if (noaccel)
var.accel_flags &= ~FB_ACCELF_TEXT;
else
var.accel_flags |= FB_ACCELF_TEXT; var.accel_flags |= FB_ACCELF_TEXT;
info->var = var;
if (aty128_decode_var(&var, par, info)) { if (aty128_decode_var(&var, par, info)) {
printk(KERN_ERR "aty128fb: Cannot set default mode.\n"); printk(KERN_ERR "aty128fb: Cannot set default mode.\n");
return 0; return 0;
...@@ -1502,43 +1694,61 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par, ...@@ -1502,43 +1694,61 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
/* turn off bus mastering, just in case */ /* turn off bus mastering, just in case */
aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS); aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS);
gen_set_var(&var, -1, info); aty128fb_set_var(&var, -1, &info->fb_info);
aty128_init_engine(par, info); aty128_init_engine(par, info);
board_list = aty128_board_list_add(board_list, info);
size = (var.bits_per_pixel <= 8) ? 256 : 32; size = (var.bits_per_pixel <= 8) ? 256 : 32;
fb_alloc_cmap(&info->cmap, size, 0); fb_alloc_cmap(&info->fb_info.cmap, size, 0);
if (register_framebuffer(info) < 0) if (register_framebuffer(&info->fb_info) < 0)
return 0; return 0;
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
/* Could be extended to Rage128Pro LVDS output too */ /* Could be extended to Rage128Pro LVDS output too */
if (info->chip_gen == rage_M3) if (info->chip_gen == rage_M3)
register_backlight_controller(&aty128_backlight_controller, register_backlight_controller(&aty128_backlight_controller, info, "ati");
par, "ati");
#endif /* CONFIG_PMAC_BACKLIGHT */ #endif /* CONFIG_PMAC_BACKLIGHT */
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
GET_FB_IDX(info->node), info->fix.id, name); GET_FB_IDX(info->fb_info.node), info->fb_info.fix.id, name);
return 1; /* success! */ return 1; /* success! */
} }
int __init aty128fb_init(void)
/* add a new card to the list ++ajoshi */
static struct
fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128 *board_list,
struct fb_info_aty128 *new_node)
{
struct fb_info_aty128 *i_p = board_list;
new_node->next = NULL;
if(board_list == NULL)
return new_node;
while(i_p->next != NULL)
i_p = i_p->next;
i_p->next = new_node;
return board_list;
}
int __init
aty128fb_init(void)
{ {
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
while (aci->name != NULL) { while (aci->name != NULL) {
pdev = pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev);
pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev);
while (pdev != NULL) { while (pdev != NULL) {
if (aty128_pci_register(pdev, aci) == 0) if (aty128_pci_register(pdev, aci) == 0)
return 0; return 0;
pdev = pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev);
pci_find_device(PCI_VENDOR_ID_ATI, aci->device,
pdev);
} }
aci++; aci++;
} }
...@@ -1554,12 +1764,12 @@ static int __init ...@@ -1554,12 +1764,12 @@ static int __init
aty128_pci_register(struct pci_dev *pdev, aty128_pci_register(struct pci_dev *pdev,
const struct aty128_chip_info *aci) const struct aty128_chip_info *aci)
{ {
struct aty128fb_par *par = NULL; struct fb_info_aty128 *info = NULL;
struct fb_info *info = NULL; struct aty128fb_par *par;
int err;
#if !defined(CONFIG_PPC) && !defined(__sparc__) #if !defined(CONFIG_PPC) && !defined(__sparc__)
char *bios_seg = NULL; char *bios_seg = NULL;
#endif #endif
int err;
/* Enable device in PCI config */ /* Enable device in PCI config */
if ((err = pci_enable_device(pdev))) { if ((err = pci_enable_device(pdev))) {
...@@ -1569,8 +1779,7 @@ aty128_pci_register(struct pci_dev *pdev, ...@@ -1569,8 +1779,7 @@ aty128_pci_register(struct pci_dev *pdev,
} }
aty128fb_fix.smem_start = pci_resource_start(pdev, 0); aty128fb_fix.smem_start = pci_resource_start(pdev, 0);
if (!request_mem_region if (!request_mem_region(aty128fb_fix.smem_start, pci_resource_len(pdev, 0),
(aty128fb_fix.smem_start, pci_resource_len(pdev, 0),
"aty128fb FB")) { "aty128fb FB")) {
printk(KERN_ERR "aty128fb: cannot reserve frame " printk(KERN_ERR "aty128fb: cannot reserve frame "
"buffer memory\n"); "buffer memory\n");
...@@ -1578,20 +1787,15 @@ aty128_pci_register(struct pci_dev *pdev, ...@@ -1578,20 +1787,15 @@ aty128_pci_register(struct pci_dev *pdev,
} }
aty128fb_fix.mmio_start = pci_resource_start(pdev, 2); aty128fb_fix.mmio_start = pci_resource_start(pdev, 2);
if (!request_mem_region if (!request_mem_region(aty128fb_fix.mmio_start, pci_resource_len(pdev, 2),
(aty128fb_fix.mmio_start, pci_resource_len(pdev, 2),
"aty128fb MMIO")) { "aty128fb MMIO")) {
printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n"); printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n");
goto err_free_mmio; goto err_free_mmio;
} }
/* We have the resources. Now virtualize them */ /* We have the resources. Now virtualize them */
if (! if (!(info = kmalloc(sizeof(struct fb_info_aty128) + sizeof(struct display) + sizeof(u32) * 17, GFP_ATOMIC))) {
(info = printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
kmalloc(sizeof(struct fb_info) +
sizeof(struct display) + sizeof(u32) * 17,
GFP_ATOMIC))) {
printk(KERN_ERR "aty128fb: can't alloc fb_info\n");
goto err_unmap_out; goto err_unmap_out;
} }
...@@ -1600,68 +1804,66 @@ aty128_pci_register(struct pci_dev *pdev, ...@@ -1600,68 +1804,66 @@ aty128_pci_register(struct pci_dev *pdev,
goto err_unmap_out; goto err_unmap_out;
} }
memset(info, 0, sizeof(struct fb_info)); memset(info, 0, sizeof(struct fb_info_aty128));
memset(par, 0, sizeof(struct aty128fb_par)); memset(par, 0, sizeof(struct aty128fb_par));
info->disp = (struct display *) (info + 1); info->fb_info.disp = (struct display *)(info + 1);
info->pseudo_palette = (void *) (info->disp + 1); info->fb_info.pseudo_palette = (void *)(info->fb_info.disp + 1);
info->par = par; info->fb_info.par = par;
info->currcon = -1; info->fb_info.currcon = -1;
info->fix = aty128fb_fix; info->fb_info.fix = aty128fb_fix;
/* Virtualize mmio region */ /* Virtualize mmio region */
par->regbase = ioremap(aty128fb_fix.mmio_start, 0x1FFF); info->regbase = ioremap(aty128fb_fix.mmio_start, 0x1FFF);
if (!par->regbase) if (!info->regbase)
goto err_free_info; goto err_free_info;
/* Grab memory size from the card */ /* Grab memory size from the card */
info->fix.smem_len = info->fb_info.fix.smem_len = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
/* Virtualize the framebuffer */ /* Virtualize the framebuffer */
info->screen_base = info->fb_info.screen_base = ioremap(aty128fb_fix.smem_start, info->fb_info.fix.smem_len);
ioremap(aty128fb_fix.smem_start, info->fix.smem_len);
if (!info->screen_base) { if (!info->fb_info.screen_base) {
iounmap((void *) par->regbase); iounmap((void *)info->regbase);
goto err_free_info; goto err_free_info;
} }
/* If we can't test scratch registers, something is seriously wrong */ /* If we can't test scratch registers, something is seriously wrong */
if (!register_test(par)) { if (!register_test(info)) {
printk(KERN_ERR printk(KERN_ERR "aty128fb: Can't write to video register!\n");
"aty128fb: Can't write to video register!\n");
goto err_out; goto err_out;
} }
#if !defined(CONFIG_PPC) && !defined(__sparc__) #if !defined(CONFIG_PPC) && !defined(__sparc__)
if (!(bios_seg = aty128find_ROM(info))) if (!(bios_seg = aty128find_ROM(info)))
printk(KERN_INFO "aty128fb: Rage128 BIOS not located. " printk(KERN_INFO "aty128fb: Rage128 BIOS not located. "
"Guessing...\n"); "Guessing...\n");
else { else {
printk(KERN_INFO "aty128fb: Rage128 BIOS located at " printk(KERN_INFO "aty128fb: Rage128 BIOS located at "
"segment %4.4X\n", (unsigned int) bios_seg); "segment %4.4X\n", (unsigned int)bios_seg);
aty128_get_pllinfo(par, bios_seg); aty128_get_pllinfo(info, bios_seg);
} }
#endif #endif
aty128_timings(par); aty128_timings(info);
if (!aty128_init(info, par, pdev, "PCI")) if (!aty128_init(info, par, pdev, "PCI"))
goto err_out; goto err_out;
return 0; return 0;
err_out: err_out:
iounmap(info->screen_base); iounmap(info->fb_info.screen_base);
iounmap(par->regbase); iounmap(info->regbase);
err_free_info: err_free_info:
kfree(info); kfree(info);
err_unmap_out: err_unmap_out:
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));
err_free_mmio: err_free_mmio:
release_mem_region(pci_resource_start(pdev, 0), release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0)); pci_resource_len(pdev, 0));
err_free_fb: err_free_fb:
release_mem_region(pci_resource_start(pdev, 1), release_mem_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1)); pci_resource_len(pdev, 1));
return -ENODEV; return -ENODEV;
...@@ -1671,7 +1873,8 @@ aty128_pci_register(struct pci_dev *pdev, ...@@ -1671,7 +1873,8 @@ aty128_pci_register(struct pci_dev *pdev,
/* PPC and Sparc cannot read video ROM */ /* PPC and Sparc cannot read video ROM */
#if !defined(CONFIG_PPC) && !defined(__sparc__) #if !defined(CONFIG_PPC) && !defined(__sparc__)
static char __init * aty128find_ROM(struct fb_info *info) static char __init
*aty128find_ROM(struct fb_info_aty128 *info)
{ {
u32 segstart; u32 segstart;
char *rom_base; char *rom_base;
...@@ -1681,14 +1884,12 @@ static char __init * aty128find_ROM(struct fb_info *info) ...@@ -1681,14 +1884,12 @@ static char __init * aty128find_ROM(struct fb_info *info)
char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */ char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */
char R128_sig[] = "R128"; /* Rage128 ROM identifier */ char R128_sig[] = "R128"; /* Rage128 ROM identifier */
for (segstart = 0x000c0000; segstart < 0x000f0000; for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
segstart += 0x00001000) {
stage = 1; stage = 1;
rom_base = (char *) ioremap(segstart, 0x1000); rom_base = (char *)ioremap(segstart, 0x1000);
if ((*rom_base == 0x55) if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
&& (((*(rom_base + 1)) & 0xff) == 0xaa))
stage = 2; stage = 2;
if (stage != 2) { if (stage != 2) {
...@@ -1697,9 +1898,7 @@ static char __init * aty128find_ROM(struct fb_info *info) ...@@ -1697,9 +1898,7 @@ static char __init * aty128find_ROM(struct fb_info *info)
} }
rom = rom_base; rom = rom_base;
for (i = 0; for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) {
(i < 128 - strlen(aty_rom_sig)) && (stage != 3);
i++) {
if (aty_rom_sig[0] == *rom) if (aty_rom_sig[0] == *rom)
if (strncmp(aty_rom_sig, rom, if (strncmp(aty_rom_sig, rom,
strlen(aty_rom_sig)) == 0) strlen(aty_rom_sig)) == 0)
...@@ -1733,7 +1932,7 @@ static char __init * aty128find_ROM(struct fb_info *info) ...@@ -1733,7 +1932,7 @@ static char __init * aty128find_ROM(struct fb_info *info)
static void __init static void __init
aty128_get_pllinfo(struct aty128fb_par *par, char *bios_seg) aty128_get_pllinfo(struct fb_info_aty128 *info, char *bios_seg)
{ {
void *bios_header; void *bios_header;
void *header_ptr; void *header_ptr;
...@@ -1753,23 +1952,24 @@ aty128_get_pllinfo(struct aty128fb_par *par, char *bios_seg) ...@@ -1753,23 +1952,24 @@ aty128_get_pllinfo(struct aty128fb_par *par, char *bios_seg)
memcpy_fromio(&pll, header_ptr, 50); memcpy_fromio(&pll, header_ptr, 50);
par->constants.ppll_max = pll.PCLK_max_freq; info->constants.ppll_max = pll.PCLK_max_freq;
par->constants.ppll_min = pll.PCLK_min_freq; info->constants.ppll_min = pll.PCLK_min_freq;
par->constants.xclk = (u32) pll.XCLK; info->constants.xclk = (u32)pll.XCLK;
par->constants.ref_divider = (u32) pll.PCLK_ref_divider; info->constants.ref_divider = (u32)pll.PCLK_ref_divider;
par->constants.dotclock = (u32) pll.PCLK_ref_freq; info->constants.dotclock = (u32)pll.PCLK_ref_freq;
DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n", DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n",
par->constants.ppll_max, par->constants.ppll_min, info->constants.ppll_max, info->constants.ppll_min,
par->constants.xclk, par->constants.ref_divider, info->constants.xclk, info->constants.ref_divider,
par->constants.dotclock); info->constants.dotclock);
} }
#endif /* !CONFIG_PPC */ #endif /* !CONFIG_PPC */
/* fill in known card constants if pll_block is not available */ /* fill in known card constants if pll_block is not available */
static void __init aty128_timings(struct aty128fb_par *par) static void __init
aty128_timings(struct fb_info_aty128 *info)
{ {
#ifdef CONFIG_PPC #ifdef CONFIG_PPC
/* instead of a table lookup, assume OF has properly /* instead of a table lookup, assume OF has properly
...@@ -1779,11 +1979,12 @@ static void __init aty128_timings(struct aty128fb_par *par) ...@@ -1779,11 +1979,12 @@ static void __init aty128_timings(struct aty128fb_par *par)
u32 x_mpll_ref_fb_div; u32 x_mpll_ref_fb_div;
u32 xclk_cntl; u32 xclk_cntl;
u32 Nx, M; u32 Nx, M;
unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 }; unsigned PostDivSet[] =
{ 0, 1, 2, 4, 8, 3, 6, 12 };
#endif #endif
if (!par->constants.dotclock) if (!info->constants.dotclock)
par->constants.dotclock = 2950; info->constants.dotclock = 2950;
#ifdef CONFIG_PPC #ifdef CONFIG_PPC
x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
...@@ -1791,55 +1992,84 @@ static void __init aty128_timings(struct aty128fb_par *par) ...@@ -1791,55 +1992,84 @@ static void __init aty128_timings(struct aty128fb_par *par)
Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
M = x_mpll_ref_fb_div & 0x0000ff; M = x_mpll_ref_fb_div & 0x0000ff;
par->constants.xclk = round_div((2 * Nx * info->constants.xclk = round_div((2 * Nx *
par->constants.dotclock), info->constants.dotclock), (M * PostDivSet[xclk_cntl]));
(M * PostDivSet[xclk_cntl]));
par->constants.ref_divider = info->constants.ref_divider =
aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
#endif #endif
if (!par->constants.ref_divider) { if (!info->constants.ref_divider) {
par->constants.ref_divider = 0x3b; info->constants.ref_divider = 0x3b;
aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
aty_pll_writeupdate(par); aty_pll_writeupdate(info);
} }
aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider); aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
aty_pll_writeupdate(par); aty_pll_writeupdate(info);
/* from documentation */ /* from documentation */
if (!par->constants.ppll_min) if (!info->constants.ppll_min)
par->constants.ppll_min = 12500; info->constants.ppll_min = 12500;
if (!par->constants.ppll_max) if (!info->constants.ppll_max)
par->constants.ppll_max = 25000; /* 23000 on some cards? */ info->constants.ppll_max = 25000; /* 23000 on some cards? */
if (!par->constants.xclk) if (!info->constants.xclk)
par->constants.xclk = 0x1d4d; /* same as mclk */ info->constants.xclk = 0x1d4d; /* same as mclk */
par->constants.fifo_width = 128; info->constants.fifo_width = 128;
par->constants.fifo_depth = 32; info->constants.fifo_depth = 32;
switch (aty_ld_le32(MEM_CNTL) & 0x3) { switch (aty_ld_le32(MEM_CNTL) & 0x3) {
case 0: case 0:
par->mem = &sdr_128; info->mem = &sdr_128;
break; break;
case 1: case 1:
par->mem = &sdr_sgram; info->mem = &sdr_sgram;
break; break;
case 2: case 2:
par->mem = &ddr_sgram; info->mem = &ddr_sgram;
break; break;
default: default:
par->mem = &sdr_sgram; info->mem = &sdr_sgram;
}
}
static int
aty128fbcon_switch(int con, struct fb_info *fb)
{
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct display *disp;
struct aty128fb_par par;
if (info->fb_info.currcon >= 0) {
disp = fb_display + info->fb_info.currcon;
if (disp->cmap.len)
fb_copy_cmap(&info->fb_info.cmap, &disp->cmap, 0);
} }
/* set the current console */
fb->currcon = con;
aty128_decode_var(&fb_display[con].var, &par, info);
aty128_set_par(&par, info);
aty128_set_dispsw(&fb_display[con], info, par.crtc.bpp,
par.accel_flags & FB_ACCELF_TEXT);
do_install_cmap(con, fb);
return 1;
} }
/* /*
* Blank the display. * Blank the display.
*/ */
static int aty128fb_blank(int blank, struct fb_info *info) static int
aty128fb_blank(int blank, struct fb_info *fb)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par; struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
u8 state = 0; u8 state = 0;
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
...@@ -1854,7 +2084,7 @@ static int aty128fb_blank(int blank, struct fb_info *info) ...@@ -1854,7 +2084,7 @@ static int aty128fb_blank(int blank, struct fb_info *info)
if (blank & VESA_POWERDOWN) if (blank & VESA_POWERDOWN)
state |= 4; state |= 4;
aty_st_8(CRTC_EXT_CNTL + 1, state); aty_st_8(CRTC_EXT_CNTL+1, state);
#ifdef CONFIG_PMAC_BACKLIGHT #ifdef CONFIG_PMAC_BACKLIGHT
if ((_machine == _MACH_Pmac) && !blank) if ((_machine == _MACH_Pmac) && !blank)
...@@ -1870,9 +2100,10 @@ static int aty128fb_blank(int blank, struct fb_info *info) ...@@ -1870,9 +2100,10 @@ static int aty128fb_blank(int blank, struct fb_info *info)
*/ */
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 *fb)
{ {
struct aty128fb_par *par = (struct aty128fb_par *) info->par; struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
u32 col; u32 col;
if (regno > 255) if (regno > 255)
...@@ -1890,23 +2121,19 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -1890,23 +2121,19 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
if ((par->crtc.bpp > 8) && (regno == 0)) { if ((par->crtc.bpp > 8) && (regno == 0)) {
int i; int i;
if (par->chip_gen == rage_M3) if (info->chip_gen == rage_M3)
aty_st_le32(DAC_CNTL, aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
aty_ld_le32(DAC_CNTL) &
~DAC_PALETTE_ACCESS_CNTL);
for (i = 16; i < 256; i++) { for (i=16; i<256; i++) {
aty_st_8(PALETTE_INDEX, i); aty_st_8(PALETTE_INDEX, i);
col = (i << 16) | (i << 8) | i; col = (i << 16) | (i << 8) | i;
aty_st_le32(PALETTE_DATA, col); aty_st_le32(PALETTE_DATA, col);
} }
if (par->chip_gen == rage_M3) { if (info->chip_gen == rage_M3) {
aty_st_le32(DAC_CNTL, aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
aty_ld_le32(DAC_CNTL) |
DAC_PALETTE_ACCESS_CNTL);
for (i = 16; i < 256; i++) { for (i=16; i<256; i++) {
aty_st_8(PALETTE_INDEX, i); aty_st_8(PALETTE_INDEX, i);
col = (i << 16) | (i << 8) | i; col = (i << 16) | (i << 8) | i;
aty_st_le32(PALETTE_DATA, col); aty_st_le32(PALETTE_DATA, col);
...@@ -1916,10 +2143,8 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -1916,10 +2143,8 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/* initialize palette */ /* initialize palette */
if (par->chip_gen == rage_M3) if (info->chip_gen == rage_M3)
aty_st_le32(DAC_CNTL, aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
aty_ld_le32(DAC_CNTL) &
~DAC_PALETTE_ACCESS_CNTL);
if (par->crtc.bpp == 16) if (par->crtc.bpp == 16)
aty_st_8(PALETTE_INDEX, (regno << 3)); aty_st_8(PALETTE_INDEX, (regno << 3));
...@@ -1927,10 +2152,8 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -1927,10 +2152,8 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
aty_st_8(PALETTE_INDEX, regno); aty_st_8(PALETTE_INDEX, regno);
col = (red << 16) | (green << 8) | blue; col = (red << 16) | (green << 8) | blue;
aty_st_le32(PALETTE_DATA, col); aty_st_le32(PALETTE_DATA, col);
if (par->chip_gen == rage_M3) { if (info->chip_gen == rage_M3) {
aty_st_le32(DAC_CNTL, aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
aty_ld_le32(DAC_CNTL) |
DAC_PALETTE_ACCESS_CNTL);
if (par->crtc.bpp == 16) if (par->crtc.bpp == 16)
aty_st_8(PALETTE_INDEX, (regno << 3)); aty_st_8(PALETTE_INDEX, (regno << 3));
else else
...@@ -1940,22 +2163,25 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -1940,22 +2163,25 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
if (regno < 16) if (regno < 16)
switch (par->crtc.bpp) { switch (par->crtc.bpp) {
#ifdef FBCON_HAS_CFB16
case 9 ... 16: case 9 ... 16:
((u32 *) (info->pseudo_palette))[regno] = ((u32*) (info->fb_info.pseudo_palette))[regno] = (regno << 10) | (regno << 5) | regno;
(regno << 10) | (regno << 5) | regno;
break; break;
#endif
#ifdef FBCON_HAS_CFB24
case 17 ... 24: case 17 ... 24:
((u32 *) (info->pseudo_palette))[regno] = ((u32*) (info->fb_info.pseudo_palette))[regno] = (regno << 16) | (regno << 8) | regno;
(regno << 16) | (regno << 8) | regno;
break; break;
case 25 ... 32:{ #endif
#ifdef FBCON_HAS_CFB32
case 25 ... 32: {
u32 i; u32 i;
i = (regno << 8) | regno; i = (regno << 8) | regno;
((u32 *) (info->pseudo_palette))[regno] = ((u32*) (info->fb_info.pseudo_palette))[regno] = (i << 16) | i;
(i << 16) | i;
break; break;
} }
#endif
} }
return 0; return 0;
} }
...@@ -1966,9 +2192,10 @@ static int backlight_conv[] = { ...@@ -1966,9 +2192,10 @@ static int backlight_conv[] = {
0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
}; };
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 = (struct aty128fb_par *) data; struct fb_info_aty128 *info = (struct fb_info_aty128 *)data;
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_BL_MOD_EN | LVDS_BLON; reg |= LVDS_BL_MOD_EN | LVDS_BLON;
...@@ -1984,7 +2211,8 @@ static int aty128_set_backlight_enable(int on, int level, void *data) ...@@ -1984,7 +2211,8 @@ static int aty128_set_backlight_enable(int on, int level, void *data)
return 0; 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); return aty128_set_backlight_enable(1, level, data);
} }
...@@ -1996,10 +2224,10 @@ static int aty128_set_backlight_level(int level, void *data) ...@@ -1996,10 +2224,10 @@ static int aty128_set_backlight_level(int level, void *data)
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, struct fb_info *info) u_int width, u_int height,
struct fb_info_aty128 *info)
{ {
struct aty128fb_par *par = struct aty128fb_par *par = (struct aty128fb_par *) info->fb_info.par;
(struct aty128fb_par *) info->par;
u32 save_dp_datatype, save_dp_cntl, bppval; u32 save_dp_datatype, save_dp_cntl, bppval;
if (!width || !height) if (!width || !height)
...@@ -2015,11 +2243,11 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, ...@@ -2015,11 +2243,11 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
return; return;
} }
wait_for_fifo(2, par); wait_for_fifo(2, info);
save_dp_datatype = aty_ld_le32(DP_DATATYPE); save_dp_datatype = aty_ld_le32(DP_DATATYPE);
save_dp_cntl = aty_ld_le32(DP_CNTL); save_dp_cntl = aty_ld_le32(DP_CNTL);
wait_for_fifo(6, par); wait_for_fifo(6, info);
aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
...@@ -2028,40 +2256,256 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, ...@@ -2028,40 +2256,256 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
aty_st_le32(DST_Y_X, (dsty << 16) | dstx); aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
par->blitter_may_be_busy = 1; info->blitter_may_be_busy = 1;
wait_for_fifo(2, par); wait_for_fifo(2, info);
aty_st_le32(DP_DATATYPE, save_dp_datatype); aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl); aty_st_le32(DP_CNTL, save_dp_cntl);
} }
/*
* Text mode accelerated functions
*/
static void
fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
sx *= fontwidth(p);
sy *= fontheight(p);
dx *= fontwidth(p);
dy *= fontheight(p);
width *= fontwidth(p);
height *= fontheight(p);
aty128_rectcopy(sx, sy, dx, dy, width, height,
(struct fb_info_aty128 *)p->fb_info);
}
#ifdef FBCON_HAS_CFB8
static void fbcon_aty8_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb8_putc(conp, p, c, yy, xx);
}
static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty8_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb8_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_8 = {
setup: fbcon_cfb8_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb8_clear,
putc: fbcon_aty8_putc,
putcs: fbcon_aty8_putcs,
revc: fbcon_cfb8_revc,
clear_margins: fbcon_aty8_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef FBCON_HAS_CFB16
static void fbcon_aty16_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb16_putc(conp, p, c, yy, xx);
}
static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty16_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb16_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_16 = {
setup: fbcon_cfb16_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb16_clear,
putc: fbcon_aty16_putc,
putcs: fbcon_aty16_putcs,
revc: fbcon_cfb16_revc,
clear_margins: fbcon_aty16_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef FBCON_HAS_CFB24
static void fbcon_aty24_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb24_putc(conp, p, c, yy, xx);
}
static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty24_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb24_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_24 = {
setup: fbcon_cfb24_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb24_clear,
putc: fbcon_aty24_putc,
putcs: fbcon_aty24_putcs,
revc: fbcon_cfb24_revc,
clear_margins: fbcon_aty24_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef FBCON_HAS_CFB32
static void fbcon_aty32_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb32_putc(conp, p, c, yy, xx);
}
static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty32_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb32_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_32 = {
setup: fbcon_cfb32_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb32_clear,
putc: fbcon_aty32_putc,
putcs: fbcon_aty32_putcs,
revc: fbcon_cfb32_revc,
clear_margins: fbcon_aty32_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef MODULE #ifdef MODULE
MODULE_AUTHOR("(c)1999-2000 Brad Douglas <brad@neruo.com>"); MODULE_AUTHOR("(c)1999-2000 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(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disable hardware acceleration (0 or 1=disabled) (default=0)");
MODULE_PARM(font, "s"); MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, MODULE_PARM_DESC(font, "Specify one of the compiled-in fonts (default=none)");
"Specify one of the compiled-in fonts (default=none)");
MODULE_PARM(mode, "s"); MODULE_PARM(mode, "s");
MODULE_PARM_DESC(mode, MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i"); MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
"Disable MTRR support (0 or 1=disabled) (default=0)");
#endif #endif
int __init init_module(void) int __init
init_module(void)
{ {
if (noaccel) {
noaccel = 1;
printk(KERN_INFO "aty128fb: Parameter NOACCEL set\n");
}
if (font) { if (font) {
strncpy(fontname, font, sizeof(fontname) - 1); strncpy(fontname, font, sizeof(fontname)-1);
printk(KERN_INFO "aty128fb: Parameter FONT set to %s\n", printk(KERN_INFO "aty128fb: Parameter FONT set to %s\n", font);
font);
} }
if (mode) { if (mode) {
mode_option = mode; mode_option = mode;
printk(KERN_INFO "aty128fb: Parameter MODE set to %s\n", printk(KERN_INFO "aty128fb: Parameter MODE set to %s\n", mode);
mode);
} }
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
if (nomtrr) { if (nomtrr) {
...@@ -2074,22 +2518,25 @@ int __init init_module(void) ...@@ -2074,22 +2518,25 @@ int __init init_module(void)
return 0; return 0;
} }
void __exit cleanup_module(void) void __exit
cleanup_module(void)
{ {
struct fb_info *info = board_list; struct fb_info_aty128 *info = board_list;
struct aty128fb_par *par; struct aty128fb_par *par;
par = info->par; while (board_list) {
info = board_list;
board_list = board_list->next;
par = info->fb_info.par;
unregister_framebuffer(info); unregister_framebuffer(&info->fb_info);
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
if (par->mtrr.vram_valid) if (par->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, mtrr_del(par->mtrr.vram, info->fb_info.fix.smem_start,
info->fix.smem_start, info->fb_info.fix.smem_len);
info->fix.smem_len);
#endif /* CONFIG_MTRR */ #endif /* CONFIG_MTRR */
iounmap(par->regbase); iounmap(info->regbase);
iounmap(info->screen_base); iounmap(info->fb_info.screen_base);
release_mem_region(pci_resource_start(info->pdev, 0), release_mem_region(pci_resource_start(info->pdev, 0),
pci_resource_len(info->pdev, 0)); pci_resource_len(info->pdev, 0));
...@@ -2097,6 +2544,8 @@ void __exit cleanup_module(void) ...@@ -2097,6 +2544,8 @@ void __exit cleanup_module(void)
pci_resource_len(info->pdev, 1)); pci_resource_len(info->pdev, 1));
release_mem_region(pci_resource_start(info->pdev, 2), release_mem_region(pci_resource_start(info->pdev, 2),
pci_resource_len(info->pdev, 2)); pci_resource_len(info->pdev, 2));
kfree(info); kfree(info);
}
} }
#endif /* MODULE */ #endif /* MODULE */
/* /*
* linux/drivers/video/riva/fbdevar->c - nVidia RIVA 128/TNT/TNT2 fb driver * linux/drivers/video/riva/fbdev.c - nVidia RIVA 128/TNT/TNT2 fb driver
* *
* Maintained by Ani Joshi <ajoshi@shell.unixbox.com> * Maintained by Ani Joshi <ajoshi@shell.unixbox.com>
* *
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* Known bugs and issues: * Known bugs and issues:
* restoring text mode fails * restoring text mode fails
* doublescan modes are broken * doublescan modes are broken
* option 'noaccel' has no effect
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -51,10 +52,12 @@ ...@@ -51,10 +52,12 @@
#error This driver requires PCI support. #error This driver requires PCI support.
#endif #endif
#include "../fbcon-accel.h"
/* version number of this driver */ /* version number of this driver */
#define RIVAFB_VERSION "0.9.3" #define RIVAFB_VERSION "0.9.2a"
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
...@@ -88,8 +91,8 @@ ...@@ -88,8 +91,8 @@
#define Set8Bits(value) ((value)&0xff) #define Set8Bits(value) ((value)&0xff)
/* HW cursor parameters */ /* HW cursor parameters */
#define DEFAULT_CURSOR_BLINK_RATE (20) #define DEFAULT_CURSOR_BLINK_RATE (40)
#define CURSOR_HIDE_DELAY (10) #define CURSOR_HIDE_DELAY (20)
#define CURSOR_SHOW_DELAY (3) #define CURSOR_SHOW_DELAY (3)
#define CURSOR_COLOR 0x7fff #define CURSOR_COLOR 0x7fff
...@@ -97,6 +100,7 @@ ...@@ -97,6 +100,7 @@
#define MAX_CURS 32 #define MAX_CURS 32
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
* prototypes * prototypes
...@@ -105,6 +109,11 @@ ...@@ -105,6 +109,11 @@
static int rivafb_blank(int blank, struct fb_info *info); static int rivafb_blank(int blank, struct fb_info *info);
extern void riva_setup_accel(struct rivafb_info *rinfo);
extern inline void wait_for_idle(struct rivafb_info *rinfo);
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
* card identification * card identification
...@@ -127,11 +136,6 @@ enum riva_chips { ...@@ -127,11 +136,6 @@ enum riva_chips {
CH_GEFORCE2_GTS, CH_GEFORCE2_GTS,
CH_GEFORCE2_ULTRA, CH_GEFORCE2_ULTRA,
CH_QUADRO2_PRO, CH_QUADRO2_PRO,
CH_GEFORCE2_GO,
CH_GEFORCE3,
CH_GEFORCE3_1,
CH_GEFORCE3_2,
CH_QUADRO_DDC
}; };
/* directly indexed by riva_chips enum, above */ /* directly indexed by riva_chips enum, above */
...@@ -154,11 +158,6 @@ static struct riva_chip_info { ...@@ -154,11 +158,6 @@ static struct riva_chip_info {
{ "GeForce2-GTS", NV_ARCH_10}, { "GeForce2-GTS", NV_ARCH_10},
{ "GeForce2-ULTRA", NV_ARCH_10}, { "GeForce2-ULTRA", NV_ARCH_10},
{ "Quadro2-PRO", NV_ARCH_10}, { "Quadro2-PRO", NV_ARCH_10},
{ "GeForce2-Go", NV_ARCH_10},
{ "GeForce3", NV_ARCH_20},
{ "GeForce3 Ti 200", NV_ARCH_20},
{ "GeForce3 Ti 500", NV_ARCH_20},
{ "Quadro DDC", NV_ARCH_20}
}; };
static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
...@@ -196,30 +195,64 @@ static struct pci_device_id rivafb_pci_tbl[] __devinitdata = { ...@@ -196,30 +195,64 @@ static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_ULTRA },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GO },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_1 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE3_2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO_DDC },
{ 0, } /* terminate list */ { 0, } /* terminate list */
}; };
MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl); MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
/* ------------------------------------------------------------------------- *
*
* framebuffer related structures
*
* ------------------------------------------------------------------------- */
#ifdef FBCON_HAS_CFB8
extern struct display_switch fbcon_riva8;
#endif
#ifdef FBCON_HAS_CFB16
extern struct display_switch fbcon_riva16;
#endif
#ifdef FBCON_HAS_CFB32
extern struct display_switch fbcon_riva32;
#endif
#if 0
/* describes the state of a Riva board */
struct rivafb_par {
struct riva_regs state; /* state of hw board */
__u32 visual; /* FB_VISUAL_xxx */
unsigned depth; /* bpp of current mode */
};
#endif
struct riva_cursor {
int enable;
int on;
int vbl_cnt;
int last_move_delay;
int blink_rate;
struct {
u16 x, y;
} pos, size;
unsigned short image[MAX_CURS*MAX_CURS];
struct timer_list *timer;
};
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
* global variables * global variables
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
struct fb_info *riva_boards = NULL; struct rivafb_info *riva_boards = NULL;
/* command line data, set in rivafb_setup() */ /* command line data, set in rivafb_setup() */
static char fontname[40] __initdata = { 0 }; static char fontname[40] __initdata = { 0 };
static char noaccel __initdata = 0;
static char nomove = 0;
static char nohwcursor __initdata = 0; static char nohwcursor __initdata = 0;
static char noblink = 0; static char noblink = 0;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
...@@ -232,26 +265,24 @@ static char *mode_option __initdata = NULL; ...@@ -232,26 +265,24 @@ static char *mode_option __initdata = NULL;
static char *font = NULL; static char *font = NULL;
#endif #endif
static struct fb_fix_screeninfo rivafb_fix = {
id: "nVidia",
type: FB_TYPE_PACKED_PIXELS,
xpanstep: 1,
ypanstep: 1,
};
static struct fb_var_screeninfo rivafb_default_var = { static struct fb_var_screeninfo rivafb_default_var = {
xres: 640, xres: 640,
yres: 480, yres: 480,
xres_virtual: 640, xres_virtual: 640,
yres_virtual: 480, yres_virtual: 480,
xoffset: 0,
yoffset: 0,
bits_per_pixel: 8, bits_per_pixel: 8,
grayscale: 0,
red: {0, 6, 0}, red: {0, 6, 0},
green: {0, 6, 0}, green: {0, 6, 0},
blue: {0, 6, 0}, blue: {0, 6, 0},
activate: FB_ACTIVATE_NOW, transp: {0, 0, 0},
nonstd: 0,
activate: 0,
height: -1, height: -1,
width: -1, width: -1,
accel_flags: FB_ACCELF_TEXT, accel_flags: 0,
pixclock: 39721, pixclock: 39721,
left_margin: 40, left_margin: 40,
right_margin: 24, right_margin: 24,
...@@ -259,28 +290,10 @@ static struct fb_var_screeninfo rivafb_default_var = { ...@@ -259,28 +290,10 @@ static struct fb_var_screeninfo rivafb_default_var = {
lower_margin: 11, lower_margin: 11,
hsync_len: 96, hsync_len: 96,
vsync_len: 2, vsync_len: 2,
sync: 0,
vmode: FB_VMODE_NONINTERLACED vmode: FB_VMODE_NONINTERLACED
}; };
static u8 byte_rev[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
/* from GGI */ /* from GGI */
static const struct riva_regs reg_template = { static const struct riva_regs reg_template = {
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */
...@@ -302,76 +315,78 @@ static const struct riva_regs reg_template = { ...@@ -302,76 +315,78 @@ static const struct riva_regs reg_template = {
0xEB /* MISC */ 0xEB /* MISC */
}; };
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
* MMIO access macros * MMIO access macros
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
static inline void CRTCout(struct riva_par *par, unsigned char index, static inline void CRTCout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val) unsigned char val)
{ {
VGA_WR08(par->riva.PCIO, 0x3d4, index); VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
VGA_WR08(par->riva.PCIO, 0x3d5, val); VGA_WR08(rinfo->riva.PCIO, 0x3d5, val);
} }
static inline unsigned char CRTCin(struct riva_par *par, static inline unsigned char CRTCin(struct rivafb_info *rinfo,
unsigned char index) unsigned char index)
{ {
VGA_WR08(par->riva.PCIO, 0x3d4, index); VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
return (VGA_RD08(par->riva.PCIO, 0x3d5)); return (VGA_RD08(rinfo->riva.PCIO, 0x3d5));
} }
static inline void GRAout(struct riva_par *par, unsigned char index, static inline void GRAout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val) unsigned char val)
{ {
VGA_WR08(par->riva.PVIO, 0x3ce, index); VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
VGA_WR08(par->riva.PVIO, 0x3cf, val); VGA_WR08(rinfo->riva.PVIO, 0x3cf, val);
} }
static inline unsigned char GRAin(struct riva_par *par, static inline unsigned char GRAin(struct rivafb_info *rinfo,
unsigned char index) unsigned char index)
{ {
VGA_WR08(par->riva.PVIO, 0x3ce, index); VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
return (VGA_RD08(par->riva.PVIO, 0x3cf)); return (VGA_RD08(rinfo->riva.PVIO, 0x3cf));
} }
static inline void SEQout(struct riva_par *par, unsigned char index, static inline void SEQout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val) unsigned char val)
{ {
VGA_WR08(par->riva.PVIO, 0x3c4, index); VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
VGA_WR08(par->riva.PVIO, 0x3c5, val); VGA_WR08(rinfo->riva.PVIO, 0x3c5, val);
} }
static inline unsigned char SEQin(struct riva_par *par, static inline unsigned char SEQin(struct rivafb_info *rinfo,
unsigned char index) unsigned char index)
{ {
VGA_WR08(par->riva.PVIO, 0x3c4, index); VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
return (VGA_RD08(par->riva.PVIO, 0x3c5)); return (VGA_RD08(rinfo->riva.PVIO, 0x3c5));
} }
static inline void ATTRout(struct riva_par *par, unsigned char index, static inline void ATTRout(struct rivafb_info *rinfo, unsigned char index,
unsigned char val) unsigned char val)
{ {
VGA_WR08(par->riva.PCIO, 0x3c0, index); VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
VGA_WR08(par->riva.PCIO, 0x3c0, val); VGA_WR08(rinfo->riva.PCIO, 0x3c0, val);
} }
static inline unsigned char ATTRin(struct riva_par *par, static inline unsigned char ATTRin(struct rivafb_info *rinfo,
unsigned char index) unsigned char index)
{ {
VGA_WR08(par->riva.PCIO, 0x3c0, index); VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
return (VGA_RD08(par->riva.PCIO, 0x3c1)); return (VGA_RD08(rinfo->riva.PCIO, 0x3c1));
} }
static inline void MISCout(struct riva_par *par, unsigned char val) static inline void MISCout(struct rivafb_info *rinfo, unsigned char val)
{ {
VGA_WR08(par->riva.PVIO, 0x3c2, val); VGA_WR08(rinfo->riva.PVIO, 0x3c2, val);
} }
static inline unsigned char MISCin(struct riva_par *par) static inline unsigned char MISCin(struct rivafb_info *rinfo)
{ {
return (VGA_RD08(par->riva.PVIO, 0x3cc)); return (VGA_RD08(rinfo->riva.PVIO, 0x3cc));
} }
...@@ -384,40 +399,39 @@ static inline unsigned char MISCin(struct riva_par *par) ...@@ -384,40 +399,39 @@ static inline unsigned char MISCin(struct riva_par *par)
/** /**
* riva_cursor_timer_handler - blink timer * riva_cursor_timer_handler - blink timer
* @dev_addr: pointer to fb_info object containing info for current riva board * @dev_addr: pointer to rivafb_info object containing info for current riva board
* *
* DESCRIPTION: * DESCRIPTION:
* Cursor blink timer. * Cursor blink timer.
*/ */
static void riva_cursor_timer_handler(unsigned long dev_addr) static void riva_cursor_timer_handler(unsigned long dev_addr)
{ {
struct fb_info *info = (struct fb_info *)dev_addr; struct rivafb_info *rinfo = (struct rivafb_info *)dev_addr;
struct riva_par *par = (struct riva_par *) info->par;
if (!par->cursor) return; if (!rinfo->cursor) return;
if (!par->cursor->enable) goto out; if (!rinfo->cursor->enable) goto out;
par->cursor->prev_slice_moves = par->cursor->last_slice_moves; if (rinfo->cursor->last_move_delay < 1000)
par->cursor->last_slice_moves = 0; rinfo->cursor->last_move_delay++;
if (par->cursor->vbl_cnt && --par->cursor->vbl_cnt == 0) { if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) {
par->cursor->on ^= 1; rinfo->cursor->on ^= 1;
if (par->cursor->on) if (rinfo->cursor->on)
*(par->riva.CURSORPOS) = (par->cursor->pos.x & 0xFFFF) *(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF)
| (par->cursor->pos.y << 16); | (rinfo->cursor->pos.y << 16);
par->riva.ShowHideCursor(&par->riva, par->cursor->on); rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on);
if (!noblink) if (!noblink)
par->cursor->vbl_cnt = par->cursor->blink_rate; rinfo->cursor->vbl_cnt = rinfo->cursor->blink_rate;
} }
out: out:
par->cursor->timer->expires = jiffies + (HZ / 50); rinfo->cursor->timer->expires = jiffies + (HZ / 100);
add_timer(par->cursor->timer); add_timer(rinfo->cursor->timer);
} }
/** /**
* rivafb_init_cursor - allocates cursor structure and starts blink timer * rivafb_init_cursor - allocates cursor structure and starts blink timer
* @info: pointer to fb_info object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* *
* DESCRIPTION: * DESCRIPTION:
* Allocates cursor structure and starts blink timer. * Allocates cursor structure and starts blink timer.
...@@ -428,7 +442,7 @@ static void riva_cursor_timer_handler(unsigned long dev_addr) ...@@ -428,7 +442,7 @@ static void riva_cursor_timer_handler(unsigned long dev_addr)
* CALLED FROM: * CALLED FROM:
* rivafb_init_one() * rivafb_init_one()
*/ */
static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info) static struct riva_cursor * __init rivafb_init_cursor(struct rivafb_info *rinfo)
{ {
struct riva_cursor *cursor; struct riva_cursor *cursor;
...@@ -446,8 +460,8 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info) ...@@ -446,8 +460,8 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
init_timer(cursor->timer); init_timer(cursor->timer);
cursor->timer->expires = jiffies + (HZ / 50); cursor->timer->expires = jiffies + (HZ / 100);
cursor->timer->data = (unsigned long)info; cursor->timer->data = (unsigned long)rinfo;
cursor->timer->function = riva_cursor_timer_handler; cursor->timer->function = riva_cursor_timer_handler;
add_timer(cursor->timer); add_timer(cursor->timer);
...@@ -456,7 +470,7 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info) ...@@ -456,7 +470,7 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
/** /**
* rivafb_exit_cursor - stops blink timer and releases cursor structure * rivafb_exit_cursor - stops blink timer and releases cursor structure
* @par: pointer to riva_par object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* *
* DESCRIPTION: * DESCRIPTION:
* Stops blink timer and releases cursor structure. * Stops blink timer and releases cursor structure.
...@@ -465,9 +479,9 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info) ...@@ -465,9 +479,9 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info)
* rivafb_init_one() * rivafb_init_one()
* rivafb_remove_one() * rivafb_remove_one()
*/ */
static void rivafb_exit_cursor(struct riva_par *par) static void rivafb_exit_cursor(struct rivafb_info *rinfo)
{ {
struct riva_cursor *cursor = par->cursor; struct riva_cursor *cursor = rinfo->cursor;
if (cursor) { if (cursor) {
if (cursor->timer) { if (cursor->timer) {
...@@ -475,13 +489,13 @@ static void rivafb_exit_cursor(struct riva_par *par) ...@@ -475,13 +489,13 @@ static void rivafb_exit_cursor(struct riva_par *par)
kfree(cursor->timer); kfree(cursor->timer);
} }
kfree(cursor); kfree(cursor);
par->cursor = NULL; rinfo->cursor = 0;
} }
} }
/** /**
* rivafb_download_cursor - writes cursor shape into card registers * rivafb_download_cursor - writes cursor shape into card registers
* @par: pointer to riva_par object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* *
* DESCRIPTION: * DESCRIPTION:
* Writes cursor shape into card registers. * Writes cursor shape into card registers.
...@@ -489,24 +503,24 @@ static void rivafb_exit_cursor(struct riva_par *par) ...@@ -489,24 +503,24 @@ static void rivafb_exit_cursor(struct riva_par *par)
* CALLED FROM: * CALLED FROM:
* riva_load_video_mode() * riva_load_video_mode()
*/ */
static void rivafb_download_cursor(struct riva_par *par) static void rivafb_download_cursor(struct rivafb_info *rinfo)
{ {
int i, save; int i, save;
int *image; int *image;
if (!par->cursor) return; if (!rinfo->cursor) return;
image = (int *)par->cursor->image; image = (int *)rinfo->cursor->image;
save = par->riva.ShowHideCursor(&par->riva, 0); save = rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
for (i = 0; i < (MAX_CURS*MAX_CURS*2)/sizeof(int); i++) for (i = 0; i < (MAX_CURS*MAX_CURS*2)/sizeof(int); i++)
writel(image[i], par->riva.CURSOR + i); writel(image[i], rinfo->riva.CURSOR + i);
par->riva.ShowHideCursor(&par->riva, save); rinfo->riva.ShowHideCursor(&rinfo->riva, save);
} }
/** /**
* rivafb_create_cursor - sets rectangular cursor * rivafb_create_cursor - sets rectangular cursor
* @par: pointer to riva_par object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* @width: cursor width in pixels * @width: cursor width in pixels
* @height: cursor height in pixels * @height: cursor height in pixels
* *
...@@ -515,11 +529,11 @@ static void rivafb_download_cursor(struct riva_par *par) ...@@ -515,11 +529,11 @@ static void rivafb_download_cursor(struct riva_par *par)
* *
* CALLED FROM: * CALLED FROM:
* rivafb_set_font() * rivafb_set_font()
* rivafb_set_par() * rivafb_set_var()
*/ */
static void rivafb_create_cursor(struct riva_par *par, int width, int height) static void rivafb_create_cursor(struct rivafb_info *rinfo, int width, int height)
{ {
struct riva_cursor *c = par->cursor; struct riva_cursor *c = rinfo->cursor;
int i, j, idx; int i, j, idx;
if (c) { if (c) {
...@@ -561,10 +575,9 @@ static void rivafb_create_cursor(struct riva_par *par, int width, int height) ...@@ -561,10 +575,9 @@ static void rivafb_create_cursor(struct riva_par *par, int width, int height)
*/ */
static int rivafb_set_font(struct display *p, int width, int height) static int rivafb_set_font(struct display *p, int width, int height)
{ {
struct fb_info *fb = p->fb_info; struct rivafb_info *fb = (struct rivafb_info *)(p->fb_info);
struct riva_par *par = (struct riva_par *) fb->par;
rivafb_create_cursor(par, width, height); rivafb_create_cursor(fb, width, height);
return 1; return 1;
} }
...@@ -580,9 +593,8 @@ static int rivafb_set_font(struct display *p, int width, int height) ...@@ -580,9 +593,8 @@ static int rivafb_set_font(struct display *p, int width, int height)
*/ */
static void rivafb_cursor(struct display *p, int mode, int x, int y) static void rivafb_cursor(struct display *p, int mode, int x, int y)
{ {
struct fb_info *info = p->fb_info; struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
struct riva_par *par = (struct riva_par *) info->par; struct riva_cursor *c = rinfo->cursor;
struct riva_cursor *c = par->cursor;
if (!c) return; if (!c) return;
...@@ -593,7 +605,7 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y) ...@@ -593,7 +605,7 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
return; return;
c->enable = 0; c->enable = 0;
if (c->on) par->riva.ShowHideCursor(&par->riva, 0); if (c->on) rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
c->pos.x = x; c->pos.x = x;
c->pos.y = y; c->pos.y = y;
...@@ -604,15 +616,15 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y) ...@@ -604,15 +616,15 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
break; break;
case CM_DRAW: case CM_DRAW:
case CM_MOVE: case CM_MOVE:
if (c->last_slice_moves > 2 || c->prev_slice_moves > 2) { if (c->last_move_delay <= 1) { /* rapid cursor movement */
c->vbl_cnt = CURSOR_SHOW_DELAY; c->vbl_cnt = CURSOR_SHOW_DELAY;
} else { } else {
*(par->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16); *(rinfo->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16);
par->riva.ShowHideCursor(&par->riva, 1); rinfo->riva.ShowHideCursor(&rinfo->riva, 1);
if (!noblink) c->vbl_cnt = CURSOR_HIDE_DELAY; if (!noblink) c->vbl_cnt = CURSOR_HIDE_DELAY;
c->on = 1; c->on = 1;
} }
c->last_slice_moves++; c->last_move_delay = 0;
c->enable = 1; c->enable = 1;
break; break;
} }
...@@ -626,6 +638,80 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y) ...@@ -626,6 +638,80 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
/**
* riva_set_dispsw - sets dispsw
* @rinfo: pointer to internal driver struct for a given Riva card
* @disp: pointer to display object
*
* DESCRIPTION:
* Sets up console low level operations depending on the current? color depth
* of the display.
*
* CALLED FROM:
* rivafb_set_var()
* rivafb_switch()
* riva_init_disp()
*/
static void riva_set_dispsw(struct rivafb_info *rinfo, struct display *disp)
{
int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
disp->dispsw_data = NULL;
disp->type = FB_TYPE_PACKED_PIXELS;
disp->type_aux = 0;
disp->ypanstep = 1;
disp->ywrapstep = 0;
disp->can_soft_blank = 1;
disp->inverse = 0;
switch (disp->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
rinfo->dispsw = accel ? fbcon_riva8 : fbcon_cfb8;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual;
disp->visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
rinfo->dispsw = accel ? fbcon_riva16 : fbcon_cfb16;
disp->dispsw_data = &rinfo->con_cmap.cfb16;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual * 2;
disp->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
rinfo->dispsw = accel ? fbcon_riva32 : fbcon_cfb32;
disp->dispsw_data = rinfo->con_cmap.cfb32;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual * 4;
disp->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
default:
DPRINTK("Setting fbcon_dummy renderer\n");
rinfo->dispsw = fbcon_dummy;
disp->dispsw = &rinfo->dispsw;
}
/* FIXME: verify that the above code sets dsp->* fields correctly */
if (rinfo->cursor) {
rinfo->dispsw.cursor = rivafb_cursor;
rinfo->dispsw.set_font = rivafb_set_font;
}
DPRINTK("EXIT\n");
}
/** /**
* riva_wclut - set CLUT entry * riva_wclut - set CLUT entry
* @chip: pointer to RIVA_HW_INST object * @chip: pointer to RIVA_HW_INST object
...@@ -652,7 +738,7 @@ static void riva_wclut(RIVA_HW_INST *chip, ...@@ -652,7 +738,7 @@ static void riva_wclut(RIVA_HW_INST *chip,
/** /**
* riva_save_state - saves current chip state * riva_save_state - saves current chip state
* @par: pointer to riva_par object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* @regs: pointer to riva_regs object * @regs: pointer to riva_regs object
* *
* DESCRIPTION: * DESCRIPTION:
...@@ -662,36 +748,36 @@ static void riva_wclut(RIVA_HW_INST *chip, ...@@ -662,36 +748,36 @@ static void riva_wclut(RIVA_HW_INST *chip,
* rivafb_init_one() * rivafb_init_one()
*/ */
/* from GGI */ /* from GGI */
static void riva_save_state(struct riva_par *par, struct riva_regs *regs) static void riva_save_state(struct rivafb_info *rinfo, struct riva_regs *regs)
{ {
int i; int i;
par->riva.LockUnlock(&par->riva, 0); rinfo->riva.LockUnlock(&rinfo->riva, 0);
par->riva.UnloadStateExt(&par->riva, &regs->ext); rinfo->riva.UnloadStateExt(&rinfo->riva, &regs->ext);
regs->misc_output = MISCin(par); regs->misc_output = MISCin(rinfo);
for (i = 0; i < NUM_CRT_REGS; i++) { for (i = 0; i < NUM_CRT_REGS; i++) {
regs->crtc[i] = CRTCin(par, i); regs->crtc[i] = CRTCin(rinfo, i);
} }
for (i = 0; i < NUM_ATC_REGS; i++) { for (i = 0; i < NUM_ATC_REGS; i++) {
regs->attr[i] = ATTRin(par, i); regs->attr[i] = ATTRin(rinfo, i);
} }
for (i = 0; i < NUM_GRC_REGS; i++) { for (i = 0; i < NUM_GRC_REGS; i++) {
regs->gra[i] = GRAin(par, i); regs->gra[i] = GRAin(rinfo, i);
} }
for (i = 0; i < NUM_SEQ_REGS; i++) { for (i = 0; i < NUM_SEQ_REGS; i++) {
regs->seq[i] = SEQin(par, i); regs->seq[i] = SEQin(rinfo, i);
} }
} }
/** /**
* riva_load_state - loads current chip state * riva_load_state - loads current chip state
* @par: pointer to riva_par object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* @regs: pointer to riva_regs object * @regs: pointer to riva_regs object
* *
* DESCRIPTION: * DESCRIPTION:
...@@ -703,18 +789,18 @@ static void riva_save_state(struct riva_par *par, struct riva_regs *regs) ...@@ -703,18 +789,18 @@ static void riva_save_state(struct riva_par *par, struct riva_regs *regs)
* rivafb_remove_one() * rivafb_remove_one()
*/ */
/* from GGI */ /* from GGI */
static void riva_load_state(struct riva_par *par, struct riva_regs *regs) static void riva_load_state(struct rivafb_info *rinfo, struct riva_regs *regs)
{ {
RIVA_HW_STATE *state = &regs->ext;
int i; int i;
RIVA_HW_STATE *state = &regs->ext;
CRTCout(par, 0x11, 0x00); CRTCout(rinfo, 0x11, 0x00);
par->riva.LockUnlock(&par->riva, 0); rinfo->riva.LockUnlock(&rinfo->riva, 0);
par->riva.LoadStateExt(&par->riva, state); rinfo->riva.LoadStateExt(&rinfo->riva, state);
MISCout(par, regs->misc_output); MISCout(rinfo, regs->misc_output);
for (i = 0; i < NUM_CRT_REGS; i++) { for (i = 0; i < NUM_CRT_REGS; i++) {
switch (i) { switch (i) {
...@@ -722,44 +808,44 @@ static void riva_load_state(struct riva_par *par, struct riva_regs *regs) ...@@ -722,44 +808,44 @@ static void riva_load_state(struct riva_par *par, struct riva_regs *regs)
case 0x20 ... 0x40: case 0x20 ... 0x40:
break; break;
default: default:
CRTCout(par, i, regs->crtc[i]); CRTCout(rinfo, i, regs->crtc[i]);
} }
} }
for (i = 0; i < NUM_ATC_REGS; i++) { for (i = 0; i < NUM_ATC_REGS; i++) {
ATTRout(par, i, regs->attr[i]); ATTRout(rinfo, i, regs->attr[i]);
} }
for (i = 0; i < NUM_GRC_REGS; i++) { for (i = 0; i < NUM_GRC_REGS; i++) {
GRAout(par, i, regs->gra[i]); GRAout(rinfo, i, regs->gra[i]);
} }
for (i = 0; i < NUM_SEQ_REGS; i++) { for (i = 0; i < NUM_SEQ_REGS; i++) {
SEQout(par, i, regs->seq[i]); SEQout(rinfo, i, regs->seq[i]);
} }
} }
/** /**
* riva_load_video_mode - calculate timings * riva_load_video_mode - calculate timings
* @info: pointer to fb_info object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* @video_mode: video mode to set * @video_mode: video mode to set
* *
* DESCRIPTION: * DESCRIPTION:
* Calculate some timings and then send em off to riva_load_state(). * Calculate some timings and then send em off to riva_load_state().
* *
* CALLED FROM: * CALLED FROM:
* rivafb_set_par() * rivafb_set_var()
*/ */
static void riva_load_video_mode(struct fb_info *info, static void riva_load_video_mode(struct rivafb_info *rinfo,
struct fb_var_screeninfo *video_mode) struct fb_var_screeninfo *video_mode)
{ {
struct riva_par *par = (struct riva_par *) info->par;
struct riva_regs newmode; struct riva_regs newmode;
int bpp, width, hDisplaySize, hDisplay, hStart, int bpp, width, hDisplaySize, hDisplay, hStart,
hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock; hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
/* time to calculate */ /* time to calculate */
rivafb_blank(1, info);
rivafb_blank(1, (struct fb_info *)rinfo);
bpp = video_mode->bits_per_pixel; bpp = video_mode->bits_per_pixel;
if (bpp == 16 && video_mode->green.length == 5) if (bpp == 16 && video_mode->green.length == 5)
...@@ -813,27 +899,83 @@ static void riva_load_video_mode(struct fb_info *info, ...@@ -813,27 +899,83 @@ static void riva_load_video_mode(struct fb_info *info,
newmode.ext.width = width; newmode.ext.width = width;
newmode.ext.height = height; newmode.ext.height = height;
par->riva.CalcStateExt(&par->riva, &newmode.ext, bpp, width, rinfo->riva.CalcStateExt(&rinfo->riva, &newmode.ext, bpp, width,
hDisplaySize, hDisplay, hStart, hEnd, hDisplaySize, hDisplay, hStart, hEnd,
hTotal, height, vDisplay, vStart, vEnd, hTotal, height, vDisplay, vStart, vEnd,
vTotal, dotClock); vTotal, dotClock);
if (video_mode->sync & FB_SYNC_HOR_HIGH_ACT) rinfo->current_state = newmode;
newmode.misc_output &= ~0x40; riva_load_state(rinfo, &rinfo->current_state);
if (video_mode->sync & FB_SYNC_VERT_HIGH_ACT)
newmode.misc_output &= ~0x80; rinfo->riva.LockUnlock(&rinfo->riva, 0); /* important for HW cursor */
rivafb_download_cursor(rinfo);
}
/**
* riva_board_list_add - maintains board list
* @board_list: root node of list of boards
* @new_node: new node to be added
*
* DESCRIPTION:
* Adds @new_node to the list referenced by @board_list.
*
* RETURNS:
* New root node
*
* CALLED FROM:
* rivafb_init_one()
*/
static struct rivafb_info *riva_board_list_add(struct rivafb_info *board_list,
struct rivafb_info *new_node)
{
struct rivafb_info *i_p = board_list;
new_node->next = NULL;
if (board_list == NULL)
return new_node;
while (i_p->next != NULL)
i_p = i_p->next;
i_p->next = new_node;
return board_list;
}
/**
* riva_board_list_del - maintains board list
* @board_list: root node of list of boards
* @del_node: node to be removed
*
* DESCRIPTION:
* Removes @del_node from the list referenced by @board_list.
*
* RETURNS:
* New root node
*
* CALLED FROM:
* rivafb_remove_one()
*/
static struct rivafb_info *riva_board_list_del(struct rivafb_info *board_list,
struct rivafb_info *del_node)
{
struct rivafb_info *i_p = board_list;
if (board_list == del_node)
return del_node->next;
par->current_state = newmode; while (i_p->next != del_node)
riva_load_state(par, &par->current_state); i_p = i_p->next;
i_p->next = del_node->next;
par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */ return board_list;
rivafb_download_cursor(par);
} }
/** /**
* rivafb_do_maximize - * rivafb_do_maximize -
* @info: pointer to fb_info object containing info for current riva board * @rinfo: pointer to rivafb_info object containing info for current riva board
* @var: * @var:
* @v:
* @nom: * @nom:
* @den: * @den:
* *
...@@ -845,13 +987,13 @@ static void riva_load_video_mode(struct fb_info *info, ...@@ -845,13 +987,13 @@ static void riva_load_video_mode(struct fb_info *info,
* *
* *
* CALLED FROM: * CALLED FROM:
* rivafb_check_var() * rivafb_set_var()
*/ */
static int rivafb_do_maximize(struct fb_info *info, static int rivafb_do_maximize(struct rivafb_info *rinfo,
struct fb_var_screeninfo *var, struct fb_var_screeninfo *var,
struct fb_var_screeninfo *v,
int nom, int den) int nom, int den)
{ {
struct riva_par *par = (struct riva_par *) info->par;
static struct { static struct {
int xres, yres; int xres, yres;
} modes[] = { } modes[] = {
...@@ -865,12 +1007,12 @@ static int rivafb_do_maximize(struct fb_info *info, ...@@ -865,12 +1007,12 @@ static int rivafb_do_maximize(struct fb_info *info,
int i; int i;
/* use highest possible virtual resolution */ /* use highest possible virtual resolution */
if (var->xres_virtual == -1 && var->yres_virtual == -1) { if (v->xres_virtual == -1 && v->yres_virtual == -1) {
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"using maximum available virtual resolution\n"); "using maximum available virtual resolution\n");
for (i = 0; modes[i].xres != -1; i++) { for (i = 0; modes[i].xres != -1; i++) {
if (modes[i].xres * nom / den * modes[i].yres < if (modes[i].xres * nom / den * modes[i].yres <
par->ram_amount / 2) rinfo->ram_amount / 2)
break; break;
} }
if (modes[i].xres == -1) { if (modes[i].xres == -1) {
...@@ -879,26 +1021,26 @@ static int rivafb_do_maximize(struct fb_info *info, ...@@ -879,26 +1021,26 @@ static int rivafb_do_maximize(struct fb_info *info,
DPRINTK("EXIT - EINVAL error\n"); DPRINTK("EXIT - EINVAL error\n");
return -EINVAL; return -EINVAL;
} }
var->xres_virtual = modes[i].xres; v->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres; v->yres_virtual = modes[i].yres;
printk(KERN_INFO PFX printk(KERN_INFO PFX
"virtual resolution set to maximum of %dx%d\n", "virtual resolution set to maximum of %dx%d\n",
var->xres_virtual, var->yres_virtual); v->xres_virtual, v->yres_virtual);
} else if (var->xres_virtual == -1) { } else if (v->xres_virtual == -1) {
var->xres_virtual = (par->ram_amount * den / v->xres_virtual = (rinfo->ram_amount * den /
(nom * var->yres_virtual * 2)) & ~15; (nom * v->yres_virtual * 2)) & ~15;
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"setting virtual X resolution to %d\n", var->xres_virtual); "setting virtual X resolution to %d\n", v->xres_virtual);
} else if (var->yres_virtual == -1) { } else if (v->yres_virtual == -1) {
var->xres_virtual = (var->xres_virtual + 15) & ~15; v->xres_virtual = (v->xres_virtual + 15) & ~15;
var->yres_virtual = par->ram_amount * den / v->yres_virtual = rinfo->ram_amount * den /
(nom * var->xres_virtual * 2); (nom * v->xres_virtual * 2);
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"setting virtual Y resolution to %d\n", var->yres_virtual); "setting virtual Y resolution to %d\n", v->yres_virtual);
} else { } else {
var->xres_virtual = (var->xres_virtual + 15) & ~15; v->xres_virtual = (v->xres_virtual + 15) & ~15;
if (var->xres_virtual * nom / den * var->yres_virtual > par->ram_amount) { if (v->xres_virtual * nom / den * v->yres_virtual > rinfo->ram_amount) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel); var->xres, var->yres, var->bits_per_pixel);
...@@ -907,146 +1049,29 @@ static int rivafb_do_maximize(struct fb_info *info, ...@@ -907,146 +1049,29 @@ static int rivafb_do_maximize(struct fb_info *info,
} }
} }
if (var->xres_virtual * nom / den >= 8192) { if (v->xres_virtual * nom / den >= 8192) {
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"virtual X resolution (%d) is too high, lowering to %d\n", "virtual X resolution (%d) is too high, lowering to %d\n",
var->xres_virtual, 8192 * den / nom - 16); v->xres_virtual, 8192 * den / nom - 16);
var->xres_virtual = 8192 * den / nom - 16; v->xres_virtual = 8192 * den / nom - 16;
} }
if (var->xres_virtual < var->xres) { if (v->xres_virtual < v->xres) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"virtual X resolution (%d) is smaller than real\n", var->xres_virtual); "virtual X resolution (%d) is smaller than real\n", v->xres_virtual);
return -EINVAL; return -EINVAL;
} }
if (var->yres_virtual < var->yres) { if (v->yres_virtual < v->yres) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"virtual Y resolution (%d) is smaller than real\n", var->yres_virtual); "virtual Y resolution (%d) is smaller than real\n", v->yres_virtual);
return -EINVAL; return -EINVAL;
} }
return 0;
}
/* acceleration routines */
static inline void convert_bgcolor_16(u32 *col) return 0;
{
*col = ((*col & 0x00007C00) << 9)
| ((*col & 0x000003E0) << 6)
| ((*col & 0x0000001F) << 3)
| 0xFF000000;
}
inline void wait_for_idle(struct riva_par *par)
{
while (par->riva.Busy(&par->riva));
}
/* set copy ROP, no mask */
static void riva_setup_ROP(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Patt, 5);
par->riva.Patt->Shape = 0;
par->riva.Patt->Color0 = 0xffffffff;
par->riva.Patt->Color1 = 0xffffffff;
par->riva.Patt->Monochrome[0] = 0xffffffff;
par->riva.Patt->Monochrome[1] = 0xffffffff;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = 0xCC;
}
void riva_setup_accel(struct riva_par *par)
{
RIVA_FIFO_FREE(par->riva, Clip, 2);
par->riva.Clip->TopLeft = 0x0;
par->riva.Clip->WidthHeight = 0x80008000;
riva_setup_ROP(par);
wait_for_idle(par);
}
static inline void reverse_order(u32 *l)
{
u8 *a = (u8 *)l;
*a++ = byte_rev[*a];
/* *a++ = byte_rev[*a];
*a++ = byte_rev[*a];*/
*a = byte_rev[*a];
}
static void rivafb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = rect->rop ? 0x66 : 0xCC;
RIVA_FIFO_FREE(par->riva, Bitmap, 1);
if (info->fix.visual == FB_VISUAL_TRUECOLOR)
par->riva.Bitmap->Color1A = ((u32 *) (info->pseudo_palette))[rect->color];
else
par->riva.Bitmap->Color1A = rect->color;
RIVA_FIFO_FREE(par->riva, Bitmap, 2);
par->riva.Bitmap->UnclippedRectangle[0].TopLeft = (rect->dx << 16) | rect->dy;
par->riva.Bitmap->UnclippedRectangle[0].WidthHeight = (rect->width << 16) | rect->height;
RIVA_FIFO_FREE(par->riva, Rop, 1);
par->riva.Rop->Rop3 = 0xCC; // back to COPY
}
static void rivafb_copyarea(struct fb_info *info, struct fb_copyarea *area)
{
struct riva_par *par = (struct riva_par *) info->par;
RIVA_FIFO_FREE(par->riva, Blt, 3);
par->riva.Blt->TopLeftSrc = (area->sy << 16) | area->sx;
par->riva.Blt->TopLeftDst = (area->dy << 16) | area->dx;
par->riva.Blt->WidthHeight = (area->height << 16) | area->width;
} }
static void rivafb_imageblit(struct fb_info *info, struct fb_image *image)
{
struct riva_par *par = (struct riva_par *) info->par;
volatile u32 *d;
int i, j, cnt;
u32 cdat2;
RIVA_FIFO_FREE(par->riva, Bitmap, 7);
par->riva.Bitmap->ClipE.TopLeft = (image->dy << 16) | (image->dx & 0xFFFF);
par->riva.Bitmap->ClipE.BottomRight = ((image->dy + image->height) << 16) | ((image->dx + image->width) & 0xffff);
if (info->var.green.length == 6)
convert_bgcolor_16(&image->bg_color);
if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
par->riva.Bitmap->Color0E = ((u32 *) (info->pseudo_palette))[image->bg_color];
par->riva.Bitmap->Color1E = ((u32 *) (info->pseudo_palette))[image->fg_color];
} else {
par->riva.Bitmap->Color0E = image->bg_color;
par->riva.Bitmap->Color1E = image->fg_color;
}
par->riva.Bitmap->WidthHeightInE = (image->height << 16) | 32;
par->riva.Bitmap->WidthHeightOutE = (image->height << 16) | 32;
par->riva.Bitmap->PointE = (image->dy << 16) | (image->dx & 0xFFFF);
d = &par->riva.Bitmap->MonochromeData01E;
for (i = image->height; i > 0; i -= 16) {
if (i >= 16)
cnt = 16;
else
cnt = i;
RIVA_FIFO_FREE(par->riva, Bitmap, cnt);
for (j = 0; j < cnt; j++) {
if (image->width <= 8)
cdat2 = *image->data++;
else
cdat2 = *((u16*)image->data)++;
reverse_order(&cdat2);
d[j] = cdat2;
}
}
}
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
...@@ -1065,7 +1090,10 @@ static void rivafb_imageblit(struct fb_info *info, struct fb_image *image) ...@@ -1065,7 +1090,10 @@ static void rivafb_imageblit(struct fb_info *info, struct fb_image *image)
* Length of color map * Length of color map
* *
* CALLED FROM: * CALLED FROM:
* riva_getcolreg()
* rivafb_setcolreg() * rivafb_setcolreg()
* rivafb_get_cmap()
* rivafb_set_cmap()
*/ */
static int riva_get_cmap_len(const struct fb_var_screeninfo *var) static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
{ {
...@@ -1074,18 +1102,24 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) ...@@ -1074,18 +1102,24 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
assert(var != NULL); assert(var != NULL);
switch (var->bits_per_pixel) { switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8: case 8:
rc = 256; /* pseudocolor... 256 entries HW palette */ rc = 256; /* pseudocolor... 256 entries HW palette */
break; break;
#endif
#ifdef FBCON_HAS_CFB16
case 15: case 15:
rc = 15; /* fix for 15 bpp depths on Riva 128 based cards */ rc = 15; /* fix for 15 bpp depths on Riva 128 based cards */
break; break;
case 16: case 16:
rc = 16; /* directcolor... 16 entries SW palette */ rc = 16; /* directcolor... 16 entries SW palette */
break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
#endif
#ifdef FBCON_HAS_CFB32
case 32: case 32:
rc = 16; /* directcolor... 16 entries SW palette */ rc = 16; /* directcolor... 16 entries SW palette */
break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
#endif
default: default:
/* should not occur */ /* should not occur */
break; break;
...@@ -1094,6 +1128,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) ...@@ -1094,6 +1128,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
return rc; return rc;
} }
/**
* riva_getcolreg
* @regno: register index
* @red: red component
* @green: green component
* @blue: blue component
* @transp: transparency
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Read a single color register and split it into colors/transparent.
* The return values must have a 16 bit magnitude.
*
* RETURNS:
* Return != 0 for invalid regno.
*
* CALLED FROM:
* rivafb_get_cmap()
* rivafb_switch()
* fbcmap.c:fb_get_cmap()
* fbgen.c:fbgen_get_cmap()
* fbgen.c:fbgen_switch()
*/
static int riva_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
if (regno >= riva_get_cmap_len(&rivainfo->currcon_display->var))
return 1;
*red = rivainfo->palette[regno].red;
*green = rivainfo->palette[regno].green;
*blue = rivainfo->palette[regno].blue;
*transp = 0;
return 0;
}
/** /**
* rivafb_setcolreg * rivafb_setcolreg
* @regno: register index * @regno: register index
...@@ -1101,7 +1175,7 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) ...@@ -1101,7 +1175,7 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* @green: green component * @green: green component
* @blue: blue component * @blue: blue component
* @transp: transparency * @transp: transparency
* @info: pointer to fb_info object containing info for current riva board * @info: pointer to rivafb_info object containing info for current riva board
* *
* DESCRIPTION: * DESCRIPTION:
* Set a single color register. The values supplied have a 16 bit * Set a single color register. The values supplied have a 16 bit
...@@ -1111,54 +1185,79 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) ...@@ -1111,54 +1185,79 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* Return != 0 for invalid regno. * Return != 0 for invalid regno.
* *
* CALLED FROM: * CALLED FROM:
* rivafb_set_cmap()
* fbcmap.c:fb_set_cmap() * fbcmap.c:fb_set_cmap()
* fbgen.c:gen_get_cmap() * fbgen.c:fbgen_get_cmap()
* fbgen.c:do_install_cmap()
* fbgen.c:fbgen_set_var()
* fbgen.c:fbgen_switch()
* fbgen.c:fbgen_blank()
* fbgen.c:fbgen_blank()
*/ */
static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green, static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, unsigned blue, unsigned transp,
struct fb_info *info) struct fb_info *info)
{ {
struct riva_par *par = (struct riva_par *) info->par; struct rivafb_info *rivainfo = (struct rivafb_info *)info;
RIVA_HW_INST *chip = &par->riva; RIVA_HW_INST *chip = &rivainfo->riva;
struct display *p;
if (regno >= riva_get_cmap_len(&info->var)) DPRINTK("ENTER\n");
assert(rivainfo != NULL);
assert(rivainfo->currcon_display != NULL);
p = rivainfo->currcon_display;
if (regno >= riva_get_cmap_len(&p->var))
return -EINVAL; return -EINVAL;
if (info->var.grayscale) { rivainfo->palette[regno].red = red;
rivainfo->palette[regno].green = green;
rivainfo->palette[regno].blue = blue;
if (p->var.grayscale) {
/* gray = 0.30*R + 0.59*G + 0.11*B */ /* gray = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = red = green = blue =
(red * 77 + green * 151 + blue * 28) >> 8; (red * 77 + green * 151 + blue * 28) >> 8;
} }
switch (info->var.bits_per_pixel) { switch (p->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8: case 8:
/* "transparent" stuff is completely ignored. */ /* "transparent" stuff is completely ignored. */
riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8); riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
break; break;
#endif /* FBCON_HAS_CFB8 */
#ifdef FBCON_HAS_CFB16
case 16: case 16:
assert(regno < 16); assert(regno < 16);
if (info->var.green.length == 5) { if (p->var.green.length == 5) {
/* 0rrrrrgg gggbbbbb */ /* 0rrrrrgg gggbbbbb */
((u16 *)(info->pseudo_palette))[regno] = rivainfo->con_cmap.cfb16[regno] =
((red & 0xf800) >> 1) | ((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
} else { } else {
/* rrrrrggg gggbbbbb */ /* rrrrrggg gggbbbbb */
((u16 *)(info->pseudo_palette))[regno] = rivainfo->con_cmap.cfb16[regno] =
((red & 0xf800) >> 0) | ((red & 0xf800) >> 0) |
((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11); ((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
} }
break; break;
#endif /* FBCON_HAS_CFB16 */
#ifdef FBCON_HAS_CFB32
case 32: case 32:
assert(regno < 16); assert(regno < 16);
((u32 *)(info->pseudo_palette))[regno] = rivainfo->con_cmap.cfb32[regno] =
((red & 0xff00) << 8) | ((red & 0xff00) << 8) |
((green & 0xff00)) | ((blue & 0xff00) >> 8); ((green & 0xff00)) | ((blue & 0xff00) >> 8);
break; break;
#endif /* FBCON_HAS_CFB32 */
default: default:
/* do nothing */ /* do nothing */
break; break;
} }
return 0; return 0;
} }
...@@ -1170,58 +1269,177 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green, ...@@ -1170,58 +1269,177 @@ static int rivafb_setcolreg(unsigned regno, unsigned red, unsigned green,
* *
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int rivafb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
{ {
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *p;
DPRINTK("ENTER\n");
assert(fix != NULL);
assert(info != NULL);
assert(rivainfo->drvr_name && rivainfo->drvr_name[0]);
assert(rivainfo->fb_base_phys > 0);
assert(rivainfo->ram_amount > 0);
p = (con < 0) ? rivainfo->info.disp : &fb_display[con];
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
sprintf(fix->id, "nVidia %s", rivainfo->drvr_name);
fix->smem_start = rivainfo->fb_base_phys;
fix->smem_len = rivainfo->ram_amount;
fix->type = p->type;
fix->type_aux = p->type_aux;
fix->visual = p->visual;
fix->xpanstep = 1;
fix->ypanstep = 1;
fix->ywrapstep = 0; /* FIXME: no ywrap for now */
fix->line_length = p->line_length;
fix->mmio_start = rivainfo->ctrl_base_phys;
fix->mmio_len = rivainfo->base0_region_size;
fix->smem_start = rivainfo->fb_base_phys;
fix->smem_len = rivainfo->base1_region_size;
switch (rivainfo->riva.Architecture) {
case NV_ARCH_03:
fix->accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04: /* riva_hw.c now doesn't distinguish between TNT & TNT2 */
fix->accel = FB_ACCEL_NV4;
break;
case NV_ARCH_10: /* FIXME: ID for GeForce */
fix->accel = FB_ACCEL_NV4;
break;
}
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(info != NULL);
assert(var != NULL);
*var = (con < 0) ? rivainfo->disp.var : fb_display[con].var;
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *dsp;
struct fb_var_screeninfo v;
int nom, den; /* translating from pixels->bytes */ int nom, den; /* translating from pixels->bytes */
int accel;
unsigned chgvar = 0;
switch (var->bits_per_pixel) { DPRINTK("ENTER\n");
assert(info != NULL);
assert(var != NULL);
DPRINTK("Requested: %dx%dx%d\n", var->xres, var->yres,
var->bits_per_pixel);
DPRINTK(" virtual: %dx%d\n", var->xres_virtual,
var->yres_virtual);
DPRINTK(" offset: (%d,%d)\n", var->xoffset, var->yoffset);
DPRINTK("grayscale: %d\n", var->grayscale);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
assert(dsp != NULL);
/* if var has changed, we should call changevar() later */
if (con >= 0) {
chgvar = ((dsp->var.xres != var->xres) ||
(dsp->var.yres != var->yres) ||
(dsp->var.xres_virtual != var->xres_virtual) ||
(dsp->var.yres_virtual != var->yres_virtual) ||
(dsp->var.accel_flags != var->accel_flags) ||
(dsp->var.bits_per_pixel != var->bits_per_pixel)
|| memcmp(&dsp->var.red, &var->red,
sizeof(var->red))
|| memcmp(&dsp->var.green, &var->green,
sizeof(var->green))
|| memcmp(&dsp->var.blue, &var->blue,
sizeof(var->blue)));
}
memcpy(&v, var, sizeof(v));
accel = v.accel_flags & FB_ACCELF_TEXT;
switch (v.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 1 ... 8: case 1 ... 8:
var->bits_per_pixel = 8; v.bits_per_pixel = 8;
nom = 1; nom = 1;
den = 1; den = 1;
var->red.offset = 0; v.red.offset = 0;
var->red.length = 8; v.red.length = 8;
var->green.offset = 0; v.green.offset = 0;
var->green.length = 8; v.green.length = 8;
var->blue.offset = 0; v.blue.offset = 0;
var->blue.length = 8; v.blue.length = 8;
break; break;
#endif
#ifdef FBCON_HAS_CFB16
case 9 ... 15: case 9 ... 15:
var->green.length = 5; v.green.length = 5;
/* fall through */ /* fall through */
case 16: case 16:
var->bits_per_pixel = 16; v.bits_per_pixel = 16;
nom = 2; nom = 2;
den = 1; den = 1;
if (var->green.length == 5) { if (v.green.length == 5) {
/* 0rrrrrgg gggbbbbb */ /* 0rrrrrgg gggbbbbb */
var->red.offset = 10; v.red.offset = 10;
var->green.offset = 5; v.green.offset = 5;
var->blue.offset = 0; v.blue.offset = 0;
var->red.length = 5; v.red.length = 5;
var->green.length = 5; v.green.length = 5;
var->blue.length = 5; v.blue.length = 5;
} else { } else {
/* rrrrrggg gggbbbbb */ /* rrrrrggg gggbbbbb */
var->red.offset = 11; v.red.offset = 11;
var->green.offset = 5; v.green.offset = 5;
var->blue.offset = 0; v.blue.offset = 0;
var->red.length = 5; v.red.length = 5;
var->green.length = 6; v.green.length = 6;
var->blue.length = 5; v.blue.length = 5;
} }
break; break;
#endif
#ifdef FBCON_HAS_CFB32
case 17 ... 32: case 17 ... 32:
var->bits_per_pixel = 32; v.bits_per_pixel = 32;
nom = 4; nom = 4;
den = 1; den = 1;
var->red.offset = 16; v.red.offset = 16;
var->green.offset = 8; v.green.offset = 8;
var->blue.offset = 0; v.blue.offset = 0;
var->red.length = 8; v.red.length = 8;
var->green.length = 8; v.green.length = 8;
var->blue.length = 8; v.blue.length = 8;
break; break;
#endif
default: default:
printk(KERN_ERR PFX printk(KERN_ERR PFX
"mode %dx%dx%d rejected...color depth not supported.\n", "mode %dx%dx%d rejected...color depth not supported.\n",
...@@ -1230,57 +1448,122 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ...@@ -1230,57 +1448,122 @@ static int rivafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL; return -EINVAL;
} }
if (rivafb_do_maximize(info, var, nom, den) < 0) if (rivafb_do_maximize(rivainfo, var, &v, nom, den) < 0)
return -EINVAL; return -EINVAL;
if (var->xoffset < 0) if (v.xoffset < 0)
var->xoffset = 0; v.xoffset = 0;
if (var->yoffset < 0) if (v.yoffset < 0)
var->yoffset = 0; v.yoffset = 0;
/* truncate xoffset and yoffset to maximum if too high */ /* truncate xoffset and yoffset to maximum if too high */
if (var->xoffset > var->xres_virtual - var->xres) if (v.xoffset > v.xres_virtual - v.xres)
var->xoffset = var->xres_virtual - var->xres - 1; v.xoffset = v.xres_virtual - v.xres - 1;
if (v.yoffset > v.yres_virtual - v.yres)
v.yoffset = v.yres_virtual - v.yres - 1;
v.red.msb_right =
v.green.msb_right =
v.blue.msb_right =
v.transp.offset = v.transp.length = v.transp.msb_right = 0;
switch (v.activate & FB_ACTIVATE_MASK) {
case FB_ACTIVATE_TEST:
DPRINTK("EXIT - FB_ACTIVATE_TEST\n");
return 0;
case FB_ACTIVATE_NXTOPEN: /* ?? */
case FB_ACTIVATE_NOW:
break; /* continue */
default:
DPRINTK("EXIT - unknown activation type\n");
return -EINVAL; /* unknown */
}
memcpy(&dsp->var, &v, sizeof(v));
if (chgvar) {
riva_set_dispsw(rivainfo, dsp);
if (var->yoffset > var->yres_virtual - var->yres) if (accel) {
var->yoffset = var->yres_virtual - var->yres - 1; if (nomove)
dsp->scrollmode = SCROLL_YNOMOVE;
else
dsp->scrollmode = 0;
} else
dsp->scrollmode = SCROLL_YREDRAW;
if (info && info->changevar)
info->changevar(con);
}
rivafb_create_cursor(rivainfo, fontwidth(dsp), fontheight(dsp));
riva_load_video_mode(rivainfo, &v);
if (accel) riva_setup_accel(rivainfo);
var->red.msb_right = DPRINTK("EXIT, returning 0\n");
var->green.msb_right =
var->blue.msb_right =
var->transp.offset = var->transp.length = var->transp.msb_right = 0;
var->accel_flags |= FB_ACCELF_TEXT;
return 0; return 0;
} }
static int rivafb_set_par(struct fb_info *info) static int rivafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{ {
struct riva_par *par = (struct riva_par *) info->par; struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *dsp;
switch (info->var.bits_per_pixel) { DPRINTK("ENTER\n");
case 8:
info->fix.line_length = info->var.xres_virtual; assert(rivainfo != NULL);
info->fix.visual = FB_VISUAL_PSEUDOCOLOR; assert(cmap != NULL);
break;
case 16: dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
info->fix.line_length = info->var.xres_virtual * 2;
info->fix.visual = FB_VISUAL_DIRECTCOLOR; if (con == info->currcon) { /* current console? */
break; int rc = fb_get_cmap(cmap, kspc, riva_getcolreg, info);
case 32: DPRINTK("EXIT - returning %d\n", rc);
info->fix.line_length = info->var.xres_virtual * 4; return rc;
info->fix.visual = FB_VISUAL_DIRECTCOLOR; } else if (dsp->cmap.len) /* non default colormap? */
break; fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
else
fb_copy_cmap(fb_default_cmap
(riva_get_cmap_len(&dsp->var)), cmap,
kspc ? 0 : 2);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct display *dsp;
unsigned int cmap_len;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
assert(cmap != NULL);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
cmap_len = riva_get_cmap_len(&dsp->var);
if (dsp->cmap.len != cmap_len) {
int err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
if (err) {
DPRINTK("EXIT - returning %d\n", err);
return err;
} }
/*
if (par->cursor) {
disp->dispsw.cursor = rivafb_cursor;
disp->dispsw.set_font = rivafb_set_font;
} }
rivafb_create_cursor(par, fontwidth(dsp), fontheight(dsp)); if (con == info->currcon) { /* current console? */
*/ int rc = fb_set_cmap(cmap, kspc, info);
DPRINTK("EXIT - returning %d\n", rc);
return rc;
} else
fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
DPRINTK("EXIT, returning 0\n");
riva_load_video_mode(info, &info->var);
riva_setup_accel(par);
return 0; return 0;
} }
...@@ -1288,7 +1571,7 @@ static int rivafb_set_par(struct fb_info *info) ...@@ -1288,7 +1571,7 @@ static int rivafb_set_par(struct fb_info *info)
* rivafb_pan_display * rivafb_pan_display
* @var: standard kernel fb changeable data * @var: standard kernel fb changeable data
* @con: TODO * @con: TODO
* @info: pointer to fb_info object containing info for current riva board * @info: pointer to rivafb_info object containing info for current riva board
* *
* DESCRIPTION: * DESCRIPTION:
* Pan (or wrap, depending on the `vmode' field) the display using the * Pan (or wrap, depending on the `vmode' field) the display using the
...@@ -1300,58 +1583,132 @@ static int rivafb_set_par(struct fb_info *info) ...@@ -1300,58 +1583,132 @@ static int rivafb_set_par(struct fb_info *info)
static int rivafb_pan_display(struct fb_var_screeninfo *var, int con, static int rivafb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info) struct fb_info *info)
{ {
struct riva_par *par = (struct riva_par *) info->par;
struct display *dsp;
unsigned int base; unsigned int base;
struct display *dsp;
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
if (var->xoffset > (var->xres_virtual - var->xres)) if (var->xoffset > (var->xres_virtual - var->xres))
return -EINVAL; return -EINVAL;
if (var->yoffset > (var->yres_virtual - var->yres)) if (var->yoffset > (var->yres_virtual - var->yres))
return -EINVAL; return -EINVAL;
dsp = (con < 0) ? info->disp : &fb_display[con]; dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
if (var->vmode & FB_VMODE_YWRAP) { if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0 if (var->yoffset < 0
|| var->yoffset >= info->var.yres_virtual || var->yoffset >= dsp->var.yres_virtual
|| var->xoffset) return -EINVAL; || var->xoffset) return -EINVAL;
} else { } else {
if (var->xoffset + info->var.xres > info->var.xres_virtual || if (var->xoffset + dsp->var.xres > dsp->var.xres_virtual ||
var->yoffset + info->var.yres > info->var.yres_virtual) var->yoffset + dsp->var.yres > dsp->var.yres_virtual)
return -EINVAL; return -EINVAL;
} }
base = var->yoffset * dsp->line_length + var->xoffset; base = var->yoffset * dsp->line_length + var->xoffset;
if (con == info->currcon) if (con == info->currcon) {
par->riva.SetStartAddress(&par->riva, base); rivainfo->riva.SetStartAddress(&rivainfo->riva, base);
}
info->var.xoffset = var->xoffset; dsp->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset; dsp->var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP) if (var->vmode & FB_VMODE_YWRAP)
info->var.vmode |= FB_VMODE_YWRAP; dsp->var.vmode |= FB_VMODE_YWRAP;
else else
info->var.vmode &= ~FB_VMODE_YWRAP; dsp->var.vmode &= ~FB_VMODE_YWRAP;
DPRINTK("EXIT, returning 0\n");
return 0; return 0;
} }
static int rivafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
/* no rivafb-specific ioctls */
DPRINTK("EXIT, returning -EINVAL\n");
return -EINVAL;
}
static int rivafb_rasterimg(struct fb_info *info, int start) static int rivafb_rasterimg(struct fb_info *info, int start)
{ {
struct riva_par *par = (struct riva_par *) info->par; struct rivafb_info *rinfo = (struct rivafb_info *)info;
wait_for_idle(par); wait_for_idle(rinfo);
return 0; return 0;
} }
static int rivafb_switch(int con, struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
struct fb_cmap *cmap;
struct display *dsp;
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
if (info->currcon >= 0) {
/* Do we have to save the colormap? */
cmap = &(rivainfo->currcon_display->cmap);
DPRINTK("switch1: con = %d, cmap.len = %d\n",
info->currcon, cmap->len);
if (cmap->len) {
DPRINTK("switch1a: %p %p %p %p\n", cmap->red,
cmap->green, cmap->blue, cmap->transp);
fb_get_cmap(cmap, 1, riva_getcolreg, info);
}
}
info->currcon = con;
rivainfo->currcon_display = dsp;
rivafb_set_var(&dsp->var, con, info);
riva_set_dispsw(rivainfo, dsp);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int rivafb_updatevar(int con, struct fb_info *info)
{
int rc;
DPRINTK("ENTER\n");
rc = (con < 0) ? -EINVAL : rivafb_pan_display(&fb_display[con].var,
con, info);
DPRINTK("EXIT, returning %d\n", rc);
return rc;
}
static int rivafb_blank(int blank, struct fb_info *info) static int rivafb_blank(int blank, struct fb_info *info)
{ {
struct riva_par *par = (struct riva_par *)info->par;
unsigned char tmp, vesa; unsigned char tmp, vesa;
struct rivafb_info *rinfo = (struct rivafb_info *)info;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
tmp = SEQin(par, 0x01) & ~0x20; /* screen on/off */ tmp = SEQin(rinfo, 0x01) & ~0x20; /* screen on/off */
vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */ vesa = CRTCin(rinfo, 0x1a) & ~0xc0; /* sync on/off */
if (blank) { if (blank) {
tmp |= 0x20; tmp |= 0x20;
...@@ -1370,11 +1727,15 @@ static int rivafb_blank(int blank, struct fb_info *info) ...@@ -1370,11 +1727,15 @@ static int rivafb_blank(int blank, struct fb_info *info)
} }
} }
SEQout(par, 0x01, tmp); SEQout(rinfo, 0x01, tmp);
CRTCout(par, 0x1a, vesa); CRTCout(rinfo, 0x1a, vesa);
DPRINTK("EXIT\n");
return 0; return 0;
} }
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
* initialization helper functions * initialization helper functions
...@@ -1384,29 +1745,78 @@ static int rivafb_blank(int blank, struct fb_info *info) ...@@ -1384,29 +1745,78 @@ static int rivafb_blank(int blank, struct fb_info *info)
/* kernel interface */ /* kernel interface */
static struct fb_ops riva_fb_ops = { static struct fb_ops riva_fb_ops = {
owner: THIS_MODULE, owner: THIS_MODULE,
fb_get_fix: gen_get_fix, fb_get_fix: rivafb_get_fix,
fb_get_var: gen_get_var, fb_get_var: rivafb_get_var,
fb_set_var: gen_set_var, fb_set_var: rivafb_set_var,
fb_get_cmap: gen_get_cmap, fb_get_cmap: rivafb_get_cmap,
fb_set_cmap: gen_set_cmap, fb_set_cmap: rivafb_set_cmap,
fb_check_var: rivafb_check_var,
fb_set_par: rivafb_set_par,
fb_setcolreg: rivafb_setcolreg, fb_setcolreg: rivafb_setcolreg,
fb_pan_display: rivafb_pan_display, fb_pan_display: rivafb_pan_display,
fb_blank: rivafb_blank, fb_blank: rivafb_blank,
fb_fillrect: rivafb_fillrect, fb_ioctl: rivafb_ioctl,
fb_copyarea: rivafb_copyarea,
fb_imageblit: rivafb_imageblit,
fb_rasterimg: rivafb_rasterimg, fb_rasterimg: rivafb_rasterimg,
}; };
static int __devinit riva_set_fbinfo(struct fb_info *info) static int __devinit riva_init_disp_var(struct rivafb_info *rinfo)
{
#ifndef MODULE
if (mode_option)
fb_find_mode(&rinfo->disp.var, &rinfo->info, mode_option,
NULL, 0, NULL, 8);
#endif
return 0;
}
static int __devinit riva_init_disp(struct rivafb_info *rinfo)
{
struct fb_info *info;
struct display *disp;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
info = &rinfo->info;
disp = &rinfo->disp;
disp->var = rivafb_default_var;
if (noaccel)
disp->var.accel_flags &= ~FB_ACCELF_TEXT;
else
disp->var.accel_flags |= FB_ACCELF_TEXT;
info->disp = disp;
/* FIXME: assure that disp->cmap is completely filled out */
rinfo->currcon_display = disp;
if ((riva_init_disp_var(rinfo)) < 0) {
DPRINTK("EXIT, returning -1\n");
return -1;
}
riva_set_dispsw(rinfo, disp);
DPRINTK("EXIT, returning 0\n");
return 0;
}
static int __devinit riva_set_fbinfo(struct rivafb_info *rinfo)
{ {
strcpy(info->modename, rivafb_fix.id); struct fb_info *info;
assert(rinfo != NULL);
info = &rinfo->info;
strcpy(info->modename, rinfo->drvr_name);
info->node = NODEV; info->node = NODEV;
info->flags = FBINFO_FLAG_DEFAULT; info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &riva_fb_ops; info->fbops = &riva_fb_ops;
info->fix = rivafb_fix; info->screen_base = rinfo->fb_base;
/* FIXME: set monspecs to what??? */ /* FIXME: set monspecs to what??? */
info->display_fg = NULL; info->display_fg = NULL;
...@@ -1415,21 +1825,12 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) ...@@ -1415,21 +1825,12 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
info->fontname[sizeof(info->fontname) - 1] = 0; info->fontname[sizeof(info->fontname) - 1] = 0;
info->changevar = NULL; info->changevar = NULL;
info->switch_con = gen_switch; info->switch_con = rivafb_switch;
info->updatevar = gen_update_var; info->updatevar = rivafb_updatevar;
#ifndef MODULE if (riva_init_disp(rinfo) < 0) /* must be done last */
if (mode_option) { return -1;
int err = fb_find_mode(&info->var, info, mode_option,
NULL, 0, NULL, 8);
if (!err || err == 4)
info->var = rivafb_default_var;
} else
#endif
info->var = rivafb_default_var;
fb_alloc_cmap(&info->cmap, riva_get_cmap_len(&info->var), 0);
gen_set_var(&info->var, -1, info);
return 0; return 0;
} }
...@@ -1444,230 +1845,194 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) ...@@ -1444,230 +1845,194 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
static int __devinit rivafb_init_one(struct pci_dev *pd, static int __devinit rivafb_init_one(struct pci_dev *pd,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
struct rivafb_info *rinfo;
struct riva_chip_info *rci = &riva_chip_info[ent->driver_data]; struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
struct riva_par *default_par;
struct fb_info *info;
int size;
assert(pd != NULL); assert(pd != NULL);
assert(rci != NULL); assert(rci != NULL);
size = sizeof(struct fb_info) + sizeof(struct display) + sizeof(u32) * 16; rinfo = kmalloc(sizeof(struct rivafb_info), GFP_KERNEL);
if (!rinfo)
info = kmalloc(size, GFP_KERNEL);
if (!info)
goto err_out; goto err_out;
memset(info, 0, size); memset(rinfo, 0, sizeof(struct rivafb_info));
default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL); rinfo->drvr_name = rci->name;
if (!default_par) rinfo->riva.Architecture = rci->arch_rev;
goto err_out;
memset(default_par, 0, sizeof(struct riva_par));
info->disp = (struct display *)(info + 1);
info->pseudo_palette = (void *)(info->disp + 1);
strcat(rivafb_fix.id, rci->name); rinfo->pd = pd;
default_par->riva.Architecture = rci->arch_rev; rinfo->base0_region_size = pci_resource_len(pd, 0);
rinfo->base1_region_size = pci_resource_len(pd, 1);
rivafb_fix.mmio_len = pci_resource_len(pd, 0); assert(rinfo->base0_region_size >= 0x00800000); /* from GGI */
rivafb_fix.smem_len = pci_resource_len(pd, 1); assert(rinfo->base1_region_size >= 0x01000000); /* from GGI */
assert(rivafb_fix.mmio_len >= 0x00800000); /* from GGI */ rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0);
assert(rivafb_fix.smem_len >= 0x01000000); /* from GGI */ rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1);
rivafb_fix.mmio_start = pci_resource_start(pd, 0); if (!request_mem_region(rinfo->ctrl_base_phys,
rivafb_fix.smem_start = pci_resource_start(pd, 1); rinfo->base0_region_size, "rivafb")) {
if (!request_mem_region(rivafb_fix.mmio_start,
rivafb_fix.mmio_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve MMIO region\n"); printk(KERN_ERR PFX "cannot reserve MMIO region\n");
goto err_out_kfree; goto err_out_kfree;
} }
default_par->ctrl_base = ioremap(rivafb_fix.mmio_start, if (!request_mem_region(rinfo->fb_base_phys,
rivafb_fix.mmio_len); rinfo->base1_region_size, "rivafb")) {
if (!default_par->ctrl_base) {
printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
goto err_out_free_base1;
}
default_par->riva.EnableIRQ = 0;
default_par->riva.PRAMDAC = (unsigned *)(default_par->ctrl_base + 0x00680000);
default_par->riva.PFB = (unsigned *)(default_par->ctrl_base + 0x00100000);
default_par->riva.PFIFO = (unsigned *)(default_par->ctrl_base + 0x00002000);
default_par->riva.PGRAPH = (unsigned *)(default_par->ctrl_base + 0x00400000);
default_par->riva.PEXTDEV = (unsigned *)(default_par->ctrl_base + 0x00101000);
default_par->riva.PTIMER = (unsigned *)(default_par->ctrl_base + 0x00009000);
default_par->riva.PMC = (unsigned *)(default_par->ctrl_base + 0x00000000);
default_par->riva.FIFO = (unsigned *)(default_par->ctrl_base + 0x00800000);
default_par->riva.PCIO = (U008 *)(default_par->ctrl_base + 0x00601000);
default_par->riva.PDIO = (U008 *)(default_par->ctrl_base + 0x00681000);
default_par->riva.PVIO = (U008 *)(default_par->ctrl_base + 0x000C0000);
default_par->riva.IO = (MISCin(default_par) & 0x01) ? 0x3D0 : 0x3B0;
switch (default_par->riva.Architecture) {
case NV_ARCH_03:
/*
* We have to map the full BASE_1 aperture for Riva128's
* because they use the PRAMIN set in "framebuffer" space
*/
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n"); printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0; goto err_out_free_base0;
} }
info->screen_base = ioremap(rivafb_fix.smem_start, rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys,
rivafb_fix.smem_len); rinfo->base0_region_size);
if (!info->screen_base) { if (!rinfo->ctrl_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n"); printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
goto err_out_iounmap_ctrl; goto err_out_free_base1;
}
default_par->riva.PRAMIN = (unsigned *)(info->screen_base + 0x00C00000);
rivafb_fix.accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
/* riva_hw.c now doesn't distinguish between TNT & TNT2 */
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base + 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000);
rivafb_fix.accel = FB_ACCEL_NV4;
break;
}
RivaGetConfig(&default_par->riva);
/* unlock io */
CRTCout(default_par, 0x11, 0xFF);/* vgaHWunlock()+riva unlock (0x7F) */
default_par->riva.LockUnlock(&default_par->riva, 0);
riva_save_state(default_par, &default_par->initial_state);
default_par->ram_amount = default_par->riva.RamAmountKBytes * 1024;
default_par->dclk_max = default_par->riva.MaxVClockFreqKHz * 1000;
if (default_par->riva.Architecture != NV_ARCH_03) {
/*
* Now the _normal_ chipsets can just map the amount of real
* physical ram instead of the whole aperture
*/
rivafb_fix.smem_len = default_par->ram_amount;
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
} }
info->screen_base = ioremap(rivafb_fix.smem_start, rinfo->fb_base = ioremap(rinfo->fb_base_phys,
rivafb_fix.smem_len); rinfo->base1_region_size);
if (!info->screen_base) { if (!rinfo->fb_base) {
printk(KERN_ERR PFX "cannot ioremap FB base\n"); printk(KERN_ERR PFX "cannot ioremap FB base\n");
goto err_out_iounmap_ctrl; goto err_out_iounmap_ctrl;
} }
}
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
if (!nomtrr) { if (!nomtrr) {
default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start, rinfo->mtrr.vram = mtrr_add(rinfo->fb_base_phys,
rivafb_fix.smem_len, MTRR_TYPE_WRCOMB, 1); rinfo->base1_region_size, MTRR_TYPE_WRCOMB, 1);
if (default_par->mtrr.vram < 0) { if (rinfo->mtrr.vram < 0) {
printk(KERN_ERR PFX "unable to setup MTRR\n"); printk(KERN_ERR PFX "unable to setup MTRR\n");
} else { } else {
default_par->mtrr.vram_valid = 1; rinfo->mtrr.vram_valid = 1;
/* let there be speed */ /* let there be speed */
printk(KERN_INFO PFX "RIVA MTRR set to ON\n"); printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
} }
} }
#endif /* CONFIG_MTRR */ #endif /* CONFIG_MTRR */
if (!nohwcursor) default_par->cursor = rivafb_init_cursor(info); rinfo->riva.EnableIRQ = 0;
rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000);
rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000);
rinfo->riva.PFIFO = (unsigned *)(rinfo->ctrl_base + 0x00002000);
rinfo->riva.PGRAPH = (unsigned *)(rinfo->ctrl_base + 0x00400000);
rinfo->riva.PEXTDEV = (unsigned *)(rinfo->ctrl_base + 0x00101000);
rinfo->riva.PTIMER = (unsigned *)(rinfo->ctrl_base + 0x00009000);
rinfo->riva.PMC = (unsigned *)(rinfo->ctrl_base + 0x00000000);
rinfo->riva.FIFO = (unsigned *)(rinfo->ctrl_base + 0x00800000);
rinfo->riva.PCIO = (U008 *)(rinfo->ctrl_base + 0x00601000);
rinfo->riva.PDIO = (U008 *)(rinfo->ctrl_base + 0x00681000);
rinfo->riva.PVIO = (U008 *)(rinfo->ctrl_base + 0x000C0000);
rinfo->riva.IO = (MISCin(rinfo) & 0x01) ? 0x3D0 : 0x3B0;
switch (rinfo->riva.Architecture) {
case NV_ARCH_03:
rinfo->riva.PRAMIN = (unsigned *)(rinfo->fb_base + 0x00C00000);
break;
case NV_ARCH_04:
case NV_ARCH_10:
rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000);
rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000);
break;
}
info->par = default_par; RivaGetConfig(&rinfo->riva);
if (riva_set_fbinfo(info) < 0) { /* back to normal */
assert(rinfo->pd != NULL);
/* unlock io */
CRTCout(rinfo, 0x11, 0xFF); /* vgaHWunlock() + riva unlock (0x7F) */
rinfo->riva.LockUnlock(&rinfo->riva, 0);
riva_save_state(rinfo, &rinfo->initial_state);
rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;
rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000;
if (!nohwcursor) rinfo->cursor = rivafb_init_cursor(rinfo);
if (riva_set_fbinfo(rinfo) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n"); printk(KERN_ERR PFX "error setting initial video mode\n");
goto err_out_cursor; goto err_out_cursor;
} }
if (register_framebuffer(info) < 0) { if (register_framebuffer((struct fb_info *)rinfo) < 0) {
printk(KERN_ERR PFX printk(KERN_ERR PFX
"error registering riva framebuffer\n"); "error registering riva framebuffer\n");
goto err_out_load_state; goto err_out_load_state;
} }
pci_set_drvdata(pd, info); riva_boards = riva_board_list_add(riva_boards, rinfo);
pci_set_drvdata(pd, rinfo);
printk(KERN_INFO PFX printk(KERN_INFO PFX
"PCI nVidia NV%x framebuffer ver %s (%s, %dMB @ 0x%lX)\n", "PCI nVidia NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
default_par->riva.Architecture, rinfo->riva.Architecture,
RIVAFB_VERSION, RIVAFB_VERSION,
info->fix.id, rinfo->drvr_name,
default_par->ram_amount / (1024 * 1024), rinfo->ram_amount / (1024 * 1024),
info->fix.smem_start); rinfo->fb_base_phys);
return 0; return 0;
err_out_load_state: err_out_load_state:
riva_load_state(default_par, &default_par->initial_state); riva_load_state(rinfo, &rinfo->initial_state);
err_out_cursor: err_out_cursor:
rivafb_exit_cursor(default_par); rivafb_exit_cursor(rinfo);
/* err_out_iounmap_fb: */ /* err_out_iounmap_fb: */
iounmap(info->screen_base); iounmap(rinfo->fb_base);
err_out_iounmap_ctrl: err_out_iounmap_ctrl:
iounmap(default_par->ctrl_base); iounmap(rinfo->ctrl_base);
err_out_free_base1: err_out_free_base1:
release_mem_region(info->fix.smem_start, info->fix.smem_len); release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size);
err_out_free_base0: err_out_free_base0:
release_mem_region(info->fix.mmio_start, info->fix.mmio_len); release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size);
err_out_kfree: err_out_kfree:
kfree(default_par); kfree(rinfo);
kfree(info);
err_out: err_out:
return -ENODEV; return -ENODEV;
} }
static void __devexit rivafb_remove_one(struct pci_dev *pd) static void __devexit rivafb_remove_one(struct pci_dev *pd)
{ {
struct fb_info *board = pci_get_drvdata(pd); struct rivafb_info *board = pci_get_drvdata(pd);
struct riva_par *par = (struct riva_par *) board->par;
if (!board) if (!board)
return; return;
riva_load_state(par, &par->initial_state); riva_boards = riva_board_list_del(riva_boards, board);
riva_load_state(board, &board->initial_state);
unregister_framebuffer(board); unregister_framebuffer((struct fb_info *)board);
rivafb_exit_cursor(par); rivafb_exit_cursor(board);
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
if (par->mtrr.vram_valid) if (board->mtrr.vram_valid)
mtrr_del(par->mtrr.vram, board->fix.smem_start, mtrr_del(board->mtrr.vram, board->fb_base_phys,
board->fix.smem_len); board->base1_region_size);
#endif /* CONFIG_MTRR */ #endif /* CONFIG_MTRR */
iounmap(par->ctrl_base); iounmap(board->ctrl_base);
iounmap(board->screen_base); iounmap(board->fb_base);
release_mem_region(board->fix.mmio_start, release_mem_region(board->ctrl_base_phys,
board->fix.mmio_len); board->base0_region_size);
release_mem_region(board->fix.smem_start, release_mem_region(board->fb_base_phys,
board->fix.smem_len); board->base1_region_size);
kfree(par);
kfree(board); kfree(board);
pci_set_drvdata(pd, NULL); pci_set_drvdata(pd, NULL);
} }
/* ------------------------------------------------------------------------- * /* ------------------------------------------------------------------------- *
* *
* initialization * initialization
...@@ -1698,6 +2063,10 @@ int __init rivafb_setup(char *options) ...@@ -1698,6 +2063,10 @@ int __init rivafb_setup(char *options)
} else if (!strncmp(this_opt, "noblink", 7)) { } else if (!strncmp(this_opt, "noblink", 7)) {
noblink = 1; noblink = 1;
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
} else if (!strncmp(this_opt, "nomove", 6)) {
nomove = 1;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
} else if (!strncmp(this_opt, "nomtrr", 6)) { } else if (!strncmp(this_opt, "nomtrr", 6)) {
nomtrr = 1; nomtrr = 1;
...@@ -1750,6 +2119,10 @@ module_exit(rivafb_exit); ...@@ -1750,6 +2119,10 @@ module_exit(rivafb_exit);
MODULE_PARM(font, "s"); MODULE_PARM(font, "s");
MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)"); MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
MODULE_PARM(nomove, "i");
MODULE_PARM_DESC(nomove, "Enables YSCROLL_NOMOVE (0 or 1=enabled) (default=0)");
MODULE_PARM(nohwcursor, "i"); MODULE_PARM(nohwcursor, "i");
MODULE_PARM_DESC(nohwcursor, "Disables hardware cursor (0 or 1=disabled) (default=0)"); MODULE_PARM_DESC(nohwcursor, "Disables hardware cursor (0 or 1=disabled) (default=0)");
MODULE_PARM(noblink, "i"); MODULE_PARM(noblink, "i");
......
...@@ -1220,7 +1220,6 @@ static void CalcStateExt ...@@ -1220,7 +1220,6 @@ static void CalcStateExt
state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
break; break;
case NV_ARCH_10: case NV_ARCH_10:
case NV_ARCH_20:
nv10UpdateArbitrationSettings(VClk, nv10UpdateArbitrationSettings(VClk,
pixelDepth * 8, pixelDepth * 8,
&(state->arbitration0), &(state->arbitration0),
...@@ -1286,7 +1285,6 @@ static void UpdateFifoState ...@@ -1286,7 +1285,6 @@ static void UpdateFifoState
chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]);
break; break;
case NV_ARCH_10: case NV_ARCH_10:
case NV_ARCH_20:
/* /*
* Initialize state for the RivaTriangle3D05 routines. * Initialize state for the RivaTriangle3D05 routines.
*/ */
...@@ -1395,7 +1393,6 @@ static void LoadStateExt ...@@ -1395,7 +1393,6 @@ static void LoadStateExt
chip->PGRAPH[0x0000067C/4] = state->pitch3; chip->PGRAPH[0x0000067C/4] = state->pitch3;
break; break;
case NV_ARCH_10: case NV_ARCH_10:
case NV_ARCH_20:
LOAD_FIXED_STATE(nv10,PFIFO); LOAD_FIXED_STATE(nv10,PFIFO);
LOAD_FIXED_STATE(nv10,PRAMIN); LOAD_FIXED_STATE(nv10,PRAMIN);
LOAD_FIXED_STATE(nv10,PGRAPH); LOAD_FIXED_STATE(nv10,PGRAPH);
...@@ -1424,8 +1421,6 @@ static void LoadStateExt ...@@ -1424,8 +1421,6 @@ static void LoadStateExt
chip->Tri03 = 0L; chip->Tri03 = 0L;
break; break;
} }
if (chip->Architecture == NV_ARCH_10) {
chip->PGRAPH[0x00000640/4] = state->offset0; chip->PGRAPH[0x00000640/4] = state->offset0;
chip->PGRAPH[0x00000644/4] = state->offset1; chip->PGRAPH[0x00000644/4] = state->offset1;
chip->PGRAPH[0x00000648/4] = state->offset2; chip->PGRAPH[0x00000648/4] = state->offset2;
...@@ -1435,20 +1430,6 @@ static void LoadStateExt ...@@ -1435,20 +1430,6 @@ static void LoadStateExt
chip->PGRAPH[0x00000678/4] = state->pitch2; chip->PGRAPH[0x00000678/4] = state->pitch2;
chip->PGRAPH[0x0000067C/4] = state->pitch3; chip->PGRAPH[0x0000067C/4] = state->pitch3;
chip->PGRAPH[0x00000680/4] = state->pitch3; chip->PGRAPH[0x00000680/4] = state->pitch3;
} else {
chip->PGRAPH[0x00000820/4] = state->offset0;
chip->PGRAPH[0x00000824/4] = state->offset1;
chip->PGRAPH[0x00000828/4] = state->offset2;
chip->PGRAPH[0x0000082C/4] = state->offset3;
chip->PGRAPH[0x00000850/4] = state->pitch0;
chip->PGRAPH[0x00000854/4] = state->pitch1;
chip->PGRAPH[0x00000858/4] = state->pitch2;
chip->PGRAPH[0x0000085C/4] = state->pitch3;
chip->PGRAPH[0x00000860/4] = state->pitch3;
chip->PGRAPH[0x00000864/4] = state->pitch3;
chip->PGRAPH[0x000009A4/4] = chip->PFB[0x00000200/4];
chip->PGRAPH[0x000009A8/4] = chip->PFB[0x00000204/4];
}
chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4]; chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4];
chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4]; chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4];
chip->PGRAPH[0x00000B08/4] = chip->PFB[0x00000248/4]; chip->PGRAPH[0x00000B08/4] = chip->PFB[0x00000248/4];
...@@ -1626,7 +1607,6 @@ static void UnloadStateExt ...@@ -1626,7 +1607,6 @@ static void UnloadStateExt
state->pitch3 = chip->PGRAPH[0x0000067C/4]; state->pitch3 = chip->PGRAPH[0x0000067C/4];
break; break;
case NV_ARCH_10: case NV_ARCH_10:
case NV_ARCH_20:
state->offset0 = chip->PGRAPH[0x00000640/4]; state->offset0 = chip->PGRAPH[0x00000640/4];
state->offset1 = chip->PGRAPH[0x00000644/4]; state->offset1 = chip->PGRAPH[0x00000644/4];
state->offset2 = chip->PGRAPH[0x00000648/4]; state->offset2 = chip->PGRAPH[0x00000648/4];
......
...@@ -74,8 +74,6 @@ typedef unsigned int U032; ...@@ -74,8 +74,6 @@ typedef unsigned int U032;
#define NV_ARCH_03 0x03 #define NV_ARCH_03 0x03
#define NV_ARCH_04 0x04 #define NV_ARCH_04 0x04
#define NV_ARCH_10 0x10 #define NV_ARCH_10 0x10
#define NV_ARCH_20 0x20
/***************************************************************************\ /***************************************************************************\
* * * *
* FIFO registers. * * FIFO registers. *
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/fb.h> #include <linux/fb.h>
#include <linux/timer.h>
#include <video/fbcon.h> #include <video/fbcon.h>
#include <video/fbcon-cfb4.h> #include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h> #include <video/fbcon-cfb8.h>
...@@ -28,33 +27,56 @@ struct riva_regs { ...@@ -28,33 +27,56 @@ struct riva_regs {
RIVA_HW_STATE ext; RIVA_HW_STATE ext;
}; };
#define MAX_CURS 32 typedef struct {
unsigned char red, green, blue, transp;
struct riva_cursor { } riva_cfb8_cmap_t;
int enable;
int on; struct rivafb_info;
int vbl_cnt; struct rivafb_info {
int last_slice_moves, prev_slice_moves; struct fb_info info; /* kernel framebuffer info */
int blink_rate;
struct {
u16 x, y;
} pos, size;
unsigned short image[MAX_CURS*MAX_CURS];
struct timer_list *timer;
};
/* describes the state of a Riva board */
struct riva_par {
RIVA_HW_INST riva; /* interface to riva_hw.c */ RIVA_HW_INST riva; /* interface to riva_hw.c */
const char *drvr_name; /* Riva hardware board type */
unsigned long ctrl_base_phys; /* physical control register base addr */
unsigned long fb_base_phys; /* physical framebuffer base addr */
caddr_t ctrl_base; /* virtual control register base addr */
caddr_t fb_base; /* virtual framebuffer base addr */
unsigned ram_amount; /* amount of RAM on card, in bytes */ unsigned ram_amount; /* amount of RAM on card, in bytes */
unsigned dclk_max; /* max DCLK */ unsigned dclk_max; /* max DCLK */
struct riva_regs initial_state; /* initial startup video mode */ struct riva_regs initial_state; /* initial startup video mode */
struct riva_regs current_state; struct riva_regs current_state;
struct display disp;
int currcon;
struct display *currcon_display;
struct rivafb_info *next;
struct pci_dev *pd; /* pointer to board's pci info */
unsigned base0_region_size; /* size of control register region */
unsigned base1_region_size; /* size of framebuffer region */
struct riva_cursor *cursor; struct riva_cursor *cursor;
caddr_t ctrl_base; /* Virtual control register base addr */
struct display_switch dispsw;
riva_cfb8_cmap_t palette[256]; /* VGA DAC palette cache */
#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
union {
#ifdef FBCON_HAS_CFB16
u_int16_t cfb16[16];
#endif
#ifdef FBCON_HAS_CFB32
u_int32_t cfb32[16];
#endif
} con_cmap;
#endif /* FBCON_HAS_CFB16 | FBCON_HAS_CFB32 */
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr; struct { int vram; int vram_valid; } mtrr;
#endif #endif
......
...@@ -661,7 +661,7 @@ static struct sa1100fb_mach_info xp860_info __initdata = { ...@@ -661,7 +661,7 @@ static struct sa1100fb_mach_info xp860_info __initdata = {
static struct sa1100fb_mach_info * __init static struct sa1100fb_mach_info * __init
sa1100fb_get_machine_info(struct sa1100_par *par) sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
{ {
struct sa1100fb_mach_info *inf = NULL; struct sa1100fb_mach_info *inf = NULL;
...@@ -683,7 +683,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par) ...@@ -683,7 +683,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
#ifdef CONFIG_SA1100_H3XXX #ifdef CONFIG_SA1100_H3XXX
if (machine_is_h3600()) { if (machine_is_h3600()) {
inf = &h3600_info; inf = &h3600_info;
par->rgb[RGB_16] = &h3600_rgb_16; fbi->rgb[RGB_16] = &h3600_rgb_16;
} }
if (machine_is_h3100()) { if (machine_is_h3100()) {
inf = &h3100_info; inf = &h3100_info;
...@@ -705,7 +705,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par) ...@@ -705,7 +705,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
#ifdef CONFIG_SA1100_FREEBIRD #ifdef CONFIG_SA1100_FREEBIRD
if (machine_is_freebird()) { if (machine_is_freebird()) {
inf = &freebird_info; inf = &freebird_info;
par->rgb[RGB_16] = &freebird_rgb16; fbi->rgb[RGB_16] = &freebird_rgb16;
} }
#endif #endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT #ifdef CONFIG_SA1100_GRAPHICSCLIENT
...@@ -758,10 +758,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par) ...@@ -758,10 +758,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
if (machine_is_stork()) { if (machine_is_stork()) {
#if STORK_TFT #if STORK_TFT
inf = &stork_tft_info; inf = &stork_tft_info;
par->rgb[RGB_16] = &stork_tft_rgb_16; fbi->rgb[RGB_16] = &stork_tft_rgb_16;
#else #else
inf = &stork_dstn_info; inf = &stork_dstn_info;
par->rgb[RGB_16] = &stork_dstn_rgb_16; fbi->rgb[RGB_16] = &stork_dstn_rgb_16;
#endif #endif
} }
#endif #endif
...@@ -773,10 +773,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par) ...@@ -773,10 +773,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par)
return inf; return inf;
} }
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *); static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
static void set_ctrlr_state(struct sa1100_par *par, u_int state); static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
static inline void sa1100fb_schedule_task(struct sa1100_par *par, u_int state) static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state)
{ {
unsigned long flags; unsigned long flags;
...@@ -789,18 +789,43 @@ static inline void sa1100fb_schedule_task(struct sa1100_par *par, u_int state) ...@@ -789,18 +789,43 @@ static inline void sa1100fb_schedule_task(struct sa1100_par *par, u_int state)
* 2. When we are blanking, but immediately unblank before we have * 2. When we are blanking, but immediately unblank before we have
* blanked. We do the "REENABLE" thing here as well, just to be sure. * blanked. We do the "REENABLE" thing here as well, just to be sure.
*/ */
if (par->task_state == C_ENABLE && state == C_REENABLE) if (fbi->task_state == C_ENABLE && state == C_REENABLE)
state = (u_int) -1; state = (u_int) -1;
if (par->task_state == C_DISABLE && state == C_ENABLE) if (fbi->task_state == C_DISABLE && state == C_ENABLE)
state = C_REENABLE; state = C_REENABLE;
if (state != (u_int)-1) { if (state != (u_int)-1) {
par->task_state = state; fbi->task_state = state;
schedule_task(&par->task); schedule_task(&fbi->task);
} }
local_irq_restore(flags); local_irq_restore(flags);
} }
/*
* Get the VAR structure pointer for the specified console
*/
static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
{
return (con == info->currcon || con == -1) ? &info->var : &fb_display[con].var;
}
/*
* Get the DISPLAY structure pointer for the specified console
*/
static inline struct display *get_con_display(struct fb_info *info, int con)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
return (con < 0) ? fbi->fb.disp : &fb_display[con];
}
/*
* Get the CMAP pointer for the specified console
*/
static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
{
return (con == info->currcon || con == -1) ? &info->cmap : &fb_display[con].cmap;
}
static inline u_int static inline u_int
chan_to_field(u_int chan, struct fb_bitfield *bf) chan_to_field(u_int chan, struct fb_bitfield *bf)
{ {
...@@ -813,13 +838,19 @@ chan_to_field(u_int chan, struct fb_bitfield *bf) ...@@ -813,13 +838,19 @@ chan_to_field(u_int chan, struct fb_bitfield *bf)
* Convert bits-per-pixel to a hardware palette PBS value. * Convert bits-per-pixel to a hardware palette PBS value.
*/ */
static inline u_int static inline u_int
palette_pbs(int bpp) palette_pbs(struct fb_var_screeninfo *var)
{ {
int ret = 0; int ret = 0;
switch (bpp) { switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4: ret = 0 << 12; break; case 4: ret = 0 << 12; break;
#endif
#ifdef FBCON_HAS_CFB8
case 8: ret = 1 << 12; break; case 8: ret = 1 << 12; break;
#endif
#ifdef FBCON_HAS_CFB16
case 16: ret = 2 << 12; break; case 16: ret = 2 << 12; break;
#endif
} }
return ret; return ret;
} }
...@@ -828,18 +859,18 @@ static int ...@@ -828,18 +859,18 @@ static int
sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info) u_int trans, struct fb_info *info)
{ {
struct sa1100_par *par = (struct sa1100_par *) info->par; struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
u_int val, ret = 1; u_int val, ret = 1;
if (regno < par->palette_size) { if (regno < fbi->palette_size) {
val = ((red >> 4) & 0xf00); val = ((red >> 4) & 0xf00);
val |= ((green >> 8) & 0x0f0); val |= ((green >> 8) & 0x0f0);
val |= ((blue >> 12) & 0x00f); val |= ((blue >> 12) & 0x00f);
if (regno == 0) if (regno == 0)
val |= palette_pbs(info->var.bits_per_pixel); val |= palette_pbs(&fbi->fb.var);
par->palette_cpu[regno] = val; fbi->palette_cpu[regno] = val;
ret = 0; ret = 0;
} }
return ret; return ret;
...@@ -849,6 +880,8 @@ static int ...@@ -849,6 +880,8 @@ static int
sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info) u_int trans, struct fb_info *info)
{ {
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp = get_con_display(info, info->currcon);
u_int val; u_int val;
int ret = 1; int ret = 1;
...@@ -857,34 +890,33 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -857,34 +890,33 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* rather than the register number. The register number * rather than the register number. The register number
* is what you poke into the framebuffer to produce the * is what you poke into the framebuffer to produce the
* colour you requested. * colour you requested.
* */
if (inverse) { if (disp->inverse) {
red = 0xffff - red; red = 0xffff - red;
green = 0xffff - green; green = 0xffff - green;
blue = 0xffff - blue; blue = 0xffff - blue;
} }
*/
/* /*
* If greyscale is true, then we convert the RGB value * If greyscale is true, then we convert the RGB value
* to greyscale no mater what visual we are using. * to greyscale no mater what visual we are using.
*/ */
if (info->var.grayscale) if (fbi->fb.var.grayscale)
red = green = blue = (19595 * red + 38470 * green + red = green = blue = (19595 * red + 38470 * green +
7471 * blue) >> 16; 7471 * blue) >> 16;
switch (info->fix.visual) { switch (fbi->fb.disp->visual) {
case FB_VISUAL_TRUECOLOR: case FB_VISUAL_TRUECOLOR:
/* /*
* 12 or 16-bit True Colour. We encode the RGB value * 12 or 16-bit True Colour. We encode the RGB value
* according to the RGB bitfield information. * according to the RGB bitfield information.
*/ */
if (regno < 16) { if (regno < 16) {
u16 *pal = info->pseudo_palette; u16 *pal = fbi->fb.pseudo_palette;
val = chan_to_field(red, &info->var.red); val = chan_to_field(red, &fbi->fb.var.red);
val |= chan_to_field(green, &info->var.green); val |= chan_to_field(green, &fbi->fb.var.green);
val |= chan_to_field(blue, &info->var.blue); val |= chan_to_field(blue, &fbi->fb.var.blue);
pal[regno] = val; pal[regno] = val;
ret = 0; ret = 0;
...@@ -931,20 +963,19 @@ sa1100fb_display_dma_period(struct fb_var_screeninfo *var) ...@@ -931,20 +963,19 @@ sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
* bitfields, horizontal timing, vertical timing. * bitfields, horizontal timing, vertical timing.
*/ */
static int static int
sa1100fb_check_var(struct fb_var_screeninfo *var, sa1100fb_validate_var(struct fb_var_screeninfo *var,
struct fb_info *info) struct sa1100fb_info *fbi)
{ {
struct sa1100_par *par = (struct sa1100_par *) info->par; int ret = -EINVAL;
int rgbidx = RGB_16, ret = -EINVAL;
if (var->xres < MIN_XRES) if (var->xres < MIN_XRES)
var->xres = MIN_XRES; var->xres = MIN_XRES;
if (var->yres < MIN_YRES) if (var->yres < MIN_YRES)
var->yres = MIN_YRES; var->yres = MIN_YRES;
if (var->xres > par->max_xres) if (var->xres > fbi->max_xres)
var->xres = par->max_xres; var->xres = fbi->max_xres;
if (var->yres > par->max_yres) if (var->yres > fbi->max_yres)
var->yres = par->max_yres; var->yres = fbi->max_yres;
var->xres_virtual = var->xres_virtual =
var->xres_virtual < var->xres ? var->xres : var->xres_virtual; var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
var->yres_virtual = var->yres_virtual =
...@@ -952,22 +983,23 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, ...@@ -952,22 +983,23 @@ sa1100fb_check_var(struct fb_var_screeninfo *var,
DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
switch (var->bits_per_pixel) { switch (var->bits_per_pixel) {
case 4: rgbidx = RGB_8; ret = 0; break; #ifdef FBCON_HAS_CFB4
case 8: rgbidx = RGB_8; ret = 0; break; case 4: ret = 0; break;
case 16: rgbidx = RGB_16; ret = 0; break; #endif
#ifdef FBCON_HAS_CFB8
case 8: ret = 0; break;
#endif
#ifdef FBCON_HAS_CFB16
case 16: ret = 0; break;
#endif
default: default:
break; break;
} }
var->red = par->rgb[rgbidx]->red;
var->green = par->rgb[rgbidx]->green;
var->blue = par->rgb[rgbidx]->blue;
var->transp = par->rgb[rgbidx]->transp;
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n", printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
sa1100fb_display_dma_period(var), sa1100fb_display_dma_period(var),
cpufreq_get()); cpufreq_get(smp_processor_id()));
#endif #endif
return ret; return ret;
...@@ -994,26 +1026,24 @@ static inline void sa1100fb_set_truecolor(u_int is_true_color) ...@@ -994,26 +1026,24 @@ static inline void sa1100fb_set_truecolor(u_int is_true_color)
} }
} }
static int static void
sa1100fb_set_par(struct fb_info *info) sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
{ {
struct sa1100_par *par = (struct sa1100_par *) info->par;
u_long palette_mem_size; u_long palette_mem_size;
par->bpp = info->var.bits_per_pixel; fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
par->palette_size = par->bpp == 8 ? 256 : 16;
palette_mem_size = par->palette_size * sizeof(u16); palette_mem_size = fbi->palette_size * sizeof(u16);
DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
par->palette_cpu = (u16 *)(par->map_cpu + PAGE_SIZE - palette_mem_size); fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
par->palette_dma = par->map_dma + PAGE_SIZE - palette_mem_size; fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
fb_set_cmap(&info->cmap, 1, info); fb_set_cmap(&fbi->fb.cmap, 1, &fbi->fb);
/* Set board control register to handle new color depth */ /* Set board control register to handle new color depth */
sa1100fb_set_truecolor(info->var.bits_per_pixel >= 16); sa1100fb_set_truecolor(var->bits_per_pixel >= 16);
#ifdef CONFIG_SA1100_OMNIMETER #ifdef CONFIG_SA1100_OMNIMETER
#error Do we have to do this here? We already do it at init time. #error Do we have to do this here? We already do it at init time.
...@@ -1021,31 +1051,210 @@ sa1100fb_set_par(struct fb_info *info) ...@@ -1021,31 +1051,210 @@ sa1100fb_set_par(struct fb_info *info)
SetLCDContrast(DefaultLCDContrast); SetLCDContrast(DefaultLCDContrast);
#endif #endif
sa1100fb_activate_var(&info->var, info); sa1100fb_activate_var(var, fbi);
par->palette_cpu[0] = (par->palette_cpu[0] & fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
0xcfff) | palette_pbs(info->var.bits_per_pixel); 0xcfff) | palette_pbs(var);
}
switch (info->var.bits_per_pixel) { /*
* sa1100fb_set_var():
* Set the user defined part of the display for the specified console
*/
static int
sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
struct display *display = get_con_display(&fbi->fb, con);
int err, chgvar = 0, rgbidx;
DPRINTK("set_var\n");
/*
* Decode var contents into a par structure, adjusting any
* out of range values.
*/
err = sa1100fb_validate_var(var, fbi);
if (err)
return err;
if (var->activate & FB_ACTIVATE_TEST)
return 0;
if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
return -EINVAL;
if (dvar->xres != var->xres)
chgvar = 1;
if (dvar->yres != var->yres)
chgvar = 1;
if (dvar->xres_virtual != var->xres_virtual)
chgvar = 1;
if (dvar->yres_virtual != var->yres_virtual)
chgvar = 1;
if (dvar->bits_per_pixel != var->bits_per_pixel)
chgvar = 1;
if (con < 0)
chgvar = 0;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4: case 4:
if (par->cmap_static) if (fbi->cmap_static)
info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
else else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR; display->visual = FB_VISUAL_PSEUDOCOLOR;
info->fix.line_length = info->var.xres / 2; display->line_length = var->xres / 2;
display->dispsw = &fbcon_cfb4;
rgbidx = RGB_8;
break; break;
#endif
#ifdef FBCON_HAS_CFB8
case 8: case 8:
if (par->cmap_static) if (fbi->cmap_static)
info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
else else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR; display->visual = FB_VISUAL_PSEUDOCOLOR;
info->fix.line_length = info->var.xres; display->line_length = var->xres;
display->dispsw = &fbcon_cfb8;
rgbidx = RGB_8;
break; break;
#endif
#ifdef FBCON_HAS_CFB16
case 16: case 16:
info->fix.visual = FB_VISUAL_TRUECOLOR; display->visual = FB_VISUAL_TRUECOLOR;
info->fix.line_length = info->var.xres * 2; display->line_length = var->xres * 2;
display->dispsw = &fbcon_cfb16;
display->dispsw_data = fbi->fb.pseudo_palette;
rgbidx = RGB_16;
break;
#endif
default:
rgbidx = 0;
display->dispsw = &fbcon_dummy;
break; break;
} }
display->next_line = display->line_length;
display->type = fbi->fb.fix.type;
display->type_aux = fbi->fb.fix.type_aux;
display->ypanstep = fbi->fb.fix.ypanstep;
display->ywrapstep = fbi->fb.fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = fbi->cmap_inverse;
*dvar = *var;
dvar->activate &= ~FB_ACTIVATE_ALL;
/*
* Copy the RGB parameters for this display
* from the machine specific parameters.
*/
dvar->red = fbi->rgb[rgbidx]->red;
dvar->green = fbi->rgb[rgbidx]->green;
dvar->blue = fbi->rgb[rgbidx]->blue;
dvar->transp = fbi->rgb[rgbidx]->transp;
DPRINTK("RGBT length = %d:%d:%d:%d\n",
dvar->red.length, dvar->green.length, dvar->blue.length,
dvar->transp.length);
DPRINTK("RGBT offset = %d:%d:%d:%d\n",
dvar->red.offset, dvar->green.offset, dvar->blue.offset,
dvar->transp.offset);
/*
* Update the old var. The fbcon drivers still use this.
* Once they are using fbi->fb.var, this can be dropped.
*/
display->var = *dvar;
/*
* If we are setting all the virtual consoles, also set the
* defaults used to create new consoles.
*/
if (var->activate & FB_ACTIVATE_ALL)
fbi->fb.disp->var = *dvar;
/*
* If the console has changed and the console has defined
* a changevar function, call that function.
*/
if (chgvar && info && fbi->fb.changevar)
fbi->fb.changevar(con);
/* If the current console is selected, activate the new var. */
if (con != fbi->fb.currcon)
return 0;
sa1100fb_hw_set_var(dvar, fbi);
return 0;
}
static int
__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_cmap *dcmap = get_con_cmap(info, con);
int err = 0;
if (con == -1)
con = info->currcon;
/* no colormap allocated? (we always have "this" colour map allocated) */
if (con >= 0)
err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
if (!err && con == info->currcon)
err = fb_set_cmap(cmap, kspc, info);
if (!err)
fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
return err;
}
static int
sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct display *disp = get_con_display(info, con);
if (disp->visual == FB_VISUAL_TRUECOLOR ||
disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
return -EINVAL;
return __do_set_cmap(cmap, kspc, con, info);
}
static int
sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
{
struct display *display = get_con_display(info, con);
*fix = info->fix;
fix->line_length = display->line_length;
fix->visual = display->visual;
return 0;
}
static int
sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
*var = *get_con_var(info, con);
return 0;
}
static int
sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
{
struct fb_cmap *dcmap = get_con_cmap(info, con);
fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
return 0; return 0;
} }
...@@ -1086,21 +1295,21 @@ sa1100fb_set_par(struct fb_info *info) ...@@ -1086,21 +1295,21 @@ sa1100fb_set_par(struct fb_info *info)
*/ */
static int sa1100fb_blank(int blank, struct fb_info *info) static int sa1100fb_blank(int blank, struct fb_info *info)
{ {
struct sa1100_par *par = (struct sa1100_par *) info->par; struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
int i; int i;
DPRINTK("sa1100fb_blank: blank=%d fix.id=%s\n", blank, DPRINTK("sa1100fb_blank: blank=%d info->modename=%s\n", blank,
info->fix.id); fbi->fb.modename);
switch (blank) { switch (blank) {
case VESA_POWERDOWN: case VESA_POWERDOWN:
case VESA_VSYNC_SUSPEND: case VESA_VSYNC_SUSPEND:
case VESA_HSYNC_SUSPEND: case VESA_HSYNC_SUSPEND:
if (info->disp->visual == FB_VISUAL_PSEUDOCOLOR || if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
info->disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
for (i = 0; i < par->palette_size; i++) for (i = 0; i < fbi->palette_size; i++)
sa1100fb_setpalettereg(i, 0, 0, 0, 0, info); sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
sa1100fb_schedule_task(par, C_DISABLE); sa1100fb_schedule_task(fbi, C_DISABLE);
if (sa1100fb_blank_helper) if (sa1100fb_blank_helper)
sa1100fb_blank_helper(blank); sa1100fb_blank_helper(blank);
break; break;
...@@ -1108,30 +1317,83 @@ static int sa1100fb_blank(int blank, struct fb_info *info) ...@@ -1108,30 +1317,83 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
case VESA_NO_BLANKING: case VESA_NO_BLANKING:
if (sa1100fb_blank_helper) if (sa1100fb_blank_helper)
sa1100fb_blank_helper(blank); sa1100fb_blank_helper(blank);
if (info->disp->visual == FB_VISUAL_PSEUDOCOLOR || if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
info->disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&info->cmap, 1, info); fb_set_cmap(&fbi->fb.cmap, 1, info);
sa1100fb_schedule_task(par, C_ENABLE); sa1100fb_schedule_task(fbi, C_ENABLE);
} }
return 0; return 0;
} }
static struct fb_ops sa1100fb_ops = { static struct fb_ops sa1100fb_ops = {
owner: THIS_MODULE, owner: THIS_MODULE,
fb_get_fix: gen_get_fix, fb_get_fix: sa1100fb_get_fix,
fb_get_var: gen_get_var, fb_get_var: sa1100fb_get_var,
fb_set_var: gen_set_var, fb_set_var: sa1100fb_set_var,
fb_get_cmap: gen_get_cmap, fb_get_cmap: sa1100fb_get_cmap,
fb_set_cmap: gen_set_cmap, fb_set_cmap: sa1100fb_set_cmap,
fb_check_var: sa1100fb_check_var,
fb_set_par: sa1100fb_set_par,
fb_setcolreg: sa1100fb_setcolreg, fb_setcolreg: sa1100fb_setcolreg,
fb_blank: sa1100fb_blank, fb_blank: sa1100fb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
}; };
/*
* sa1100fb_switch():
* Change to the specified console. Palette and video mode
* are changed to the console's stored parameters.
*
* Uh oh, this can be called from a tasklet (IRQ)
*/
static int sa1100fb_switch(int con, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp;
struct fb_cmap *cmap;
DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
if (con == info->currcon)
return 0;
if (info->currcon >= 0) {
disp = fb_display + info->currcon;
/*
* Save the old colormap and video mode.
*/
disp->var = fbi->fb.var;
if (disp->cmap.len)
fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
}
info->currcon = con;
disp = fb_display + con;
/*
* Make sure that our colourmap contains 256 entries.
*/
fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
if (disp->cmap.len)
cmap = &disp->cmap;
else
cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
fbi->fb.var = disp->var;
fbi->fb.var.activate = FB_ACTIVATE_NOW;
sa1100fb_set_var(&fbi->fb.var, con, info);
return 0;
}
static int sa1100fb_updatevar(int con, struct fb_info *info)
{
DPRINTK("entered\n");
return 0;
}
/* /*
* Calculate the PCD value from the clock rate (in picoseconds). * Calculate the PCD value from the clock rate (in picoseconds).
* We take account of the PPCR clock setting. * We take account of the PPCR clock setting.
...@@ -1141,7 +1403,7 @@ static inline int get_pcd(unsigned int pixclock) ...@@ -1141,7 +1403,7 @@ static inline int get_pcd(unsigned int pixclock)
unsigned int pcd; unsigned int pcd;
if (pixclock) { if (pixclock) {
pcd = cpufreq_get() / 100; pcd = cpufreq_get(0) / 100;
pcd *= pixclock; pcd *= pixclock;
pcd /= 10000000; pcd /= 10000000;
pcd += 1; /* make up for integer math truncations */ pcd += 1; /* make up for integer math truncations */
...@@ -1171,9 +1433,8 @@ static inline int get_pcd(unsigned int pixclock) ...@@ -1171,9 +1433,8 @@ static inline int get_pcd(unsigned int pixclock)
* Configures LCD Controller based on entries in var parameter. Settings are * Configures LCD Controller based on entries in var parameter. Settings are
* only written to the controller if changes were made. * only written to the controller if changes were made.
*/ */
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
{ {
struct sa1100_par *par = (struct sa1100_par *) info->par;
struct sa1100fb_lcd_reg new_regs; struct sa1100fb_lcd_reg new_regs;
u_int half_screen_size, yres, pcd = get_pcd(var->pixclock); u_int half_screen_size, yres, pcd = get_pcd(var->pixclock);
u_long flags; u_long flags;
...@@ -1190,31 +1451,31 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * ...@@ -1190,31 +1451,31 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
#if DEBUG_VAR #if DEBUG_VAR
if (var->xres < 16 || var->xres > 1024) if (var->xres < 16 || var->xres > 1024)
printk(KERN_ERR "%s: invalid xres %d\n", printk(KERN_ERR "%s: invalid xres %d\n",
info->fix.id, var->xres); fbi->fb.fix.id, var->xres);
if (var->hsync_len < 1 || var->hsync_len > 64) if (var->hsync_len < 1 || var->hsync_len > 64)
printk(KERN_ERR "%s: invalid hsync_len %d\n", printk(KERN_ERR "%s: invalid hsync_len %d\n",
info->fix.id, var->hsync_len); fbi->fb.fix.id, var->hsync_len);
if (var->left_margin < 1 || var->left_margin > 255) if (var->left_margin < 1 || var->left_margin > 255)
printk(KERN_ERR "%s: invalid left_margin %d\n", printk(KERN_ERR "%s: invalid left_margin %d\n",
info->fix.id, var->left_margin); fbi->fb.fix.id, var->left_margin);
if (var->right_margin < 1 || var->right_margin > 255) if (var->right_margin < 1 || var->right_margin > 255)
printk(KERN_ERR "%s: invalid right_margin %d\n", printk(KERN_ERR "%s: invalid right_margin %d\n",
info->fix.id, var->right_margin); fbi->fb.fix.id, var->right_margin);
if (var->yres < 1 || var->yres > 1024) if (var->yres < 1 || var->yres > 1024)
printk(KERN_ERR "%s: invalid yres %d\n", printk(KERN_ERR "%s: invalid yres %d\n",
info->fix.id, var->yres); fbi->fb.fix.id, var->yres);
if (var->vsync_len < 1 || var->vsync_len > 64) if (var->vsync_len < 1 || var->vsync_len > 64)
printk(KERN_ERR "%s: invalid vsync_len %d\n", printk(KERN_ERR "%s: invalid vsync_len %d\n",
info->fix.id, var->vsync_len); fbi->fb.fix.id, var->vsync_len);
if (var->upper_margin < 0 || var->upper_margin > 255) if (var->upper_margin < 0 || var->upper_margin > 255)
printk(KERN_ERR "%s: invalid upper_margin %d\n", printk(KERN_ERR "%s: invalid upper_margin %d\n",
info->fix.id, var->upper_margin); fbi->fb.fix.id, var->upper_margin);
if (var->lower_margin < 0 || var->lower_margin > 255) if (var->lower_margin < 0 || var->lower_margin > 255)
printk(KERN_ERR "%s: invalid lower_margin %d\n", printk(KERN_ERR "%s: invalid lower_margin %d\n",
info->fix.id, var->lower_margin); fbi->fb.fix.id, var->lower_margin);
#endif #endif
new_regs.lccr0 = par->lccr0 | new_regs.lccr0 = fbi->lccr0 |
LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
...@@ -1229,7 +1490,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * ...@@ -1229,7 +1490,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
* the YRES parameter. * the YRES parameter.
*/ */
yres = var->yres; yres = var->yres;
if (par->lccr0 & LCCR0_Dual) if (fbi->lccr0 & LCCR0_Dual)
yres /= 2; yres /= 2;
new_regs.lccr2 = new_regs.lccr2 =
...@@ -1238,7 +1499,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * ...@@ -1238,7 +1499,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
LCCR2_BegFrmDel(var->upper_margin) + LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin); LCCR2_EndFrmDel(var->lower_margin);
new_regs.lccr3 = par->lccr3 | new_regs.lccr3 = fbi->lccr3 |
(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) | (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
LCCR3_ACBsCntOff; LCCR3_ACBsCntOff;
...@@ -1256,23 +1517,23 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * ...@@ -1256,23 +1517,23 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
/* Update shadow copy atomically */ /* Update shadow copy atomically */
local_irq_save(flags); local_irq_save(flags);
par->dbar1 = par->palette_dma; fbi->dbar1 = fbi->palette_dma;
par->dbar2 = par->screen_dma + half_screen_size; fbi->dbar2 = fbi->screen_dma + half_screen_size;
par->reg_lccr0 = new_regs.lccr0; fbi->reg_lccr0 = new_regs.lccr0;
par->reg_lccr1 = new_regs.lccr1; fbi->reg_lccr1 = new_regs.lccr1;
par->reg_lccr2 = new_regs.lccr2; fbi->reg_lccr2 = new_regs.lccr2;
par->reg_lccr3 = new_regs.lccr3; fbi->reg_lccr3 = new_regs.lccr3;
local_irq_restore(flags); local_irq_restore(flags);
/* /*
* Only update the registers if the controller is enabled * Only update the registers if the controller is enabled
* and something has changed. * and something has changed.
*/ */
if ((LCCR0 != par->reg_lccr0) || (LCCR1 != par->reg_lccr1) || if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
(LCCR2 != par->reg_lccr2) || (LCCR3 != par->reg_lccr3) || (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
(DBAR1 != par->dbar1) || (DBAR2 != par->dbar2)) (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2))
sa1100fb_schedule_task(par, C_REENABLE); sa1100fb_schedule_task(fbi, C_REENABLE);
return 0; return 0;
} }
...@@ -1289,7 +1550,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * ...@@ -1289,7 +1550,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *
* Also, I'm expecting that the backlight stuff should * Also, I'm expecting that the backlight stuff should
* be handled differently. * be handled differently.
*/ */
static inline void sa1100fb_backlight_on(struct sa1100_par *par) static inline void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
{ {
DPRINTK("backlight on\n"); DPRINTK("backlight on\n");
...@@ -1302,7 +1563,7 @@ static inline void sa1100fb_backlight_on(struct sa1100_par *par) ...@@ -1302,7 +1563,7 @@ static inline void sa1100fb_backlight_on(struct sa1100_par *par)
* Also, I'm expecting that the backlight stuff should * Also, I'm expecting that the backlight stuff should
* be handled differently. * be handled differently.
*/ */
static inline void sa1100fb_backlight_off(struct sa1100_par *par) static inline void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
{ {
DPRINTK("backlight off\n"); DPRINTK("backlight off\n");
...@@ -1310,7 +1571,7 @@ static inline void sa1100fb_backlight_off(struct sa1100_par *par) ...@@ -1310,7 +1571,7 @@ static inline void sa1100fb_backlight_off(struct sa1100_par *par)
sa1100fb_backlight_power(0); sa1100fb_backlight_power(0);
} }
static inline void sa1100fb_power_up_lcd(struct sa1100_par *par) static inline void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
{ {
DPRINTK("LCD power on\n"); DPRINTK("LCD power on\n");
...@@ -1325,7 +1586,7 @@ static inline void sa1100fb_power_up_lcd(struct sa1100_par *par) ...@@ -1325,7 +1586,7 @@ static inline void sa1100fb_power_up_lcd(struct sa1100_par *par)
#endif #endif
} }
static inline void sa1100fb_power_down_lcd(struct sa1100_par *par) static inline void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
{ {
DPRINTK("LCD power off\n"); DPRINTK("LCD power off\n");
...@@ -1340,7 +1601,7 @@ static inline void sa1100fb_power_down_lcd(struct sa1100_par *par) ...@@ -1340,7 +1601,7 @@ static inline void sa1100fb_power_down_lcd(struct sa1100_par *par)
#endif #endif
} }
static void sa1100fb_setup_gpio(struct sa1100_par *par) static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
{ {
u_int mask = 0; u_int mask = 0;
...@@ -1356,12 +1617,12 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par) ...@@ -1356,12 +1617,12 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par)
* clear LDD15 to 12 for 4 or 8bpp modes with active * clear LDD15 to 12 for 4 or 8bpp modes with active
* panels. * panels.
*/ */
if ((par->reg_lccr0 & LCCR0_CMS) == LCCR0_Color && if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
(par->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) { (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8; mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
if (par->bpp > 8 || if (fbi->fb.var.bits_per_pixel > 8 ||
(par->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual) (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12; mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
} }
...@@ -1405,23 +1666,23 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par) ...@@ -1405,23 +1666,23 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par)
} }
} }
static void sa1100fb_enable_controller(struct sa1100_par *par) static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
{ {
DPRINTK("Enabling LCD controller\n"); DPRINTK("Enabling LCD controller\n");
/* /*
* Make sure the mode bits are present in the first palette entry * Make sure the mode bits are present in the first palette entry
*/ */
par->palette_cpu[0] &= 0xcfff; fbi->palette_cpu[0] &= 0xcfff;
par->palette_cpu[0] |= palette_pbs(par->bpp); fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
/* Sequence from 11.7.10 */ /* Sequence from 11.7.10 */
LCCR3 = par->reg_lccr3; LCCR3 = fbi->reg_lccr3;
LCCR2 = par->reg_lccr2; LCCR2 = fbi->reg_lccr2;
LCCR1 = par->reg_lccr1; LCCR1 = fbi->reg_lccr1;
LCCR0 = par->reg_lccr0 & ~LCCR0_LEN; LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
DBAR1 = par->dbar1; DBAR1 = fbi->dbar1;
DBAR2 = par->dbar2; DBAR2 = fbi->dbar2;
LCCR0 |= LCCR0_LEN; LCCR0 |= LCCR0_LEN;
#ifdef CONFIG_SA1100_GRAPHICSCLIENT #ifdef CONFIG_SA1100_GRAPHICSCLIENT
...@@ -1447,7 +1708,7 @@ static void sa1100fb_enable_controller(struct sa1100_par *par) ...@@ -1447,7 +1708,7 @@ static void sa1100fb_enable_controller(struct sa1100_par *par)
DPRINTK("LCCR3 = 0x%08x\n", LCCR3); DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
} }
static void sa1100fb_disable_controller(struct sa1100_par *par) static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -1481,7 +1742,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par) ...@@ -1481,7 +1742,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par)
GPCR |= SHANNON_GPIO_DISP_EN; GPCR |= SHANNON_GPIO_DISP_EN;
} }
add_wait_queue(&par->ctrlr_wait, &wait); add_wait_queue(&fbi->ctrlr_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
LCSR = 0xffffffff; /* Clear LCD Status Register */ LCSR = 0xffffffff; /* Clear LCD Status Register */
...@@ -1490,7 +1751,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par) ...@@ -1490,7 +1751,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par)
schedule_timeout(20 * HZ / 1000); schedule_timeout(20 * HZ / 1000);
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
remove_wait_queue(&par->ctrlr_wait, &wait); remove_wait_queue(&fbi->ctrlr_wait, &wait);
} }
/* /*
...@@ -1498,12 +1759,12 @@ static void sa1100fb_disable_controller(struct sa1100_par *par) ...@@ -1498,12 +1759,12 @@ static void sa1100fb_disable_controller(struct sa1100_par *par)
*/ */
static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct sa1100_par *par = dev_id; struct sa1100fb_info *fbi = dev_id;
unsigned int lcsr = LCSR; unsigned int lcsr = LCSR;
if (lcsr & LCSR_LDD) { if (lcsr & LCSR_LDD) {
LCCR0 |= LCCR0_LDM; LCCR0 |= LCCR0_LDM;
wake_up(&par->ctrlr_wait); wake_up(&fbi->ctrlr_wait);
} }
LCSR = lcsr; LCSR = lcsr;
...@@ -1514,13 +1775,13 @@ static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1514,13 +1775,13 @@ static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
* sleep when disabling the LCD controller, or if we get two contending * sleep when disabling the LCD controller, or if we get two contending
* processes trying to alter state. * processes trying to alter state.
*/ */
static void set_ctrlr_state(struct sa1100_par *par, u_int state) static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
{ {
u_int old_state; u_int old_state;
down(&par->ctrlr_sem); down(&fbi->ctrlr_sem);
old_state = par->state; old_state = fbi->state;
switch (state) { switch (state) {
case C_DISABLE_CLKCHANGE: case C_DISABLE_CLKCHANGE:
...@@ -1529,8 +1790,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) ...@@ -1529,8 +1790,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* controller is already disabled, then do nothing. * controller is already disabled, then do nothing.
*/ */
if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
par->state = state; fbi->state = state;
sa1100fb_disable_controller(par); sa1100fb_disable_controller(fbi);
} }
break; break;
...@@ -1540,12 +1801,12 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) ...@@ -1540,12 +1801,12 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* Disable controller * Disable controller
*/ */
if (old_state != C_DISABLE) { if (old_state != C_DISABLE) {
par->state = state; fbi->state = state;
sa1100fb_backlight_off(par); sa1100fb_backlight_off(fbi);
if (old_state != C_DISABLE_CLKCHANGE) if (old_state != C_DISABLE_CLKCHANGE)
sa1100fb_disable_controller(par); sa1100fb_disable_controller(fbi);
sa1100fb_power_down_lcd(par); sa1100fb_power_down_lcd(fbi);
} }
break; break;
...@@ -1555,8 +1816,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) ...@@ -1555,8 +1816,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* do this if we were disabled for the clock change. * do this if we were disabled for the clock change.
*/ */
if (old_state == C_DISABLE_CLKCHANGE) { if (old_state == C_DISABLE_CLKCHANGE) {
par->state = C_ENABLE; fbi->state = C_ENABLE;
sa1100fb_enable_controller(par); sa1100fb_enable_controller(fbi);
} }
break; break;
...@@ -1567,9 +1828,9 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) ...@@ -1567,9 +1828,9 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* registers. * registers.
*/ */
if (old_state == C_ENABLE) { if (old_state == C_ENABLE) {
sa1100fb_disable_controller(par); sa1100fb_disable_controller(fbi);
sa1100fb_setup_gpio(par); sa1100fb_setup_gpio(fbi);
sa1100fb_enable_controller(par); sa1100fb_enable_controller(fbi);
} }
break; break;
...@@ -1589,15 +1850,15 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) ...@@ -1589,15 +1850,15 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
* turn on the backlight. * turn on the backlight.
*/ */
if (old_state != C_ENABLE) { if (old_state != C_ENABLE) {
par->state = C_ENABLE; fbi->state = C_ENABLE;
sa1100fb_setup_gpio(par); sa1100fb_setup_gpio(fbi);
sa1100fb_power_up_lcd(par); sa1100fb_power_up_lcd(fbi);
sa1100fb_enable_controller(par); sa1100fb_enable_controller(fbi);
sa1100fb_backlight_on(par); sa1100fb_backlight_on(fbi);
} }
break; break;
} }
up(&par->ctrlr_sem); up(&fbi->ctrlr_sem);
} }
/* /*
...@@ -1606,12 +1867,10 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) ...@@ -1606,12 +1867,10 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state)
*/ */
static void sa1100fb_task(void *dummy) static void sa1100fb_task(void *dummy)
{ {
struct fb_info *info = dummy; struct sa1100fb_info *fbi = dummy;
struct sa1100_par *par = (struct sa1100_par *) info->par; u_int state = xchg(&fbi->task_state, -1);
u_int state = xchg(&par->task_state, -1);
set_ctrlr_state(par, state); set_ctrlr_state(fbi, state);
} }
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
...@@ -1620,7 +1879,7 @@ static void sa1100fb_task(void *dummy) ...@@ -1620,7 +1879,7 @@ static void sa1100fb_task(void *dummy)
* This, together with the SDRAM bandwidth defines the slowest CPU * This, together with the SDRAM bandwidth defines the slowest CPU
* frequency that can be selected. * frequency that can be selected.
*/ */
static unsigned int sa1100fb_min_dma_period(struct fb_info *info) static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
{ {
unsigned int min_period = (unsigned int)-1; unsigned int min_period = (unsigned int)-1;
int i; int i;
...@@ -1631,13 +1890,13 @@ static unsigned int sa1100fb_min_dma_period(struct fb_info *info) ...@@ -1631,13 +1890,13 @@ static unsigned int sa1100fb_min_dma_period(struct fb_info *info)
/* /*
* Do we own this display? * Do we own this display?
*/ */
if (fb_display[i].fb_info != info) if (fb_display[i].fb_info != &fbi->fb)
continue; continue;
/* /*
* Ok, calculate its DMA period * Ok, calculate its DMA period
*/ */
period = sa1100fb_display_dma_period(&info->var); period = sa1100fb_display_dma_period(get_con_var(&fbi->fb, i));
if (period < min_period) if (period < min_period)
min_period = period; min_period = period;
} }
...@@ -1654,27 +1913,26 @@ static int ...@@ -1654,27 +1913,26 @@ static int
sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val, sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
void *data) void *data)
{ {
struct fb_info *info = TO_INF(nb, clockchg); struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
struct sa1100_par *par = (struct sa1100_par *) info->par; struct cpufreq_minmax *mm = data;
struct cpufreq_freqs *mm = data;
u_int pcd; u_int pcd;
switch (val) { switch (val) {
case CPUFREQ_MINMAX: case CPUFREQ_MINMAX:
printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, " printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
"new clock %d kHz\n", sa1100fb_min_dma_period(info), "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
mm->cur, mm->new); mm->cur_freq, mm->new_freq);
/* todo: fill in min/max values */ /* todo: fill in min/max values */
break; break;
case CPUFREQ_PRECHANGE: case CPUFREQ_PRECHANGE:
set_ctrlr_state(par, C_DISABLE_CLKCHANGE); set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
break; break;
case CPUFREQ_POSTCHANGE: case CPUFREQ_POSTCHANGE:
pcd = get_pcd(info->var.pixclock); pcd = get_pcd(fbi->fb.var.pixclock);
par->reg_lccr3 = (par->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(par, C_ENABLE_CLKCHANGE); set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break; break;
} }
return 0; return 0;
...@@ -1689,7 +1947,7 @@ sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val, ...@@ -1689,7 +1947,7 @@ sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
static int static int
sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
{ {
struct sa1100_par *par = pm_dev->data; struct sa1100fb_info *fbi = pm_dev->data;
DPRINTK("pm_callback: %d\n", req); DPRINTK("pm_callback: %d\n", req);
...@@ -1698,10 +1956,10 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ...@@ -1698,10 +1956,10 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
if (state == 0) { if (state == 0) {
/* Enter D0. */ /* Enter D0. */
set_ctrlr_state(par, C_ENABLE_PM); set_ctrlr_state(fbi, C_ENABLE_PM);
} else { } else {
/* Enter D1-D3. Disable the LCD controller. */ /* Enter D1-D3. Disable the LCD controller. */
set_ctrlr_state(par, C_DISABLE_PM); set_ctrlr_state(fbi, C_DISABLE_PM);
} }
} }
DPRINTK("done\n"); DPRINTK("done\n");
...@@ -1717,142 +1975,133 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ...@@ -1717,142 +1975,133 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
* cache. Once this area is remapped, all virtual memory * cache. Once this area is remapped, all virtual memory
* access to the video memory should occur at the new region. * access to the video memory should occur at the new region.
*/ */
static int __init sa1100fb_map_video_memory(struct fb_info *info) static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
{ {
struct sa1100_par *par= (struct sa1100_par *) info->par;
/* /*
* We reserve one page for the palette, plus the size * We reserve one page for the palette, plus the size
* of the framebuffer. * of the framebuffer.
*/ */
par->map_size = PAGE_ALIGN(info->fix.smem_len + PAGE_SIZE); fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
par->map_cpu = consistent_alloc(GFP_KERNEL, par->map_size, fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
&par->map_dma); &fbi->map_dma);
if (par->map_cpu) { if (fbi->map_cpu) {
info->screen_base = par->map_cpu + PAGE_SIZE; fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
par->screen_dma = par->map_dma + PAGE_SIZE; fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
info->fix.smem_start = par->screen_dma; fbi->fb.fix.smem_start = fbi->screen_dma;
} }
return par->map_cpu ? 0 : -ENOMEM; return fbi->map_cpu ? 0 : -ENOMEM;
} }
/* Fake monspecs to fill in infonfo structure */ /* Fake monspecs to fill in fbinfo structure */
static struct fb_monspecs monspecs __initdata = { static struct fb_monspecs monspecs __initdata = {
30000, 70000, 50, 65, 0 /* Generic */ 30000, 70000, 50, 65, 0 /* Generic */
}; };
static struct fb_info * __init sa1100fb_init_fbinfo(void) static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
{ {
struct sa1100fb_mach_info *inf; struct sa1100fb_mach_info *inf;
struct fb_info *info; struct sa1100fb_info *fbi;
struct sa1100_par *par;
info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) + fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) +
sizeof(u16) * 16, GFP_KERNEL); sizeof(u16) * 16, GFP_KERNEL);
if (!info) if (!fbi)
return NULL; return NULL;
memset(info, 0, sizeof(struct fb_info) + sizeof(struct display)); memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
par = kmalloc(sizeof(struct sa1100_par), GFP_KERNEL); fbi->fb.currcon = -1;
memset(par, 0, sizeof(struct sa1100_par));
strcpy(fbi->fb.fix.id, SA1100_NAME);
info->currcon = -1;
fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
strcpy(info->fix.id, SA1100_NAME); fbi->fb.fix.type_aux = 0;
fbi->fb.fix.xpanstep = 0;
info->fix.type = FB_TYPE_PACKED_PIXELS; fbi->fb.fix.ypanstep = 0;
info->fix.type_aux = 0; fbi->fb.fix.ywrapstep = 0;
info->fix.xpanstep = 0; fbi->fb.fix.accel = FB_ACCEL_NONE;
info->fix.ypanstep = 0;
info->fix.ywrapstep = 0; fbi->fb.var.nonstd = 0;
info->fix.accel = FB_ACCEL_NONE; fbi->fb.var.activate = FB_ACTIVATE_NOW;
fbi->fb.var.height = -1;
info->var.nonstd = 0; fbi->fb.var.width = -1;
info->var.activate = FB_ACTIVATE_NOW; fbi->fb.var.accel_flags = 0;
info->var.height = -1; fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
info->var.width = -1;
info->var.accel_flags = 0; strcpy(fbi->fb.modename, SA1100_NAME);
info->var.vmode = FB_VMODE_NONINTERLACED; strcpy(fbi->fb.fontname, "Acorn8x8");
strcpy(info->modename, info->fix.id); fbi->fb.fbops = &sa1100fb_ops;
strcpy(info->fontname, "Acorn8x8"); fbi->fb.changevar = NULL;
fbi->fb.switch_con = sa1100fb_switch;
info->fbops = &sa1100fb_ops; fbi->fb.updatevar = sa1100fb_updatevar;
info->changevar = NULL; fbi->fb.flags = FBINFO_FLAG_DEFAULT;
info->switch_con = gen_switch; fbi->fb.node = NODEV;
info->updatevar = gen_update_var; fbi->fb.monspecs = monspecs;
info->flags = FBINFO_FLAG_DEFAULT; fbi->fb.currcon = -1;
info->node = NODEV; fbi->fb.disp = (struct display *)(fbi + 1);
info->monspecs = monspecs; fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
info->currcon = -1;
info->disp = (struct display *)(info + 1); fbi->rgb[RGB_8] = &rgb_8;
info->pseudo_palette = (void *)(info->disp + 1); fbi->rgb[RGB_16] = &def_rgb_16;
info->par = par;
inf = sa1100fb_get_machine_info(fbi);
par->rgb[RGB_8] = &rgb_8;
par->rgb[RGB_16] = &def_rgb_16; fbi->max_xres = inf->xres;
fbi->fb.var.xres = inf->xres;
inf = sa1100fb_get_machine_info(par); fbi->fb.var.xres_virtual = inf->xres;
fbi->max_yres = inf->yres;
par->max_xres = inf->xres; fbi->fb.var.yres = inf->yres;
info->var.xres = inf->xres; fbi->fb.var.yres_virtual = inf->yres;
info->var.xres_virtual = inf->xres; fbi->max_bpp = inf->bpp;
par->max_yres = inf->yres; fbi->fb.var.bits_per_pixel = inf->bpp;
info->var.yres = inf->yres; fbi->fb.var.pixclock = inf->pixclock;
info->var.yres_virtual = inf->yres; fbi->fb.var.hsync_len = inf->hsync_len;
par->max_bpp = inf->bpp; fbi->fb.var.left_margin = inf->left_margin;
info->var.bits_per_pixel = inf->bpp; fbi->fb.var.right_margin = inf->right_margin;
info->var.pixclock = inf->pixclock; fbi->fb.var.vsync_len = inf->vsync_len;
info->var.hsync_len = inf->hsync_len; fbi->fb.var.upper_margin = inf->upper_margin;
info->var.left_margin = inf->left_margin; fbi->fb.var.lower_margin = inf->lower_margin;
info->var.right_margin = inf->right_margin; fbi->fb.var.sync = inf->sync;
info->var.vsync_len = inf->vsync_len; fbi->fb.var.grayscale = inf->cmap_greyscale;
info->var.upper_margin = inf->upper_margin; fbi->cmap_inverse = inf->cmap_inverse;
info->var.lower_margin = inf->lower_margin; fbi->cmap_static = inf->cmap_static;
info->var.sync = inf->sync; fbi->lccr0 = inf->lccr0;
info->var.grayscale = inf->cmap_greyscale; fbi->lccr3 = inf->lccr3;
par->cmap_inverse = inf->cmap_inverse; fbi->state = C_DISABLE;
par->cmap_static = inf->cmap_static; fbi->task_state = (u_char)-1;
par->lccr0 = inf->lccr0; fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
par->lccr3 = inf->lccr3; fbi->max_bpp / 8;
par->state = C_DISABLE;
par->task_state = (u_char)-1; init_waitqueue_head(&fbi->ctrlr_wait);
info->fix.smem_len = par->max_xres * par->max_yres * INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
par->max_bpp / 8; init_MUTEX(&fbi->ctrlr_sem);
init_waitqueue_head(&par->ctrlr_wait); return fbi;
INIT_TQUEUE(&par->task, sa1100fb_task, info);
init_MUTEX(&par->ctrlr_sem);
fb_alloc_cmap(&info->cmap, 256, 0);
return info;
} }
int __init sa1100fb_init(void) int __init sa1100fb_init(void)
{ {
struct fb_info *info; struct sa1100fb_info *fbi;
struct sa1100_par *par;
int ret; int ret;
if (!request_mem_region(0xb0100000, 0x10000, "LCD")) if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
return -EBUSY; return -EBUSY;
info = sa1100fb_init_fbinfo(); fbi = sa1100fb_init_fbinfo();
ret = -ENOMEM; ret = -ENOMEM;
if (!info) if (!fbi)
goto failed; goto failed;
/* Initialize video memory */ /* Initialize video memory */
ret = sa1100fb_map_video_memory(info); ret = sa1100fb_map_video_memory(fbi);
if (ret) if (ret)
goto failed; goto failed;
ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT, ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
"LCD", info->par); "LCD", fbi);
if (ret) { if (ret) {
printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
goto failed; goto failed;
...@@ -1873,32 +2122,30 @@ int __init sa1100fb_init(void) ...@@ -1873,32 +2122,30 @@ int __init sa1100fb_init(void)
} }
#endif #endif
gen_set_var(&info->var, -1, info); sa1100fb_set_var(&fbi->fb.var, -1, &fbi->fb);
ret = register_framebuffer(info); ret = register_framebuffer(&fbi->fb);
if (ret < 0) if (ret < 0)
goto failed; goto failed;
par = info->par;
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* /*
* Note that the console registers this as well, but we want to * Note that the console registers this as well, but we want to
* power down the display prior to sleeping. * power down the display prior to sleeping.
*/ */
par->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback); fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
if (par->pm) if (fbi->pm)
par->pm->data = par; fbi->pm->data = fbi;
#endif #endif
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
info->clockchg.notifier_call = sa1100fb_clkchg_notifier; fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
cpufreq_register_notifier(&info->clockchg); cpufreq_register_notifier(&fbi->clockchg);
#endif #endif
/* /*
* Ok, now enable the LCD controller * Ok, now enable the LCD controller
*/ */
set_ctrlr_state(par, C_ENABLE); set_ctrlr_state(fbi, C_ENABLE);
/* This driver cannot be unloaded at the moment */ /* This driver cannot be unloaded at the moment */
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -1906,8 +2153,8 @@ int __init sa1100fb_init(void) ...@@ -1906,8 +2153,8 @@ int __init sa1100fb_init(void)
return 0; return 0;
failed: failed:
if (info) if (fbi)
kfree(info); kfree(fbi);
release_mem_region(0xb0100000, 0x10000); release_mem_region(0xb0100000, 0x10000);
return ret; return ret;
} }
......
...@@ -61,13 +61,13 @@ struct sa1100fb_lcd_reg { ...@@ -61,13 +61,13 @@ struct sa1100fb_lcd_reg {
#define RGB_16 (1) #define RGB_16 (1)
#define NR_RGB 2 #define NR_RGB 2
struct sa1100_par { struct sa1100fb_info {
struct fb_info fb;
struct sa1100fb_rgb *rgb[NR_RGB]; struct sa1100fb_rgb *rgb[NR_RGB];
u_int max_bpp;
u_int max_xres; u_int max_xres;
u_int max_yres; u_int max_yres;
u_int max_bpp;
u_int bpp;
/* /*
* These are the addresses we mapped * These are the addresses we mapped
...@@ -86,13 +86,12 @@ struct sa1100_par { ...@@ -86,13 +86,12 @@ struct sa1100_par {
dma_addr_t dbar1; dma_addr_t dbar1;
dma_addr_t dbar2; dma_addr_t dbar2;
u_int lccr0;
u_int lccr3;
u_int cmap_inverse:1, u_int cmap_inverse:1,
cmap_static:1, cmap_static:1,
unused:30; unused:30;
u_int lccr0;
u_int lccr3;
u_int reg_lccr0; u_int reg_lccr0;
u_int reg_lccr1; u_int reg_lccr1;
u_int reg_lccr2; u_int reg_lccr2;
...@@ -103,14 +102,18 @@ struct sa1100_par { ...@@ -103,14 +102,18 @@ struct sa1100_par {
struct semaphore ctrlr_sem; struct semaphore ctrlr_sem;
wait_queue_head_t ctrlr_wait; wait_queue_head_t ctrlr_wait;
struct tq_struct task; struct tq_struct task;
#ifdef CONFIG_PM #ifdef CONFIG_PM
struct pm_dev *pm; struct pm_dev *pm;
#endif #endif
#ifdef CONFIG_CPU_FREQ
struct notifier_block clockchg;
#endif
}; };
#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member))) #define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
#define TO_INF(ptr,member) __type_entry(ptr, struct fb_info, member) #define TO_INF(ptr,member) __type_entry(ptr,struct sa1100fb_info,member)
#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9) #define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)
......
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