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

Port step some changes at authors request.

parent 8ef1bf6d
......@@ -109,36 +109,35 @@ static struct fb_var_screeninfo default_var = {
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
FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
};
#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 */
......@@ -156,21 +155,19 @@ enum {
};
/* supported Rage128 chipsets */
static struct aty128_chip_info aty128_pci_probe_list[] __initdata = {
static struct aty128_chip_info aty128_pci_probe_list[] __initdata =
{
{"Rage128 RE (PCI)", PCI_DEVICE_ID_ATI_RAGE128_RE, rage_128},
{"Rage128 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},
{"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
......@@ -227,6 +224,7 @@ 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;
......@@ -265,7 +263,7 @@ struct aty128_crtc {
u32 pitch;
u32 offset, offset_cntl;
u32 xoffset, yoffset;
u32 vyres;
u32 vxres, vyres;
u32 bpp;
};
......@@ -285,79 +283,136 @@ struct aty128fb_par {
struct aty128_crtc crtc;
struct aty128_pll pll;
struct aty128_ddafifo fifo_reg;
const struct aty128_meminfo *mem; /* onboard mem info */
u32 accel_flags;
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
#endif
};
struct fb_info_aty128 {
struct fb_info fb_info;
struct fb_info_aty128 *next;
struct aty128_constants constants; /* PLL and others */
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) */
int chip_gen;
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
#endif
};
static struct fb_info_aty128 *board_list = NULL;
#define round_div(n, d) ((n+(d/2))/d)
/*
* 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,
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);
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);
const struct fb_info_aty128 *info);
static int aty128_pci_register(struct pci_dev *pdev,
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,
static void __init aty128_get_pllinfo(struct fb_info_aty128 *info,
char *bios_seg);
static char __init *aty128find_ROM(struct fb_info *info);
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,
......@@ -371,55 +426,60 @@ static struct backlight_controller aty128_backlight_controller = {
* 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;
#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;
}
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_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);
......@@ -427,7 +487,8 @@ _aty_ld_pll(unsigned int pll_index, const struct aty128fb_par *par)
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);
......@@ -435,19 +496,21 @@ _aty_st_pll(unsigned int pll_index, u32 val, const struct aty128fb_par *par)
/* return true when the PLL has completed an atomic update */
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);
}
static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
static void
aty_pll_wait_readupdate(const struct fb_info_aty128 *info)
{
unsigned long timeout = jiffies + HZ / 100; // should be more than enough
unsigned long timeout = jiffies + HZ/100; // should be more than enough
int reset = 1;
while (time_before(jiffies, timeout))
if (aty_pll_readupdate(par)) {
if (aty_pll_readupdate(info)) {
reset = 0;
break;
}
......@@ -458,9 +521,10 @@ static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
/* tell PLL to update */
static void aty_pll_writeupdate(const struct aty128fb_par *par)
static void
aty_pll_writeupdate(const struct 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);
......@@ -468,7 +532,8 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par)
/* write to the scratch register to test r/w functionality */
static int __init register_test(const struct aty128fb_par *par)
static int __init
register_test(const struct fb_info_aty128 *info)
{
u32 val;
int flag = 0;
......@@ -491,51 +556,56 @@ static int __init register_test(const struct aty128fb_par *par)
/*
* Accelerator engine functions
*/
static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
static void
do_wait_for_fifo(u16 entries, struct 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)
info->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff;
if (info->fifo_slots >= entries)
return;
}
aty128_reset_engine(par);
aty128_reset_engine(info);
}
}
static void wait_for_idle(struct aty128fb_par *par)
static void
wait_for_idle(struct fb_info_aty128 *info)
{
int i;
do_wait_for_fifo(64, par);
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(par);
par->blitter_may_be_busy = 0;
aty128_flush_pixel_cache(info);
info->blitter_may_be_busy = 0;
return;
}
}
aty128_reset_engine(par);
aty128_reset_engine(info);
}
}
static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
static void
wait_for_fifo(u16 entries, struct fb_info_aty128 *info)
{
if (par->fifo_slots < entries)
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;
u32 tmp;
tmp = aty_ld_le32(PC_NGUI_CTLSTAT);
tmp &= ~(0x00ff);
......@@ -548,11 +618,12 @@ static void aty128_flush_pixel_cache(struct aty128fb_par *par)
}
static void aty128_reset_engine(struct aty128fb_par *par)
static void
aty128_reset_engine(const struct fb_info_aty128 *info)
{
u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
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);
......@@ -577,25 +648,25 @@ static void aty128_reset_engine(struct aty128fb_par *par)
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);
wait_for_idle(info);
/* 3D scaler not spoken here */
wait_for_fifo(1, par);
wait_for_fifo(1, info);
aty_st_le32(SCALE_3D_CNTL, 0x00000000);
aty128_reset_engine(par);
aty128_reset_engine(info);
pitch_value = par->crtc.pitch;
if (par->crtc.bpp == 24) {
pitch_value = pitch_value * 3;
}
wait_for_fifo(4, par);
wait_for_fifo(4, info);
/* setup engine offset registers */
aty_st_le32(DEFAULT_OFFSET, 0x00000000);
......@@ -620,9 +691,10 @@ aty128_init_engine(struct aty128fb_par *par,
GMC_DP_SRC_RECT |
GMC_3D_FCN_EN_CLR |
GMC_DST_CLR_CMP_FCN_CLEAR |
GMC_AUX_CLIP_CLEAR | GMC_WRITE_MASK_SET);
GMC_AUX_CLIP_CLEAR |
GMC_WRITE_MASK_SET);
wait_for_fifo(8, par);
wait_for_fifo(8, info);
/* clear the line drawing registers */
aty_st_le32(DST_BRES_ERR, 0);
aty_st_le32(DST_BRES_INC, 0);
......@@ -640,12 +712,13 @@ aty128_init_engine(struct aty128fb_par *par,
aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);
/* Wait for all the writes to be completed before returning */
wait_for_idle(par);
wait_for_idle(info);
}
/* convert bpp values to their register representation */
static u32 bpp_to_depth(u32 bpp)
static u32
bpp_to_depth(u32 bpp)
{
if (bpp <= 8)
return DST_8BPP;
......@@ -667,7 +740,7 @@ 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)
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);
......@@ -687,9 +760,9 @@ aty128_set_crtc(const struct aty128_crtc *crtc,
static int
aty128_var_to_crtc(struct fb_var_screeninfo *var,
aty128_var_to_crtc(const struct fb_var_screeninfo *var,
struct aty128_crtc *crtc,
const struct fb_info *info)
const struct fb_info_aty128 *info)
{
u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
u32 left, right, upper, lower, hslen, vslen, sync, vmode;
......@@ -744,7 +817,7 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
bytpp = mode_bytpp[depth];
/* make sure there is enough video ram for the mode */
if ((u32) (vxres * vyres * bytpp) > info->fix.smem_len) {
if ((u32)(vxres * vyres * bytpp) > info->fb_info.fix.smem_len) {
printk(KERN_ERR "aty128fb: Not enough memory for mode\n");
return -EINVAL;
}
......@@ -787,11 +860,10 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
crtc->h_total = h_total | (h_disp << 16);
crtc->v_total = v_total | (v_disp << 16);
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);
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);
crtc->pitch = vxres >> 3;
......@@ -802,7 +874,7 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
else
crtc->offset_cntl = 0;
var->xres_virtual = vxres;
crtc->vxres = vxres;
crtc->vyres = vyres;
crtc->xoffset = xoffset;
crtc->yoffset = yoffset;
......@@ -812,7 +884,8 @@ aty128_var_to_crtc(struct fb_var_screeninfo *var,
}
static int aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var)
static int
aty128_bpp_to_var(int pix_width, struct fb_var_screeninfo *var)
{
/* fill in pixel info */
......@@ -876,8 +949,7 @@ 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 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;
......@@ -913,6 +985,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
var->xres = xres;
var->yres = yres;
var->xres_virtual = crtc->vxres;
var->yres_virtual = crtc->vyres;
var->xoffset = crtc->xoffset;
var->yoffset = crtc->yoffset;
......@@ -929,7 +1002,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
}
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;
......@@ -937,18 +1010,16 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
{ 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
/* select PPLL_DIV_3 */
aty_st_le32(CLOCK_CNTL_INDEX,
aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
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);
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);
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;
......@@ -957,13 +1028,13 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
div3 |= post_conv[pll->post_divider] << 16;
/* write feedback and post dividers */
aty_pll_wait_readupdate(par);
aty_pll_wait_readupdate(info);
aty_st_pll(PPLL_DIV_3, div3);
aty_pll_writeupdate(par);
aty_pll_writeupdate(info);
aty_pll_wait_readupdate(par);
aty_pll_wait_readupdate(info);
aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */
aty_pll_writeupdate(par);
aty_pll_writeupdate(info);
/* clear the reset, just in case */
aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);
......@@ -972,10 +1043,10 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
static int
aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
const struct aty128fb_par *par)
const struct fb_info_aty128 *info)
{
const struct aty128_constants c = par->constants;
unsigned char post_dividers[] = { 1, 2, 4, 8, 3, 6, 12 };
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;
......@@ -987,7 +1058,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
if (vclk > c.ppll_max)
vclk = c.ppll_max;
if (vclk * 12 < c.ppll_min)
vclk = c.ppll_min / 12;
vclk = c.ppll_min/12;
/* now, find an acceptable divider */
for (i = 0; i < sizeof(post_dividers); i++) {
......@@ -1014,9 +1085,8 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
static int
aty128_pll_to_var(const struct aty128_pll *pll,
struct fb_var_screeninfo *var,
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;
......@@ -1026,7 +1096,7 @@ aty128_pll_to_var(const struct aty128_pll *pll,
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);
......@@ -1036,13 +1106,13 @@ aty128_set_fifo(const struct aty128_ddafifo *dsp,
static int
aty128_ddafifo(struct aty128_ddafifo *dsp,
const struct aty128_pll *pll,
u32 bpp, const struct fb_info *info)
u32 bpp,
const struct fb_info_aty128 *info)
{
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
const struct aty128_meminfo *m = par->mem;
u32 xclk = par->constants.xclk;
u32 fifo_width = par->constants.fifo_width;
u32 fifo_depth = par->constants.fifo_depth;
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;
......@@ -1056,7 +1126,11 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
ron = 4 * m->MB +
3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +
2 * m->Trp + m->Twr + m->CL + m->Tr2w + x;
2 * m->Trp +
m->Twr +
m->CL +
m->Tr2w +
x;
DBG("x %x\n", x);
......@@ -1091,14 +1165,16 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
/*
* 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);
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);
......@@ -1116,9 +1192,9 @@ aty128fb_set_par(struct fb_info *info)
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);
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;
......@@ -1132,19 +1208,16 @@ aty128fb_set_par(struct fb_info *info)
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)
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,
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);
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;
}
/*
......@@ -1153,29 +1226,90 @@ 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;
if ((err = aty128_var_to_crtc(var, &par->crtc, info)))
return err;
if ((err = aty128_var_to_pll(var->pixclock, &par->pll, par)))
if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info)))
return err;
if ((err =
aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.bpp,
info)))
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;
if ((err = aty128_crtc_to_var(&par->crtc, var)))
return err;
if ((err = aty128_pll_to_var(&par->pll, var, info)))
return err;
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
var->nonstd = 0;
var->activate = 0;
var->height = -1;
var->width = -1;
var->accel_flags = par->accel_flags;
return 0;
}
/*
* Get the User Defined Part of the Display
*/
static int
aty128fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
{
const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
if (con == -1)
aty128_encode_var(var, par, info);
else
*var = fb_display[con].var;
return 0;
}
/*
* Set the User Defined Part of the Display
*/
static int
aty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb)
{
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par par;
struct display *display;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel;
int accel, err;
display = (con >= 0) ? &fb_display[con] : fb->disp;
/* basic (in)sanity checks */
if (!var->xres)
var->xres = 1;
......@@ -1203,28 +1337,141 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL;
}
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
var->transp.msb_right = 0;
if ((err = aty128_decode_var(var, &par, info)))
return err;
var->nonstd = 0;
var->activate = 0;
aty128_encode_var(var, &par, info);
var->height = -1;
var->width = -1;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
return 0;
if ((err = aty128_decode_var(var, par, info)))
return err;
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;
if ((err = aty128_crtc_to_var(&par->crtc, var)))
return err;
if (info->fb_info.changevar)
(*info->fb_info.changevar)(con);
}
if ((err = aty128_pll_to_var(&par->pll, var, info)))
if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con)
aty128_set_par(&par, info);
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
do_install_cmap(con, &info->fb_info);
}
return 0;
}
static void
aty128_set_dispsw(struct display *disp,
struct fb_info_aty128 *info, int bpp, int accel)
{
switch (bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 15:
case 16:
disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16;
disp->dispsw_data = info->fb_info.pseudo_palette;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24;
disp->dispsw_data = info->fb_info.pseudo_palette;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32;
disp->dispsw_data = info->fb_info.pseudo_palette;
break;
#endif
default:
disp->dispsw = &fbcon_dummy;
}
}
static void
aty128_encode_fix(struct fb_fix_screeninfo *fix,
struct aty128fb_par *par,
const struct fb_info_aty128 *info)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, info->fb_info.fix.id);
fix->smem_start = info->fb_info.fix.smem_start;
fix->mmio_start = info->fb_info.fix.mmio_start;
fix->smem_len = info->fb_info.fix.smem_len;
fix->mmio_len = info->fb_info.fix.mmio_len;
fix->type = info->fb_info.fix.type;
fix->type_aux = info->fb_info.fix.type_aux;
fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3;
fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR;
fix->ywrapstep = info->fb_info.fix.ywrapstep;
fix->xpanstep = info->fb_info.fix.xpanstep;
fix->ypanstep = info->fb_info.fix.ypanstep;
fix->accel = info->fb_info.fix.accel;
return;
}
/*
* Get the Fixed Part of the Display
*/
static int
aty128fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
{
const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
aty128_decode_var(&fb_display[con].var, par, info);
aty128_encode_fix(fix, par, info);
return 0;
}
/*
* Pan or Wrap the Display
*
......@@ -1232,9 +1479,10 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
*/
static int
aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
struct fb_info *fb)
{
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
u32 xoffset, yoffset;
u32 offset;
u32 xres, yres;
......@@ -1242,79 +1490,36 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, int con,
xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
xoffset = (var->xoffset + 7) & ~7;
xoffset = (var->xoffset +7) & ~7;
yoffset = var->yoffset;
if (xoffset + xres > info->var.xres_virtual
|| yoffset + yres > par->crtc.vyres)
if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
return -EINVAL;
par->crtc.xoffset = xoffset;
par->crtc.yoffset = yoffset;
offset =
((yoffset * info->var.xres_virtual + xoffset) * par->crtc.bpp) >> 6;
offset = ((yoffset * par->crtc.vxres + xoffset) * par->crtc.bpp) >> 6;
aty_st_le32(CRTC_OFFSET, offset);
return 0;
}
/*
* Accelerated functions
*/
static void
aty128fb_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height, struct fb_info *info)
static int
aty128fb_rasterimg(struct fb_info *info, int start)
{
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);
wait_for_fifo(6, par);
aty_st_le32(SRC_Y_X, (srcy << 16) | srcx);
aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT);
aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR);
aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
par->blitter_may_be_busy = 1;
wait_for_fifo(2, par);
aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl);
}
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info;
static int aty128fb_rasterimg(struct fb_info *info, int start)
{
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
if (par->blitter_may_be_busy)
wait_for_idle(par);
return 0;
}
int __init aty128fb_setup(char *options)
int __init
aty128fb_setup(char *options)
{
char *this_opt;
......@@ -1326,28 +1531,28 @@ int __init aty128fb_setup(char *options)
char *p;
int i;
p = this_opt + 5;
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)) {
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);
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);
unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
switch (cmode) {
case 0:
case 8:
......@@ -1376,8 +1581,7 @@ 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;
......@@ -1386,15 +1590,13 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
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");
......@@ -1405,43 +1607,35 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
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;
par->chip_gen = aci->chip_gen;
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);
printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
if (info->fix.smem_len % (1024 * 1024) == 0)
printk("%dM %s\n",
info->fix.smem_len / (1024 * 1024),
par->mem->name);
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->fix.smem_len / 1024,
par->mem->name);
printk("%dk %s\n", info->fb_info.fix.smem_len / 1024, info->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;
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, mode_option, 8))
if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
var = default_var;
} else {
if (default_vmode <= 0
|| default_vmode > VMODE_MAX)
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_1024_768_60;
/* iMacs need that resolution
......@@ -1467,27 +1661,25 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
if (machine_is_compatible("PowerBook3,2"))
default_vmode = VMODE_1152_768_60;
if (default_cmode < CMODE_8
|| default_cmode > CMODE_32)
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
if (mac_vmode_to_var
(default_vmode, default_cmode, &var))
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
}
} else
#endif /* CONFIG_PPC */
{
if (fb_find_mode
(&var, info, mode_option, NULL, 0,
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;
info->var = var;
if (aty128_decode_var(&var, par, info)) {
printk(KERN_ERR "aty128fb: Cannot set default mode.\n");
return 0;
......@@ -1502,43 +1694,61 @@ aty128_init(struct fb_info *info, struct aty128fb_par *par,
/* turn off bus mastering, just in case */
aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS);
gen_set_var(&var, -1, info);
aty128fb_set_var(&var, -1, &info->fb_info);
aty128_init_engine(par, info);
board_list = aty128_board_list_add(board_list, info);
size = (var.bits_per_pixel <= 8) ? 256 : 32;
fb_alloc_cmap(&info->cmap, size, 0);
fb_alloc_cmap(&info->fb_info.cmap, size, 0);
if (register_framebuffer(info) < 0)
if (register_framebuffer(&info->fb_info) < 0)
return 0;
#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");
register_backlight_controller(&aty128_backlight_controller, info, "ati");
#endif /* CONFIG_PMAC_BACKLIGHT */
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
GET_FB_IDX(info->node), info->fix.id, name);
GET_FB_IDX(info->fb_info.node), info->fb_info.fix.id, name);
return 1; /* success! */
}
int __init aty128fb_init(void)
/* add a new card to the list ++ajoshi */
static struct
fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128 *board_list,
struct fb_info_aty128 *new_node)
{
struct fb_info_aty128 *i_p = board_list;
new_node->next = NULL;
if(board_list == NULL)
return new_node;
while(i_p->next != NULL)
i_p = i_p->next;
i_p->next = new_node;
return board_list;
}
int __init
aty128fb_init(void)
{
#ifdef CONFIG_PCI
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);
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);
pdev = pci_find_device(PCI_VENDOR_ID_ATI, aci->device, pdev);
}
aci++;
}
......@@ -1554,12 +1764,12 @@ static int __init
aty128_pci_register(struct pci_dev *pdev,
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))) {
......@@ -1569,8 +1779,7 @@ aty128_pci_register(struct pci_dev *pdev,
}
aty128fb_fix.smem_start = pci_resource_start(pdev, 0);
if (!request_mem_region
(aty128fb_fix.smem_start, pci_resource_len(pdev, 0),
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");
......@@ -1578,20 +1787,15 @@ aty128_pci_register(struct pci_dev *pdev,
}
aty128fb_fix.mmio_start = pci_resource_start(pdev, 2);
if (!request_mem_region
(aty128fb_fix.mmio_start, pci_resource_len(pdev, 2),
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;
}
......@@ -1600,68 +1804,66 @@ aty128_pci_register(struct pci_dev *pdev,
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");
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:
err_free_mmio:
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
err_free_fb:
err_free_fb:
release_mem_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1));
return -ENODEV;
......@@ -1671,7 +1873,8 @@ aty128_pci_register(struct pci_dev *pdev,
/* 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;
char *rom_base;
......@@ -1681,14 +1884,12 @@ static char __init * aty128find_ROM(struct fb_info *info)
char aty_rom_sig[] = "761295520"; /* ATI ROM Signature */
char R128_sig[] = "R128"; /* Rage128 ROM identifier */
for (segstart = 0x000c0000; segstart < 0x000f0000;
segstart += 0x00001000) {
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,9 +1898,7 @@ 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)
......@@ -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;
......@@ -1753,23 +1952,24 @@ 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 */
/* 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
......@@ -1779,11 +1979,12 @@ static void __init aty128_timings(struct aty128fb_par *par)
u32 x_mpll_ref_fb_div;
u32 xclk_cntl;
u32 Nx, M;
unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
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);
......@@ -1791,55 +1992,84 @@ static void __init aty128_timings(struct aty128fb_par *par)
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 =
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(par);
aty_pll_writeupdate(info);
}
aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
aty_pll_writeupdate(par);
aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider);
aty_pll_writeupdate(info);
/* 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 */
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 */
par->constants.fifo_width = 128;
par->constants.fifo_depth = 32;
info->constants.fifo_width = 128;
info->constants.fifo_depth = 32;
switch (aty_ld_le32(MEM_CNTL) & 0x3) {
case 0:
par->mem = &sdr_128;
info->mem = &sdr_128;
break;
case 1:
par->mem = &sdr_sgram;
info->mem = &sdr_sgram;
break;
case 2:
par->mem = &ddr_sgram;
info->mem = &ddr_sgram;
break;
default:
par->mem = &sdr_sgram;
info->mem = &sdr_sgram;
}
}
static int
aty128fbcon_switch(int con, struct fb_info *fb)
{
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct display *disp;
struct aty128fb_par par;
if (info->fb_info.currcon >= 0) {
disp = fb_display + info->fb_info.currcon;
if (disp->cmap.len)
fb_copy_cmap(&info->fb_info.cmap, &disp->cmap, 0);
}
/* set the current console */
fb->currcon = con;
aty128_decode_var(&fb_display[con].var, &par, info);
aty128_set_par(&par, info);
aty128_set_dispsw(&fb_display[con], info, par.crtc.bpp,
par.accel_flags & FB_ACCELF_TEXT);
do_install_cmap(con, fb);
return 1;
}
/*
* Blank the display.
*/
static int aty128fb_blank(int blank, struct fb_info *info)
static int
aty128fb_blank(int blank, struct fb_info *fb)
{
struct aty128fb_par *par = (struct aty128fb_par *) info->par;
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
u8 state = 0;
#ifdef CONFIG_PMAC_BACKLIGHT
......@@ -1854,7 +2084,7 @@ static int aty128fb_blank(int blank, struct fb_info *info)
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)
......@@ -1870,9 +2100,10 @@ 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;
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
struct aty128fb_par *par = (struct aty128fb_par *) fb->par;
u32 col;
if (regno > 255)
......@@ -1890,23 +2121,19 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
if ((par->crtc.bpp > 8) && (regno == 0)) {
int i;
if (par->chip_gen == rage_M3)
aty_st_le32(DAC_CNTL,
aty_ld_le32(DAC_CNTL) &
~DAC_PALETTE_ACCESS_CNTL);
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++) {
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);
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++) {
for (i=16; i<256; i++) {
aty_st_8(PALETTE_INDEX, i);
col = (i << 16) | (i << 8) | i;
aty_st_le32(PALETTE_DATA, col);
......@@ -1916,10 +2143,8 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/* initialize palette */
if (par->chip_gen == rage_M3)
aty_st_le32(DAC_CNTL,
aty_ld_le32(DAC_CNTL) &
~DAC_PALETTE_ACCESS_CNTL);
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));
......@@ -1927,10 +2152,8 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
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 (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
......@@ -1940,22 +2163,25 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
if (regno < 16)
switch (par->crtc.bpp) {
#ifdef FBCON_HAS_CFB16
case 9 ... 16:
((u32 *) (info->pseudo_palette))[regno] =
(regno << 10) | (regno << 5) | regno;
((u32*) (info->fb_info.pseudo_palette))[regno] = (regno << 10) | (regno << 5) | regno;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 17 ... 24:
((u32 *) (info->pseudo_palette))[regno] =
(regno << 16) | (regno << 8) | regno;
((u32*) (info->fb_info.pseudo_palette))[regno] = (regno << 16) | (regno << 8) | regno;
break;
case 25 ... 32:{
#endif
#ifdef FBCON_HAS_CFB32
case 25 ... 32: {
u32 i;
i = (regno << 8) | regno;
((u32 *) (info->pseudo_palette))[regno] =
(i << 16) | i;
((u32*) (info->fb_info.pseudo_palette))[regno] = (i << 16) | i;
break;
}
#endif
}
return 0;
}
......@@ -1966,9 +2192,10 @@ 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;
......@@ -1984,7 +2211,8 @@ 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);
}
......@@ -1996,10 +2224,10 @@ 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)
u_int width, u_int height,
struct fb_info_aty128 *info)
{
struct aty128fb_par *par =
(struct aty128fb_par *) info->par;
struct aty128fb_par *par = (struct aty128fb_par *) info->fb_info.par;
u32 save_dp_datatype, save_dp_cntl, bppval;
if (!width || !height)
......@@ -2015,11 +2243,11 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
return;
}
wait_for_fifo(2, par);
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, par);
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);
......@@ -2028,40 +2256,256 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
aty_st_le32(DST_Y_X, (dsty << 16) | dstx);
aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width);
par->blitter_may_be_busy = 1;
info->blitter_may_be_busy = 1;
wait_for_fifo(2, par);
wait_for_fifo(2, info);
aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl);
}
/*
* Text mode accelerated functions
*/
static void
fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
sx *= fontwidth(p);
sy *= fontheight(p);
dx *= fontwidth(p);
dy *= fontheight(p);
width *= fontwidth(p);
height *= fontheight(p);
aty128_rectcopy(sx, sy, dx, dy, width, height,
(struct fb_info_aty128 *)p->fb_info);
}
#ifdef FBCON_HAS_CFB8
static void fbcon_aty8_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb8_putc(conp, p, c, yy, xx);
}
static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty8_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb8_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_8 = {
setup: fbcon_cfb8_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb8_clear,
putc: fbcon_aty8_putc,
putcs: fbcon_aty8_putcs,
revc: fbcon_cfb8_revc,
clear_margins: fbcon_aty8_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef FBCON_HAS_CFB16
static void fbcon_aty16_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb16_putc(conp, p, c, yy, xx);
}
static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty16_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb16_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_16 = {
setup: fbcon_cfb16_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb16_clear,
putc: fbcon_aty16_putc,
putcs: fbcon_aty16_putcs,
revc: fbcon_cfb16_revc,
clear_margins: fbcon_aty16_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef FBCON_HAS_CFB24
static void fbcon_aty24_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb24_putc(conp, p, c, yy, xx);
}
static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty24_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb24_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_24 = {
setup: fbcon_cfb24_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb24_clear,
putc: fbcon_aty24_putc,
putcs: fbcon_aty24_putcs,
revc: fbcon_cfb24_revc,
clear_margins: fbcon_aty24_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef FBCON_HAS_CFB32
static void fbcon_aty32_putc(struct vc_data *conp, struct display *p,
int c, int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb32_putc(conp, p, c, yy, xx);
}
static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
const unsigned short *s, int count,
int yy, int xx)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
}
static void fbcon_aty32_clear_margins(struct vc_data *conp,
struct display *p, int bottom_only)
{
struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info);
if (fb->blitter_may_be_busy)
wait_for_idle(fb);
fbcon_cfb32_clear_margins(conp, p, bottom_only);
}
static struct display_switch fbcon_aty128_32 = {
setup: fbcon_cfb32_setup,
bmove: fbcon_aty128_bmove,
clear: fbcon_cfb32_clear,
putc: fbcon_aty32_putc,
putcs: fbcon_aty32_putcs,
revc: fbcon_cfb32_revc,
clear_margins: fbcon_aty32_clear_margins,
fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
#ifdef MODULE
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 (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);
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);
printk(KERN_INFO "aty128fb: Parameter MODE set to %s\n", mode);
}
#ifdef CONFIG_MTRR
if (nomtrr) {
......@@ -2074,22 +2518,25 @@ int __init init_module(void)
return 0;
}
void __exit cleanup_module(void)
void __exit
cleanup_module(void)
{
struct fb_info *info = board_list;
struct fb_info_aty128 *info = board_list;
struct aty128fb_par *par;
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);
mtrr_del(par->mtrr.vram, info->fb_info.fix.smem_start,
info->fb_info.fix.smem_len);
#endif /* CONFIG_MTRR */
iounmap(par->regbase);
iounmap(info->screen_base);
iounmap(info->regbase);
iounmap(info->fb_info.screen_base);
release_mem_region(pci_resource_start(info->pdev, 0),
pci_resource_len(info->pdev, 0));
......@@ -2097,6 +2544,8 @@ void __exit cleanup_module(void)
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 */
/*
* 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 @@ static void riva_cursor_timer_handler(unsigned long dev_addr)
* 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;
}
......@@ -626,6 +638,80 @@ static void rivafb_cursor(struct display *p, int mode, int x, int y)
*
* ------------------------------------------------------------------------- */
/**
* riva_set_dispsw - sets dispsw
* @rinfo: pointer to internal driver struct for a given Riva card
* @disp: pointer to display object
*
* DESCRIPTION:
* Sets up console low level operations depending on the current? color depth
* of the display.
*
* CALLED FROM:
* rivafb_set_var()
* rivafb_switch()
* riva_init_disp()
*/
static void riva_set_dispsw(struct rivafb_info *rinfo, struct display *disp)
{
int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
DPRINTK("ENTER\n");
assert(rinfo != NULL);
disp->dispsw_data = NULL;
disp->type = FB_TYPE_PACKED_PIXELS;
disp->type_aux = 0;
disp->ypanstep = 1;
disp->ywrapstep = 0;
disp->can_soft_blank = 1;
disp->inverse = 0;
switch (disp->var.bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
case 8:
rinfo->dispsw = accel ? fbcon_riva8 : fbcon_cfb8;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual;
disp->visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
rinfo->dispsw = accel ? fbcon_riva16 : fbcon_cfb16;
disp->dispsw_data = &rinfo->con_cmap.cfb16;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual * 2;
disp->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
rinfo->dispsw = accel ? fbcon_riva32 : fbcon_cfb32;
disp->dispsw_data = rinfo->con_cmap.cfb32;
disp->dispsw = &rinfo->dispsw;
disp->line_length = disp->var.xres_virtual * 4;
disp->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
default:
DPRINTK("Setting fbcon_dummy renderer\n");
rinfo->dispsw = fbcon_dummy;
disp->dispsw = &rinfo->dispsw;
}
/* FIXME: verify that the above code sets dsp->* fields correctly */
if (rinfo->cursor) {
rinfo->dispsw.cursor = rivafb_cursor;
rinfo->dispsw.set_font = rivafb_set_font;
}
DPRINTK("EXIT\n");
}
/**
* riva_wclut - set CLUT entry
* @chip: pointer to RIVA_HW_INST object
......@@ -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, &regs->ext);
rinfo->riva.UnloadStateExt(&rinfo->riva, &regs->ext);
regs->misc_output = MISCin(par);
regs->misc_output = MISCin(rinfo);
for (i = 0; i < NUM_CRT_REGS; i++) {
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 = &regs->ext;
int i;
RIVA_HW_STATE *state = &regs->ext;
CRTCout(par, 0x11, 0x00);
CRTCout(rinfo, 0x11, 0x00);
par->riva.LockUnlock(&par->riva, 0);
rinfo->riva.LockUnlock(&rinfo->riva, 0);
par->riva.LoadStateExt(&par->riva, state);
rinfo->riva.LoadStateExt(&rinfo->riva, state);
MISCout(par, regs->misc_output);
MISCout(rinfo, regs->misc_output);
for (i = 0; i < NUM_CRT_REGS; i++) {
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;
while (i_p->next != NULL)
i_p = i_p->next;
i_p->next = new_node;
return board_list;
}
/**
* riva_board_list_del - maintains board list
* @board_list: root node of list of boards
* @del_node: node to be removed
*
* DESCRIPTION:
* Removes @del_node from the list referenced by @board_list.
*
* RETURNS:
* New root node
*
* CALLED FROM:
* rivafb_remove_one()
*/
static struct rivafb_info *riva_board_list_del(struct rivafb_info *board_list,
struct rivafb_info *del_node)
{
struct rivafb_info *i_p = board_list;
if (board_list == del_node)
return del_node->next;
par->current_state = newmode;
riva_load_state(par, &par->current_state);
while (i_p->next != del_node)
i_p = i_p->next;
i_p->next = del_node->next;
par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
rivafb_download_cursor(par);
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;
return 0;
}
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;
......@@ -1094,6 +1128,46 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
return rc;
}
/**
* riva_getcolreg
* @regno: register index
* @red: red component
* @green: green component
* @blue: blue component
* @transp: transparency
* @info: pointer to rivafb_info object containing info for current riva board
*
* DESCRIPTION:
* Read a single color register and split it into colors/transparent.
* The return values must have a 16 bit magnitude.
*
* RETURNS:
* Return != 0 for invalid regno.
*
* CALLED FROM:
* rivafb_get_cmap()
* rivafb_switch()
* fbcmap.c:fb_get_cmap()
* fbgen.c:fbgen_get_cmap()
* fbgen.c:fbgen_switch()
*/
static int riva_getcolreg(unsigned regno, unsigned *red, unsigned *green,
unsigned *blue, unsigned *transp,
struct fb_info *info)
{
struct rivafb_info *rivainfo = (struct rivafb_info *)info;
if (regno >= riva_get_cmap_len(&rivainfo->currcon_display->var))
return 1;
*red = rivainfo->palette[regno].red;
*green = rivainfo->palette[regno].green;
*blue = rivainfo->palette[regno].blue;
*transp = 0;
return 0;
}
/**
* rivafb_setcolreg
* @regno: register index
......@@ -1101,7 +1175,7 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
* @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;
if (regno >= riva_get_cmap_len(&info->var))
DPRINTK("ENTER\n");
assert(rivainfo != NULL);
assert(rivainfo->currcon_display != NULL);
p = rivainfo->currcon_display;
if (regno >= riva_get_cmap_len(&p->var))
return -EINVAL;
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 (v.yoffset > v.yres_virtual - v.yres)
v.yoffset = v.yres_virtual - v.yres - 1;
v.red.msb_right =
v.green.msb_right =
v.blue.msb_right =
v.transp.offset = v.transp.length = v.transp.msb_right = 0;
switch (v.activate & FB_ACTIVATE_MASK) {
case FB_ACTIVATE_TEST:
DPRINTK("EXIT - FB_ACTIVATE_TEST\n");
return 0;
case FB_ACTIVATE_NXTOPEN: /* ?? */
case FB_ACTIVATE_NOW:
break; /* continue */
default:
DPRINTK("EXIT - unknown activation type\n");
return -EINVAL; /* unknown */
}
memcpy(&dsp->var, &v, sizeof(v));
if (chgvar) {
riva_set_dispsw(rivainfo, dsp);
if (var->yoffset > var->yres_virtual - var->yres)
var->yoffset = var->yres_virtual - var->yres - 1;
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);
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;
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;
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;
}
/*
if (par->cursor) {
disp->dispsw.cursor = rivafb_cursor;
disp->dispsw.set_font = rivafb_set_font;
}
rivafb_create_cursor(par, fontwidth(dsp), fontheight(dsp));
*/
if (con == info->currcon) { /* current console? */
int rc = fb_set_cmap(cmap, kspc, info);
DPRINTK("EXIT - returning %d\n", rc);
return rc;
} else
fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
DPRINTK("EXIT, returning 0\n");
riva_load_video_mode(info, &info->var);
riva_setup_accel(par);
return 0;
}
......@@ -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);
memset(rinfo, 0, sizeof(struct rivafb_info));
default_par = kmalloc(sizeof(struct riva_par), GFP_KERNEL);
if (!default_par)
goto err_out;
memset(default_par, 0, sizeof(struct riva_par));
info->disp = (struct display *)(info + 1);
info->pseudo_palette = (void *)(info->disp + 1);
rinfo->drvr_name = rci->name;
rinfo->riva.Architecture = rci->arch_rev;
strcat(rivafb_fix.id, rci->name);
default_par->riva.Architecture = rci->arch_rev;
rinfo->pd = pd;
rinfo->base0_region_size = pci_resource_len(pd, 0);
rinfo->base1_region_size = pci_resource_len(pd, 1);
rivafb_fix.mmio_len = pci_resource_len(pd, 0);
rivafb_fix.smem_len = pci_resource_len(pd, 1);
assert(rinfo->base0_region_size >= 0x00800000); /* from GGI */
assert(rinfo->base1_region_size >= 0x01000000); /* from GGI */
assert(rivafb_fix.mmio_len >= 0x00800000); /* from GGI */
assert(rivafb_fix.smem_len >= 0x01000000); /* from GGI */
rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0);
rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1);
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) {
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")) {
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;
}
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;
}
default_par->riva.PRAMIN = (unsigned *)(info->screen_base + 0x00C00000);
rivafb_fix.accel = FB_ACCEL_NV3;
break;
case NV_ARCH_04:
case NV_ARCH_10:
case NV_ARCH_20:
/* riva_hw.c now doesn't distinguish between TNT & TNT2 */
default_par->riva.PCRTC = (unsigned *)(default_par->ctrl_base + 0x00600000);
default_par->riva.PRAMIN = (unsigned *)(default_par->ctrl_base + 0x00710000);
rivafb_fix.accel = FB_ACCEL_NV4;
break;
}
RivaGetConfig(&default_par->riva);
/* unlock io */
CRTCout(default_par, 0x11, 0xFF);/* vgaHWunlock()+riva unlock (0x7F) */
default_par->riva.LockUnlock(&default_par->riva, 0);
riva_save_state(default_par, &default_par->initial_state);
default_par->ram_amount = default_par->riva.RamAmountKBytes * 1024;
default_par->dclk_max = default_par->riva.MaxVClockFreqKHz * 1000;
if (default_par->riva.Architecture != NV_ARCH_03) {
/*
* Now the _normal_ chipsets can just map the amount of real
* physical ram instead of the whole aperture
*/
rivafb_fix.smem_len = default_par->ram_amount;
if (!request_mem_region(rivafb_fix.smem_start,
rivafb_fix.smem_len, "rivafb")) {
printk(KERN_ERR PFX "cannot reserve FB region\n");
goto err_out_free_base0;
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;
}
info->screen_base = ioremap(rivafb_fix.smem_start,
rivafb_fix.smem_len);
if (!info->screen_base) {
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) {
default_par->mtrr.vram = mtrr_add(rivafb_fix.smem_start,
rivafb_fix.smem_len, MTRR_TYPE_WRCOMB, 1);
if (default_par->mtrr.vram < 0) {
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 {
default_par->mtrr.vram_valid = 1;
rinfo->mtrr.vram_valid = 1;
/* let there be speed */
printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
}
}
#endif /* CONFIG_MTRR */
if (!nohwcursor) default_par->cursor = rivafb_init_cursor(info);
rinfo->riva.EnableIRQ = 0;
rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000);
rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000);
rinfo->riva.PFIFO = (unsigned *)(rinfo->ctrl_base + 0x00002000);
rinfo->riva.PGRAPH = (unsigned *)(rinfo->ctrl_base + 0x00400000);
rinfo->riva.PEXTDEV = (unsigned *)(rinfo->ctrl_base + 0x00101000);
rinfo->riva.PTIMER = (unsigned *)(rinfo->ctrl_base + 0x00009000);
rinfo->riva.PMC = (unsigned *)(rinfo->ctrl_base + 0x00000000);
rinfo->riva.FIFO = (unsigned *)(rinfo->ctrl_base + 0x00800000);
rinfo->riva.PCIO = (U008 *)(rinfo->ctrl_base + 0x00601000);
rinfo->riva.PDIO = (U008 *)(rinfo->ctrl_base + 0x00681000);
rinfo->riva.PVIO = (U008 *)(rinfo->ctrl_base + 0x000C0000);
rinfo->riva.IO = (MISCin(rinfo) & 0x01) ? 0x3D0 : 0x3B0;
switch (rinfo->riva.Architecture) {
case NV_ARCH_03:
rinfo->riva.PRAMIN = (unsigned *)(rinfo->fb_base + 0x00C00000);
break;
case NV_ARCH_04:
case NV_ARCH_10:
rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000);
rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000);
break;
}
info->par = default_par;
RivaGetConfig(&rinfo->riva);
if (riva_set_fbinfo(info) < 0) {
/* back to normal */
assert(rinfo->pd != NULL);
/* unlock io */
CRTCout(rinfo, 0x11, 0xFF); /* vgaHWunlock() + riva unlock (0x7F) */
rinfo->riva.LockUnlock(&rinfo->riva, 0);
riva_save_state(rinfo, &rinfo->initial_state);
rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;
rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000;
if (!nohwcursor) rinfo->cursor = rivafb_init_cursor(rinfo);
if (riva_set_fbinfo(rinfo) < 0) {
printk(KERN_ERR PFX "error setting initial video mode\n");
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");
......
......@@ -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,8 +1421,6 @@ 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;
......@@ -1435,20 +1430,6 @@ static void LoadStateExt
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[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];
......
......@@ -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. *
......
......@@ -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,33 +27,56 @@ 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;
#endif
......
......@@ -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);
par->palette_cpu[0] = (par->palette_cpu[0] &
0xcfff) | palette_pbs(info->var.bits_per_pixel);
fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
0xcfff) | palette_pbs(var);
}
switch (info->var.bits_per_pixel) {
/*
* sa1100fb_set_var():
* Set the user defined part of the display for the specified console
*/
static int
sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
struct display *display = get_con_display(&fbi->fb, con);
int err, chgvar = 0, rgbidx;
DPRINTK("set_var\n");
/*
* Decode var contents into a par structure, adjusting any
* out of range values.
*/
err = sa1100fb_validate_var(var, fbi);
if (err)
return err;
if (var->activate & FB_ACTIVATE_TEST)
return 0;
if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
return -EINVAL;
if (dvar->xres != var->xres)
chgvar = 1;
if (dvar->yres != var->yres)
chgvar = 1;
if (dvar->xres_virtual != var->xres_virtual)
chgvar = 1;
if (dvar->yres_virtual != var->yres_virtual)
chgvar = 1;
if (dvar->bits_per_pixel != var->bits_per_pixel)
chgvar = 1;
if (con < 0)
chgvar = 0;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
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,30 +1317,83 @@ 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;
u_int state = xchg(&par->task_state, -1);
struct sa1100fb_info *fbi = dummy;
u_int state = xchg(&fbi->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;
}
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment