diff options
| author | James Simmons <jsimmons@heisenberg.transvirtual.com> | 2002-07-07 23:12:00 -0700 |
|---|---|---|
| committer | James Simmons <jsimmons@heisenberg.transvirtual.com> | 2002-07-07 23:12:00 -0700 |
| commit | 2eaf7c63e1b100708abd60a6c1c2e2f133bd6704 (patch) | |
| tree | 2980bb42ecd602628573285d2b3b5bf13d128aff | |
| parent | 8ef1bf6df837a5f92e2d8d50ca26c77998602ff4 (diff) | |
Port step some changes at authors request.
| -rw-r--r-- | drivers/video/aty128fb.c | 3117 | ||||
| -rw-r--r-- | drivers/video/riva/fbdev.c | 1529 | ||||
| -rw-r--r-- | drivers/video/riva/riva_hw.c | 38 | ||||
| -rw-r--r-- | drivers/video/riva/riva_hw.h | 2 | ||||
| -rw-r--r-- | drivers/video/riva/rivafb.h | 60 | ||||
| -rw-r--r-- | drivers/video/sa1100fb.c | 823 | ||||
| -rw-r--r-- | drivers/video/sa1100fb.h | 17 |
7 files changed, 3329 insertions, 2257 deletions
diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index 2d8646e3d417..9d07d3d30e27 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -69,7 +69,7 @@ #ifdef CONFIG_BOOTX_TEXT #include <asm/btext.h> -#endif /* CONFIG_BOOTX_TEXT */ +#endif /* CONFIG_BOOTX_TEXT */ #include <video/aty128.h> #include <video/fbcon.h> @@ -94,58 +94,57 @@ #ifndef CONFIG_PPC /* default mode */ static struct fb_var_screeninfo default_var __initdata = { - /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ - 640, 480, 640, 480, 0, 0, 8, 0, - {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, - 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, - 0, FB_VMODE_NONINTERLACED + /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2, + 0, FB_VMODE_NONINTERLACED }; -#else /* CONFIG_PPC */ +#else /* CONFIG_PPC */ /* default to 1024x768 at 75Hz on PPC - this will work * on the iMac, the usual 640x480 @ 60Hz doesn't. */ static struct fb_var_screeninfo default_var = { - /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ - 1024, 768, 1024, 768, 0, 0, 8, 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, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED + /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */ + 1024, 768, 1024, 768, 0, 0, 8, 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, + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }; -#endif /* CONFIG_PPC */ +#endif /* CONFIG_PPC */ /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ static struct fb_videomode defaultmode __initdata = { - refresh:60, - xres:640, - yres:480, - pixclock:39722, - left_margin:48, - right_margin:16, - upper_margin:33, - lower_margin:10, - hsync_len:96, - vsync_len:2, - sync:0, - vmode:FB_VMODE_NONINTERLACED + refresh: 60, + xres: 640, + yres: 480, + pixclock: 39722, + left_margin: 48, + right_margin: 16, + upper_margin: 33, + lower_margin: 10, + hsync_len: 96, + vsync_len: 2, + sync: 0, + vmode: FB_VMODE_NONINTERLACED }; static struct fb_fix_screeninfo aty128fb_fix __initdata = { - id:"ATY Rage128", - type:FB_TYPE_PACKED_PIXELS, - visual:FB_VISUAL_PSEUDOCOLOR, - xpanstep:8, - ypanstep:1, - mmio_len:0x1fff, - accel:FB_ACCEL_ATI_RAGE128 + id: "ATY Rage128", + type: FB_TYPE_PACKED_PIXELS, + visual: FB_VISUAL_PSEUDOCOLOR, + xpanstep: 8, + ypanstep: 1, + mmio_len: 0x1fff, + accel: FB_ACCEL_ATI_RAGE128 }; /* struct to hold chip description information */ struct aty128_chip_info { - const char *name; - unsigned short device; - int chip_gen; + const char *name; + unsigned short device; + int chip_gen; }; /* Chip generations */ @@ -156,21 +155,19 @@ enum { }; /* supported Rage128 chipsets */ -static struct aty128_chip_info aty128_pci_probe_list[] __initdata = { - {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, 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 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128}, - {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, - rage_128_pro}, - {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, - 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 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3}, - {NULL, 0, rage_128} -}; +static struct aty128_chip_info aty128_pci_probe_list[] __initdata = +{ + {"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, 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 RL (AGP)", PCI_DEVICE_ID_ATI_RAGE128_RL, rage_128}, + {"Rage128 Pro PF (AGP)", PCI_DEVICE_ID_ATI_RAGE128_PF, rage_128_pro}, + {"Rage128 Pro PR (PCI)", PCI_DEVICE_ID_ATI_RAGE128_PR, 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 (AGP)", PCI_DEVICE_ID_ATI_RAGE128_LF, rage_M3}, + {NULL, 0, rage_128} + }; /* packed BIOS settings */ #ifndef CONFIG_PPC @@ -198,27 +195,27 @@ typedef struct { u32 XCLK_min_freq; u32 XCLK_max_freq; } __attribute__ ((packed)) PLL_BLOCK; -#endif /* !CONFIG_PPC */ +#endif /* !CONFIG_PPC */ /* onboard memory information */ struct aty128_meminfo { - u8 ML; - u8 MB; - u8 Trcd; - u8 Trp; - u8 Twr; - u8 CL; - u8 Tr2w; - u8 LoopLatency; - u8 DspOn; - u8 Rloop; - const char *name; + u8 ML; + u8 MB; + u8 Trcd; + u8 Trp; + u8 Twr; + u8 CL; + u8 Tr2w; + u8 LoopLatency; + u8 DspOn; + u8 Rloop; + const char *name; }; /* various memory configurations */ -static const struct aty128_meminfo sdr_128 = +static const struct aty128_meminfo sdr_128 = { 4, 4, 3, 3, 1, 3, 1, 16, 30, 16, "128-bit SDR SGRAM (1:1)" }; -static const struct aty128_meminfo sdr_64 = +static const struct aty128_meminfo sdr_64 = { 4, 8, 3, 3, 1, 3, 1, 17, 46, 17, "64-bit SDR SGRAM (1:1)" }; static const struct aty128_meminfo sdr_sgram = { 4, 4, 1, 2, 1, 2, 1, 16, 24, 16, "64-bit SDR SGRAM (2:1)" }; @@ -227,13 +224,14 @@ static const struct aty128_meminfo ddr_sgram = static char fontname[40] __initdata = { 0 }; +static int noaccel __initdata = 0; #ifdef MODULE static char *font __initdata = NULL; static char *mode __initdata = NULL; #ifdef CONFIG_MTRR -static int nomtrr __initdata = 0; +static int nomtrr __initdata = 0; #endif -#endif /* MODULE */ +#endif /* MODULE */ static char *mode_option __initdata = NULL; @@ -248,415 +246,490 @@ static int mtrr = 1; /* PLL constants */ struct aty128_constants { - u32 dotclock; - u32 ppll_min; - u32 ppll_max; - u32 ref_divider; - u32 xclk; - u32 fifo_width; - u32 fifo_depth; + u32 dotclock; + u32 ppll_min; + u32 ppll_max; + u32 ref_divider; + u32 xclk; + u32 fifo_width; + u32 fifo_depth; }; struct aty128_crtc { - u32 gen_cntl; - u32 ext_cntl; - u32 h_total, h_sync_strt_wid; - u32 v_total, v_sync_strt_wid; - u32 pitch; - u32 offset, offset_cntl; - u32 xoffset, yoffset; - u32 vyres; - u32 bpp; + u32 gen_cntl; + u32 ext_cntl; + u32 h_total, h_sync_strt_wid; + u32 v_total, v_sync_strt_wid; + u32 pitch; + u32 offset, offset_cntl; + u32 xoffset, yoffset; + u32 vxres, vyres; + u32 bpp; }; struct aty128_pll { - u32 post_divider; - u32 feedback_divider; - u32 vclk; + u32 post_divider; + u32 feedback_divider; + u32 vclk; }; struct aty128_ddafifo { - u32 dda_config; - u32 dda_on_off; + u32 dda_config; + u32 dda_on_off; }; /* register values for a specific mode */ struct aty128fb_par { - struct aty128_crtc crtc; - struct aty128_pll pll; - struct aty128_ddafifo fifo_reg; - const struct aty128_meminfo *mem; /* onboard mem info */ - struct aty128_constants constants; /* PLL and others */ - void *regbase; /* remapped mmio */ - int blitter_may_be_busy; - int fifo_slots; /* free slots in FIFO (64 max) */ - int chip_gen; + struct aty128_crtc crtc; + struct aty128_pll pll; + struct aty128_ddafifo fifo_reg; + u32 accel_flags; #ifdef CONFIG_MTRR - struct { int vram; int vram_valid; } 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 */ + void *regbase; /* remapped mmio */ + int chip_gen; + const struct aty128_meminfo *mem; /* onboard mem info */ + int blitter_may_be_busy; + int fifo_slots; /* free slots in FIFO (64 max) */ +}; + +static struct fb_info_aty128 *board_list = NULL; + #define round_div(n, d) ((n+(d/2))/d) /* * Interface used by the world */ -int aty128fb_init(void); + int aty128fb_setup(char *options); -static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); -static int aty128fb_set_par(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_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int aty128fb_get_var(struct fb_var_screeninfo *var, int con, + 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, - struct fb_info *fb); -static int aty128fb_blank(int blank, struct fb_info *info); + struct fb_info *fb); +static int aty128fb_blank(int blank, struct fb_info *fb); 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 */ + +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, - struct aty128fb_par *par, - const struct fb_info *info); + struct aty128fb_par *par, + const struct fb_info_aty128 *info); 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__) -static void __init aty128_get_pllinfo(struct aty128fb_par *par, - char *bios_seg); -static char __init *aty128find_ROM(struct fb_info *info); +static void __init aty128_get_pllinfo(struct fb_info_aty128 *info, + char *bios_seg); +static char __init *aty128find_ROM(struct fb_info_aty128 *info); #endif -static void aty128_timings(struct aty128fb_par *par); -static void aty128_init_engine(struct aty128fb_par *par, - struct fb_info *info); -static void aty128_reset_engine(struct aty128fb_par *par); -static void aty128_flush_pixel_cache(struct aty128fb_par *par); -static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par); -static void wait_for_fifo(u16 entries, struct aty128fb_par *par); -static void wait_for_idle(struct aty128fb_par *par); +static void aty128_timings(struct fb_info_aty128 *info); +static void aty128_init_engine(const struct aty128fb_par *par, + struct fb_info_aty128 *info); +static void aty128_reset_engine(const struct fb_info_aty128 *info); +static void aty128_flush_pixel_cache(const struct fb_info_aty128 *info); +static void do_wait_for_fifo(u16 entries, struct fb_info_aty128 *info); +static void wait_for_fifo(u16 entries, struct fb_info_aty128 *info); +static void wait_for_idle(struct fb_info_aty128 *info); 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 = { owner: THIS_MODULE, - fb_get_fix: gen_get_fix, - fb_get_var: gen_get_var, - fb_set_var: gen_set_var, + fb_get_fix: aty128fb_get_fix, + fb_get_var: aty128fb_get_var, + fb_set_var: aty128fb_set_var, fb_get_cmap: gen_get_cmap, fb_set_cmap: gen_set_cmap, - fb_check_var: aty128fb_check_var, - fb_set_par: aty128fb_set_par, fb_setcolreg: aty128fb_setcolreg, fb_pan_display: aty128fb_pan_display, fb_blank: aty128fb_blank, - fb_fillrect: cfb_fillrect, - fb_copyarea: cfb_copyarea, - fb_imageblit: cfb_imageblit, fb_rasterimg: aty128fb_rasterimg, }; #ifdef CONFIG_PMAC_BACKLIGHT -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_enable(int on, int level, void* data); +static int aty128_set_backlight_level(int level, void* data); static struct backlight_controller aty128_backlight_controller = { aty128_set_backlight_enable, aty128_set_backlight_level }; -#endif /* CONFIG_PMAC_BACKLIGHT */ +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Functions to read from/write to the mmio registers - * - endian conversions may possibly be avoided by + * - endian conversions may possibly be avoided by * using the other register aperture. TODO. */ static inline u32 -_aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par) +_aty_ld_le32(volatile unsigned int regindex, + const struct fb_info_aty128 *info) { - u32 val; + u32 val; #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 - val = readl(par->regbase + regindex); + val = readl (info->regbase + regindex); #endif - return val; + + return val; } 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__) - 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 - writel(val, par->regbase + regindex); + writel (val, info->regbase + regindex); #endif } 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 -_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_st_le32(regindex, val) _aty_st_le32(regindex, val, par) -#define aty_ld_8(regindex) _aty_ld_8(regindex, par) -#define aty_st_8(regindex, val) _aty_st_8(regindex, val, par) +#define aty_ld_le32(regindex) _aty_ld_le32(regindex, info) +#define aty_st_le32(regindex, val) _aty_st_le32(regindex, val, info) +#define aty_ld_8(regindex) _aty_ld_8(regindex, info) +#define aty_st_8(regindex, val) _aty_st_8(regindex, val, info) /* * Functions to read from/write to the pll registers */ -#define aty_ld_pll(pll_index) _aty_ld_pll(pll_index, par) -#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, 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, info) static u32 -_aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par) -{ - aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F); - return aty_ld_le32(CLOCK_CNTL_DATA); +_aty_ld_pll(unsigned int pll_index, + const struct fb_info_aty128 *info) +{ + aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x1F); + return aty_ld_le32(CLOCK_CNTL_DATA); } - + 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_le32(CLOCK_CNTL_DATA, val); + aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x1F) | PLL_WR_EN); + aty_st_le32(CLOCK_CNTL_DATA, val); } /* return true when the PLL has completed an atomic update */ -static int aty_pll_readupdate(const struct aty128fb_par *par) +static int +aty_pll_readupdate(const struct 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 - int reset = 1; + unsigned long timeout = jiffies + HZ/100; // should be more than enough + int reset = 1; - while (time_before(jiffies, timeout)) - if (aty_pll_readupdate(par)) { - reset = 0; - break; - } + while (time_before(jiffies, timeout)) + if (aty_pll_readupdate(info)) { + reset = 0; + break; + } - if (reset) /* reset engine?? */ - printk(KERN_DEBUG "aty128fb: PLL write timeout!\n"); + if (reset) /* reset engine?? */ + printk(KERN_DEBUG "aty128fb: PLL write timeout!\n"); } /* 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_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W); + aty_st_pll(PPLL_REF_DIV, + aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W); } /* 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; - int flag = 0; + u32 val; + int flag = 0; - val = aty_ld_le32(BIOS_0_SCRATCH); + val = aty_ld_le32(BIOS_0_SCRATCH); - aty_st_le32(BIOS_0_SCRATCH, 0x55555555); - if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) { - aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA); + aty_st_le32(BIOS_0_SCRATCH, 0x55555555); + if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) { + aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA); - if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA) - flag = 1; - } + if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA) + flag = 1; + } - aty_st_le32(BIOS_0_SCRATCH, val); // restore value - return flag; + aty_st_le32(BIOS_0_SCRATCH, val); // restore value + return flag; } /* * 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; - - for (;;) { - for (i = 0; i < 2000000; i++) { - par->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff; - if (par->fifo_slots >= entries) - return; - } - aty128_reset_engine(par); - } + int i; + + for (;;) { + for (i = 0; i < 2000000; i++) { + info->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff; + if (info->fifo_slots >= entries) + return; + } + aty128_reset_engine(info); + } } -static void wait_for_idle(struct aty128fb_par *par) -{ - int i; - do_wait_for_fifo(64, par); - - for (;;) { - for (i = 0; i < 2000000; i++) { - if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) { - aty128_flush_pixel_cache(par); - par->blitter_may_be_busy = 0; - return; - } - } - aty128_reset_engine(par); - } +static void +wait_for_idle(struct fb_info_aty128 *info) +{ + int i; + + do_wait_for_fifo(64, info); + + for (;;) { + for (i = 0; i < 2000000; i++) { + if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) { + aty128_flush_pixel_cache(info); + info->blitter_may_be_busy = 0; + return; + } + } + 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) - do_wait_for_fifo(64, par); - par->fifo_slots -= entries; + if (info->fifo_slots < entries) + do_wait_for_fifo(64, info); + 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 &= ~(0x00ff); - tmp |= 0x00ff; - aty_st_le32(PC_NGUI_CTLSTAT, tmp); + tmp = aty_ld_le32(PC_NGUI_CTLSTAT); + tmp &= ~(0x00ff); + tmp |= 0x00ff; + aty_st_le32(PC_NGUI_CTLSTAT, tmp); - for (i = 0; i < 2000000; i++) - if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY)) - break; + for (i = 0; i < 2000000; i++) + if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY)) + break; } -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); - mclk_cntl = aty_ld_pll(MCLK_CNTL); + clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX); + mclk_cntl = aty_ld_pll(MCLK_CNTL); - aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000); + aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000); - gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL); - aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI); - aty_ld_le32(GEN_RESET_CNTL); - aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI)); - aty_ld_le32(GEN_RESET_CNTL); + gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL); + aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI); + aty_ld_le32(GEN_RESET_CNTL); + aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI)); + aty_ld_le32(GEN_RESET_CNTL); - aty_st_pll(MCLK_CNTL, mclk_cntl); - aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index); - aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl); + aty_st_pll(MCLK_CNTL, mclk_cntl); + aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index); + aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl); - /* use old pio mode */ - aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4); + /* use old pio mode */ + aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4); - DBG("engine reset"); + DBG("engine reset"); } static void -aty128_init_engine(struct aty128fb_par *par, - struct fb_info *info) +aty128_init_engine(const struct aty128fb_par *par, + struct fb_info_aty128 *info) { - u32 pitch_value; - - wait_for_idle(par); - - /* 3D scaler not spoken here */ - wait_for_fifo(1, par); - aty_st_le32(SCALE_3D_CNTL, 0x00000000); - - aty128_reset_engine(par); - - pitch_value = par->crtc.pitch; - if (par->crtc.bpp == 24) { - pitch_value = pitch_value * 3; - } - - wait_for_fifo(4, par); - /* setup engine offset registers */ - aty_st_le32(DEFAULT_OFFSET, 0x00000000); - - /* setup engine pitch registers */ - aty_st_le32(DEFAULT_PITCH, pitch_value); - - /* set the default scissor register to max dimensions */ - aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF); - - /* set the drawing controls registers */ - aty_st_le32(DP_GUI_MASTER_CNTL, - GMC_SRC_PITCH_OFFSET_DEFAULT | - GMC_DST_PITCH_OFFSET_DEFAULT | - GMC_SRC_CLIP_DEFAULT | - GMC_DST_CLIP_DEFAULT | - GMC_BRUSH_SOLIDCOLOR | - (bpp_to_depth(par->crtc.bpp) << 8) | - GMC_SRC_DSTCOLOR | - GMC_BYTE_ORDER_MSB_TO_LSB | - GMC_DP_CONVERSION_TEMP_6500 | - ROP3_PATCOPY | - GMC_DP_SRC_RECT | - GMC_3D_FCN_EN_CLR | - GMC_DST_CLR_CMP_FCN_CLEAR | - GMC_AUX_CLIP_CLEAR | GMC_WRITE_MASK_SET); - - wait_for_fifo(8, par); - /* clear the line drawing registers */ - aty_st_le32(DST_BRES_ERR, 0); - aty_st_le32(DST_BRES_INC, 0); - aty_st_le32(DST_BRES_DEC, 0); - - /* set brush color registers */ - aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */ - aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */ - - /* set source color registers */ - aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF); /* white */ - aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000); /* black */ - - /* default write mask */ - aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF); - - /* Wait for all the writes to be completed before returning */ - wait_for_idle(par); + u32 pitch_value; + + wait_for_idle(info); + + /* 3D scaler not spoken here */ + wait_for_fifo(1, info); + aty_st_le32(SCALE_3D_CNTL, 0x00000000); + + aty128_reset_engine(info); + + pitch_value = par->crtc.pitch; + if (par->crtc.bpp == 24) { + pitch_value = pitch_value * 3; + } + + wait_for_fifo(4, info); + /* setup engine offset registers */ + aty_st_le32(DEFAULT_OFFSET, 0x00000000); + + /* setup engine pitch registers */ + aty_st_le32(DEFAULT_PITCH, pitch_value); + + /* set the default scissor register to max dimensions */ + aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF); + + /* set the drawing controls registers */ + aty_st_le32(DP_GUI_MASTER_CNTL, + GMC_SRC_PITCH_OFFSET_DEFAULT | + GMC_DST_PITCH_OFFSET_DEFAULT | + GMC_SRC_CLIP_DEFAULT | + GMC_DST_CLIP_DEFAULT | + GMC_BRUSH_SOLIDCOLOR | + (bpp_to_depth(par->crtc.bpp) << 8) | + GMC_SRC_DSTCOLOR | + GMC_BYTE_ORDER_MSB_TO_LSB | + GMC_DP_CONVERSION_TEMP_6500 | + ROP3_PATCOPY | + GMC_DP_SRC_RECT | + GMC_3D_FCN_EN_CLR | + GMC_DST_CLR_CMP_FCN_CLEAR | + GMC_AUX_CLIP_CLEAR | + GMC_WRITE_MASK_SET); + + wait_for_fifo(8, info); + /* clear the line drawing registers */ + aty_st_le32(DST_BRES_ERR, 0); + aty_st_le32(DST_BRES_INC, 0); + aty_st_le32(DST_BRES_DEC, 0); + + /* set brush color registers */ + aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */ + aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */ + + /* set source color registers */ + aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF); /* white */ + aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000); /* black */ + + /* default write mask */ + aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF); + + /* Wait for all the writes to be completed before returning */ + wait_for_idle(info); } /* convert bpp values to their register representation */ -static u32 bpp_to_depth(u32 bpp) +static u32 +bpp_to_depth(u32 bpp) { - if (bpp <= 8) - return DST_8BPP; - else if (bpp <= 16) - return DST_15BPP; - else if (bpp <= 24) - return DST_24BPP; - else if (bpp <= 32) - return DST_32BPP; - - return -EINVAL; + if (bpp <= 8) + return DST_8BPP; + else if (bpp <= 16) + return DST_15BPP; + else if (bpp <= 24) + return DST_24BPP; + else if (bpp <= 32) + return DST_32BPP; + + return -EINVAL; } @@ -667,484 +740,484 @@ static u32 bpp_to_depth(u32 bpp) /* Program the CRTC registers */ static void aty128_set_crtc(const struct aty128_crtc *crtc, - const struct aty128fb_par *par) -{ - aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl); - aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total); - aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid); - aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total); - aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid); - aty_st_le32(CRTC_PITCH, crtc->pitch); - aty_st_le32(CRTC_OFFSET, crtc->offset); - aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); - /* Disable ATOMIC updating. Is this the right place? - * -- BenH: Breaks on my G4 - */ + const struct fb_info_aty128 *info) +{ + aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl); + aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total); + aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid); + aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total); + aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid); + aty_st_le32(CRTC_PITCH, crtc->pitch); + aty_st_le32(CRTC_OFFSET, crtc->offset); + aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl); + /* Disable ATOMIC updating. Is this the right place? + * -- BenH: Breaks on my G4 + */ #if 0 - aty_st_le32(PPLL_CNTL, aty_ld_le32(PPLL_CNTL) & ~(0x00030000)); + aty_st_le32(PPLL_CNTL, aty_ld_le32(PPLL_CNTL) & ~(0x00030000)); #endif } static int -aty128_var_to_crtc(struct fb_var_screeninfo *var, - struct aty128_crtc *crtc, - const struct fb_info *info) -{ - u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; - u32 left, right, upper, lower, hslen, vslen, sync, vmode; - u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; - u32 depth, bytpp; - u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 }; - u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 }; - - /* input */ - xres = var->xres; - yres = var->yres; - vxres = var->xres_virtual; - vyres = var->yres_virtual; - xoffset = var->xoffset; - yoffset = var->yoffset; - bpp = var->bits_per_pixel; - left = var->left_margin; - right = var->right_margin; - upper = var->upper_margin; - lower = var->lower_margin; - hslen = var->hsync_len; - vslen = var->vsync_len; - sync = var->sync; - vmode = var->vmode; - - /* check for mode eligibility - * accept only non interlaced modes */ - if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) - return -EINVAL; - - /* convert (and round up) and validate */ - xres = (xres + 7) & ~7; - xoffset = (xoffset + 7) & ~7; - - if (vxres < xres + xoffset) - vxres = xres + xoffset; - - if (vyres < yres + yoffset) - vyres = yres + yoffset; - - /* convert bpp into ATI register depth */ - depth = bpp_to_depth(bpp); - - /* make sure we didn't get an invalid depth */ - if (depth == -EINVAL) { - printk(KERN_ERR "aty128fb: Invalid depth\n"); - return -EINVAL; - } +aty128_var_to_crtc(const struct fb_var_screeninfo *var, + struct aty128_crtc *crtc, + const struct fb_info_aty128 *info) +{ + u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; + u32 left, right, upper, lower, hslen, vslen, sync, vmode; + u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 depth, bytpp; + u8 hsync_strt_pix[5] = { 0, 0x12, 9, 6, 5 }; + u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 }; + + /* input */ + xres = var->xres; + yres = var->yres; + vxres = var->xres_virtual; + vyres = var->yres_virtual; + xoffset = var->xoffset; + yoffset = var->yoffset; + bpp = var->bits_per_pixel; + left = var->left_margin; + right = var->right_margin; + upper = var->upper_margin; + lower = var->lower_margin; + hslen = var->hsync_len; + vslen = var->vsync_len; + sync = var->sync; + vmode = var->vmode; + + /* check for mode eligibility + * accept only non interlaced modes */ + if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) + return -EINVAL; - /* convert depth to bpp */ - bytpp = mode_bytpp[depth]; + /* convert (and round up) and validate */ + xres = (xres + 7) & ~7; + xoffset = (xoffset + 7) & ~7; - /* make sure there is enough video ram for the mode */ - if ((u32) (vxres * vyres * bytpp) > info->fix.smem_len) { - printk(KERN_ERR "aty128fb: Not enough memory for mode\n"); - return -EINVAL; - } + if (vxres < xres + xoffset) + vxres = xres + xoffset; - h_disp = (xres >> 3) - 1; - h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL; + if (vyres < yres + yoffset) + vyres = yres + yoffset; - v_disp = yres - 1; - v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL; + /* convert bpp into ATI register depth */ + depth = bpp_to_depth(bpp); - /* check to make sure h_total and v_total are in range */ - if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { - printk(KERN_ERR "aty128fb: invalid width ranges\n"); - return -EINVAL; - } + /* make sure we didn't get an invalid depth */ + if (depth == -EINVAL) { + printk(KERN_ERR "aty128fb: Invalid depth\n"); + return -EINVAL; + } - h_sync_wid = (hslen + 7) >> 3; - if (h_sync_wid == 0) - h_sync_wid = 1; - else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */ - h_sync_wid = 0x3f; + /* convert depth to bpp */ + bytpp = mode_bytpp[depth]; - h_sync_strt = h_disp + (right >> 3); + /* make sure there is enough video ram for the mode */ + if ((u32)(vxres * vyres * bytpp) > info->fb_info.fix.smem_len) { + printk(KERN_ERR "aty128fb: Not enough memory for mode\n"); + return -EINVAL; + } - v_sync_wid = vslen; - if (v_sync_wid == 0) - v_sync_wid = 1; - else if (v_sync_wid > 0x1f) /* 0x1f = max vwidth */ - v_sync_wid = 0x1f; + h_disp = (xres >> 3) - 1; + h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL; - v_sync_strt = v_disp + lower; + v_disp = yres - 1; + v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL; - h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; - v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + /* check to make sure h_total and v_total are in range */ + if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) { + printk(KERN_ERR "aty128fb: invalid width ranges\n"); + return -EINVAL; + } - c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; + h_sync_wid = (hslen + 7) >> 3; + if (h_sync_wid == 0) + h_sync_wid = 1; + else if (h_sync_wid > 0x3f) /* 0x3f = max hwidth */ + h_sync_wid = 0x3f; - crtc->gen_cntl = 0x3000000L | c_sync | (depth << 8); + h_sync_strt = h_disp + (right >> 3); - crtc->h_total = h_total | (h_disp << 16); - crtc->v_total = v_total | (v_disp << 16); + v_sync_wid = vslen; + if (v_sync_wid == 0) + v_sync_wid = 1; + else if (v_sync_wid > 0x1f) /* 0x1f = max vwidth */ + v_sync_wid = 0x1f; + + v_sync_strt = v_disp + lower; - crtc->h_sync_strt_wid = - hsync_strt_pix[bytpp] | (h_sync_strt << 3) | (h_sync_wid << 16) - | (h_sync_pol << 23); - crtc->v_sync_strt_wid = - v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 23); + h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; + v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; + + c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; - crtc->pitch = vxres >> 3; + crtc->gen_cntl = 0x3000000L | c_sync | (depth << 8); - crtc->offset = 0; + crtc->h_total = h_total | (h_disp << 16); + crtc->v_total = v_total | (v_disp << 16); - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) - crtc->offset_cntl = 0x00010000; - else - crtc->offset_cntl = 0; + crtc->h_sync_strt_wid = hsync_strt_pix[bytpp] | (h_sync_strt << 3) | + (h_sync_wid << 16) | (h_sync_pol << 23); + crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) | + (v_sync_pol << 23); - var->xres_virtual = vxres; - crtc->vyres = vyres; - crtc->xoffset = xoffset; - crtc->yoffset = yoffset; - crtc->bpp = bpp; + crtc->pitch = vxres >> 3; - return 0; + crtc->offset = 0; + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) + crtc->offset_cntl = 0x00010000; + else + crtc->offset_cntl = 0; + + crtc->vxres = vxres; + crtc->vyres = vyres; + crtc->xoffset = xoffset; + crtc->yoffset = yoffset; + crtc->bpp = bpp; + + return 0; } -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 */ - switch (pix_width) { - case CRTC_PIX_WIDTH_8BPP: - var->bits_per_pixel = 8; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_15BPP: - case CRTC_PIX_WIDTH_16BPP: - var->bits_per_pixel = 16; - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_24BPP: - var->bits_per_pixel = 24; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case CRTC_PIX_WIDTH_32BPP: - var->bits_per_pixel = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - default: - printk(KERN_ERR "aty128fb: Invalid pixel width\n"); - return -EINVAL; - } - - return 0; + /* fill in pixel info */ + switch (pix_width) { + case CRTC_PIX_WIDTH_8BPP: + var->bits_per_pixel = 8; + var->red.offset = 0; + var->red.length = 8; + var->green.offset = 0; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_15BPP: + case CRTC_PIX_WIDTH_16BPP: + var->bits_per_pixel = 16; + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_24BPP: + var->bits_per_pixel = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + break; + case CRTC_PIX_WIDTH_32BPP: + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + break; + default: + printk(KERN_ERR "aty128fb: Invalid pixel width\n"); + return -EINVAL; + } + + return 0; } static int aty128_crtc_to_var(const struct aty128_crtc *crtc, - struct fb_var_screeninfo *var) -{ - u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; - u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, - h_sync_pol; - u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; - u32 pix_width; - - /* fun with masking */ - h_total = crtc->h_total & 0x1ff; - h_disp = (crtc->h_total >> 16) & 0xff; - h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; - h_sync_dly = crtc->h_sync_strt_wid & 0x7; - h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; - h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; - v_total = crtc->v_total & 0x7ff; - v_disp = (crtc->v_total >> 16) & 0x7ff; - v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; - v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; - v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; - c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; - pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; - - /* do conversions */ - xres = (h_disp + 1) << 3; - yres = v_disp + 1; - left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; - right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; - hslen = h_sync_wid << 3; - upper = v_total - v_sync_strt - v_sync_wid; - lower = v_sync_strt - v_disp; - vslen = v_sync_wid; - sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | - (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | - (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); - - aty128_bpp_to_var(pix_width, var); - - var->xres = xres; - var->yres = yres; - var->yres_virtual = crtc->vyres; - var->xoffset = crtc->xoffset; - var->yoffset = crtc->yoffset; - var->left_margin = left; - var->right_margin = right; - var->upper_margin = upper; - var->lower_margin = lower; - var->hsync_len = hslen; - var->vsync_len = vslen; - var->sync = sync; - var->vmode = FB_VMODE_NONINTERLACED; - - return 0; + struct fb_var_screeninfo *var) +{ + u32 xres, yres, left, right, upper, lower, hslen, vslen, sync; + u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; + u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; + u32 pix_width; + + /* fun with masking */ + h_total = crtc->h_total & 0x1ff; + h_disp = (crtc->h_total >> 16) & 0xff; + h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; + h_sync_dly = crtc->h_sync_strt_wid & 0x7; + h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; + h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; + v_total = crtc->v_total & 0x7ff; + v_disp = (crtc->v_total >> 16) & 0x7ff; + v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; + v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f; + v_sync_pol = (crtc->v_sync_strt_wid >> 23) & 0x1; + c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; + pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; + + /* do conversions */ + xres = (h_disp + 1) << 3; + yres = v_disp + 1; + left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; + right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; + hslen = h_sync_wid << 3; + upper = v_total - v_sync_strt - v_sync_wid; + lower = v_sync_strt - v_disp; + vslen = v_sync_wid; + sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | + (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | + (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); + + aty128_bpp_to_var(pix_width, var); + + var->xres = xres; + var->yres = yres; + var->xres_virtual = crtc->vxres; + var->yres_virtual = crtc->vyres; + var->xoffset = crtc->xoffset; + var->yoffset = crtc->yoffset; + var->left_margin = left; + var->right_margin = right; + var->upper_margin = upper; + var->lower_margin = lower; + var->hsync_len = hslen; + var->vsync_len = vslen; + var->sync = sync; + var->vmode = FB_VMODE_NONINTERLACED; + + return 0; } 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; - unsigned char post_conv[] = /* register values for post dividers */ - { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; + unsigned char post_conv[] = /* register values for post dividers */ + { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; - /* select PPLL_DIV_3 */ - aty_st_le32(CLOCK_CNTL_INDEX, - aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8)); + /* select PPLL_DIV_3 */ + aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8)); - /* reset PLL */ - aty_st_pll(PPLL_CNTL, - aty_ld_pll(PPLL_CNTL) | PPLL_RESET | - PPLL_ATOMIC_UPDATE_EN); + /* reset PLL */ + aty_st_pll(PPLL_CNTL, + aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN); - /* write the reference divider */ - aty_pll_wait_readupdate(par); - aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider & 0x3ff); - aty_pll_writeupdate(par); + /* write the reference divider */ + aty_pll_wait_readupdate(info); + aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff); + aty_pll_writeupdate(info); - div3 = aty_ld_pll(PPLL_DIV_3); - div3 &= ~PPLL_FB3_DIV_MASK; - div3 |= pll->feedback_divider; - div3 &= ~PPLL_POST3_DIV_MASK; - div3 |= post_conv[pll->post_divider] << 16; + div3 = aty_ld_pll(PPLL_DIV_3); + div3 &= ~PPLL_FB3_DIV_MASK; + div3 |= pll->feedback_divider; + div3 &= ~PPLL_POST3_DIV_MASK; + div3 |= post_conv[pll->post_divider] << 16; - /* write feedback and post dividers */ - aty_pll_wait_readupdate(par); - aty_st_pll(PPLL_DIV_3, div3); - aty_pll_writeupdate(par); + /* write feedback and post dividers */ + aty_pll_wait_readupdate(info); + aty_st_pll(PPLL_DIV_3, div3); + aty_pll_writeupdate(info); - aty_pll_wait_readupdate(par); - aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */ - aty_pll_writeupdate(par); + aty_pll_wait_readupdate(info); + aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */ + aty_pll_writeupdate(info); - /* clear the reset, just in case */ - aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET); + /* clear the reset, just in case */ + aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET); } static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, - const struct aty128fb_par *par) -{ - const struct aty128_constants c = par->constants; - unsigned char post_dividers[] = { 1, 2, 4, 8, 3, 6, 12 }; - u32 output_freq; - u32 vclk; /* in .01 MHz */ - int i; - u32 n, d; - - vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ - - /* adjust pixel clock if necessary */ - if (vclk > c.ppll_max) - vclk = c.ppll_max; - if (vclk * 12 < c.ppll_min) - vclk = c.ppll_min / 12; - - /* now, find an acceptable divider */ - for (i = 0; i < sizeof(post_dividers); i++) { - output_freq = post_dividers[i] * vclk; - if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) - break; - } - - /* calculate feedback divider */ - n = c.ref_divider * output_freq; - d = c.dotclock; - - pll->post_divider = post_dividers[i]; - pll->feedback_divider = round_div(n, d); - pll->vclk = vclk; - - DBG("post %d feedback %d vlck %d output %d ref_divider %d " - "vclk_per: %d\n", pll->post_divider, - pll->feedback_divider, vclk, output_freq, - c.ref_divider, period_in_ps); - - return 0; + const struct fb_info_aty128 *info) +{ + const struct aty128_constants c = info->constants; + unsigned char post_dividers[] = {1,2,4,8,3,6,12}; + u32 output_freq; + u32 vclk; /* in .01 MHz */ + int i; + u32 n, d; + + vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ + + /* adjust pixel clock if necessary */ + if (vclk > c.ppll_max) + vclk = c.ppll_max; + if (vclk * 12 < c.ppll_min) + vclk = c.ppll_min/12; + + /* now, find an acceptable divider */ + for (i = 0; i < sizeof(post_dividers); i++) { + output_freq = post_dividers[i] * vclk; + if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) + break; + } + + /* calculate feedback divider */ + n = c.ref_divider * output_freq; + d = c.dotclock; + + pll->post_divider = post_dividers[i]; + pll->feedback_divider = round_div(n, d); + pll->vclk = vclk; + + DBG("post %d feedback %d vlck %d output %d ref_divider %d " + "vclk_per: %d\n", pll->post_divider, + pll->feedback_divider, vclk, output_freq, + c.ref_divider, period_in_ps); + + return 0; } static int -aty128_pll_to_var(const struct aty128_pll *pll, - struct fb_var_screeninfo *var, - const struct fb_info *info) +aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var, + const struct fb_info_aty128 *info) { - var->pixclock = 100000000 / pll->vclk; + var->pixclock = 100000000 / pll->vclk; - return 0; + return 0; } static void 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_ON_OFF, dsp->dda_on_off); + aty_st_le32(DDA_CONFIG, dsp->dda_config); + aty_st_le32(DDA_ON_OFF, dsp->dda_on_off); } static int aty128_ddafifo(struct aty128_ddafifo *dsp, - const struct aty128_pll *pll, - u32 bpp, const struct fb_info *info) -{ - struct aty128fb_par *par = (struct aty128fb_par *) info->par; - const struct aty128_meminfo *m = par->mem; - u32 xclk = par->constants.xclk; - u32 fifo_width = par->constants.fifo_width; - u32 fifo_depth = par->constants.fifo_depth; - s32 x, b, p, ron, roff; - u32 n, d; - - /* 15bpp is really 16bpp */ - if (bpp == 15) - bpp = 16; - - n = xclk * fifo_width; - d = pll->vclk * bpp; - x = round_div(n, d); - - ron = 4 * m->MB + - 3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) + - 2 * m->Trp + m->Twr + m->CL + m->Tr2w + x; - - DBG("x %x\n", x); - - b = 0; - while (x) { - x >>= 1; - b++; - } - p = b + 1; - - ron <<= (11 - p); - - n <<= (11 - p); - x = round_div(n, d); - roff = x * (fifo_depth - 4); - - if ((ron + m->Rloop) >= roff) { - printk(KERN_ERR "aty128fb: Mode out of range!\n"); - return -EINVAL; - } + const struct aty128_pll *pll, + u32 bpp, + const struct fb_info_aty128 *info) +{ + const struct aty128_meminfo *m = info->mem; + u32 xclk = info->constants.xclk; + u32 fifo_width = info->constants.fifo_width; + u32 fifo_depth = info->constants.fifo_depth; + s32 x, b, p, ron, roff; + u32 n, d; + + /* 15bpp is really 16bpp */ + if (bpp == 15) + bpp = 16; + + n = xclk * fifo_width; + d = pll->vclk * bpp; + x = round_div(n, d); + + ron = 4 * m->MB + + 3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) + + 2 * m->Trp + + m->Twr + + m->CL + + m->Tr2w + + x; + + DBG("x %x\n", x); + + b = 0; + while (x) { + x >>= 1; + b++; + } + p = b + 1; + + ron <<= (11 - p); + + n <<= (11 - p); + x = round_div(n, d); + roff = x * (fifo_depth - 4); + + if ((ron + m->Rloop) >= roff) { + printk(KERN_ERR "aty128fb: Mode out of range!\n"); + return -EINVAL; + } - DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n", - p, m->Rloop, x, ron, roff); + DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n", + p, m->Rloop, x, ron, roff); - dsp->dda_config = p << 16 | m->Rloop << 20 | x; - dsp->dda_on_off = ron << 16 | roff; + dsp->dda_config = p << 16 | m->Rloop << 20 | x; + dsp->dda_on_off = ron << 16 | roff; - return 0; + return 0; } /* * This actually sets the video mode. */ -static int -aty128fb_set_par(struct fb_info *info) +static void +aty128_set_par(struct aty128fb_par *par, + struct fb_info_aty128 *info) { - struct aty128fb_par *par = (struct aty128fb_par *) info->par; - u32 config; - - if (par->blitter_may_be_busy) - wait_for_idle(par); - - /* clear all registers that may interfere with mode setting */ - aty_st_le32(OVR_CLR, 0); - aty_st_le32(OVR_WID_LEFT_RIGHT, 0); - aty_st_le32(OVR_WID_TOP_BOTTOM, 0); - aty_st_le32(OV0_SCALE_CNTL, 0); - aty_st_le32(MPP_TB_CONFIG, 0); - aty_st_le32(MPP_GP_CONFIG, 0); - aty_st_le32(SUBPIC_CNTL, 0); - aty_st_le32(VIPH_CONTROL, 0); - aty_st_le32(I2C_CNTL_1, 0); /* turn off i2c */ - aty_st_le32(GEN_INT_CNTL, 0); /* turn off interrupts */ - aty_st_le32(CAP0_TRIG_CNTL, 0); - aty_st_le32(CAP1_TRIG_CNTL, 0); - - aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */ - - aty128_set_crtc(&par->crtc, par); - aty128_set_pll(&par->pll, par); - aty128_set_fifo(&par->fifo_reg, par); - - config = aty_ld_le32(CONFIG_CNTL) & ~3; + u32 config; + + info->fb_info.par = par; + + if (info->blitter_may_be_busy) + wait_for_idle(info); + + /* clear all registers that may interfere with mode setting */ + aty_st_le32(OVR_CLR, 0); + aty_st_le32(OVR_WID_LEFT_RIGHT, 0); + aty_st_le32(OVR_WID_TOP_BOTTOM, 0); + aty_st_le32(OV0_SCALE_CNTL, 0); + aty_st_le32(MPP_TB_CONFIG, 0); + aty_st_le32(MPP_GP_CONFIG, 0); + aty_st_le32(SUBPIC_CNTL, 0); + aty_st_le32(VIPH_CONTROL, 0); + aty_st_le32(I2C_CNTL_1, 0); /* turn off i2c */ + aty_st_le32(GEN_INT_CNTL, 0); /* turn off interrupts */ + aty_st_le32(CAP0_TRIG_CNTL, 0); + aty_st_le32(CAP1_TRIG_CNTL, 0); + + aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */ + + aty128_set_crtc(&par->crtc, info); + aty128_set_pll(&par->pll, info); + aty128_set_fifo(&par->fifo_reg, info); + + config = aty_ld_le32(CONFIG_CNTL) & ~3; #if defined(__BIG_ENDIAN) - if (par->crtc.bpp >= 24) - config |= 2; /* make aperture do 32 byte swapping */ - else if (par->crtc.bpp > 8) - config |= 1; /* make aperture do 16 byte swapping */ + if (par->crtc.bpp >= 24) + config |= 2; /* make aperture do 32 byte swapping */ + else if (par->crtc.bpp > 8) + config |= 1; /* make aperture do 16 byte swapping */ #endif - aty_st_le32(CONFIG_CNTL, config); - aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ + aty_st_le32(CONFIG_CNTL, config); + aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ - if (info->var.accel_flags & FB_ACCELF_TEXT) - aty128_init_engine(par, info); + if (par->accel_flags & FB_ACCELF_TEXT) + aty128_init_engine(par, info); #if defined(CONFIG_BOOTX_TEXT) - btext_update_display(info->fix.smem_start, - (((par->crtc.h_total >> 16) & 0xff) + 1) * 8, - ((par->crtc.v_total >> 16) & 0x7ff) + 1, - par->crtc.bpp, - par->crtc.vxres * par->crtc.bpp / 8); -#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; + btext_update_display(info->fb_info.fix.smem_start, + (((par->crtc.h_total>>16) & 0xff)+1)*8, + ((par->crtc.v_total>>16) & 0x7ff)+1, + par->crtc.bpp, + par->crtc.vxres*par->crtc.bpp/8); +#endif /* CONFIG_BOOTX_TEXT */ } /* @@ -1153,221 +1226,353 @@ aty128fb_set_par(struct fb_info *info) static int 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))) - return err; + if ((err = aty128_var_to_crtc(var, &par->crtc, info))) + return err; - if ((err = aty128_var_to_pll(var->pixclock, &par->pll, par))) - return err; + if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info))) + return err; - if ((err = - aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, - info))) - return err; - return 0; + if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp, info))) + return err; + + if (var->accel_flags & FB_ACCELF_TEXT) + par->accel_flags = FB_ACCELF_TEXT; + else + par->accel_flags = 0; + + return 0; } + 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; - /* basic (in)sanity checks */ - if (!var->xres) - var->xres = 1; - if (!var->yres) - var->yres = 1; - if (var->xres > var->xres_virtual) - var->xres_virtual = var->xres; - if (var->yres > var->yres_virtual) - var->yres_virtual = var->yres; - - switch (var->bits_per_pixel) { - case 0 ... 8: - var->bits_per_pixel = 8; - break; - case 9 ... 16: - var->bits_per_pixel = 16; - break; - case 17 ... 24: - var->bits_per_pixel = 24; - break; - case 25 ... 32: - var->bits_per_pixel = 32; - break; - default: - return -EINVAL; - } + if ((err = aty128_crtc_to_var(&par->crtc, var))) + return err; - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; + if ((err = aty128_pll_to_var(&par->pll, var, info))) + return err; - var->nonstd = 0; - var->activate = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; - var->height = -1; - var->width = -1; + var->nonstd = 0; + var->activate = 0; - if ((err = aty128_decode_var(var, par, info))) - return err; - - if ((err = aty128_crtc_to_var(&par->crtc, var))) - return err; + var->height = -1; + var->width = -1; + var->accel_flags = par->accel_flags; - if ((err = aty128_pll_to_var(&par->pll, var, info))) - return err; - return 0; + 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; } + /* - * Pan or Wrap the Display - * - * Not supported (yet!) + * Set the User Defined Part of the Display */ + static int -aty128fb_pan_display(struct fb_var_screeninfo *var, int con, - struct fb_info *info) +aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb) { - struct aty128fb_par *par = (struct aty128fb_par *) info->par; - u32 xoffset, yoffset; - u32 offset; - u32 xres, yres; + 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 */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->xres > var->xres_virtual) + var->xres_virtual = var->xres; + if (var->yres > var->yres_virtual) + var->yres_virtual = var->yres; + + switch (var->bits_per_pixel) { + case 0 ... 8: + var->bits_per_pixel = 8; + break; + case 9 ... 16: + var->bits_per_pixel = 16; + break; + case 17 ... 24: + var->bits_per_pixel = 24; + break; + case 25 ... 32: + var->bits_per_pixel = 32; + break; + default: + return -EINVAL; + } + + if ((err = aty128_decode_var(var, &par, info))) + return err; + + aty128_encode_var(var, &par, info); + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) + return 0; + + oldxres = display->var.xres; + 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; - xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; - yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; + if (info->fb_info.changevar) + (*info->fb_info.changevar)(con); + } - xoffset = (var->xoffset + 7) & ~7; - yoffset = var->yoffset; + if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con) + aty128_set_par(&par, info); - if (xoffset + xres > info->var.xres_virtual - || yoffset + yres > par->crtc.vyres) - return -EINVAL; + if (oldbpp != var->bits_per_pixel) { + if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) + return err; + do_install_cmap(con, &info->fb_info); + } - par->crtc.xoffset = xoffset; - par->crtc.yoffset = yoffset; + return 0; +} - offset = - ((yoffset * info->var.xres_virtual + xoffset) * par->crtc.bpp) >> 6; - aty_st_le32(CRTC_OFFSET, offset); +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; + } +} - return 0; + +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; } + /* - * Accelerated functions + * 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; +} -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; - 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); + /* + * Pan or Wrap the Display + * + * Not supported (yet!) + */ +static int +aty128fb_pan_display(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 aty128fb_par *) fb->par; + u32 xoffset, yoffset; + u32 offset; + u32 xres, yres; + + xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; + yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1; + + xoffset = (var->xoffset +7) & ~7; + yoffset = var->yoffset; + + if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres) + return -EINVAL; - 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); + par->crtc.xoffset = xoffset; + par->crtc.yoffset = yoffset; - aty_st_le32(DST_Y_X, (dsty << 16) | dstx); - aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); + offset = ((yoffset * par->crtc.vxres + xoffset) * par->crtc.bpp) >> 6; - par->blitter_may_be_busy = 1; + aty_st_le32(CRTC_OFFSET, offset); - wait_for_fifo(2, par); - aty_st_le32(DP_DATATYPE, save_dp_datatype); - aty_st_le32(DP_CNTL, save_dp_cntl); + return 0; } -static int aty128fb_rasterimg(struct fb_info *info, int start) +static int +aty128fb_rasterimg(struct fb_info *info, int start) { - struct aty128fb_par *par = (struct aty128fb_par *) info->par; + struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; - if (par->blitter_may_be_busy) - wait_for_idle(par); - return 0; + if (fb->blitter_may_be_busy) + wait_for_idle(fb); + + return 0; } -int __init aty128fb_setup(char *options) +int __init +aty128fb_setup(char *options) { - char *this_opt; + char *this_opt; - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!strncmp(this_opt, "font:", 5)) { - char *p; - int i; + if (!options || !*options) + return 0; - p = this_opt + 5; - for (i = 0; i < sizeof(fontname) - 1; i++) - if (!*p || *p == ' ' || *p == ',') - break; - memcpy(fontname, this_opt + 5, i); - fontname[i] = 0; - } + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "font:", 5)) { + char *p; + int i; + + p = this_opt +5; + for (i = 0; i < sizeof(fontname) - 1; i++) + if (!*p || *p == ' ' || *p == ',') + break; + memcpy(fontname, this_opt + 5, i); + fontname[i] = 0; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } #ifdef CONFIG_MTRR - else if (!strncmp(this_opt, "nomtrr", 6)) { - mtrr = 0; - } + else if(!strncmp(this_opt, "nomtrr", 6)) { + mtrr = 0; + } #endif #ifdef CONFIG_PPC - /* vmode and cmode depreciated */ - else if (!strncmp(this_opt, "vmode:", 6)) { - unsigned int vmode = - simple_strtoul(this_opt + 6, NULL, 0); - if (vmode > 0 && vmode <= VMODE_MAX) - default_vmode = vmode; - } else if (!strncmp(this_opt, "cmode:", 6)) { - unsigned int cmode = - simple_strtoul(this_opt + 6, NULL, 0); - switch (cmode) { - case 0: - case 8: - default_cmode = CMODE_8; - break; - case 15: - case 16: - default_cmode = CMODE_16; - break; - case 24: - case 32: - default_cmode = CMODE_32; - break; - } - } -#endif /* CONFIG_PPC */ - else - mode_option = this_opt; - } - return 0; + /* vmode and cmode depreciated */ + else if (!strncmp(this_opt, "vmode:", 6)) { + unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); + if (vmode > 0 && vmode <= VMODE_MAX) + default_vmode = vmode; + } else if (!strncmp(this_opt, "cmode:", 6)) { + unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0); + switch (cmode) { + case 0: + case 8: + default_cmode = CMODE_8; + break; + case 15: + case 16: + default_cmode = CMODE_16; + break; + case 24: + case 32: + default_cmode = CMODE_32; + break; + } + } +#endif /* CONFIG_PPC */ + else + mode_option = this_opt; + } + return 0; } @@ -1376,175 +1581,180 @@ int __init aty128fb_setup(char *options) */ static int __init -aty128_init(struct fb_info *info, struct aty128fb_par *par, - struct pci_dev *pdev, const char *name) +aty128_init(struct fb_info_aty128 *info, struct aty128fb_par *par, struct pci_dev *pdev, const char *name) { - struct fb_var_screeninfo var; - u32 dac; - int size; - u8 chip_rev; - const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; - char *video_card = "Rage128"; + struct fb_var_screeninfo var; + u32 dac; + int size; + u8 chip_rev; + const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; + char *video_card = "Rage128"; - if (!info->fix.smem_len) /* may have already been probed */ - info->fix.smem_len = - aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; + if (!info->fb_info.fix.smem_len) /* may have already been probed */ + info->fb_info.fix.smem_len = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; #ifdef CONFIG_MTRR if (mtrr) { - par->mtrr.vram = mtrr_add(info->fix.smem_start, - info->fix.smem_len, - MTRR_TYPE_WRCOMB, 1); + par->mtrr.vram = mtrr_add(info->fb_info.fix.smem_start, + info->fb_info.fix.smem_len, MTRR_TYPE_WRCOMB, 1); par->mtrr.vram_valid = 1; /* let there be speed */ printk(KERN_INFO "aty128fb: Rage128 MTRR set to ON\n"); } -#endif /* CONFIG_MTRR */ +#endif /* CONFIG_MTRR */ + + /* Get the chip revision */ + chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; + + /* put a name with the face */ + while (aci->name && pdev->device != aci->device) { aci++; } + video_card = (char *)aci->name; + info->chip_gen = aci->chip_gen; + + printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev); + + if (info->fb_info.fix.smem_len % (1024 * 1024) == 0) + printk("%dM %s\n", info->fb_info.fix.smem_len / (1024*1024), info->mem->name); + else + printk("%dk %s\n", info->fb_info.fix.smem_len / 1024, info->mem->name); + + /* fill in info */ + strcpy(info->fb_info.modename, info->fb_info.fix.id); + info->fb_info.node = NODEV; + info->fb_info.fbops = &aty128fb_ops; + strcpy(info->fb_info.fontname, fontname); + info->fb_info.changevar = NULL; + info->fb_info.switch_con = &aty128fbcon_switch; + info->fb_info.updatevar = NULL; + info->fb_info.flags = FBINFO_FLAG_DEFAULT; + + var = default_var; +#ifdef CONFIG_PPC + if (_machine == _MACH_Pmac) { + if (mode_option) { + if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) + var = default_var; + } else { + if (default_vmode <= 0 || default_vmode > VMODE_MAX) + default_vmode = VMODE_1024_768_60; + + /* iMacs need that resolution + * PowerMac2,1 first r128 iMacs + * PowerMac2,2 summer 2000 iMacs + * PowerMac4,1 january 2001 iMacs "flower power" + */ + if (machine_is_compatible("PowerMac2,1") || + machine_is_compatible("PowerMac2,2") || + machine_is_compatible("PowerMac4,1")) + default_vmode = VMODE_1024_768_75; + + /* iBook SE */ + if (machine_is_compatible("PowerBook2,2")) + default_vmode = VMODE_800_600_60; + + /* PowerBook Firewire (Pismo), iBook Dual USB */ + if (machine_is_compatible("PowerBook3,1") || + machine_is_compatible("PowerBook4,1")) + default_vmode = VMODE_1024_768_60; + + /* PowerBook Titanium */ + if (machine_is_compatible("PowerBook3,2")) + default_vmode = VMODE_1152_768_60; + + if (default_cmode < CMODE_8 || default_cmode > CMODE_32) + default_cmode = CMODE_8; + + if (mac_vmode_to_var(default_vmode, default_cmode, &var)) + var = default_var; + } + } else +#endif /* CONFIG_PPC */ + { + if (fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, + &defaultmode, 8) == 0) + var = default_var; + } + + if (noaccel) + var.accel_flags &= ~FB_ACCELF_TEXT; + else + var.accel_flags |= FB_ACCELF_TEXT; + + if (aty128_decode_var(&var, par, info)) { + printk(KERN_ERR "aty128fb: Cannot set default mode.\n"); + return 0; + } - /* Get the chip revision */ - chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F; + /* setup the DAC the way we like it */ + dac = aty_ld_le32(DAC_CNTL); + dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL); + dac |= DAC_MASK; + aty_st_le32(DAC_CNTL, dac); - /* put a name with the face */ - while (aci->name && pdev->device != aci->device) { - aci++; - } - video_card = (char *) aci->name; - par->chip_gen = aci->chip_gen; + /* turn off bus mastering, just in case */ + aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS); - printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, - chip_rev); + aty128fb_set_var(&var, -1, &info->fb_info); + aty128_init_engine(par, info); - if (info->fix.smem_len % (1024 * 1024) == 0) - printk("%dM %s\n", - info->fix.smem_len / (1024 * 1024), - par->mem->name); - else - printk("%dk %s\n", info->fix.smem_len / 1024, - par->mem->name); - - /* fill in info */ - strcpy(info->modename, info->fix.id); - info->node = NODEV; - info->fbops = &aty128fb_ops; - strcpy(info->fontname, fontname); - info->changevar = NULL; - info->switch_con = gen_switch; - info->updatevar = NULL; - info->flags = FBINFO_FLAG_DEFAULT; - - var = default_var; -#ifdef CONFIG_PPC - if (_machine == _MACH_Pmac) { - if (mode_option) { - if (!mac_find_mode - (&var, info, mode_option, 8)) - var = default_var; - } else { - if (default_vmode <= 0 - || default_vmode > VMODE_MAX) - default_vmode = VMODE_1024_768_60; - - /* iMacs need that resolution - * PowerMac2,1 first r128 iMacs - * PowerMac2,2 summer 2000 iMacs - * PowerMac4,1 january 2001 iMacs "flower power" - */ - if (machine_is_compatible("PowerMac2,1") || - machine_is_compatible("PowerMac2,2") || - machine_is_compatible("PowerMac4,1")) - default_vmode = VMODE_1024_768_75; - - /* iBook SE */ - if (machine_is_compatible("PowerBook2,2")) - default_vmode = VMODE_800_600_60; - - /* PowerBook Firewire (Pismo), iBook Dual USB */ - if (machine_is_compatible("PowerBook3,1") || - machine_is_compatible("PowerBook4,1")) - default_vmode = VMODE_1024_768_60; - - /* PowerBook Titanium */ - if (machine_is_compatible("PowerBook3,2")) - default_vmode = VMODE_1152_768_60; - - if (default_cmode < CMODE_8 - || default_cmode > CMODE_32) - default_cmode = CMODE_8; - - if (mac_vmode_to_var - (default_vmode, default_cmode, &var)) - var = default_var; - } - } else -#endif /* CONFIG_PPC */ - { - if (fb_find_mode - (&var, info, mode_option, NULL, 0, - &defaultmode, 8) == 0) - var = default_var; - } - - var.accel_flags |= FB_ACCELF_TEXT; + board_list = aty128_board_list_add(board_list, info); - info->var = var; + size = (var.bits_per_pixel <= 8) ? 256 : 32; + fb_alloc_cmap(&info->fb_info.cmap, size, 0); - if (aty128_decode_var(&var, par, info)) { - printk(KERN_ERR "aty128fb: Cannot set default mode.\n"); - return 0; - } - - /* setup the DAC the way we like it */ - dac = aty_ld_le32(DAC_CNTL); - dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL); - dac |= DAC_MASK; - aty_st_le32(DAC_CNTL, dac); + if (register_framebuffer(&info->fb_info) < 0) + return 0; - /* turn off bus mastering, just in case */ - aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS); +#ifdef CONFIG_PMAC_BACKLIGHT + /* Could be extended to Rage128Pro LVDS output too */ + if (info->chip_gen == rage_M3) + register_backlight_controller(&aty128_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ - gen_set_var(&var, -1, info); - aty128_init_engine(par, info); + printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", + GET_FB_IDX(info->fb_info.node), info->fb_info.fix.id, name); - size = (var.bits_per_pixel <= 8) ? 256 : 32; - fb_alloc_cmap(&info->cmap, size, 0); + return 1; /* success! */ +} - if (register_framebuffer(info) < 0) - return 0; -#ifdef CONFIG_PMAC_BACKLIGHT - /* Could be extended to Rage128Pro LVDS output too */ - if (info->chip_gen == rage_M3) - register_backlight_controller(&aty128_backlight_controller, - par, "ati"); -#endif /* CONFIG_PMAC_BACKLIGHT */ +/* 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; - printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", - GET_FB_IDX(info->node), info->fix.id, name); + 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 1; /* success! */ + return board_list; } -int __init aty128fb_init(void) + +int __init +aty128fb_init(void) { #ifdef CONFIG_PCI - struct pci_dev *pdev = NULL; - const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; - - while (aci->name != NULL) { - pdev = - pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); - while (pdev != NULL) { - if (aty128_pci_register(pdev, aci) == 0) - return 0; - pdev = - pci_find_device(PCI_VENDOR_ID_ATI, aci->device, - pdev); - } - aci++; - } + struct pci_dev *pdev = NULL; + const struct aty128_chip_info *aci = &aty128_pci_probe_list[0]; + + while (aci->name != NULL) { + pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); + while (pdev != NULL) { + if (aty128_pci_register(pdev, aci) == 0) + return 0; + pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev); + } + aci++; + } #endif - return 0; + return 0; } @@ -1552,143 +1762,134 @@ int __init aty128fb_init(void) /* register a card ++ajoshi */ static int __init 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 *info = NULL; + struct fb_info_aty128 *info = NULL; + struct aty128fb_par *par; + int err; #if !defined(CONFIG_PPC) && !defined(__sparc__) char *bios_seg = NULL; #endif - int err; /* Enable device in PCI config */ if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n", - err); + err); goto err_out; } aty128fb_fix.smem_start = pci_resource_start(pdev, 0); - if (!request_mem_region - (aty128fb_fix.smem_start, pci_resource_len(pdev, 0), - "aty128fb FB")) { + if (!request_mem_region(aty128fb_fix.smem_start, pci_resource_len(pdev, 0), + "aty128fb FB")) { printk(KERN_ERR "aty128fb: cannot reserve frame " - "buffer memory\n"); + "buffer memory\n"); goto err_free_fb; } aty128fb_fix.mmio_start = pci_resource_start(pdev, 2); - if (!request_mem_region - (aty128fb_fix.mmio_start, pci_resource_len(pdev, 2), - "aty128fb MMIO")) { + if (!request_mem_region(aty128fb_fix.mmio_start, pci_resource_len(pdev, 2), + "aty128fb MMIO")) { printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n"); goto err_free_mmio; } /* We have the resources. Now virtualize them */ - if (! - (info = - kmalloc(sizeof(struct fb_info) + - sizeof(struct display) + sizeof(u32) * 17, - GFP_ATOMIC))) { - printk(KERN_ERR "aty128fb: can't alloc fb_info\n"); + if (!(info = kmalloc(sizeof(struct fb_info_aty128) + sizeof(struct display) + sizeof(u32) * 17, GFP_ATOMIC))) { + printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n"); goto err_unmap_out; } - if (!(par = kmalloc(sizeof(struct aty128fb_par), GFP_ATOMIC))) { + if (!(par = kmalloc(sizeof(struct aty128fb_par), GFP_ATOMIC))) { printk(KERN_ERR "aty128fb: can't alloc aty128fb_par\n"); 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)); - info->disp = (struct display *) (info + 1); - info->pseudo_palette = (void *) (info->disp + 1); - info->par = par; + info->fb_info.disp = (struct display *)(info + 1); + info->fb_info.pseudo_palette = (void *)(info->fb_info.disp + 1); + info->fb_info.par = par; - info->currcon = -1; - info->fix = aty128fb_fix; + info->fb_info.currcon = -1; + info->fb_info.fix = aty128fb_fix; /* 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; /* Grab memory size from the card */ - info->fix.smem_len = - aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; + info->fb_info.fix.smem_len = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF; /* Virtualize the framebuffer */ - info->screen_base = - ioremap(aty128fb_fix.smem_start, info->fix.smem_len); + info->fb_info.screen_base = ioremap(aty128fb_fix.smem_start, info->fb_info.fix.smem_len); - if (!info->screen_base) { - iounmap((void *) par->regbase); + if (!info->fb_info.screen_base) { + iounmap((void *)info->regbase); goto err_free_info; } /* If we can't test scratch registers, something is seriously wrong */ - if (!register_test(par)) { - printk(KERN_ERR - "aty128fb: Can't write to video register!\n"); + if (!register_test(info)) { + printk(KERN_ERR "aty128fb: Can't write to video register!\n"); goto err_out; } + #if !defined(CONFIG_PPC) && !defined(__sparc__) if (!(bios_seg = aty128find_ROM(info))) printk(KERN_INFO "aty128fb: Rage128 BIOS not located. " - "Guessing...\n"); + "Guessing...\n"); else { printk(KERN_INFO "aty128fb: Rage128 BIOS located at " - "segment %4.4X\n", (unsigned int) bios_seg); - aty128_get_pllinfo(par, bios_seg); + "segment %4.4X\n", (unsigned int)bios_seg); + aty128_get_pllinfo(info, bios_seg); } #endif - aty128_timings(par); + aty128_timings(info); if (!aty128_init(info, par, pdev, "PCI")) goto err_out; return 0; - err_out: - iounmap(info->screen_base); - iounmap(par->regbase); - err_free_info: +err_out: + iounmap(info->fb_info.screen_base); + iounmap(info->regbase); +err_free_info: kfree(info); - err_unmap_out: +err_unmap_out: release_mem_region(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); - err_free_mmio: + pci_resource_len(pdev, 2)); +err_free_mmio: release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - err_free_fb: + pci_resource_len(pdev, 0)); +err_free_fb: release_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); + pci_resource_len(pdev, 1)); return -ENODEV; } -#endif /* CONFIG_PCI */ +#endif /* CONFIG_PCI */ /* PPC and Sparc cannot read video ROM */ #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; - int stage; - int i; - char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */ - char R128_sig[] = "R128"; /* Rage128 ROM identifier */ + int stage; + int i; + char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */ + char R128_sig[] = "R128"; /* Rage128 ROM identifier */ - for (segstart = 0x000c0000; segstart < 0x000f0000; - segstart += 0x00001000) { - stage = 1; + for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { + stage = 1; - rom_base = (char *) ioremap(segstart, 0x1000); + rom_base = (char *)ioremap(segstart, 0x1000); - if ((*rom_base == 0x55) - && (((*(rom_base + 1)) & 0xff) == 0xaa)) + if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) stage = 2; if (stage != 2) { @@ -1697,12 +1898,10 @@ static char __init * aty128find_ROM(struct fb_info *info) } rom = rom_base; - for (i = 0; - (i < 128 - strlen(aty_rom_sig)) && (stage != 3); - i++) { + for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) { if (aty_rom_sig[0] == *rom) if (strncmp(aty_rom_sig, rom, - strlen(aty_rom_sig)) == 0) + strlen(aty_rom_sig)) == 0) stage = 3; rom++; } @@ -1715,8 +1914,8 @@ static char __init * aty128find_ROM(struct fb_info *info) /* ATI signature found. Let's see if it's a Rage128 */ for (i = 0; (i < 512) && (stage != 4); i++) { if (R128_sig[0] == *rom) - if (strncmp(R128_sig, rom, - strlen(R128_sig)) == 0) + if (strncmp(R128_sig, rom, + strlen(R128_sig)) == 0) stage = 4; rom++; } @@ -1733,7 +1932,7 @@ static char __init * aty128find_ROM(struct fb_info *info) 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 *header_ptr; @@ -1741,7 +1940,7 @@ aty128_get_pllinfo(struct aty128fb_par *par, char *bios_seg) PLL_BLOCK pll; bios_header = bios_seg + 0x48L; - header_ptr = bios_header; + header_ptr = bios_header; bios_header_offset = readw(header_ptr); bios_header = bios_seg + bios_header_offset; @@ -1753,114 +1952,145 @@ aty128_get_pllinfo(struct aty128fb_par *par, char *bios_seg) memcpy_fromio(&pll, header_ptr, 50); - par->constants.ppll_max = pll.PCLK_max_freq; - par->constants.ppll_min = pll.PCLK_min_freq; - par->constants.xclk = (u32) pll.XCLK; - par->constants.ref_divider = (u32) pll.PCLK_ref_divider; - par->constants.dotclock = (u32) pll.PCLK_ref_freq; + info->constants.ppll_max = pll.PCLK_max_freq; + info->constants.ppll_min = pll.PCLK_min_freq; + info->constants.xclk = (u32)pll.XCLK; + info->constants.ref_divider = (u32)pll.PCLK_ref_divider; + info->constants.dotclock = (u32)pll.PCLK_ref_freq; DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n", - par->constants.ppll_max, par->constants.ppll_min, - par->constants.xclk, par->constants.ref_divider, - par->constants.dotclock); + info->constants.ppll_max, info->constants.ppll_min, + info->constants.xclk, info->constants.ref_divider, + info->constants.dotclock); -} -#endif /* !CONFIG_PPC */ +} +#endif /* !CONFIG_PPC */ /* 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 - /* instead of a table lookup, assume OF has properly - * setup the PLL registers and use their values - * to set the XCLK values and reference divider values */ - - u32 x_mpll_ref_fb_div; - u32 xclk_cntl; - u32 Nx, M; - unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 }; + /* instead of a table lookup, assume OF has properly + * setup the PLL registers and use their values + * to set the XCLK values and reference divider values */ + + u32 x_mpll_ref_fb_div; + u32 xclk_cntl; + u32 Nx, M; + unsigned PostDivSet[] = + { 0, 1, 2, 4, 8, 3, 6, 12 }; #endif - if (!par->constants.dotclock) - par->constants.dotclock = 2950; + if (!info->constants.dotclock) + info->constants.dotclock = 2950; #ifdef CONFIG_PPC - x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); - xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; - Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; - M = x_mpll_ref_fb_div & 0x0000ff; + x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); + xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; + Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; + M = x_mpll_ref_fb_div & 0x0000ff; - par->constants.xclk = round_div((2 * Nx * - par->constants.dotclock), - (M * PostDivSet[xclk_cntl])); + info->constants.xclk = round_div((2 * Nx * + info->constants.dotclock), (M * PostDivSet[xclk_cntl])); - par->constants.ref_divider = - aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; + info->constants.ref_divider = + aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK; #endif - if (!par->constants.ref_divider) { - par->constants.ref_divider = 0x3b; + if (!info->constants.ref_divider) { + info->constants.ref_divider = 0x3b; + + aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); + aty_pll_writeupdate(info); + } + aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider); + aty_pll_writeupdate(info); + + /* from documentation */ + if (!info->constants.ppll_min) + info->constants.ppll_min = 12500; + if (!info->constants.ppll_max) + info->constants.ppll_max = 25000; /* 23000 on some cards? */ + if (!info->constants.xclk) + info->constants.xclk = 0x1d4d; /* same as mclk */ + + info->constants.fifo_width = 128; + info->constants.fifo_depth = 32; + + switch (aty_ld_le32(MEM_CNTL) & 0x3) { + case 0: + info->mem = &sdr_128; + break; + case 1: + info->mem = &sdr_sgram; + break; + case 2: + info->mem = &ddr_sgram; + break; + default: + info->mem = &sdr_sgram; + } +} - aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); - aty_pll_writeupdate(par); - } - aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider); - aty_pll_writeupdate(par); - - /* from documentation */ - if (!par->constants.ppll_min) - par->constants.ppll_min = 12500; - if (!par->constants.ppll_max) - par->constants.ppll_max = 25000; /* 23000 on some cards? */ - if (!par->constants.xclk) - par->constants.xclk = 0x1d4d; /* same as mclk */ - - par->constants.fifo_width = 128; - par->constants.fifo_depth = 32; - - switch (aty_ld_le32(MEM_CNTL) & 0x3) { - case 0: - par->mem = &sdr_128; - break; - case 1: - par->mem = &sdr_sgram; - break; - case 2: - par->mem = &ddr_sgram; - break; - default: - par->mem = &sdr_sgram; - } + +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. */ -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; - u8 state = 0; + struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; + u8 state = 0; #ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && blank) - set_backlight_enable(0); -#endif /* CONFIG_PMAC_BACKLIGHT */ + if ((_machine == _MACH_Pmac) && blank) + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ - if (blank & VESA_VSYNC_SUSPEND) - state |= 2; - if (blank & VESA_HSYNC_SUSPEND) - state |= 1; - if (blank & VESA_POWERDOWN) - state |= 4; + if (blank & VESA_VSYNC_SUSPEND) + state |= 2; + if (blank & VESA_HSYNC_SUSPEND) + state |= 1; + if (blank & VESA_POWERDOWN) + state |= 4; - aty_st_8(CRTC_EXT_CNTL + 1, state); + aty_st_8(CRTC_EXT_CNTL+1, state); #ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && !blank) - set_backlight_enable(1); -#endif /* CONFIG_PMAC_BACKLIGHT */ - return 0; + if ((_machine == _MACH_Pmac) && !blank) + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ + return 0; } /* @@ -1870,94 +2100,90 @@ static int aty128fb_blank(int blank, 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) + u_int transp, struct fb_info *fb) { - struct aty128fb_par *par = (struct aty128fb_par *) info->par; - u32 col; - - if (regno > 255) - return 1; - - red >>= 8; - green >>= 8; - blue >>= 8; - - /* Note: For now, on M3, we set palette on both heads, which may - * be useless. Can someone with a M3 check this ? */ - - /* initialize gamma ramp for hi-color+ */ - - if ((par->crtc.bpp > 8) && (regno == 0)) { - int i; - - if (par->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, - aty_ld_le32(DAC_CNTL) & - ~DAC_PALETTE_ACCESS_CNTL); - - for (i = 16; i < 256; i++) { - aty_st_8(PALETTE_INDEX, i); - col = (i << 16) | (i << 8) | i; - aty_st_le32(PALETTE_DATA, col); - } - - if (par->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, - aty_ld_le32(DAC_CNTL) | - DAC_PALETTE_ACCESS_CNTL); - - for (i = 16; i < 256; i++) { - aty_st_8(PALETTE_INDEX, i); - col = (i << 16) | (i << 8) | i; - aty_st_le32(PALETTE_DATA, col); - } - } - } - - /* initialize palette */ - - if (par->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, - aty_ld_le32(DAC_CNTL) & - ~DAC_PALETTE_ACCESS_CNTL); - - if (par->crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); - col = (red << 16) | (green << 8) | blue; - aty_st_le32(PALETTE_DATA, col); - if (par->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, - aty_ld_le32(DAC_CNTL) | - DAC_PALETTE_ACCESS_CNTL); - if (par->crtc.bpp == 16) - aty_st_8(PALETTE_INDEX, (regno << 3)); - else - aty_st_8(PALETTE_INDEX, regno); - aty_st_le32(PALETTE_DATA, col); + struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; + struct aty128fb_par *par = (struct aty128fb_par *) fb->par; + u32 col; + + if (regno > 255) + return 1; + + red >>= 8; + green >>= 8; + blue >>= 8; + + /* Note: For now, on M3, we set palette on both heads, which may + * be useless. Can someone with a M3 check this ? */ + + /* initialize gamma ramp for hi-color+ */ + + if ((par->crtc.bpp > 8) && (regno == 0)) { + int i; + + if (info->chip_gen == rage_M3) + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + + for (i=16; i<256; i++) { + aty_st_8(PALETTE_INDEX, i); + col = (i << 16) | (i << 8) | i; + aty_st_le32(PALETTE_DATA, col); + } + + if (info->chip_gen == rage_M3) { + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); + + for (i=16; i<256; i++) { + aty_st_8(PALETTE_INDEX, i); + col = (i << 16) | (i << 8) | i; + aty_st_le32(PALETTE_DATA, col); + } + } + } + + /* initialize palette */ + + if (info->chip_gen == rage_M3) + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); + + if (par->crtc.bpp == 16) + aty_st_8(PALETTE_INDEX, (regno << 3)); + else + aty_st_8(PALETTE_INDEX, regno); + col = (red << 16) | (green << 8) | blue; + aty_st_le32(PALETTE_DATA, col); + if (info->chip_gen == rage_M3) { + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); + if (par->crtc.bpp == 16) + aty_st_8(PALETTE_INDEX, (regno << 3)); + else + aty_st_8(PALETTE_INDEX, regno); + aty_st_le32(PALETTE_DATA, col); + } + + if (regno < 16) + switch (par->crtc.bpp) { +#ifdef FBCON_HAS_CFB16 + case 9 ... 16: + ((u32*) (info->fb_info.pseudo_palette))[regno] = (regno << 10) | (regno << 5) | regno; + break; +#endif +#ifdef FBCON_HAS_CFB24 + case 17 ... 24: + ((u32*) (info->fb_info.pseudo_palette))[regno] = (regno << 16) | (regno << 8) | regno; + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 25 ... 32: { + u32 i; + + i = (regno << 8) | regno; + ((u32*) (info->fb_info.pseudo_palette))[regno] = (i << 16) | i; + break; + } +#endif } - - if (regno < 16) - switch (par->crtc.bpp) { - case 9 ... 16: - ((u32 *) (info->pseudo_palette))[regno] = - (regno << 10) | (regno << 5) | regno; - break; - case 17 ... 24: - ((u32 *) (info->pseudo_palette))[regno] = - (regno << 16) | (regno << 8) | regno; - break; - case 25 ... 32:{ - u32 i; - - i = (regno << 8) | regno; - ((u32 *) (info->pseudo_palette))[regno] = - (i << 16) | i; - break; - } - } - return 0; + return 0; } #ifdef CONFIG_PMAC_BACKLIGHT @@ -1966,11 +2192,12 @@ static int backlight_conv[] = { 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); - + reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (on && level > BACKLIGHT_OFF) { reg &= ~LVDS_BL_MOD_LEVEL_MASK; @@ -1984,11 +2211,12 @@ static int aty128_set_backlight_enable(int on, int level, void *data) return 0; } -static int aty128_set_backlight_level(int level, void *data) +static int +aty128_set_backlight_level(int level, void* data) { return aty128_set_backlight_enable(1, level, data); } -#endif /* CONFIG_PMAC_BACKLIGHT */ +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Accelerated functions @@ -1996,107 +2224,328 @@ static int aty128_set_backlight_level(int level, void *data) static inline void aty128_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; - 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; - } + u_int width, u_int height, + struct fb_info_aty128 *info) +{ + struct aty128fb_par *par = (struct aty128fb_par *) info->fb_info.par; + 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, info); + save_dp_datatype = aty_ld_le32(DP_DATATYPE); + save_dp_cntl = aty_ld_le32(DP_CNTL); + + wait_for_fifo(6, info); + 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); + + info->blitter_may_be_busy = 1; + + wait_for_fifo(2, info); + aty_st_le32(DP_DATATYPE, save_dp_datatype); + 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); +} - 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); +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); - aty_st_le32(DST_Y_X, (dsty << 16) | dstx); - aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); + 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); - par->blitter_may_be_busy = 1; + if (fb->blitter_may_be_busy) + wait_for_idle(fb); - wait_for_fifo(2, par); - aty_st_le32(DP_DATATYPE, save_dp_datatype); - aty_st_le32(DP_CNTL, save_dp_cntl); + 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 MODULE_AUTHOR("(c)1999-2000 Brad Douglas <brad@neruo.com>"); MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards"); 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_DESC(font, - "Specify one of the compiled-in fonts (default=none)"); +MODULE_PARM_DESC(font, "Specify one of the compiled-in fonts (default=none)"); MODULE_PARM(mode, "s"); -MODULE_PARM_DESC(mode, - "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); +MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); #ifdef CONFIG_MTRR MODULE_PARM(nomtrr, "i"); -MODULE_PARM_DESC(nomtrr, - "Disable MTRR support (0 or 1=disabled) (default=0)"); +MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)"); #endif -int __init init_module(void) +int __init +init_module(void) { - if (font) { - strncpy(fontname, font, sizeof(fontname) - 1); - printk(KERN_INFO "aty128fb: Parameter FONT set to %s\n", - font); - } - if (mode) { - mode_option = mode; - printk(KERN_INFO "aty128fb: Parameter MODE set to %s\n", - mode); - } + if (noaccel) { + noaccel = 1; + printk(KERN_INFO "aty128fb: Parameter NOACCEL set\n"); + } + if (font) { + strncpy(fontname, font, sizeof(fontname)-1); + printk(KERN_INFO "aty128fb: Parameter FONT set to %s\n", font); + } + if (mode) { + mode_option = mode; + printk(KERN_INFO "aty128fb: Parameter MODE set to %s\n", mode); + } #ifdef CONFIG_MTRR - if (nomtrr) { - mtrr = 0; - printk(KERN_INFO "aty128fb: Parameter NOMTRR set\n"); - } + if (nomtrr) { + mtrr = 0; + printk(KERN_INFO "aty128fb: Parameter NOMTRR set\n"); + } #endif - - aty128fb_init(); - return 0; + + aty128fb_init(); + return 0; } -void __exit cleanup_module(void) +void __exit +cleanup_module(void) { - struct fb_info *info = board_list; - struct aty128fb_par *par; + struct fb_info_aty128 *info = board_list; + 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 - if (par->mtrr.vram_valid) - mtrr_del(par->mtrr.vram, - info->fix.smem_start, - info->fix.smem_len); -#endif /* CONFIG_MTRR */ - iounmap(par->regbase); - iounmap(info->screen_base); - - release_mem_region(pci_resource_start(info->pdev, 0), - pci_resource_len(info->pdev, 0)); - release_mem_region(pci_resource_start(info->pdev, 1), - pci_resource_len(info->pdev, 1)); - release_mem_region(pci_resource_start(info->pdev, 2), - pci_resource_len(info->pdev, 2)); - kfree(info); + if (par->mtrr.vram_valid) + mtrr_del(par->mtrr.vram, info->fb_info.fix.smem_start, + info->fb_info.fix.smem_len); +#endif /* CONFIG_MTRR */ + iounmap(info->regbase); + iounmap(info->fb_info.screen_base); + + release_mem_region(pci_resource_start(info->pdev, 0), + pci_resource_len(info->pdev, 0)); + release_mem_region(pci_resource_start(info->pdev, 1), + pci_resource_len(info->pdev, 1)); + release_mem_region(pci_resource_start(info->pdev, 2), + pci_resource_len(info->pdev, 2)); + + kfree(info); + } } -#endif /* MODULE */ +#endif /* MODULE */ diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 8e348621a263..77edfb918c9a 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -1,5 +1,5 @@ /* - * 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> * @@ -25,6 +25,7 @@ * Known bugs and issues: * restoring text mode fails * doublescan modes are broken + * option 'noaccel' has no effect */ #include <linux/config.h> @@ -51,10 +52,12 @@ #error This driver requires PCI support. #endif -#include "../fbcon-accel.h" + /* version number of this driver */ -#define RIVAFB_VERSION "0.9.3" +#define RIVAFB_VERSION "0.9.2a" + + /* ------------------------------------------------------------------------- * * @@ -88,8 +91,8 @@ #define Set8Bits(value) ((value)&0xff) /* HW cursor parameters */ -#define DEFAULT_CURSOR_BLINK_RATE (20) -#define CURSOR_HIDE_DELAY (10) +#define DEFAULT_CURSOR_BLINK_RATE (40) +#define CURSOR_HIDE_DELAY (20) #define CURSOR_SHOW_DELAY (3) #define CURSOR_COLOR 0x7fff @@ -97,6 +100,7 @@ #define MAX_CURS 32 + /* ------------------------------------------------------------------------- * * * prototypes @@ -105,6 +109,11 @@ 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 @@ -127,11 +136,6 @@ enum riva_chips { CH_GEFORCE2_GTS, CH_GEFORCE2_ULTRA, CH_QUADRO2_PRO, - CH_GEFORCE2_GO, - CH_GEFORCE3, - CH_GEFORCE3_1, - CH_GEFORCE3_2, - CH_QUADRO_DDC }; /* directly indexed by riva_chips enum, above */ @@ -154,11 +158,6 @@ static struct riva_chip_info { { "GeForce2-GTS", NV_ARCH_10}, { "GeForce2-ULTRA", 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 = { @@ -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_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_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 */ }; 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 * * ------------------------------------------------------------------------- */ -struct fb_info *riva_boards = NULL; +struct rivafb_info *riva_boards = NULL; /* command line data, set in rivafb_setup() */ static char fontname[40] __initdata = { 0 }; +static char noaccel __initdata = 0; +static char nomove = 0; static char nohwcursor __initdata = 0; static char noblink = 0; #ifdef CONFIG_MTRR @@ -232,26 +265,24 @@ static char *mode_option __initdata = NULL; static char *font = NULL; #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 = { xres: 640, yres: 480, xres_virtual: 640, yres_virtual: 480, + xoffset: 0, + yoffset: 0, bits_per_pixel: 8, + grayscale: 0, red: {0, 6, 0}, green: {0, 6, 0}, blue: {0, 6, 0}, - activate: FB_ACTIVATE_NOW, + transp: {0, 0, 0}, + nonstd: 0, + activate: 0, height: -1, width: -1, - accel_flags: FB_ACCELF_TEXT, + accel_flags: 0, pixclock: 39721, left_margin: 40, right_margin: 24, @@ -259,28 +290,10 @@ static struct fb_var_screeninfo rivafb_default_var = { lower_margin: 11, hsync_len: 96, vsync_len: 2, + sync: 0, 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 */ static const struct riva_regs reg_template = { {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ATTR */ @@ -302,76 +315,78 @@ static const struct riva_regs reg_template = { 0xEB /* MISC */ }; + + /* ------------------------------------------------------------------------- * * * 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) { - VGA_WR08(par->riva.PCIO, 0x3d4, index); - VGA_WR08(par->riva.PCIO, 0x3d5, val); + VGA_WR08(rinfo->riva.PCIO, 0x3d4, index); + 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) { - VGA_WR08(par->riva.PCIO, 0x3d4, index); - return (VGA_RD08(par->riva.PCIO, 0x3d5)); + VGA_WR08(rinfo->riva.PCIO, 0x3d4, index); + 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) { - VGA_WR08(par->riva.PVIO, 0x3ce, index); - VGA_WR08(par->riva.PVIO, 0x3cf, val); + VGA_WR08(rinfo->riva.PVIO, 0x3ce, index); + 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) { - VGA_WR08(par->riva.PVIO, 0x3ce, index); - return (VGA_RD08(par->riva.PVIO, 0x3cf)); + VGA_WR08(rinfo->riva.PVIO, 0x3ce, index); + 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) { - VGA_WR08(par->riva.PVIO, 0x3c4, index); - VGA_WR08(par->riva.PVIO, 0x3c5, val); + VGA_WR08(rinfo->riva.PVIO, 0x3c4, index); + 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) { - VGA_WR08(par->riva.PVIO, 0x3c4, index); - return (VGA_RD08(par->riva.PVIO, 0x3c5)); + VGA_WR08(rinfo->riva.PVIO, 0x3c4, index); + 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) { - VGA_WR08(par->riva.PCIO, 0x3c0, index); - VGA_WR08(par->riva.PCIO, 0x3c0, val); + VGA_WR08(rinfo->riva.PCIO, 0x3c0, index); + 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) { - VGA_WR08(par->riva.PCIO, 0x3c0, index); - return (VGA_RD08(par->riva.PCIO, 0x3c1)); + VGA_WR08(rinfo->riva.PCIO, 0x3c0, index); + 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) /** * 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: * Cursor blink timer. */ static void riva_cursor_timer_handler(unsigned long dev_addr) { - struct fb_info *info = (struct fb_info *)dev_addr; - struct riva_par *par = (struct riva_par *) info->par; + struct rivafb_info *rinfo = (struct rivafb_info *)dev_addr; - 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; - par->cursor->last_slice_moves = 0; + if (rinfo->cursor->last_move_delay < 1000) + rinfo->cursor->last_move_delay++; - if (par->cursor->vbl_cnt && --par->cursor->vbl_cnt == 0) { - par->cursor->on ^= 1; - if (par->cursor->on) - *(par->riva.CURSORPOS) = (par->cursor->pos.x & 0xFFFF) - | (par->cursor->pos.y << 16); - par->riva.ShowHideCursor(&par->riva, par->cursor->on); + if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) { + rinfo->cursor->on ^= 1; + if (rinfo->cursor->on) + *(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF) + | (rinfo->cursor->pos.y << 16); + rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on); if (!noblink) - par->cursor->vbl_cnt = par->cursor->blink_rate; + rinfo->cursor->vbl_cnt = rinfo->cursor->blink_rate; } out: - par->cursor->timer->expires = jiffies + (HZ / 50); - add_timer(par->cursor->timer); + rinfo->cursor->timer->expires = jiffies + (HZ / 100); + add_timer(rinfo->cursor->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: * Allocates cursor structure and starts blink timer. @@ -428,7 +442,7 @@ out: * CALLED FROM: * 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; @@ -446,8 +460,8 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info) cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE; init_timer(cursor->timer); - cursor->timer->expires = jiffies + (HZ / 50); - cursor->timer->data = (unsigned long)info; + cursor->timer->expires = jiffies + (HZ / 100); + cursor->timer->data = (unsigned long)rinfo; cursor->timer->function = riva_cursor_timer_handler; add_timer(cursor->timer); @@ -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 - * @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: * Stops blink timer and releases cursor structure. @@ -465,9 +479,9 @@ static struct riva_cursor * __init rivafb_init_cursor(struct fb_info *info) * rivafb_init_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->timer) { @@ -475,13 +489,13 @@ static void rivafb_exit_cursor(struct riva_par *par) kfree(cursor->timer); } kfree(cursor); - par->cursor = NULL; + rinfo->cursor = 0; } } /** * 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: * Writes cursor shape into card registers. @@ -489,24 +503,24 @@ static void rivafb_exit_cursor(struct riva_par *par) * CALLED FROM: * 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 *image; - if (!par->cursor) return; + if (!rinfo->cursor) return; - image = (int *)par->cursor->image; - save = par->riva.ShowHideCursor(&par->riva, 0); + image = (int *)rinfo->cursor->image; + save = rinfo->riva.ShowHideCursor(&rinfo->riva, 0); 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 - * @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 * @height: cursor height in pixels * @@ -515,11 +529,11 @@ static void rivafb_download_cursor(struct riva_par *par) * * CALLED FROM: * 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; if (c) { @@ -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) { - struct fb_info *fb = p->fb_info; - struct riva_par *par = (struct riva_par *) fb->par; + struct rivafb_info *fb = (struct rivafb_info *)(p->fb_info); - rivafb_create_cursor(par, width, height); + rivafb_create_cursor(fb, width, height); return 1; } @@ -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) { - struct fb_info *info = p->fb_info; - struct riva_par *par = (struct riva_par *) info->par; - struct riva_cursor *c = par->cursor; + struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info); + struct riva_cursor *c = rinfo->cursor; if (!c) return; @@ -593,7 +605,7 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y) return; 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.y = y; @@ -604,15 +616,15 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y) break; case CM_DRAW: 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; } else { - *(par->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16); - par->riva.ShowHideCursor(&par->riva, 1); + *(rinfo->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16); + rinfo->riva.ShowHideCursor(&rinfo->riva, 1); if (!noblink) c->vbl_cnt = CURSOR_HIDE_DELAY; c->on = 1; } - c->last_slice_moves++; + c->last_move_delay = 0; c->enable = 1; break; } @@ -627,6 +639,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 * @chip: pointer to RIVA_HW_INST object * @regnum: register number @@ -652,7 +738,7 @@ static void riva_wclut(RIVA_HW_INST *chip, /** * 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 * * DESCRIPTION: @@ -662,36 +748,36 @@ static void riva_wclut(RIVA_HW_INST *chip, * rivafb_init_one() */ /* 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; - par->riva.LockUnlock(&par->riva, 0); + rinfo->riva.LockUnlock(&rinfo->riva, 0); - par->riva.UnloadStateExt(&par->riva, ®s->ext); + rinfo->riva.UnloadStateExt(&rinfo->riva, ®s->ext); - regs->misc_output = MISCin(par); + regs->misc_output = MISCin(rinfo); 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++) { - regs->attr[i] = ATTRin(par, i); + regs->attr[i] = ATTRin(rinfo, 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++) { - regs->seq[i] = SEQin(par, i); + regs->seq[i] = SEQin(rinfo, i); } } /** * 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 * * DESCRIPTION: @@ -703,18 +789,18 @@ static void riva_save_state(struct riva_par *par, struct riva_regs *regs) * rivafb_remove_one() */ /* 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 = ®s->ext; int i; - - CRTCout(par, 0x11, 0x00); + RIVA_HW_STATE *state = ®s->ext; + + 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++) { switch (i) { @@ -722,44 +808,44 @@ static void riva_load_state(struct riva_par *par, struct riva_regs *regs) case 0x20 ... 0x40: break; default: - CRTCout(par, i, regs->crtc[i]); + CRTCout(rinfo, i, regs->crtc[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++) { - GRAout(par, i, regs->gra[i]); + GRAout(rinfo, i, regs->gra[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 - * @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 * * DESCRIPTION: * Calculate some timings and then send em off to riva_load_state(). * * 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 riva_par *par = (struct riva_par *) info->par; struct riva_regs newmode; int bpp, width, hDisplaySize, hDisplay, hStart, hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock; /* time to calculate */ - rivafb_blank(1, info); + + rivafb_blank(1, (struct fb_info *)rinfo); bpp = video_mode->bits_per_pixel; if (bpp == 16 && video_mode->green.length == 5) @@ -813,27 +899,83 @@ static void riva_load_video_mode(struct fb_info *info, newmode.ext.width = width; 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, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock); - if (video_mode->sync & FB_SYNC_HOR_HIGH_ACT) - newmode.misc_output &= ~0x40; - if (video_mode->sync & FB_SYNC_VERT_HIGH_ACT) - newmode.misc_output &= ~0x80; + rinfo->current_state = newmode; + riva_load_state(rinfo, &rinfo->current_state); + + 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; - par->current_state = newmode; - riva_load_state(par, &par->current_state); + while (i_p->next != NULL) + i_p = i_p->next; + i_p->next = new_node; - par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */ - rivafb_download_cursor(par); + 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; + + while (i_p->next != del_node) + i_p = i_p->next; + i_p->next = del_node->next; + + return board_list; } /** * 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: + * @v: * @nom: * @den: * @@ -845,13 +987,13 @@ static void riva_load_video_mode(struct fb_info *info, * * * 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 *v, int nom, int den) { - struct riva_par *par = (struct riva_par *) info->par; static struct { int xres, yres; } modes[] = { @@ -865,12 +1007,12 @@ static int rivafb_do_maximize(struct fb_info *info, int i; /* 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 "using maximum available virtual resolution\n"); for (i = 0; modes[i].xres != -1; i++) { if (modes[i].xres * nom / den * modes[i].yres < - par->ram_amount / 2) + rinfo->ram_amount / 2) break; } if (modes[i].xres == -1) { @@ -879,26 +1021,26 @@ static int rivafb_do_maximize(struct fb_info *info, DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } - var->xres_virtual = modes[i].xres; - var->yres_virtual = modes[i].yres; + v->xres_virtual = modes[i].xres; + v->yres_virtual = modes[i].yres; printk(KERN_INFO PFX "virtual resolution set to maximum of %dx%d\n", - var->xres_virtual, var->yres_virtual); - } else if (var->xres_virtual == -1) { - var->xres_virtual = (par->ram_amount * den / - (nom * var->yres_virtual * 2)) & ~15; + v->xres_virtual, v->yres_virtual); + } else if (v->xres_virtual == -1) { + v->xres_virtual = (rinfo->ram_amount * den / + (nom * v->yres_virtual * 2)) & ~15; printk(KERN_WARNING PFX - "setting virtual X resolution to %d\n", var->xres_virtual); - } else if (var->yres_virtual == -1) { - var->xres_virtual = (var->xres_virtual + 15) & ~15; - var->yres_virtual = par->ram_amount * den / - (nom * var->xres_virtual * 2); + "setting virtual X resolution to %d\n", v->xres_virtual); + } else if (v->yres_virtual == -1) { + v->xres_virtual = (v->xres_virtual + 15) & ~15; + v->yres_virtual = rinfo->ram_amount * den / + (nom * v->xres_virtual * 2); 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 { - var->xres_virtual = (var->xres_virtual + 15) & ~15; - if (var->xres_virtual * nom / den * var->yres_virtual > par->ram_amount) { + v->xres_virtual = (v->xres_virtual + 15) & ~15; + if (v->xres_virtual * nom / den * v->yres_virtual > rinfo->ram_amount) { printk(KERN_ERR PFX "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", var->xres, var->yres, var->bits_per_pixel); @@ -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 "virtual X resolution (%d) is too high, lowering to %d\n", - var->xres_virtual, 8192 * den / nom - 16); - var->xres_virtual = 8192 * den / nom - 16; + v->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 - "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; } - if (var->yres_virtual < var->yres) { + if (v->yres_virtual < v->yres) { 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 0; } -/* acceleration routines */ - -static inline void convert_bgcolor_16(u32 *col) -{ - *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) * Length of color map * * CALLED FROM: + * riva_getcolreg() * rivafb_setcolreg() + * rivafb_get_cmap() + * rivafb_set_cmap() */ 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); switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 case 8: rc = 256; /* pseudocolor... 256 entries HW palette */ break; +#endif +#ifdef FBCON_HAS_CFB16 case 15: rc = 15; /* fix for 15 bpp depths on Riva 128 based cards */ break; case 16: rc = 16; /* directcolor... 16 entries SW palette */ break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif +#ifdef FBCON_HAS_CFB32 case 32: rc = 16; /* directcolor... 16 entries SW palette */ break; /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ +#endif default: /* should not occur */ break; @@ -1095,13 +1129,53 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var) } /** + * 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 * @regno: register index * @red: red component * @green: green component * @blue: blue component * @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: * 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) * Return != 0 for invalid regno. * * CALLED FROM: + * rivafb_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, unsigned blue, unsigned transp, struct fb_info *info) { - struct riva_par *par = (struct riva_par *) info->par; - RIVA_HW_INST *chip = &par->riva; + struct rivafb_info *rivainfo = (struct rivafb_info *)info; + RIVA_HW_INST *chip = &rivainfo->riva; + struct display *p; + + DPRINTK("ENTER\n"); - if (regno >= riva_get_cmap_len(&info->var)) + assert(rivainfo != NULL); + assert(rivainfo->currcon_display != NULL); + + p = rivainfo->currcon_display; + + if (regno >= riva_get_cmap_len(&p->var)) 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 */ red = green = blue = (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: /* "transparent" stuff is completely ignored. */ riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8); break; +#endif /* FBCON_HAS_CFB8 */ +#ifdef FBCON_HAS_CFB16 case 16: assert(regno < 16); - if (info->var.green.length == 5) { + if (p->var.green.length == 5) { /* 0rrrrrgg gggbbbbb */ - ((u16 *)(info->pseudo_palette))[regno] = + rivainfo->con_cmap.cfb16[regno] = ((red & 0xf800) >> 1) | ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); } else { /* rrrrrggg gggbbbbb */ - ((u16 *)(info->pseudo_palette))[regno] = + rivainfo->con_cmap.cfb16[regno] = ((red & 0xf800) >> 0) | ((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11); } break; +#endif /* FBCON_HAS_CFB16 */ +#ifdef FBCON_HAS_CFB32 case 32: assert(regno < 16); - ((u32 *)(info->pseudo_palette))[regno] = + rivainfo->con_cmap.cfb32[regno] = ((red & 0xff00) << 8) | ((green & 0xff00)) | ((blue & 0xff00) >> 8); break; +#endif /* FBCON_HAS_CFB32 */ default: /* do nothing */ break; } + return 0; } @@ -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 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: - var->bits_per_pixel = 8; + v.bits_per_pixel = 8; nom = 1; den = 1; - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; + v.red.offset = 0; + v.red.length = 8; + v.green.offset = 0; + v.green.length = 8; + v.blue.offset = 0; + v.blue.length = 8; break; +#endif +#ifdef FBCON_HAS_CFB16 case 9 ... 15: - var->green.length = 5; + v.green.length = 5; /* fall through */ case 16: - var->bits_per_pixel = 16; + v.bits_per_pixel = 16; nom = 2; den = 1; - if (var->green.length == 5) { + if (v.green.length == 5) { /* 0rrrrrgg gggbbbbb */ - var->red.offset = 10; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 5; - var->blue.length = 5; + v.red.offset = 10; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = 5; + v.green.length = 5; + v.blue.length = 5; } else { /* rrrrrggg gggbbbbb */ - var->red.offset = 11; - var->green.offset = 5; - var->blue.offset = 0; - var->red.length = 5; - var->green.length = 6; - var->blue.length = 5; + v.red.offset = 11; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = 5; + v.green.length = 6; + v.blue.length = 5; } break; +#endif +#ifdef FBCON_HAS_CFB32 case 17 ... 32: - var->bits_per_pixel = 32; + v.bits_per_pixel = 32; nom = 4; den = 1; - var->red.offset = 16; - var->green.offset = 8; - var->blue.offset = 0; - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = 8; + v.green.length = 8; + v.blue.length = 8; break; +#endif default: printk(KERN_ERR PFX "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) return -EINVAL; } - if (rivafb_do_maximize(info, var, nom, den) < 0) + if (rivafb_do_maximize(rivainfo, var, &v, nom, den) < 0) return -EINVAL; - if (var->xoffset < 0) - var->xoffset = 0; - if (var->yoffset < 0) - var->yoffset = 0; + if (v.xoffset < 0) + v.xoffset = 0; + if (v.yoffset < 0) + v.yoffset = 0; /* truncate xoffset and yoffset to maximum if too high */ - if (var->xoffset > var->xres_virtual - var->xres) - var->xoffset = var->xres_virtual - var->xres - 1; + if (v.xoffset > v.xres_virtual - v.xres) + v.xoffset = v.xres_virtual - v.xres - 1; - if (var->yoffset > var->yres_virtual - var->yres) - var->yoffset = var->yres_virtual - var->yres - 1; + if (v.yoffset > v.yres_virtual - v.yres) + v.yoffset = v.yres_virtual - v.yres - 1; - var->red.msb_right = - 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; + 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 (accel) { + 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); + + DPRINTK("EXIT, returning 0\n"); 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) { - case 8: - info->fix.line_length = info->var.xres_virtual; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - case 16: - info->fix.line_length = info->var.xres_virtual * 2; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; - break; - case 32: - info->fix.line_length = info->var.xres_virtual * 4; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; - break; - } -/* - if (par->cursor) { - disp->dispsw.cursor = rivafb_cursor; - disp->dispsw.set_font = rivafb_set_font; + DPRINTK("ENTER\n"); + + assert(rivainfo != NULL); + assert(cmap != NULL); + + dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con]; + + if (con == info->currcon) { /* current console? */ + int rc = fb_get_cmap(cmap, kspc, riva_getcolreg, info); + DPRINTK("EXIT - returning %d\n", rc); + return rc; + } else if (dsp->cmap.len) /* non default colormap? */ + 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; + } } - 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; } @@ -1288,7 +1571,7 @@ static int rivafb_set_par(struct fb_info *info) * rivafb_pan_display * @var: standard kernel fb changeable data * @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: * 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) static int rivafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) { - struct riva_par *par = (struct riva_par *) info->par; - struct display *dsp; 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)) return -EINVAL; if (var->yoffset > (var->yres_virtual - var->yres)) 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->yoffset < 0 - || var->yoffset >= info->var.yres_virtual + || var->yoffset >= dsp->var.yres_virtual || var->xoffset) return -EINVAL; } else { - if (var->xoffset + info->var.xres > info->var.xres_virtual || - var->yoffset + info->var.yres > info->var.yres_virtual) + if (var->xoffset + dsp->var.xres > dsp->var.xres_virtual || + var->yoffset + dsp->var.yres > dsp->var.yres_virtual) return -EINVAL; } base = var->yoffset * dsp->line_length + var->xoffset; - if (con == info->currcon) - par->riva.SetStartAddress(&par->riva, base); + if (con == info->currcon) { + rivainfo->riva.SetStartAddress(&rivainfo->riva, base); + } - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; + dsp->var.xoffset = var->xoffset; + dsp->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; + dsp->var.vmode |= FB_VMODE_YWRAP; else - info->var.vmode &= ~FB_VMODE_YWRAP; + dsp->var.vmode &= ~FB_VMODE_YWRAP; + + DPRINTK("EXIT, returning 0\n"); + 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) { - 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; } +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) { - struct riva_par *par = (struct riva_par *)info->par; 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 */ - vesa = CRTCin(par, 0x1a) & ~0xc0; /* sync on/off */ + tmp = SEQin(rinfo, 0x01) & ~0x20; /* screen on/off */ + vesa = CRTCin(rinfo, 0x1a) & ~0xc0; /* sync on/off */ if (blank) { tmp |= 0x20; @@ -1370,11 +1727,15 @@ static int rivafb_blank(int blank, struct fb_info *info) } } - SEQout(par, 0x01, tmp); - CRTCout(par, 0x1a, vesa); + SEQout(rinfo, 0x01, tmp); + CRTCout(rinfo, 0x1a, vesa); + + DPRINTK("EXIT\n"); return 0; } + + /* ------------------------------------------------------------------------- * * * initialization helper functions @@ -1384,29 +1745,78 @@ static int rivafb_blank(int blank, struct fb_info *info) /* kernel interface */ static struct fb_ops riva_fb_ops = { owner: THIS_MODULE, - fb_get_fix: gen_get_fix, - fb_get_var: gen_get_var, - fb_set_var: gen_set_var, - fb_get_cmap: gen_get_cmap, - fb_set_cmap: gen_set_cmap, - fb_check_var: rivafb_check_var, - fb_set_par: rivafb_set_par, + fb_get_fix: rivafb_get_fix, + fb_get_var: rivafb_get_var, + fb_set_var: rivafb_set_var, + fb_get_cmap: rivafb_get_cmap, + fb_set_cmap: rivafb_set_cmap, fb_setcolreg: rivafb_setcolreg, fb_pan_display: rivafb_pan_display, fb_blank: rivafb_blank, - fb_fillrect: rivafb_fillrect, - fb_copyarea: rivafb_copyarea, - fb_imageblit: rivafb_imageblit, + fb_ioctl: rivafb_ioctl, 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->flags = FBINFO_FLAG_DEFAULT; info->fbops = &riva_fb_ops; - info->fix = rivafb_fix; + info->screen_base = rinfo->fb_base; /* FIXME: set monspecs to what??? */ info->display_fg = NULL; @@ -1415,21 +1825,12 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) info->fontname[sizeof(info->fontname) - 1] = 0; info->changevar = NULL; - info->switch_con = gen_switch; - info->updatevar = gen_update_var; + info->switch_con = rivafb_switch; + info->updatevar = rivafb_updatevar; -#ifndef MODULE - if (mode_option) { - 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); + if (riva_init_disp(rinfo) < 0) /* must be done last */ + return -1; - gen_set_var(&info->var, -1, info); return 0; } @@ -1444,230 +1845,194 @@ static int __devinit riva_set_fbinfo(struct fb_info *info) static int __devinit rivafb_init_one(struct pci_dev *pd, const struct pci_device_id *ent) { + struct rivafb_info *rinfo; 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(rci != NULL); - size = sizeof(struct fb_info) + sizeof(struct display) + sizeof(u32) * 16; - - info = kmalloc(size, GFP_KERNEL); - if (!info) + rinfo = kmalloc(sizeof(struct rivafb_info), GFP_KERNEL); + if (!rinfo) goto err_out; - memset(info, 0, size); - - default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL); - if (!default_par) - goto err_out; + memset(rinfo, 0, sizeof(struct rivafb_info)); - memset(default_par, 0, sizeof(struct riva_par)); + rinfo->drvr_name = rci->name; + rinfo->riva.Architecture = rci->arch_rev; - info->disp = (struct display *)(info + 1); - info->pseudo_palette = (void *)(info->disp + 1); + rinfo->pd = pd; + rinfo->base0_region_size = pci_resource_len(pd, 0); + rinfo->base1_region_size = pci_resource_len(pd, 1); - strcat(rivafb_fix.id, rci->name); - default_par->riva.Architecture = rci->arch_rev; + assert(rinfo->base0_region_size >= 0x00800000); /* from GGI */ + assert(rinfo->base1_region_size >= 0x01000000); /* from GGI */ - rivafb_fix.mmio_len = pci_resource_len(pd, 0); - rivafb_fix.smem_len = pci_resource_len(pd, 1); + rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0); + rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1); - assert(rivafb_fix.mmio_len >= 0x00800000); /* from GGI */ - assert(rivafb_fix.smem_len >= 0x01000000); /* from GGI */ - - rivafb_fix.mmio_start = pci_resource_start(pd, 0); - rivafb_fix.smem_start = pci_resource_start(pd, 1); - - if (!request_mem_region(rivafb_fix.mmio_start, - rivafb_fix.mmio_len, "rivafb")) { + if (!request_mem_region(rinfo->ctrl_base_phys, + rinfo->base0_region_size, "rivafb")) { printk(KERN_ERR PFX "cannot reserve MMIO region\n"); goto err_out_kfree; } - default_par->ctrl_base = ioremap(rivafb_fix.mmio_start, - rivafb_fix.mmio_len); - if (!default_par->ctrl_base) { + if (!request_mem_region(rinfo->fb_base_phys, + rinfo->base1_region_size, "rivafb")) { + printk(KERN_ERR PFX "cannot reserve FB region\n"); + goto err_out_free_base0; + } + + rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys, + rinfo->base0_region_size); + if (!rinfo->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"); - goto err_out_free_base0; + rinfo->fb_base = ioremap(rinfo->fb_base_phys, + rinfo->base1_region_size); + if (!rinfo->fb_base) { + printk(KERN_ERR PFX "cannot ioremap FB base\n"); + goto err_out_iounmap_ctrl; + } + +#ifdef CONFIG_MTRR + if (!nomtrr) { + rinfo->mtrr.vram = mtrr_add(rinfo->fb_base_phys, + rinfo->base1_region_size, MTRR_TYPE_WRCOMB, 1); + if (rinfo->mtrr.vram < 0) { + printk(KERN_ERR PFX "unable to setup MTRR\n"); + } else { + rinfo->mtrr.vram_valid = 1; + /* let there be speed */ + printk(KERN_INFO PFX "RIVA MTRR set to ON\n"); } + } +#endif /* CONFIG_MTRR */ - info->screen_base = ioremap(rivafb_fix.smem_start, - rivafb_fix.smem_len); - if (!info->screen_base) { - printk(KERN_ERR PFX "cannot ioremap FB base\n"); - goto err_out_iounmap_ctrl; - } + 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); - default_par->riva.PRAMIN = (unsigned *)(info->screen_base + 0x00C00000); - rivafb_fix.accel = FB_ACCEL_NV3; + 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: - 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; + rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000); + rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000); 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; + RivaGetConfig(&rinfo->riva); - 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; + /* back to normal */ - 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; - } + assert(rinfo->pd != NULL); - info->screen_base = ioremap(rivafb_fix.smem_start, - rivafb_fix.smem_len); - if (!info->screen_base) { - printk(KERN_ERR PFX "cannot ioremap FB base\n"); - goto err_out_iounmap_ctrl; - } - } + /* unlock io */ + CRTCout(rinfo, 0x11, 0xFF); /* vgaHWunlock() + riva unlock (0x7F) */ + rinfo->riva.LockUnlock(&rinfo->riva, 0); -#ifdef CONFIG_MTRR - if (!nomtrr) { - default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start, - rivafb_fix.smem_len, MTRR_TYPE_WRCOMB, 1); - if (default_par->mtrr.vram < 0) { - printk(KERN_ERR PFX "unable to setup MTRR\n"); - } else { - default_par->mtrr.vram_valid = 1; - /* let there be speed */ - printk(KERN_INFO PFX "RIVA MTRR set to ON\n"); - } - } -#endif /* CONFIG_MTRR */ + riva_save_state(rinfo, &rinfo->initial_state); - if (!nohwcursor) default_par->cursor = rivafb_init_cursor(info); + rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024; + rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000; - info->par = default_par; + if (!nohwcursor) rinfo->cursor = rivafb_init_cursor(rinfo); - if (riva_set_fbinfo(info) < 0) { + if (riva_set_fbinfo(rinfo) < 0) { printk(KERN_ERR PFX "error setting initial video mode\n"); goto err_out_cursor; } - if (register_framebuffer(info) < 0) { + if (register_framebuffer((struct fb_info *)rinfo) < 0) { printk(KERN_ERR PFX "error registering riva framebuffer\n"); 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 - "PCI nVidia NV%x framebuffer ver %s (%s, %dMB @ 0x%lX)\n", - default_par->riva.Architecture, + "PCI nVidia NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n", + rinfo->riva.Architecture, RIVAFB_VERSION, - info->fix.id, - default_par->ram_amount / (1024 * 1024), - info->fix.smem_start); + rinfo->drvr_name, + rinfo->ram_amount / (1024 * 1024), + rinfo->fb_base_phys); return 0; err_out_load_state: - riva_load_state(default_par, &default_par->initial_state); + riva_load_state(rinfo, &rinfo->initial_state); err_out_cursor: - rivafb_exit_cursor(default_par); + rivafb_exit_cursor(rinfo); /* err_out_iounmap_fb: */ - iounmap(info->screen_base); + iounmap(rinfo->fb_base); err_out_iounmap_ctrl: - iounmap(default_par->ctrl_base); + iounmap(rinfo->ctrl_base); 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: - 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: - kfree(default_par); - kfree(info); + kfree(rinfo); err_out: return -ENODEV; } static void __devexit rivafb_remove_one(struct pci_dev *pd) { - struct fb_info *board = pci_get_drvdata(pd); - struct riva_par *par = (struct riva_par *) board->par; + struct rivafb_info *board = pci_get_drvdata(pd); if (!board) 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 - if (par->mtrr.vram_valid) - mtrr_del(par->mtrr.vram, board->fix.smem_start, - board->fix.smem_len); + if (board->mtrr.vram_valid) + mtrr_del(board->mtrr.vram, board->fb_base_phys, + board->base1_region_size); #endif /* CONFIG_MTRR */ - iounmap(par->ctrl_base); - iounmap(board->screen_base); + iounmap(board->ctrl_base); + iounmap(board->fb_base); - release_mem_region(board->fix.mmio_start, - board->fix.mmio_len); - release_mem_region(board->fix.smem_start, - board->fix.smem_len); + release_mem_region(board->ctrl_base_phys, + board->base0_region_size); + release_mem_region(board->fb_base_phys, + board->base1_region_size); - kfree(par); kfree(board); pci_set_drvdata(pd, NULL); } + + /* ------------------------------------------------------------------------- * * * initialization @@ -1698,6 +2063,10 @@ int __init rivafb_setup(char *options) } else if (!strncmp(this_opt, "noblink", 7)) { noblink = 1; + } else if (!strncmp(this_opt, "noaccel", 7)) { + noaccel = 1; + } else if (!strncmp(this_opt, "nomove", 6)) { + nomove = 1; #ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; @@ -1750,6 +2119,10 @@ module_exit(rivafb_exit); MODULE_PARM(font, "s"); 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_DESC(nohwcursor, "Disables hardware cursor (0 or 1=disabled) (default=0)"); MODULE_PARM(noblink, "i"); diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c index b412f99424c9..f6f0f785bf61 100644 --- a/drivers/video/riva/riva_hw.c +++ b/drivers/video/riva/riva_hw.c @@ -1220,7 +1220,6 @@ static void CalcStateExt state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00; break; case NV_ARCH_10: - case NV_ARCH_20: nv10UpdateArbitrationSettings(VClk, pixelDepth * 8, &(state->arbitration0), @@ -1286,7 +1285,6 @@ static void UpdateFifoState chip->Tri05 = (RivaTexturedTriangle05 *)&(chip->FIFO[0x0000E000/4]); break; case NV_ARCH_10: - case NV_ARCH_20: /* * Initialize state for the RivaTriangle3D05 routines. */ @@ -1395,7 +1393,6 @@ static void LoadStateExt chip->PGRAPH[0x0000067C/4] = state->pitch3; break; case NV_ARCH_10: - case NV_ARCH_20: LOAD_FIXED_STATE(nv10,PFIFO); LOAD_FIXED_STATE(nv10,PRAMIN); LOAD_FIXED_STATE(nv10,PGRAPH); @@ -1424,31 +1421,15 @@ static void LoadStateExt chip->Tri03 = 0L; break; } - - if (chip->Architecture == NV_ARCH_10) { - chip->PGRAPH[0x00000640/4] = state->offset0; - chip->PGRAPH[0x00000644/4] = state->offset1; - chip->PGRAPH[0x00000648/4] = state->offset2; - chip->PGRAPH[0x0000064C/4] = state->offset3; - chip->PGRAPH[0x00000670/4] = state->pitch0; - chip->PGRAPH[0x00000674/4] = state->pitch1; - chip->PGRAPH[0x00000678/4] = state->pitch2; - chip->PGRAPH[0x0000067C/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[0x00000640/4] = state->offset0; + chip->PGRAPH[0x00000644/4] = state->offset1; + chip->PGRAPH[0x00000648/4] = state->offset2; + chip->PGRAPH[0x0000064C/4] = state->offset3; + chip->PGRAPH[0x00000670/4] = state->pitch0; + chip->PGRAPH[0x00000674/4] = state->pitch1; + chip->PGRAPH[0x00000678/4] = state->pitch2; + chip->PGRAPH[0x0000067C/4] = state->pitch3; + chip->PGRAPH[0x00000680/4] = state->pitch3; chip->PGRAPH[0x00000B00/4] = chip->PFB[0x00000240/4]; chip->PGRAPH[0x00000B04/4] = chip->PFB[0x00000244/4]; chip->PGRAPH[0x00000B08/4] = chip->PFB[0x00000248/4]; @@ -1626,7 +1607,6 @@ static void UnloadStateExt state->pitch3 = chip->PGRAPH[0x0000067C/4]; break; case NV_ARCH_10: - case NV_ARCH_20: state->offset0 = chip->PGRAPH[0x00000640/4]; state->offset1 = chip->PGRAPH[0x00000644/4]; state->offset2 = chip->PGRAPH[0x00000648/4]; diff --git a/drivers/video/riva/riva_hw.h b/drivers/video/riva/riva_hw.h index a51e773a6ced..da27e20a3d2e 100644 --- a/drivers/video/riva/riva_hw.h +++ b/drivers/video/riva/riva_hw.h @@ -74,8 +74,6 @@ typedef unsigned int U032; #define NV_ARCH_03 0x03 #define NV_ARCH_04 0x04 #define NV_ARCH_10 0x10 -#define NV_ARCH_20 0x20 - /***************************************************************************\ * * * FIFO registers. * diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h index c5be7ce12051..d0e64d2b0211 100644 --- a/drivers/video/riva/rivafb.h +++ b/drivers/video/riva/rivafb.h @@ -3,7 +3,6 @@ #include <linux/config.h> #include <linux/fb.h> -#include <linux/timer.h> #include <video/fbcon.h> #include <video/fbcon-cfb4.h> #include <video/fbcon-cfb8.h> @@ -28,35 +27,58 @@ struct riva_regs { RIVA_HW_STATE ext; }; -#define MAX_CURS 32 - -struct riva_cursor { - int enable; - int on; - int vbl_cnt; - int last_slice_moves, prev_slice_moves; - int blink_rate; - struct { - u16 x, y; - } pos, size; - unsigned short image[MAX_CURS*MAX_CURS]; - struct timer_list *timer; -}; +typedef struct { + unsigned char red, green, blue, transp; +} riva_cfb8_cmap_t; + +struct rivafb_info; +struct rivafb_info { + struct fb_info info; /* kernel framebuffer info */ -/* describes the state of a Riva board */ -struct riva_par { 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 dclk_max; /* max DCLK */ struct riva_regs initial_state; /* initial startup video mode */ 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; - 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 - struct { int vram; int vram_valid; } mtrr; + struct { int vram; int vram_valid; } mtrr; #endif }; diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index ba1fb26f26f1..29f2386eceb6 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -661,7 +661,7 @@ static struct sa1100fb_mach_info xp860_info __initdata = { 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; @@ -683,7 +683,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par) #ifdef CONFIG_SA1100_H3XXX if (machine_is_h3600()) { inf = &h3600_info; - par->rgb[RGB_16] = &h3600_rgb_16; + fbi->rgb[RGB_16] = &h3600_rgb_16; } if (machine_is_h3100()) { inf = &h3100_info; @@ -705,7 +705,7 @@ sa1100fb_get_machine_info(struct sa1100_par *par) #ifdef CONFIG_SA1100_FREEBIRD if (machine_is_freebird()) { inf = &freebird_info; - par->rgb[RGB_16] = &freebird_rgb16; + fbi->rgb[RGB_16] = &freebird_rgb16; } #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT @@ -758,10 +758,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par) if (machine_is_stork()) { #if STORK_TFT inf = &stork_tft_info; - par->rgb[RGB_16] = &stork_tft_rgb_16; + fbi->rgb[RGB_16] = &stork_tft_rgb_16; #else inf = &stork_dstn_info; - par->rgb[RGB_16] = &stork_dstn_rgb_16; + fbi->rgb[RGB_16] = &stork_dstn_rgb_16; #endif } #endif @@ -773,10 +773,10 @@ sa1100fb_get_machine_info(struct sa1100_par *par) return inf; } -static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info *); -static void set_ctrlr_state(struct sa1100_par *par, u_int state); +static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *); +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; @@ -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 * 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; - if (par->task_state == C_DISABLE && state == C_ENABLE) + if (fbi->task_state == C_DISABLE && state == C_ENABLE) state = C_REENABLE; if (state != (u_int)-1) { - par->task_state = state; - schedule_task(&par->task); + fbi->task_state = state; + schedule_task(&fbi->task); } 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 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. */ static inline u_int -palette_pbs(int bpp) +palette_pbs(struct fb_var_screeninfo *var) { int ret = 0; - switch (bpp) { + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 case 4: ret = 0 << 12; break; +#endif +#ifdef FBCON_HAS_CFB8 case 8: ret = 1 << 12; break; +#endif +#ifdef FBCON_HAS_CFB16 case 16: ret = 2 << 12; break; +#endif } return ret; } @@ -828,18 +859,18 @@ static int sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, 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; - if (regno < par->palette_size) { + if (regno < fbi->palette_size) { val = ((red >> 4) & 0xf00); val |= ((green >> 8) & 0x0f0); val |= ((blue >> 12) & 0x00f); 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; } return ret; @@ -849,6 +880,8 @@ static int sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 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; int ret = 1; @@ -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 * is what you poke into the framebuffer to produce the * colour you requested. - * - if (inverse) { + */ + if (disp->inverse) { red = 0xffff - red; green = 0xffff - green; blue = 0xffff - blue; } - */ /* * If greyscale is true, then we convert the RGB value * 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 + 7471 * blue) >> 16; - switch (info->fix.visual) { + switch (fbi->fb.disp->visual) { case FB_VISUAL_TRUECOLOR: /* * 12 or 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ 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(green, &info->var.green); - val |= chan_to_field(blue, &info->var.blue); + val = chan_to_field(red, &fbi->fb.var.red); + val |= chan_to_field(green, &fbi->fb.var.green); + val |= chan_to_field(blue, &fbi->fb.var.blue); pal[regno] = val; ret = 0; @@ -931,20 +963,19 @@ sa1100fb_display_dma_period(struct fb_var_screeninfo *var) * bitfields, horizontal timing, vertical timing. */ static int -sa1100fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) +sa1100fb_validate_var(struct fb_var_screeninfo *var, + struct sa1100fb_info *fbi) { - struct sa1100_par *par = (struct sa1100_par *) info->par; - int rgbidx = RGB_16, ret = -EINVAL; + int ret = -EINVAL; if (var->xres < MIN_XRES) var->xres = MIN_XRES; if (var->yres < MIN_YRES) var->yres = MIN_YRES; - if (var->xres > par->max_xres) - var->xres = par->max_xres; - if (var->yres > par->max_yres) - var->yres = par->max_yres; + if (var->xres > fbi->max_xres) + var->xres = fbi->max_xres; + if (var->yres > fbi->max_yres) + var->yres = fbi->max_yres; var->xres_virtual = var->xres_virtual < var->xres ? var->xres : var->xres_virtual; var->yres_virtual = @@ -952,22 +983,23 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); switch (var->bits_per_pixel) { - case 4: rgbidx = RGB_8; ret = 0; break; - case 8: rgbidx = RGB_8; ret = 0; break; - case 16: rgbidx = RGB_16; ret = 0; break; +#ifdef FBCON_HAS_CFB4 + case 4: 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: 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 printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n", sa1100fb_display_dma_period(var), - cpufreq_get()); + cpufreq_get(smp_processor_id())); #endif return ret; @@ -994,26 +1026,24 @@ static inline void sa1100fb_set_truecolor(u_int is_true_color) } } -static int -sa1100fb_set_par(struct fb_info *info) +static void +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; - par->bpp = info->var.bits_per_pixel; - par->palette_size = par->bpp == 8 ? 256 : 16; + fbi->palette_size = var->bits_per_pixel == 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); - par->palette_cpu = (u16 *)(par->map_cpu + PAGE_SIZE - palette_mem_size); - par->palette_dma = par->map_dma + PAGE_SIZE - palette_mem_size; + fbi->palette_cpu = (u16 *)(fbi->map_cpu + 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 */ - sa1100fb_set_truecolor(info->var.bits_per_pixel >= 16); + sa1100fb_set_truecolor(var->bits_per_pixel >= 16); #ifdef CONFIG_SA1100_OMNIMETER #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) SetLCDContrast(DefaultLCDContrast); #endif - sa1100fb_activate_var(&info->var, info); + sa1100fb_activate_var(var, fbi); + + fbi->palette_cpu[0] = (fbi->palette_cpu[0] & + 0xcfff) | palette_pbs(var); + +} + +/* + * 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; - par->palette_cpu[0] = (par->palette_cpu[0] & - 0xcfff) | palette_pbs(info->var.bits_per_pixel); - - switch (info->var.bits_per_pixel) { + switch (var->bits_per_pixel) { +#ifdef FBCON_HAS_CFB4 case 4: - if (par->cmap_static) - info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; + if (fbi->cmap_static) + display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; else - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - info->fix.line_length = info->var.xres / 2; + display->visual = FB_VISUAL_PSEUDOCOLOR; + display->line_length = var->xres / 2; + display->dispsw = &fbcon_cfb4; + rgbidx = RGB_8; break; +#endif +#ifdef FBCON_HAS_CFB8 case 8: - if (par->cmap_static) - info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; + if (fbi->cmap_static) + display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; else - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - info->fix.line_length = info->var.xres; + display->visual = FB_VISUAL_PSEUDOCOLOR; + display->line_length = var->xres; + display->dispsw = &fbcon_cfb8; + rgbidx = RGB_8; break; +#endif +#ifdef FBCON_HAS_CFB16 case 16: - info->fix.visual = FB_VISUAL_TRUECOLOR; - info->fix.line_length = info->var.xres * 2; + display->visual = FB_VISUAL_TRUECOLOR; + 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; } + + 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; } @@ -1086,21 +1295,21 @@ sa1100fb_set_par(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; - DPRINTK("sa1100fb_blank: blank=%d fix.id=%s\n", blank, - info->fix.id); + DPRINTK("sa1100fb_blank: blank=%d info->modename=%s\n", blank, + fbi->fb.modename); switch (blank) { case VESA_POWERDOWN: case VESA_VSYNC_SUSPEND: case VESA_HSYNC_SUSPEND: - if (info->disp->visual == FB_VISUAL_PSEUDOCOLOR || - info->disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) - for (i = 0; i < par->palette_size; i++) + if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || + fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + for (i = 0; i < fbi->palette_size; i++) sa1100fb_setpalettereg(i, 0, 0, 0, 0, info); - sa1100fb_schedule_task(par, C_DISABLE); + sa1100fb_schedule_task(fbi, C_DISABLE); if (sa1100fb_blank_helper) sa1100fb_blank_helper(blank); break; @@ -1108,31 +1317,84 @@ static int sa1100fb_blank(int blank, struct fb_info *info) case VESA_NO_BLANKING: if (sa1100fb_blank_helper) sa1100fb_blank_helper(blank); - if (info->disp->visual == FB_VISUAL_PSEUDOCOLOR || - info->disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) - fb_set_cmap(&info->cmap, 1, info); - sa1100fb_schedule_task(par, C_ENABLE); + if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || + fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) + fb_set_cmap(&fbi->fb.cmap, 1, info); + sa1100fb_schedule_task(fbi, C_ENABLE); } return 0; } static struct fb_ops sa1100fb_ops = { owner: THIS_MODULE, - fb_get_fix: gen_get_fix, - fb_get_var: gen_get_var, - fb_set_var: gen_set_var, - fb_get_cmap: gen_get_cmap, - fb_set_cmap: gen_set_cmap, - fb_check_var: sa1100fb_check_var, - fb_set_par: sa1100fb_set_par, + fb_get_fix: sa1100fb_get_fix, + fb_get_var: sa1100fb_get_var, + fb_set_var: sa1100fb_set_var, + fb_get_cmap: sa1100fb_get_cmap, + fb_set_cmap: sa1100fb_set_cmap, fb_setcolreg: sa1100fb_setcolreg, 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). * We take account of the PPCR clock setting. */ @@ -1141,7 +1403,7 @@ static inline int get_pcd(unsigned int pixclock) unsigned int pcd; if (pixclock) { - pcd = cpufreq_get() / 100; + pcd = cpufreq_get(0) / 100; pcd *= pixclock; pcd /= 10000000; pcd += 1; /* make up for integer math truncations */ @@ -1171,9 +1433,8 @@ static inline int get_pcd(unsigned int pixclock) * Configures LCD Controller based on entries in var parameter. Settings are * 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; u_int half_screen_size, yres, pcd = get_pcd(var->pixclock); u_long flags; @@ -1190,31 +1451,31 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * #if DEBUG_VAR if (var->xres < 16 || var->xres > 1024) 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) 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) 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) 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) 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) 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) 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) printk(KERN_ERR "%s: invalid lower_margin %d\n", - info->fix.id, var->lower_margin); + fbi->fb.fix.id, var->lower_margin); #endif - new_regs.lccr0 = par->lccr0 | + new_regs.lccr0 = fbi->lccr0 | LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); @@ -1229,7 +1490,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * * the YRES parameter. */ yres = var->yres; - if (par->lccr0 & LCCR0_Dual) + if (fbi->lccr0 & LCCR0_Dual) yres /= 2; new_regs.lccr2 = @@ -1238,7 +1499,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * LCCR2_BegFrmDel(var->upper_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_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) | LCCR3_ACBsCntOff; @@ -1256,23 +1517,23 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct fb_info * /* Update shadow copy atomically */ local_irq_save(flags); - par->dbar1 = par->palette_dma; - par->dbar2 = par->screen_dma + half_screen_size; + fbi->dbar1 = fbi->palette_dma; + fbi->dbar2 = fbi->screen_dma + half_screen_size; - par->reg_lccr0 = new_regs.lccr0; - par->reg_lccr1 = new_regs.lccr1; - par->reg_lccr2 = new_regs.lccr2; - par->reg_lccr3 = new_regs.lccr3; + fbi->reg_lccr0 = new_regs.lccr0; + fbi->reg_lccr1 = new_regs.lccr1; + fbi->reg_lccr2 = new_regs.lccr2; + fbi->reg_lccr3 = new_regs.lccr3; local_irq_restore(flags); /* * Only update the registers if the controller is enabled * and something has changed. */ - if ((LCCR0 != par->reg_lccr0) || (LCCR1 != par->reg_lccr1) || - (LCCR2 != par->reg_lccr2) || (LCCR3 != par->reg_lccr3) || - (DBAR1 != par->dbar1) || (DBAR2 != par->dbar2)) - sa1100fb_schedule_task(par, C_REENABLE); + if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || + (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || + (DBAR1 != fbi->dbar1) || (DBAR2 != fbi->dbar2)) + sa1100fb_schedule_task(fbi, C_REENABLE); return 0; } @@ -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 * 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"); @@ -1302,7 +1563,7 @@ static inline void sa1100fb_backlight_on(struct sa1100_par *par) * Also, I'm expecting that the backlight stuff should * 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"); @@ -1310,7 +1571,7 @@ static inline void sa1100fb_backlight_off(struct sa1100_par *par) 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"); @@ -1325,7 +1586,7 @@ static inline void sa1100fb_power_up_lcd(struct sa1100_par *par) #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"); @@ -1340,7 +1601,7 @@ static inline void sa1100fb_power_down_lcd(struct sa1100_par *par) #endif } -static void sa1100fb_setup_gpio(struct sa1100_par *par) +static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) { u_int mask = 0; @@ -1356,12 +1617,12 @@ static void sa1100fb_setup_gpio(struct sa1100_par *par) * clear LDD15 to 12 for 4 or 8bpp modes with active * panels. */ - if ((par->reg_lccr0 & LCCR0_CMS) == LCCR0_Color && - (par->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) { + if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color && + (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) { mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8; - if (par->bpp > 8 || - (par->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual) + if (fbi->fb.var.bits_per_pixel > 8 || + (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual) mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12; } @@ -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"); /* * Make sure the mode bits are present in the first palette entry */ - par->palette_cpu[0] &= 0xcfff; - par->palette_cpu[0] |= palette_pbs(par->bpp); + fbi->palette_cpu[0] &= 0xcfff; + fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var); /* Sequence from 11.7.10 */ - LCCR3 = par->reg_lccr3; - LCCR2 = par->reg_lccr2; - LCCR1 = par->reg_lccr1; - LCCR0 = par->reg_lccr0 & ~LCCR0_LEN; - DBAR1 = par->dbar1; - DBAR2 = par->dbar2; + LCCR3 = fbi->reg_lccr3; + LCCR2 = fbi->reg_lccr2; + LCCR1 = fbi->reg_lccr1; + LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN; + DBAR1 = fbi->dbar1; + DBAR2 = fbi->dbar2; LCCR0 |= LCCR0_LEN; #ifdef CONFIG_SA1100_GRAPHICSCLIENT @@ -1447,7 +1708,7 @@ static void sa1100fb_enable_controller(struct sa1100_par *par) 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); @@ -1481,7 +1742,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par) GPCR |= SHANNON_GPIO_DISP_EN; } - add_wait_queue(&par->ctrlr_wait, &wait); + add_wait_queue(&fbi->ctrlr_wait, &wait); set_current_state(TASK_UNINTERRUPTIBLE); LCSR = 0xffffffff; /* Clear LCD Status Register */ @@ -1490,7 +1751,7 @@ static void sa1100fb_disable_controller(struct sa1100_par *par) schedule_timeout(20 * HZ / 1000); 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) */ 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; if (lcsr & LCSR_LDD) { LCCR0 |= LCCR0_LDM; - wake_up(&par->ctrlr_wait); + wake_up(&fbi->ctrlr_wait); } LCSR = lcsr; @@ -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 * 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; - down(&par->ctrlr_sem); + down(&fbi->ctrlr_sem); - old_state = par->state; + old_state = fbi->state; switch (state) { case C_DISABLE_CLKCHANGE: @@ -1529,8 +1790,8 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) * controller is already disabled, then do nothing. */ if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { - par->state = state; - sa1100fb_disable_controller(par); + fbi->state = state; + sa1100fb_disable_controller(fbi); } break; @@ -1540,12 +1801,12 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) * Disable controller */ 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) - sa1100fb_disable_controller(par); - sa1100fb_power_down_lcd(par); + sa1100fb_disable_controller(fbi); + sa1100fb_power_down_lcd(fbi); } break; @@ -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. */ if (old_state == C_DISABLE_CLKCHANGE) { - par->state = C_ENABLE; - sa1100fb_enable_controller(par); + fbi->state = C_ENABLE; + sa1100fb_enable_controller(fbi); } break; @@ -1567,9 +1828,9 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) * registers. */ if (old_state == C_ENABLE) { - sa1100fb_disable_controller(par); - sa1100fb_setup_gpio(par); - sa1100fb_enable_controller(par); + sa1100fb_disable_controller(fbi); + sa1100fb_setup_gpio(fbi); + sa1100fb_enable_controller(fbi); } break; @@ -1589,15 +1850,15 @@ static void set_ctrlr_state(struct sa1100_par *par, u_int state) * turn on the backlight. */ if (old_state != C_ENABLE) { - par->state = C_ENABLE; - sa1100fb_setup_gpio(par); - sa1100fb_power_up_lcd(par); - sa1100fb_enable_controller(par); - sa1100fb_backlight_on(par); + fbi->state = C_ENABLE; + sa1100fb_setup_gpio(fbi); + sa1100fb_power_up_lcd(fbi); + sa1100fb_enable_controller(fbi); + sa1100fb_backlight_on(fbi); } 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) */ static void sa1100fb_task(void *dummy) { - struct fb_info *info = dummy; - struct sa1100_par *par = (struct sa1100_par *) info->par; + struct sa1100fb_info *fbi = dummy; + 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 @@ -1620,7 +1879,7 @@ static void sa1100fb_task(void *dummy) * This, together with the SDRAM bandwidth defines the slowest CPU * 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; int i; @@ -1631,13 +1890,13 @@ static unsigned int sa1100fb_min_dma_period(struct fb_info *info) /* * Do we own this display? */ - if (fb_display[i].fb_info != info) + if (fb_display[i].fb_info != &fbi->fb) continue; /* * 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) min_period = period; } @@ -1654,27 +1913,26 @@ static int sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val, void *data) { - struct fb_info *info = TO_INF(nb, clockchg); - struct sa1100_par *par = (struct sa1100_par *) info->par; - struct cpufreq_freqs *mm = data; + struct sa1100fb_info *fbi = TO_INF(nb, clockchg); + struct cpufreq_minmax *mm = data; u_int pcd; switch (val) { case CPUFREQ_MINMAX: printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, " - "new clock %d kHz\n", sa1100fb_min_dma_period(info), - mm->cur, mm->new); + "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), + mm->cur_freq, mm->new_freq); /* todo: fill in min/max values */ break; case CPUFREQ_PRECHANGE: - set_ctrlr_state(par, C_DISABLE_CLKCHANGE); + set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); break; case CPUFREQ_POSTCHANGE: - pcd = get_pcd(info->var.pixclock); - par->reg_lccr3 = (par->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); - set_ctrlr_state(par, C_ENABLE_CLKCHANGE); + pcd = get_pcd(fbi->fb.var.pixclock); + fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); + set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); break; } return 0; @@ -1689,7 +1947,7 @@ sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val, static int 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); @@ -1698,10 +1956,10 @@ sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) if (state == 0) { /* Enter D0. */ - set_ctrlr_state(par, C_ENABLE_PM); + set_ctrlr_state(fbi, C_ENABLE_PM); } else { /* Enter D1-D3. Disable the LCD controller. */ - set_ctrlr_state(par, C_DISABLE_PM); + set_ctrlr_state(fbi, C_DISABLE_PM); } } DPRINTK("done\n"); @@ -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 * 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 * of the framebuffer. */ - par->map_size = PAGE_ALIGN(info->fix.smem_len + PAGE_SIZE); - par->map_cpu = consistent_alloc(GFP_KERNEL, par->map_size, - &par->map_dma); - - if (par->map_cpu) { - info->screen_base = par->map_cpu + PAGE_SIZE; - par->screen_dma = par->map_dma + PAGE_SIZE; - info->fix.smem_start = par->screen_dma; + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); + fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, + &fbi->map_dma); + + if (fbi->map_cpu) { + fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; + fbi->screen_dma = fbi->map_dma + PAGE_SIZE; + 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 = { 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 fb_info *info; - struct sa1100_par *par; + struct sa1100fb_info *fbi; - info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) + + fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) + sizeof(u16) * 16, GFP_KERNEL); - if (!info) + if (!fbi) return NULL; - memset(info, 0, sizeof(struct fb_info) + sizeof(struct display)); - - par = kmalloc(sizeof(struct sa1100_par), GFP_KERNEL); - memset(par, 0, sizeof(struct sa1100_par)); - - info->currcon = -1; - - strcpy(info->fix.id, SA1100_NAME); - - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.type_aux = 0; - info->fix.xpanstep = 0; - info->fix.ypanstep = 0; - info->fix.ywrapstep = 0; - info->fix.accel = FB_ACCEL_NONE; - - info->var.nonstd = 0; - info->var.activate = FB_ACTIVATE_NOW; - info->var.height = -1; - info->var.width = -1; - info->var.accel_flags = 0; - info->var.vmode = FB_VMODE_NONINTERLACED; - - strcpy(info->modename, info->fix.id); - strcpy(info->fontname, "Acorn8x8"); - - info->fbops = &sa1100fb_ops; - info->changevar = NULL; - info->switch_con = gen_switch; - info->updatevar = gen_update_var; - info->flags = FBINFO_FLAG_DEFAULT; - info->node = NODEV; - info->monspecs = monspecs; - info->currcon = -1; - info->disp = (struct display *)(info + 1); - info->pseudo_palette = (void *)(info->disp + 1); - info->par = par; - - par->rgb[RGB_8] = &rgb_8; - par->rgb[RGB_16] = &def_rgb_16; - - inf = sa1100fb_get_machine_info(par); - - par->max_xres = inf->xres; - info->var.xres = inf->xres; - info->var.xres_virtual = inf->xres; - par->max_yres = inf->yres; - info->var.yres = inf->yres; - info->var.yres_virtual = inf->yres; - par->max_bpp = inf->bpp; - info->var.bits_per_pixel = inf->bpp; - info->var.pixclock = inf->pixclock; - info->var.hsync_len = inf->hsync_len; - info->var.left_margin = inf->left_margin; - info->var.right_margin = inf->right_margin; - info->var.vsync_len = inf->vsync_len; - info->var.upper_margin = inf->upper_margin; - info->var.lower_margin = inf->lower_margin; - info->var.sync = inf->sync; - info->var.grayscale = inf->cmap_greyscale; - par->cmap_inverse = inf->cmap_inverse; - par->cmap_static = inf->cmap_static; - par->lccr0 = inf->lccr0; - par->lccr3 = inf->lccr3; - par->state = C_DISABLE; - par->task_state = (u_char)-1; - info->fix.smem_len = par->max_xres * par->max_yres * - par->max_bpp / 8; - - init_waitqueue_head(&par->ctrlr_wait); - INIT_TQUEUE(&par->task, sa1100fb_task, info); - init_MUTEX(&par->ctrlr_sem); - - fb_alloc_cmap(&info->cmap, 256, 0); - - return info; + memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display)); + + fbi->fb.currcon = -1; + + strcpy(fbi->fb.fix.id, SA1100_NAME); + + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fbi->fb.fix.type_aux = 0; + fbi->fb.fix.xpanstep = 0; + fbi->fb.fix.ypanstep = 0; + fbi->fb.fix.ywrapstep = 0; + fbi->fb.fix.accel = FB_ACCEL_NONE; + + fbi->fb.var.nonstd = 0; + fbi->fb.var.activate = FB_ACTIVATE_NOW; + fbi->fb.var.height = -1; + fbi->fb.var.width = -1; + fbi->fb.var.accel_flags = 0; + fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; + + strcpy(fbi->fb.modename, SA1100_NAME); + strcpy(fbi->fb.fontname, "Acorn8x8"); + + fbi->fb.fbops = &sa1100fb_ops; + fbi->fb.changevar = NULL; + fbi->fb.switch_con = sa1100fb_switch; + fbi->fb.updatevar = sa1100fb_updatevar; + fbi->fb.flags = FBINFO_FLAG_DEFAULT; + fbi->fb.node = NODEV; + fbi->fb.monspecs = monspecs; + fbi->fb.currcon = -1; + fbi->fb.disp = (struct display *)(fbi + 1); + fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1); + + fbi->rgb[RGB_8] = &rgb_8; + fbi->rgb[RGB_16] = &def_rgb_16; + + inf = sa1100fb_get_machine_info(fbi); + + fbi->max_xres = inf->xres; + fbi->fb.var.xres = inf->xres; + fbi->fb.var.xres_virtual = inf->xres; + fbi->max_yres = inf->yres; + fbi->fb.var.yres = inf->yres; + fbi->fb.var.yres_virtual = inf->yres; + fbi->max_bpp = inf->bpp; + fbi->fb.var.bits_per_pixel = inf->bpp; + fbi->fb.var.pixclock = inf->pixclock; + fbi->fb.var.hsync_len = inf->hsync_len; + fbi->fb.var.left_margin = inf->left_margin; + fbi->fb.var.right_margin = inf->right_margin; + fbi->fb.var.vsync_len = inf->vsync_len; + fbi->fb.var.upper_margin = inf->upper_margin; + fbi->fb.var.lower_margin = inf->lower_margin; + fbi->fb.var.sync = inf->sync; + fbi->fb.var.grayscale = inf->cmap_greyscale; + fbi->cmap_inverse = inf->cmap_inverse; + fbi->cmap_static = inf->cmap_static; + fbi->lccr0 = inf->lccr0; + fbi->lccr3 = inf->lccr3; + fbi->state = C_DISABLE; + fbi->task_state = (u_char)-1; + fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * + fbi->max_bpp / 8; + + init_waitqueue_head(&fbi->ctrlr_wait); + INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi); + init_MUTEX(&fbi->ctrlr_sem); + + return fbi; } int __init sa1100fb_init(void) { - struct fb_info *info; - struct sa1100_par *par; + struct sa1100fb_info *fbi; int ret; if (!request_mem_region(0xb0100000, 0x10000, "LCD")) return -EBUSY; - info = sa1100fb_init_fbinfo(); + fbi = sa1100fb_init_fbinfo(); ret = -ENOMEM; - if (!info) + if (!fbi) goto failed; /* Initialize video memory */ - ret = sa1100fb_map_video_memory(info); + ret = sa1100fb_map_video_memory(fbi); if (ret) goto failed; ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT, - "LCD", info->par); + "LCD", fbi); if (ret) { printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret); goto failed; @@ -1873,32 +2122,30 @@ int __init sa1100fb_init(void) } #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) goto failed; - par = info->par; - #ifdef CONFIG_PM /* * Note that the console registers this as well, but we want to * power down the display prior to sleeping. */ - par->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback); - if (par->pm) - par->pm->data = par; + fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback); + if (fbi->pm) + fbi->pm->data = fbi; #endif #ifdef CONFIG_CPU_FREQ - info->clockchg.notifier_call = sa1100fb_clkchg_notifier; - cpufreq_register_notifier(&info->clockchg); + fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier; + cpufreq_register_notifier(&fbi->clockchg); #endif /* * 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 */ MOD_INC_USE_COUNT; @@ -1906,8 +2153,8 @@ int __init sa1100fb_init(void) return 0; failed: - if (info) - kfree(info); + if (fbi) + kfree(fbi); release_mem_region(0xb0100000, 0x10000); return ret; } diff --git a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h index 8b04a889ba64..96e79705be5c 100644 --- a/drivers/video/sa1100fb.h +++ b/drivers/video/sa1100fb.h @@ -61,13 +61,13 @@ struct sa1100fb_lcd_reg { #define RGB_16 (1) #define NR_RGB 2 -struct sa1100_par { +struct sa1100fb_info { + struct fb_info fb; struct sa1100fb_rgb *rgb[NR_RGB]; + u_int max_bpp; u_int max_xres; u_int max_yres; - u_int max_bpp; - u_int bpp; /* * These are the addresses we mapped @@ -86,13 +86,12 @@ struct sa1100_par { dma_addr_t dbar1; dma_addr_t dbar2; + u_int lccr0; + u_int lccr3; u_int cmap_inverse:1, cmap_static:1, unused:30; - u_int lccr0; - u_int lccr3; - u_int reg_lccr0; u_int reg_lccr1; u_int reg_lccr2; @@ -103,14 +102,18 @@ struct sa1100_par { struct semaphore ctrlr_sem; wait_queue_head_t ctrlr_wait; struct tq_struct task; + #ifdef CONFIG_PM struct pm_dev *pm; #endif +#ifdef CONFIG_CPU_FREQ + struct notifier_block clockchg; +#endif }; #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) |
