Commit c88b20f7 authored by James Simmons's avatar James Simmons

Ported over the apollo framebuffer device. Updated the Permedia 2 fbdev driver...

Ported over the apollo framebuffer device. Updated the Permedia 2 fbdev driver to the latest code. Small bug fix for the NeoMagic driver. .
parent 34dfe0cd
......@@ -372,7 +372,7 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_HP300" = "y" -o "$CONFIG_FB_Q40" = "y" -o \
"$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
"$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \
"$CONFIG_FB_3DFX" = "y" ]; then
"$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_APOLLO" = "y" ]; then
define_tristate CONFIG_FBCON_ACCEL y
else
if [ "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_HIT" = "m" -o \
......
......@@ -43,7 +43,7 @@ obj-$(CONFIG_FB_ACORN) += acornfb.o
obj-$(CONFIG_FB_AMIGA) += amifb.o
obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o cfbfillrect.o cfbimgblt.o
obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_ATARI) += atafb.o
obj-$(CONFIG_FB_ATY128) += aty128fb.o
......
......@@ -14,9 +14,8 @@
#include <asm/apollohw.h>
#include <linux/fb.h>
#include <linux/module.h>
#include "dn_accel.h"
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
/* apollo video HW definitions */
......@@ -30,45 +29,45 @@
* deals with control 1 and 3b deals with Color LUT reg.
*/
#define AP_IOBASE 0x3b0 /* Base address of 1 plane board. */
#define AP_STATUS isaIO2mem(AP_IOBASE+0) /* Status register. Read */
#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
#define AP_DEVICE_ID isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
#define AP_ROP_1 isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
#define AP_CONTROL_0 isaIO2mem(AP_IOBASE+8) /* Control Register 0. Read/Write */
#define AP_CONTROL_1 isaIO2mem(AP_IOBASE+0xa) /* Control Register 1. Read/Write */
#define AP_CONTROL_3A isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
#define AP_CONTROL_2 isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
#define AP_IOBASE 0x3b0 /* Base address of 1 plane board. */
#define AP_STATUS isaIO2mem(AP_IOBASE+0) /* Status register. Read */
#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
#define AP_DEVICE_ID isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
#define AP_ROP_1 isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
#define AP_CONTROL_0 isaIO2mem(AP_IOBASE+8) /* Control Register 0. Read/Write */
#define AP_CONTROL_1 isaIO2mem(AP_IOBASE+0xa) /* Control Register 1. Read/Write */
#define AP_CONTROL_3A isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
#define AP_CONTROL_2 isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
#define FRAME_BUFFER_START 0x0FA0000
#define FRAME_BUFFER_LEN 0x40000
/* CREG 0 */
#define VECTOR_MODE 0x40 /* 010x.xxxx */
#define DBLT_MODE 0x80 /* 100x.xxxx */
#define NORMAL_MODE 0xE0 /* 111x.xxxx */
#define SHIFT_BITS 0x1F /* xxx1.1111 */
/* other bits are Shift value */
#define VECTOR_MODE 0x40 /* 010x.xxxx */
#define DBLT_MODE 0x80 /* 100x.xxxx */
#define NORMAL_MODE 0xE0 /* 111x.xxxx */
#define SHIFT_BITS 0x1F /* xxx1.1111 */
/* other bits are Shift value */
/* CREG 1 */
#define AD_BLT 0x80 /* 1xxx.xxxx */
#define NORMAL 0x80 /* 1xxx.xxxx */ /* What is happening here ?? */
#define INVERSE 0x00 /* 0xxx.xxxx */ /* Clearing this reverses the screen */
#define PIX_BLT 0x00 /* 0xxx.xxxx */
#define AD_BLT 0x80 /* 1xxx.xxxx */
#define NORMAL 0x80 /* 1xxx.xxxx */ /* What is happening here ?? */
#define INVERSE 0x00 /* 0xxx.xxxx */ /* Clearing this reverses the screen */
#define PIX_BLT 0x00 /* 0xxx.xxxx */
#define AD_HIBIT 0x40 /* xIxx.xxxx */
#define AD_HIBIT 0x40 /* xIxx.xxxx */
#define ROP_EN 0x10 /* xxx1.xxxx */
#define DST_EQ_SRC 0x00 /* xxx0.xxxx */
#define nRESET_SYNC 0x08 /* xxxx.1xxx */
#define SYNC_ENAB 0x02 /* xxxx.xx1x */
#define ROP_EN 0x10 /* xxx1.xxxx */
#define DST_EQ_SRC 0x00 /* xxx0.xxxx */
#define nRESET_SYNC 0x08 /* xxxx.1xxx */
#define SYNC_ENAB 0x02 /* xxxx.xx1x */
#define BLANK_DISP 0x00 /* xxxx.xxx0 */
#define ENAB_DISP 0x01 /* xxxx.xxx1 */
#define BLANK_DISP 0x00 /* xxxx.xxx0 */
#define ENAB_DISP 0x01 /* xxxx.xxx1 */
#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
/* CREG 2 */
......@@ -76,13 +75,13 @@
* Following 3 defines are common to 1, 4 and 8 plane.
*/
#define S_DATA_1s 0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
#define S_DATA_PIX 0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
#define S_DATA_PLN 0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
one plane of image mem */
#define S_DATA_1s 0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
#define S_DATA_PIX 0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
#define S_DATA_PLN 0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
one plane of image mem */
/* CREG 3A/CREG 3B */
# define RESET_CREG 0x80 /* 1000.0000 */
# define RESET_CREG 0x80 /* 1000.0000 */
/* ROP REG - all one nibble */
/* ********* NOTE : this is used r0,r1,r2,r3 *********** */
......@@ -111,385 +110,169 @@
#define outw(a,d) *(unsigned short *)a=d
#endif
static struct fb_info fb_info;
static struct display disp;
/* frame buffer operations */
static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
struct fb_info *info);
static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
struct fb_info *info);
static int dn_fb_blank(int blank,struct fb_info *info);
static int dnfbcon_switch(int con,struct fb_info *info);
static int dnfbcon_updatevar(int con,struct fb_info *info);
static int dn_fb_blank(int blank, struct fb_info *info);
static void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
static void dn_fb_set_disp(int con,struct fb_info *info);
static struct display disp[MAX_NR_CONSOLES];
static struct fb_info fb_info;
static struct fb_ops dn_fb_ops = {
owner: THIS_MODULE,
fb_get_fix: dn_fb_get_fix,
fb_get_var: dn_fb_get_var,
fb_set_var: dn_fb_set_var,
fb_get_cmap: dn_fb_get_cmap,
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_blank: dn_fb_blank,
fb_blank: dnfb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: dnfb_copyarea,
fb_imageblit: cfb_imageblit,
};
#define NUM_TOTAL_MODES 1
struct fb_var_screeninfo dn_fb_predefined[] = {
{ 0, },
struct fb_var_screeninfo dnfb_var __initdata = {
xres: 1280,
yres: 1024,
xres_virtual: 2048,
yres_virtual: 1024,
bits_per_pixel: 1,
height: -1,
width: -1,
vmode: FB_VMODE_NONINTERLACED,
};
static char dn_fb_name[]="Apollo ";
/* accel stuff */
#define USE_DN_ACCEL
static struct display_switch dispsw_apollofb;
static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info) {
strcpy(fix->id,"Apollo Mono");
fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
fix->smem_len=FRAME_BUFFER_LEN;
fix->type=FB_TYPE_PACKED_PIXELS;
fix->type_aux=0;
fix->visual=FB_VISUAL_MONO10;
fix->xpanstep=0;
fix->ypanstep=0;
fix->ywrapstep=0;
fix->line_length=256;
return 0;
}
static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info) {
var->xres=1280;
var->yres=1024;
var->xres_virtual=2048;
var->yres_virtual=1024;
var->xoffset=0;
var->yoffset=0;
var->bits_per_pixel=1;
var->grayscale=0;
var->nonstd=0;
var->activate=0;
var->height=-1;
var->width=-1;
var->pixclock=0;
var->left_margin=0;
var->right_margin=0;
var->hsync_len=0;
var->vsync_len=0;
var->sync=0;
var->vmode=FB_VMODE_NONINTERLACED;
return 0;
}
static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info) {
printk("fb_set_var\n");
if(var->xres!=1280)
return -EINVAL;
if(var->yres!=1024)
return -EINVAL;
if(var->xres_virtual!=2048)
return -EINVAL;
if(var->yres_virtual!=1024)
return -EINVAL;
if(var->xoffset!=0)
return -EINVAL;
if(var->yoffset!=0)
return -EINVAL;
if(var->bits_per_pixel!=1)
return -EINVAL;
if(var->grayscale!=0)
return -EINVAL;
if(var->nonstd!=0)
return -EINVAL;
if(var->activate!=0)
return -EINVAL;
if(var->pixclock!=0)
return -EINVAL;
if(var->left_margin!=0)
return -EINVAL;
if(var->right_margin!=0)
return -EINVAL;
if(var->hsync_len!=0)
return -EINVAL;
if(var->vsync_len!=0)
return -EINVAL;
if(var->sync!=0)
return -EINVAL;
if(var->vmode!=FB_VMODE_NONINTERLACED)
return -EINVAL;
return 0;
}
static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
struct fb_info *info) {
printk("get cmap not supported\n");
return -EINVAL;
}
static void dn_fb_set_disp(int con, struct fb_info *info) {
struct fb_fix_screeninfo fix;
struct display *display;
dn_fb_get_fix(&fix,con, info);
if (con>=0)
display=&fb_display[con];
else
display=&disp[0];
if(con==-1)
con=0;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
display->ypanstep = fix.ypanstep;
display->ywrapstep = fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = 0;
display->line_length = fix.line_length;
#ifdef FBCON_HAS_MFB
display->dispsw = &fbcon_mfb;
#else
display->dispsw=&fbcon_dummy;
#endif
}
unsigned long __init dnfb_init(unsigned long mem_start) {
int err;
fb_info.changevar=NULL;
strcpy(&fb_info.modename[0],dn_fb_name);
fb_info.fontname[0]=0;
fb_info.disp=disp;
fb_info.switch_con=&dnfbcon_switch;
fb_info.updatevar=&dnfbcon_updatevar;
fb_info.node = NODEV;
fb_info.fbops = &dn_fb_ops;
fb_info.currcon = -1;
dn_fb_get_var(&disp[0].var,0, &fb_info);
dn_fb_set_disp(-1, &fb_info);
fb_info.screen_base = (u_char *)fix.smem_start;
err=register_framebuffer(&fb_info);
if(err < 0) {
panic("unable to register apollo frame buffer\n");
}
/* now we have registered we can safely setup the hardware */
outb(RESET_CREG, AP_CONTROL_3A);
outw(0x0, AP_WRITE_ENABLE);
outb(NORMAL_MODE, AP_CONTROL_0);
outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
outb(S_DATA_PLN, AP_CONTROL_2);
outw(SWAP(0x3), AP_ROP_1);
printk("apollo frame buffer alive and kicking !\n");
return mem_start;
}
static int dnfbcon_switch(int con, struct fb_info *info) {
info->currcon = con;
return 0;
}
static int dnfbcon_updatevar(int con, struct fb_info *info) {
return 0;
}
static struct fb_fix_screeninfo dnfb_fix __initdata = {
id: "Apollo Mono",
smem_start: (FRAME_BUFFER_START + IO_BASE),
smem_len: FRAME_BUFFER_LEN,
type: FB_TYPE_PACKED_PIXELS,
visual: FB_VISUAL_MONO10,
line_length: 256,
};
static int dn_fb_blank(int blank, struct fb_info *info)
static int dnfb_blank(int blank, struct fb_info *info)
{
if (blank)
outb(0x0, AP_CONTROL_3A);
outb(0x0, AP_CONTROL_3A);
else
outb(0x1, AP_CONTROL_3A);
outb(0x1, AP_CONTROL_3A);
return 0;
}
void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
int x_count, int y_count) {
int incr,y_delta,pre_read=0,x_end,x_word_count;
ushort *src,dummy;
uint start_mask,end_mask,dest;
short i,j;
incr=(y_dest<=y_src) ? 1 : -1 ;
src=(ushort *)(p->fb_info.screen_base+ y_src*p->next_line+(x_src >> 4));
dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
if(incr>0) {
y_delta=(p->next_line*8)-x_src-x_count;
x_end=x_dest+x_count-1;
x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
start_mask=0xffff0000 >> (x_dest & 0xf);
end_mask=0x7ffff >> (x_end & 0xf);
outb((((x_dest & 0xf) - (x_src &0xf)) % 16)|(0x4 << 5),AP_CONTROL_0);
if((x_dest & 0xf) < (x_src & 0xf))
pre_read=1;
}
else {
y_delta=-((p->next_line*8)-x_src-x_count);
x_end=x_dest-x_count+1;
x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
start_mask=0x7ffff >> (x_dest & 0xf);
end_mask=0xffff0000 >> (x_end & 0xf);
outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
if((x_dest & 0xf) > (x_src & 0xf))
pre_read=1;
static
void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
{
int incr, y_delta, pre_read = 0, x_end, x_word_count;
int x_count, y_count;
ushort *src, dummy;
uint start_mask, end_mask, dest;
short i, j;
incr = (area->dy <= area->sy) ? 1 : -1;
src =
(ushort *) (info->screen_base + area->sy * info->fix.next_line +
(area->sx >> 4));
dest = area->dy * (info->fix.next_line >> 1) + (area->dx >> 4);
if (incr > 0) {
y_delta = (info->fix.next_line * 8) - area->sx - x_count;
x_end = area->dx + x_count - 1;
x_word_count = (x_end >> 4) - (area->dx >> 4) + 1;
start_mask = 0xffff0000 >> (area->dx & 0xf);
end_mask = 0x7ffff >> (x_end & 0xf);
outb((((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5),
AP_CONTROL_0);
if ((area->dx & 0xf) < (area->sx & 0xf))
pre_read = 1;
} else {
y_delta = -((info->fix.next_line * 8) - area->sx - x_count);
x_end = area->dx - x_count + 1;
x_word_count = (area->dx >> 4) - (x_end >> 4) + 1;
start_mask = 0x7ffff >> (area->dx & 0xf);
end_mask = 0xffff0000 >> (x_end & 0xf);
outb(((-((area->sx & 0xf) - (area->dx & 0xf))) %
16) | (0x4 << 5), AP_CONTROL_0);
if ((area->dx & 0xf) > (area->sx & 0xf))
pre_read = 1;
}
for(i=0;i<y_count;i++) {
for (i = 0; i < y_count; i++) {
outb(0xc | (dest >> 16), AP_CONTROL_3A);
if(pre_read) {
dummy=*src;
src+=incr;
if (pre_read) {
dummy = *src;
src += incr;
}
if(x_word_count) {
outb(start_mask,AP_WRITE_ENABLE);
*src=dest;
src+=incr;
dest+=incr;
outb(0,AP_WRITE_ENABLE);
for(j=1;j<(x_word_count-1);j++) {
*src=dest;
src+=incr;
dest+=incr;
if (x_word_count) {
outb(start_mask, AP_WRITE_ENABLE);
*src = dest;
src += incr;
dest += incr;
outb(0, AP_WRITE_ENABLE);
for (j = 1; j < (x_word_count - 1); j++) {
*src = dest;
src += incr;
dest += incr;
}
outb(start_mask,AP_WRITE_ENABLE);
*src=dest;
dest+=incr;
src+=incr;
}
else {
outb(start_mask, AP_WRITE_ENABLE);
*src = dest;
dest += incr;
src += incr;
} else {
outb(start_mask | end_mask, AP_WRITE_ENABLE);
*src=dest;
dest+=incr;
src+=incr;
*src = dest;
dest += incr;
src += incr;
}
src+=(y_delta/16);
dest+=(y_delta/16);
src += (y_delta / 16);
dest += (y_delta / 16);
}
outb(NORMAL_MODE,AP_CONTROL_0);
outb(NORMAL_MODE, AP_CONTROL_0);
}
static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
unsigned long __init dnfb_init(unsigned long mem_start)
{
int err;
int fontheight,fontwidth;
fontheight=fontheight(p);
fontwidth=fontwidth(p);
#ifdef USE_DN_ACCEL
dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
height*fontheight);
#else
u_char *src, *dest;
u_int rows;
if (sx == 0 && dx == 0 && width == p->next_line) {
src = p->fb_info.screen_base+sy*fontheight*width;
dest = p->fb_info.screen_base+dy*fontheight*width;
mymemmove(dest, src, height*fontheight*width);
} else if (dy <= sy) {
src = p->fb_info.screen_base+sy*fontheight*next_line+sx;
dest = p->fb_info.screen_base+dy*fontheight*next_line+dx;
for (rows = height*fontheight; rows--;) {
mymemmove(dest, src, width);
src += p->next_line;
dest += p->next_line;
}
} else {
src = p->fb_info.screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
dest = p->fb_info.screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
for (rows = height*fontheight; rows--;) {
mymemmove(dest, src, width);
src -= p->next_line;
dest -= p->next_line;
}
}
#endif
}
strcpy(&fb_info.modename, dnfb_fix);
fb_info.changevar = NULL;
fb_info.fontname[0] = 0;
fb_info.disp = &disp;
fb_info.switch_con = gen_switch;
fb_info.updatevar = gen_update_var;
fb_info.node = NODEV;
fb_info.fbops = &dn_fb_ops;
fb_info.currcon = -1;
fb_info.fix = dnfb_fix;
fb_info.var = dnfb_var;
static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
int height, int width)
{
fbcon_mfb_clear(conp,p,sy,sx,height,width);
}
fb_alloc_cmap(&fb_info.cmap, 2, 0);
gen_set_disp(-1, &fb_info);
static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
int xx)
{
fbcon_mfb_putc(conp,p,c,yy,xx);
}
fb_info.screen_base = (u_char *) fb_info.fix.smem_start;
static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
int count, int yy, int xx)
{
fbcon_mfb_putcs(conp,p,s,count,yy,xx);
}
err = register_framebuffer(&fb_info);
if (err < 0)
panic("unable to register apollo frame buffer\n");
static void rev_char_apollofb(struct display *p, int xx, int yy)
{
fbcon_mfb_revc(p,xx,yy);
/* now we have registered we can safely setup the hardware */
outb(RESET_CREG, AP_CONTROL_3A);
outw(0x0, AP_WRITE_ENABLE);
outb(NORMAL_MODE, AP_CONTROL_0);
outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
outb(S_DATA_PLN, AP_CONTROL_2);
outw(SWAP(0x3), AP_ROP_1);
printk("apollo frame buffer alive and kicking !\n");
return mem_start;
}
static struct display_switch dispsw_apollofb = {
setup: fbcon_mfb_setup,
bmove: bmove_apollofb,
clear: clear_apollofb,
putc: putc_apollofb,
putcs: putcs_apollofb,
revc: rev_char_apollofb,
fontwidthmask: FONTWIDTH(8)
};
MODULE_LICENSE("GPL");
......@@ -2044,7 +2044,7 @@ int __init neofb_setup(char *options)
return 0;
}
static int __init initialized = 0;
static int __initdata initialized = 0;
int __init neofb_init(void)
{
......
/*
* Permedia2 framebuffer driver.
* Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
* Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
* Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
* Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
* --------------------------------------------------------------------------
* $Id: pm2fb.c,v 1.163 1999/02/21 14:06:49 illo Exp $
* $Id: pm2fb.c,v 1.213 2000/09/19 01:03:19 illo Exp $
* --------------------------------------------------------------------------
* History:
* 1999/05/09 added Jim Hague's 'var' kernel option (thanks Jim!)
* 2002/04/23 Jim Hague <jim.hague@acm.org>
* * Integrated Illo's last changes, No changelist available.
* Major items: acceleration support, hardware cursor code
* (not yet enabled).
* * Fixed -vsync, added lowhsync/lowvsync overrides for use with
* XFree GLINT driver.
* --------------------------------------------------------------------------
* TODO multiple boards support
* --------------------------------------------------------------------------
......@@ -67,6 +76,9 @@
#define DPRINTK(a,b...)
#endif
#define PICOS2KHZ(a) (1000000000UL/(a))
#define KHZ2PICOS(a) (1000000000UL/(a))
/*
* The _DEFINITIVE_ memory mapping/unmapping functions.
* This is due to the fact that they're changing soooo often...
......@@ -78,9 +90,15 @@
* The _DEFINITIVE_ memory i/o barrier functions.
* This is due to the fact that they're changing soooo often...
*/
#ifdef __mc68000__
#define DEFW()
#define DEFR()
#define DEFRW()
#else
#define DEFW() wmb()
#define DEFR() rmb()
#define DEFRW() mb()
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
......@@ -90,6 +108,10 @@
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
#define VIDEO_MASK 0x00011e7f /* r/w values for VIDEO_CONTROL */
#define PM2FF_ACCEL (1L<<0)
struct pm2fb_par {
u32 pixclock; /* pixclock in KHz */
u32 width; /* width of virtual screen */
......@@ -106,12 +128,17 @@ struct pm2fb_par {
u32 base; /* screen base (xoffset+yoffset) */
u32 depth; /* screen depth (8, 16, 24 or 32) */
u32 video; /* video control (hsync,vsync) */
u32 flags; /* internal flags (PM2FF_xxxx) */
};
#define OPTF_OLD_MEM (1L<<0)
#define OPTF_YPAN (1L<<1)
#define OPTF_VIRTUAL (1L<<2)
#define OPTF_USER (1L<<3)
#define OPTF_USER_VAR (1L<<4)
#define OPTF_LOW_HSYNC (1L<<5)
#define OPTF_LOW_VSYNC (1L<<6)
static struct {
char font[40];
u32 flags;
......@@ -126,70 +153,76 @@ static struct {
static char curblink __initdata = 1;
static struct {
static struct fb_var_screeninfo user_var __initdata={0,};
#define DEFAULT_USER_MODE 0
static const struct {
char name[16];
struct pm2fb_par par;
} user_mode[] __initdata = {
{"640x480-60",
{25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}},
{25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121,PM2FF_ACCEL}},
{"640x480-72",
{31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}},
{31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121,PM2FF_ACCEL}},
{"640x480-75",
{31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}},
{31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121,PM2FF_ACCEL}},
{"640x480-90",
{39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}},
{39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121,PM2FF_ACCEL}},
{"640x480-100",
{44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}},
{44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121,PM2FF_ACCEL}},
{"800x600-56",
{35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}},
{35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41,PM2FF_ACCEL}},
{"800x600-60",
{40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}},
{40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41,PM2FF_ACCEL}},
{"800x600-70",
{44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}},
{44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105,PM2FF_ACCEL}},
{"800x600-72",
{50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}},
{50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41,PM2FF_ACCEL}},
{"800x600-75",
{49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}},
{49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41,PM2FF_ACCEL}},
{"800x600-90",
{56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}},
{56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41,PM2FF_ACCEL}},
{"800x600-100",
{67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}},
{67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41,PM2FF_ACCEL}},
{"1024x768-60",
{64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}},
{64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121,PM2FF_ACCEL}},
{"1024x768-70",
{74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}},
{74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121,PM2FF_ACCEL}},
{"1024x768-72",
{74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}},
{74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121,PM2FF_ACCEL}},
{"1024x768-75",
{78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}},
{78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41,PM2FF_ACCEL}},
{"1024x768-90",
{100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}},
{100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121,PM2FF_ACCEL}},
{"1024x768-100",
{109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}},
{109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121,PM2FF_ACCEL}},
{"1024x768-illo",
{120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}},
{120336,1024,768,12,48,120,375,3,7,32,799,128,0,8,41,PM2FF_ACCEL}},
{"1152x864-60",
{80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}},
{80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41,PM2FF_ACCEL}},
{"1152x864-70",
{100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}},
{100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41,PM2FF_ACCEL}},
{"1152x864-75",
{109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}},
{109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41,PM2FF_ACCEL}},
{"1152x864-80",
{109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}},
{109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41,PM2FF_ACCEL}},
{"1152x900-66-sun",
{92940,1152,900,16,80,176,751,1,5,37,936,288,0,16,121,PM2FF_ACCEL}},
{"1280x1024-60",
{107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}},
{107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41,PM2FF_ACCEL}},
{"1280x1024-70",
{125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}},
{125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41,PM2FF_ACCEL}},
{"1280x1024-74",
{134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}},
{134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41,PM2FF_ACCEL}},
{"1280x1024-75",
{134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}},
{134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41,PM2FF_ACCEL}},
{"1600x1200-60",
{155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}},
{155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121,PM2FF_ACCEL}},
{"1600x1200-66",
{171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}},
{171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121,PM2FF_ACCEL}},
{"1600x1200-76",
{197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}},
{197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121,PM2FF_ACCEL}},
{"\0", },
};
......@@ -225,7 +258,7 @@ static struct pm2fb_info {
struct fb_info_gen gen;
int board; /* Permedia2 board index (see
board_table[] below) */
pm2type_t type;
pm2type_t type; /* Permedia2 board type */
struct {
unsigned long fb_base; /* physical framebuffer memory base */
u32 fb_size; /* framebuffer memory size */
......@@ -248,6 +281,7 @@ static struct pm2fb_info {
} board_par;
struct pm2fb_par current_par; /* displayed screen */
int current_par_valid;
int is_blank;
u32 memclock; /* memclock (set by the per-board
init routine) */
struct display disp;
......@@ -360,9 +394,6 @@ static void pm2fb_set_par(const void* par, struct fb_info_gen* info);
static int pm2fb_getcolreg(unsigned regno,
unsigned* red, unsigned* green, unsigned* blue,
unsigned* transp, struct fb_info* info);
static int pm2fb_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info* info);
static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
struct fb_info_gen* info);
......@@ -376,15 +407,20 @@ static struct fbgen_hwswitch pm2fb_hwswitch={
pm2fb_blank, pm2fb_set_disp
};
static int pm2fb_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info* info);
static struct fb_ops pm2fb_ops={
owner: THIS_MODULE,
fb_get_fix: fbgen_get_fix,
fb_get_var: fbgen_get_var,
fb_set_var: fbgen_set_var,
fb_get_cmap: fbgen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_setcolreg: pm2fb_setcolreg,
fb_set_cmap: fbgen_set_cmap,
fb_pan_display: fbgen_pan_display,
fb_setcolreg: pm2fb_setcolreg,
fb_blank: fbgen_blank,
};
......@@ -394,12 +430,12 @@ static struct fb_ops pm2fb_ops={
inline static u32 RD32(unsigned char* base, s32 off) {
return readl(base+off);
return fb_readl(base+off);
}
inline static void WR32(unsigned char* base, s32 off, u32 v) {
writel(v, base+off);
fb_writel(v, base+off);
}
inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
......@@ -520,7 +556,7 @@ static u32 from3264(u32 timing, int bpp, int is64) {
}
static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
unsigned char* pp) {
unsigned char* pp) {
unsigned char m;
unsigned char n;
unsigned char p;
......@@ -608,7 +644,7 @@ static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
switch (info->type) {
case PM2_TYPE_PERMEDIA2:
pm2_mnp(clk, &m, &n, &p);
WAIT_FIFO(info, 10);
WAIT_FIFO(info, 8);
pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
DEFW();
pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
......@@ -618,13 +654,16 @@ static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
DEFW();
pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
DEFR();
for (i=256; i &&
!(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
for (i=256;
i && !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED);
i--)
;
break;
case PM2_TYPE_PERMEDIA2V:
pm2v_mnp(clk/2, &m, &n, &p);
WAIT_FIFO(info, 8);
pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
pm2_WR(info, PM2VR_RD_INDEX_HIGH,
PM2VI_RD_CLK0_PRESCALE >> 8);
pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
......@@ -662,7 +701,7 @@ static void set_color(struct pm2fb_info* p, unsigned char regno,
static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
WAIT_FIFO(i, 2);
WAIT_FIFO(i, 4);
#ifdef __LITTLE_ENDIAN
pm2_WR(i, PM2R_APERTURE_ONE, 0);
pm2_WR(i, PM2R_APERTURE_TWO, 0);
......@@ -685,13 +724,113 @@ static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
#endif
}
static void set_video(struct pm2fb_info* i, u32 video) {
u32 tmp;
u32 vsync;
vsync=video;
/*
* The hardware cursor needs +vsync to recognise vert retrace.
* We may not be using the hardware cursor, but the X Glint
* driver may well. So always set +hsync/+vsync and then set
* the RAMDAC to invert the sync if necessary.
*/
vsync&=~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK);
vsync|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
WAIT_FIFO(i, 5);
pm2_WR(i, PM2R_VIDEO_CONTROL, vsync);
switch (i->type) {
case PM2_TYPE_PERMEDIA2:
tmp = PM2F_RD_PALETTE_WIDTH_8;
if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
tmp |= 4; /* invert hsync */
if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
tmp |= 8; /* invert vsync */
pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
break;
case PM2_TYPE_PERMEDIA2V:
tmp = 0;
if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
tmp |= 1; /* invert hsync */
if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
tmp |= 4; /* invert vsync */
pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
break;
}
}
static void get_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
u32 clrmode;
u32 readpx;
u32 misc;
memset(p, 0, sizeof(struct pm2fb_par));
p->base=pm2_RD(i, PM2R_SCREEN_BASE);
p->video=pm2_RD(i, PM2R_VIDEO_CONTROL) & VIDEO_MASK;
switch (i->type) {
case PM2_TYPE_PERMEDIA2:
misc=pm2_RDAC_RD(i, PM2I_RD_MISC_CONTROL);
if ( misc & 4 )
/* Hsync is actually low */
p->video |= PM2F_HSYNC_ACT_LOW;
if ( misc & 8 )
/* Vsync is actually low */
p->video |= PM2F_VSYNC_ACT_LOW;
break;
case PM2_TYPE_PERMEDIA2V:
misc=pm2_RDAC_RD(i, PM2VI_RD_SYNC_CONTROL);
if ( misc & 1 )
/* Hsync is actually low */
p->video |= PM2F_HSYNC_ACT_LOW;
if ( misc & 4 )
/* Vsync is actually low */
p->video |= PM2F_VSYNC_ACT_LOW;
break;
}
p->width=pm2_RD(i, PM2R_SCREEN_SIZE) & 0xffff;
p->height=pm2_RD(i, PM2R_SCREEN_SIZE) >> 16;
p->htotal=pm2_RD(i, PM2R_H_TOTAL);
p->hsstart=pm2_RD(i, PM2R_HS_START);
p->hsend=pm2_RD(i, PM2R_HS_END);
p->hbend=pm2_RD(i, PM2R_HB_END);
p->vtotal=pm2_RD(i, PM2R_V_TOTAL);
p->vsstart=pm2_RD(i, PM2R_VS_START);
p->vsend=pm2_RD(i, PM2R_VS_END);
p->vbend=pm2_RD(i, PM2R_VB_END);
p->stride=pm2_RD(i, PM2R_SCREEN_STRIDE);
clrmode=pm2_RDAC_RD(i, PM2I_RD_COLOR_MODE);
readpx=pm2_RD(i, PM2R_FB_READ_PIXEL);
if (clrmode & PM2F_RD_GUI_ACTIVE) {
clrmode &= ~(PM2F_RD_COLOR_MODE_RGB|PM2F_RD_GUI_ACTIVE);
if (clrmode==0 && readpx==0)
p->depth=8;
else if (clrmode==(PM2F_RD_TRUECOLOR|0x06) && readpx==1)
p->depth=16;
else if (clrmode==(PM2F_RD_TRUECOLOR|0x08) && readpx==2)
p->depth=32;
else if (clrmode==(PM2F_RD_TRUECOLOR|0x09) && readpx==4)
p->depth=24;
}
/*
* Somehow I have to manage this unretrievable fields.
* To say the truth, 'flags' field ought to be somewhere else.
*/
if (i->current_par_valid) {
p->pixclock=i->current_par.pixclock;
p->flags=i->current_par.flags;
}
}
static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
u32 clrmode=0;
u32 clrmode=PM2F_RD_COLOR_MODE_RGB;
u32 txtmap=0;
u32 pixsize=0;
u32 clrformat=0;
u32 xres;
u32 video, tmp;
if (i->type == PM2_TYPE_PERMEDIA2V) {
WAIT_FIFO(i, 1);
......@@ -700,7 +839,7 @@ static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
xres=(p->width+31)&~31;
set_aperture(i, p);
DEFRW();
WAIT_FIFO(i, 27);
WAIT_FIFO(i, 19);
pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
PM2F_COLOR_KEY_TEST_OFF);
switch (p->depth) {
......@@ -710,28 +849,29 @@ static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
break;
case 16:
pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
clrmode=PM2F_RD_TRUECOLOR|0x06;
clrmode|=PM2F_RD_TRUECOLOR|0x06;
txtmap=PM2F_TEXTEL_SIZE_16;
pixsize=1;
clrformat=0x70;
break;
case 32:
pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
clrmode=PM2F_RD_TRUECOLOR|0x08;
clrmode|=PM2F_RD_TRUECOLOR|0x08;
txtmap=PM2F_TEXTEL_SIZE_32;
pixsize=2;
clrformat=0x20;
break;
case 24:
pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
clrmode=PM2F_RD_TRUECOLOR|0x09;
clrmode|=PM2F_RD_TRUECOLOR|0x09;
#ifndef PM2FB_BE_APERTURE
clrmode&=~PM2F_RD_COLOR_MODE_RGB;
#endif
txtmap=PM2F_TEXTEL_SIZE_24;
pixsize=4;
clrformat=0x20;
break;
}
pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres));
pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres));
......@@ -747,36 +887,34 @@ static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
pm2_WR(i, PM2R_VB_END, p->vbend);
pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
DEFW();
pm2_WR(i, PM2R_WINDOW_ORIGIN, 0);
pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
DEFW();
pm2_WR(i, PM2R_SCREEN_BASE, p->base);
/* HW cursor needs /VSYNC for recognizing vert retrace */
video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
DEFW();
set_video(i, p->video);
WAIT_FIFO(i, 4);
switch (i->type) {
case PM2_TYPE_PERMEDIA2:
tmp = PM2F_RD_PALETTE_WIDTH_8;
pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
PM2F_RD_GUI_ACTIVE|clrmode);
if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
tmp |= 4; /* invert hsync */
if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
tmp |= 8; /* invert vsync */
pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
break;
case PM2_TYPE_PERMEDIA2V:
tmp = 0;
pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
tmp |= 1; /* invert hsync */
if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
tmp |= 4; /* invert vsync */
pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
break;
case PM2_TYPE_PERMEDIA2:
pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
PM2F_RD_GUI_ACTIVE|clrmode);
break;
case PM2_TYPE_PERMEDIA2V:
pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
break;
}
pm2_WR(i, PM2R_VIDEO_CONTROL, video);
pm2_set_pixclock(i, p->pixclock);
};
}
static int screen_is_valid(struct pm2fb_info* i) {
struct pm2fb_par actual;
get_screen(i, &actual);
return i->current_par_valid &&
!memcmp(&actual, &i->current_par, sizeof(struct pm2fb_par));
}
/*
* copy with packed pixels (8/16bpp only).
......@@ -788,11 +926,10 @@ static void pm2fb_pp_copy(struct pm2fb_info* i, s32 xsrc, s32 ysrc,
if (!w || !h)
return;
WAIT_FIFO(i, 7);
WAIT_FIFO(i, 6);
pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE|
PM2F_CONFIG_FB_PACKED_DATA|
PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16|
((xsrc-x)&0xfff));
offset=(x&0x3)-(xsrc&0x3);
......@@ -816,10 +953,9 @@ static void pm2fb_block_op(struct pm2fb_info* i, int copy,
if (!w || !h)
return;
WAIT_FIFO(i, 6);
WAIT_FIFO(i, 5);
pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE|
PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
(copy?PM2F_CONFIG_FB_READ_SOURCE_ENABLE:0));
if (copy)
pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16|
((xsrc-x)&0xfff));
......@@ -839,37 +975,24 @@ static void pm2fb_block_op(struct pm2fb_info* i, int copy,
* Begin of generic initialization functions
***************************************************************************/
static void pm2fb_reset(struct pm2fb_info* p) {
static void reset_units(struct pm2fb_info* p) {
if (p->type == PM2_TYPE_PERMEDIA2V)
pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
pm2_WR(p, PM2R_RESET_STATUS, 0);
DEFRW();
while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
DEFRW();
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
DPRINTK("FIFO disconnect enabled\n");
pm2_WR(p, PM2R_FIFO_DISCON, 1);
DEFRW();
#endif
if (board_table[p->board].init)
board_table[p->board].init(p);
WAIT_FIFO(p, 48);
WAIT_FIFO(p, 52);
pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
pm2_WR(p, PM2R_FIFO_CONTROL, 0);
pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
pm2_WR(p, PM2R_APERTURE_ONE, 0);
pm2_WR(p, PM2R_APERTURE_TWO, 0);
pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
pm2_WR(p, PM2R_LB_READ_MODE, 0);
pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
pm2_WR(p, PM2R_WINDOW_ORIGIN, 0);
pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
......@@ -890,6 +1013,7 @@ static void pm2fb_reset(struct pm2fb_info* p) {
pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
pm2_WR(p, PM2R_STATISTICS_MODE, 0);
pm2_WR(p, PM2R_SCISSOR_MODE, 0);
pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
switch (p->type) {
case PM2_TYPE_PERMEDIA2:
pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
......@@ -905,12 +1029,30 @@ static void pm2fb_reset(struct pm2fb_info* p) {
pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
}
static void pm2fb_reset(struct pm2fb_info* p) {
if (p->type == PM2_TYPE_PERMEDIA2V)
pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
pm2_WR(p, PM2R_RESET_STATUS, 0);
DEFRW();
while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
DEFRW();
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
DPRINTK("FIFO disconnect enabled\n");
pm2_WR(p, PM2R_FIFO_DISCON, 1);
DEFRW();
#endif
if (board_table[p->board].init)
board_table[p->board].init(p);
reset_units(p);
clear_palette(p);
if (p->memclock)
pm2_set_memclock(p, p->memclock);
}
static int __init pm2fb_conf(struct pm2fb_info* p){
static int __init pm2fb_conf(struct pm2fb_info* p) {
for (p->board=0; board_table[p->board].detect &&
!(board_table[p->board].detect(p)); p->board++);
......@@ -921,9 +1063,9 @@ static int __init pm2fb_conf(struct pm2fb_info* p){
DPRINTK("found board: %s\n", board_table[p->board].name);
p->regions.p_fb=p->regions.fb_base;
if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
"pm2fb")) {
printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
if (!request_mem_region((unsigned long )p->regions.p_fb,
p->regions.fb_size, "pm2fb")) {
printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort.\n");
return 0;
}
p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
......@@ -933,8 +1075,9 @@ static int __init pm2fb_conf(struct pm2fb_info* p){
#else
p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
#endif
if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
if (!request_mem_region((unsigned long )p->regions.p_regs,
PM2_REGS_SIZE, "pm2fb")) {
printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort.\n");
UNMAP(p->regions.v_fb, p->regions.fb_size);
return 0;
}
......@@ -994,7 +1137,7 @@ static int __init cvppc_detect(struct pm2fb_info* p) {
if (!cvppc_PCI_init(&p->board_par.cvppc))
return 0;
p->type = PM2_TYPE_PERMEDIA2;
p->type=PM2_TYPE_PERMEDIA2;
p->regions.fb_base=CVPPC_FB_APERTURE_ONE;
p->regions.fb_size=CVPPC_FB_SIZE;
p->regions.rg_base=CVPPC_REGS_REGION;
......@@ -1024,10 +1167,13 @@ struct {
char *name;
pm2type_t type;
} pm2pci_cards[] __initdata = {
{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
{ 0, 0 }
{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
"Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
"3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
"3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
{ 0, 0 }
};
static int __init pm2pci_detect(struct pm2fb_info* p) {
......@@ -1072,19 +1218,24 @@ static int __init pm2pci_detect(struct pm2fb_info* p) {
p->regions.fb_base= pci->dev->resource[1].start;
pcp = pci->dev->sysdata;
/* If the user has not asked for a particular mode, lets guess */
if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
if (pcp->prom_node &&
!(pm2fb_options.flags & (OPTF_USER|OPTF_USER_VAR))) {
char timing[256], *q, *r;
unsigned long w, h;
int i;
prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
/* FIXME: Find out what the actual pixclock is and other values as well */
/* FIXME: Find out what the actual pixclock is
* and other values as well */
if (timing[0]) {
w = simple_strtoul(timing, &q, 0);
h = 0;
if (q == timing) w = 0;
if (w) {
for (i = 0; i < 3; i++) {
for (r = q; *r && (*r < '0' || *r > '9'); r++);
for (r = q;
*r && (*r < '0' || *r > '9');
r++)
;
simple_strtoul(r, &q, 0);
if (r == q) break;
}
......@@ -1101,7 +1252,9 @@ static int __init pm2pci_detect(struct pm2fb_info* p) {
(w != user_mode[i].par.width ||
h != user_mode[i].par.height); i++);
if (user_mode[i].name[0])
memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
memcpy(&p->current_par,
&user_mode[i].par,
sizeof(user_mode[i].par));
}
}
}
......@@ -1159,7 +1312,6 @@ static void pm2pci_init(struct pm2fb_info* p) {
* Console hw acceleration
***************************************************************************/
static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
struct pm2fb_info* i=(struct pm2fb_info* )info;
u32 video;
......@@ -1168,6 +1320,7 @@ static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
return 1;
video=i->current_par.video;
if (blank_mode>0) {
i->is_blank=1;
switch (blank_mode-1) {
case VESA_NO_BLANKING: /* FIXME */
video=video&~(PM2F_VIDEO_ENABLE);
......@@ -1187,8 +1340,9 @@ static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
break;
}
}
WAIT_FIFO(i, 1);
pm2_WR(i, PM2R_VIDEO_CONTROL, video);
else
i->is_blank=0;
set_video(i, video);
return 0;
}
......@@ -1321,7 +1475,7 @@ static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
u32 sx;
u32 sy;
c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
c|=c<<16;
sx=conp->vc_cols*fontwidth(p);
sy=conp->vc_rows*fontheight(p);
......@@ -1374,26 +1528,15 @@ static void pm2fb_clear24(struct vc_data* conp, struct display* p,
static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
int bottom_only) {
struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
u32 c;
u32 sx;
u32 sy;
c=attr_bgcol_ec(p, conp);
if ( i->palette[c].red==i->palette[c].green &&
i->palette[c].green==i->palette[c].blue) {
c=((u32 *)p->dispsw_data)[c];
c|=(c&0xff0000)<<8;
sx=conp->vc_cols*fontwidth(p);
sy=conp->vc_rows*fontheight(p);
if (!bottom_only)
sx=conp->vc_cols*fontwidth(p);
sy=conp->vc_rows*fontheight(p);
if (!bottom_only)
pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
p->var.yres_virtual, c);
pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
sx, p->var.yres-sy, c);
}
else
fbcon_cfb24_clear_margins(conp, p, bottom_only);
p->var.yres_virtual, 0L);
pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy, sx, p->var.yres-sy, 0L);
}
static struct display_switch pm2_cfb24 = {
......@@ -1430,7 +1573,7 @@ static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
u32 sx;
u32 sy;
c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
sx=conp->vc_cols*fontwidth(p);
sy=conp->vc_rows*fontheight(p);
if (!bottom_only)
......@@ -1466,17 +1609,14 @@ static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
struct pm2fb_par* p=(struct pm2fb_par* )par;
strcpy(fix->id, permedia2_name);
fix->smem_start=i->regions.p_fb;
fix->smem_start=(unsigned long )i->regions.p_fb;
fix->smem_len=i->regions.fb_size;
fix->mmio_start=i->regions.p_regs;
fix->mmio_start=(unsigned long )i->regions.p_regs;
fix->mmio_len=PM2_REGS_SIZE;
fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
fix->type=FB_TYPE_PACKED_PIXELS;
fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
if (i->current_par_valid)
fix->line_length=i->current_par.width*(i->current_par.depth/8);
else
fix->line_length=0;
fix->line_length=p->width*p->depth/8;
fix->xpanstep=p->depth==24?8:64/p->depth;
fix->ypanstep=1;
fix->ywrapstep=0;
......@@ -1525,11 +1665,13 @@ static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
int data64;
memset(&p, 0, sizeof(struct pm2fb_par));
if (var->accel_flags & FB_ACCELF_TEXT)
p.flags |= PM2FF_ACCEL;
p.width=(var->xres_virtual+7)&~7;
p.height=var->yres_virtual;
p.depth=(var->bits_per_pixel+7)&~7;
p.depth=p.depth>32?32:p.depth;
data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
data64=p.depth>8 || i->type==PM2_TYPE_PERMEDIA2V;
xres=(var->xres+31)&~31;
if (p.width<xres+var->xoffset)
p.width=xres+var->xoffset;
......@@ -1578,12 +1720,22 @@ static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
if (data64)
p.video|=PM2F_DATA_64_ENABLE;
if (var->sync & FB_SYNC_HOR_HIGH_ACT)
p.video|=PM2F_HSYNC_ACT_HIGH;
if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
if (pm2fb_options.flags & OPTF_LOW_HSYNC) {
DPRINTK("ignoring +hsync, using -hsync.\n");
p.video|=PM2F_HSYNC_ACT_LOW;
} else
p.video|=PM2F_HSYNC_ACT_HIGH;
}
else
p.video|=PM2F_HSYNC_ACT_LOW;
if (var->sync & FB_SYNC_VERT_HIGH_ACT)
p.video|=PM2F_VSYNC_ACT_HIGH;
if (var->sync & FB_SYNC_VERT_HIGH_ACT) {
if (pm2fb_options.flags & OPTF_LOW_VSYNC) {
DPRINTK("ignoring +vsync, using -vsync.\n");
p.video|=PM2F_VSYNC_ACT_LOW;
} else
p.video|=PM2F_VSYNC_ACT_HIGH;
}
else
p.video|=PM2F_VSYNC_ACT_LOW;
if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
......@@ -1611,110 +1763,115 @@ static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
}
#endif
static int pm2fb_encode_var(struct fb_var_screeninfo* var,
const void* par, struct fb_info_gen* info) {
struct pm2fb_par* p=(struct pm2fb_par* )par;
struct fb_var_screeninfo v;
static void pm2fb_par2var(struct fb_var_screeninfo* v,
const struct pm2fb_par* p) {
u32 base;
memset(&v, 0, sizeof(struct fb_var_screeninfo));
v.xres_virtual=p->width;
v.yres_virtual=p->height;
v.xres=(p->htotal+1)-p->hbend;
v.yres=(p->vtotal+1)-p->vbend;
v.right_margin=p->hsstart;
v.hsync_len=p->hsend-p->hsstart;
v.left_margin=p->hbend-p->hsend;
v.lower_margin=p->vsstart+1;
v.vsync_len=p->vsend-v.lower_margin+1;
v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
v.bits_per_pixel=p->depth;
memset(v, 0, sizeof(struct fb_var_screeninfo));
if (p->flags & PM2FF_ACCEL)
v->accel_flags |= FB_ACCELF_TEXT;
v->xres_virtual=p->width;
v->yres_virtual=p->height;
v->xres=(p->htotal+1)-p->hbend;
v->yres=(p->vtotal+1)-p->vbend;
v->right_margin=p->hsstart;
v->hsync_len=p->hsend-p->hsstart;
v->left_margin=p->hbend-p->hsend;
v->lower_margin=p->vsstart+1;
v->vsync_len=p->vsend-v->lower_margin+1;
v->upper_margin=p->vbend-v->lower_margin-v->vsync_len;
v->bits_per_pixel=p->depth;
if (p->video & PM2F_DATA_64_ENABLE) {
v.xres=v.xres<<1;
v.right_margin=v.right_margin<<1;
v.hsync_len=v.hsync_len<<1;
v.left_margin=v.left_margin<<1;
v->xres=v->xres<<1;
v->right_margin=v->right_margin<<1;
v->hsync_len=v->hsync_len<<1;
v->left_margin=v->left_margin<<1;
}
switch (p->depth) {
case 8:
v.red.length=v.green.length=v.blue.length=8;
v.xres=v.xres<<2;
v.right_margin=v.right_margin<<2;
v.hsync_len=v.hsync_len<<2;
v.left_margin=v.left_margin<<2;
v->red.length=v->green.length=v->blue.length=8;
v->xres=v->xres<<2;
v->right_margin=v->right_margin<<2;
v->hsync_len=v->hsync_len<<2;
v->left_margin=v->left_margin<<2;
break;
case 16:
v.red.offset=11;
v.red.length=5;
v.green.offset=5;
v.green.length=6;
v.blue.length=5;
v.xres=v.xres<<1;
v.right_margin=v.right_margin<<1;
v.hsync_len=v.hsync_len<<1;
v.left_margin=v.left_margin<<1;
v->red.offset=11;
v->red.length=5;
v->green.offset=5;
v->green.length=6;
v->blue.length=5;
v->xres=v->xres<<1;
v->right_margin=v->right_margin<<1;
v->hsync_len=v->hsync_len<<1;
v->left_margin=v->left_margin<<1;
break;
case 32:
v.transp.offset=24;
v.red.offset=16;
v.green.offset=8;
v.red.length=v.green.length=v.blue.length=
v.transp.length=8;
v->transp.offset=24;
v->red.offset=16;
v->green.offset=8;
v->red.length=v->green.length=v->blue.length=
v->transp.length=8;
break;
case 24:
v.blue.offset=16;
v.green.offset=8;
v.red.length=v.green.length=v.blue.length=8;
v.xres=(v.xres<<2)/3;
v.right_margin=(v.right_margin<<2)/3;
v.hsync_len=(v.hsync_len<<2)/3;
v.left_margin=(v.left_margin<<2)/3;
v->blue.offset=16;
v->green.offset=8;
v->red.length=v->green.length=v->blue.length=8;
v->xres=(v->xres<<2)/3;
v->right_margin=(v->right_margin<<2)/3;
v->hsync_len=(v->hsync_len<<2)/3;
v->left_margin=(v->left_margin<<2)/3;
break;
}
base=from3264(p->base, p->depth, 1);
v.xoffset=base%v.xres;
v.yoffset=base/v.xres;
v.height=v.width=-1;
v.pixclock=KHZ2PICOS(p->pixclock);
v->xoffset=base%v->xres;
v->yoffset=base/v->xres;
v->height=v->width=-1;
v->pixclock=KHZ2PICOS(p->pixclock);
if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
v.sync|=FB_SYNC_HOR_HIGH_ACT;
v->sync|=FB_SYNC_HOR_HIGH_ACT;
if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
v.sync|=FB_SYNC_VERT_HIGH_ACT;
v->sync|=FB_SYNC_VERT_HIGH_ACT;
if (p->video & PM2F_LINE_DOUBLE)
v.vmode=FB_VMODE_DOUBLE;
*var=v;
v->vmode=FB_VMODE_DOUBLE;
}
static int pm2fb_encode_var(struct fb_var_screeninfo* var,
const void* par, struct fb_info_gen* info) {
pm2fb_par2var(var, (struct pm2fb_par* )par);
return 0;
}
static void set_user_mode(struct pm2fb_info* i) {
memcpy(&i->current_par, &pm2fb_options.user_mode,
sizeof(i->current_par));
if (pm2fb_options.flags & OPTF_YPAN) {
int h = i->current_par.height;
i->current_par.height=i->regions.fb_size/
(i->current_par.width*i->current_par.depth/8);
i->current_par.height=MIN(i->current_par.height,2047);
i->current_par.height=MAX(i->current_par.height,h);
i->current_par.height=MAX(i->current_par.height,
pm2fb_options.user_mode.height);
}
}
static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
struct pm2fb_info* i=(struct pm2fb_info* )info;
if (!i->current_par_valid) {
set_user_mode(i);
pm2fb_reset(i);
set_screen(i, &i->current_par);
i->current_par_valid=1;
pm2fb_set_par(&i->current_par, info);
}
*((struct pm2fb_par* )par)=i->current_par;
get_screen(i, (struct pm2fb_par* )par);
}
static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
struct pm2fb_info* i=(struct pm2fb_info* )info;
struct pm2fb_par* p;
struct pm2fb_par* p=(struct pm2fb_par* )par;
p=(struct pm2fb_par* )par;
if (i->current_par_valid) {
if (screen_is_valid(i)) {
i->current_par.base=p->base;
if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
WAIT_FIFO(i, 1);
......@@ -1722,12 +1879,16 @@ static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
return;
}
}
wait_pm2(i);
reset_units(i);
set_screen(i, p);
i->current_par=*p;
i->current_par_valid=1;
#ifdef PM2FB_HW_CURSOR
if (i->cursor) {
pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
pm2v_set_cursor_color(i, cursor_color_map,
cursor_color_map, cursor_color_map);
pm2v_set_cursor_shape(i);
}
#endif
......@@ -1801,35 +1962,51 @@ static int pm2fb_setcolreg(unsigned regno,
}
static void pm2fb_set_disp(const void* par, struct display* disp,
struct fb_info_gen* info) {
struct fb_info_gen* info) {
struct pm2fb_info* i=(struct pm2fb_info* )info;
struct pm2fb_par* p=(struct pm2fb_par* )par;
unsigned long flags;
unsigned long depth;
save_flags(flags);
cli();
i->gen.info.screen_base = i->regions.v_fb;
switch (depth=((struct pm2fb_par* )par)->depth) {
#ifdef __alpha__
disp->screen_base=i->regions.v_fb + dense_mem(i->regions.v_fb);
#else
disp->screen_base=i->regions.v_fb;
#endif
switch (p->depth) {
#ifdef FBCON_HAS_CFB8
case 8:
disp->dispsw=&pm2_cfb8;
if (p->flags & PM2FF_ACCEL)
disp->dispsw=&pm2_cfb8;
else
disp->dispsw=&fbcon_cfb8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
disp->dispsw=&pm2_cfb16;
if (p->flags & PM2FF_ACCEL)
disp->dispsw=&pm2_cfb16;
else
disp->dispsw=&fbcon_cfb16;
disp->dispsw_data=i->cmap.cmap16;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
disp->dispsw=&pm2_cfb24;
if (p->flags & PM2FF_ACCEL)
disp->dispsw=&pm2_cfb24;
else
disp->dispsw=&fbcon_cfb24;
disp->dispsw_data=i->cmap.cmap24;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
disp->dispsw=&pm2_cfb32;
if (p->flags & PM2FF_ACCEL)
disp->dispsw=&pm2_cfb32;
else
disp->dispsw=&fbcon_cfb32;
disp->dispsw_data=i->cmap.cmap32;
break;
#endif
......@@ -2050,46 +2227,62 @@ static int pm2fb_set_font(struct display *d, int width, int height)
#ifdef MODULE
static void pm2fb_cleanup(void) {
struct pm2fb_info* i = &fb_info;
struct pm2fb_info* i=&fb_info;
unregister_framebuffer((struct fb_info *)i);
unregister_framebuffer((struct fb_info* )info);
pm2fb_reset(i);
UNMAP(i->regions.v_fb, i->regions.fb_size);
release_mem_region(i->regions.p_fb, i->regions.fb_size);
UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
UNMAP(i->regions.v_fb, i->regions.fb_size);
release_mem_region(i->regions.p_fb, i->regions.fb_size);
UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
if (board_table[i->board].cleanup)
board_table[i->board].cleanup(i);
}
#endif /* MODULE */
int __init pm2fb_init(void){
int __init pm2fb_init(void) {
MOD_INC_USE_COUNT;
memset(&fb_info, 0, sizeof(fb_info));
memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
if (!pm2fb_conf(&fb_info)) {
MOD_DEC_USE_COUNT;
return -ENXIO;
}
/* Pick up user_var settings if set. */
if ((pm2fb_options.flags & OPTF_USER_VAR) &&
pm2fb_decode_var(&user_var, &pm2fb_options.user_mode,
&fb_info.gen)<0) {
printk("pm2fb: user supplied var: mode is bad.\n");
memcpy(&pm2fb_options.user_mode,
&user_mode[DEFAULT_USER_MODE].par,
sizeof(struct pm2fb_par));
}
memcpy(&fb_info.current_par, &pm2fb_options.user_mode,
sizeof(fb_info.current_par));
pm2fb_reset(&fb_info);
fb_info.disp.scrollmode=SCROLL_YNOMOVE;
fb_info.gen.parsize=sizeof(struct pm2fb_par);
fb_info.gen.fbhw=&pm2fb_hwswitch;
strcpy(fb_info.gen.info.modename, permedia2_name);
fb_info.gen.info.node=-1;
fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
fb_info.gen.info.fbops=&pm2fb_ops;
fb_info.gen.info.disp=&fb_info.disp;
strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
fb_info.gen.info.switch_con=&fbgen_switch;
fb_info.gen.info.updatevar=&fbgen_update_var;
fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
fbgen_set_disp(-1, &fb_info.gen);
do_install_cmap(0, &fb_info.gen.info);
fbgen_install_cmap(0, &fb_info.gen);
if (register_framebuffer(&fb_info.gen.info)<0) {
printk(KERN_ERR "pm2fb: unable to register.\n");
MOD_DEC_USE_COUNT;
......@@ -2103,7 +2296,7 @@ int __init pm2fb_init(void){
return 0;
}
static void __init pm2fb_mode_setup(char* options){
static void __init pm2fb_mode_setup(char* options) {
int i;
for (i=0; user_mode[i].name[0] &&
......@@ -2111,17 +2304,77 @@ static void __init pm2fb_mode_setup(char* options){
if (user_mode[i].name[0]) {
memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
sizeof(pm2fb_options.user_mode));
pm2fb_options.flags |= OPTF_USER;
pm2fb_options.flags|=OPTF_USER;
}
}
static void __init pm2fb_font_setup(char* options){
static void __init pm2fb_font_setup(char* options) {
strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
}
int __init pm2fb_setup(char* options){
static void __init pm2fb_var_setup(char* options) {
char* next;
pm2fb_par2var(&user_var, &pm2fb_options.user_mode);
while (options) {
if ((next=strchr(options, ';')))
*(next++)='\0';
if (!strncmp(options, "bpp:", 4))
user_var.bits_per_pixel=
simple_strtoul(options+4, NULL, 0);
else if (!strncmp(options, "xres:", 5))
user_var.xres=simple_strtoul(options+5, NULL, 0);
else if (!strncmp(options, "yres:", 5))
user_var.yres=simple_strtoul(options+5, NULL, 0);
else if (!strncmp(options, "vxres:", 6))
user_var.xres_virtual=
simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "vyres:", 6))
user_var.yres_virtual=
simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "left:", 5))
user_var.left_margin=
simple_strtoul(options+5, NULL, 0);
else if (!strncmp(options, "right:", 6))
user_var.right_margin=
simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "lower:", 6))
user_var.lower_margin=
simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "upper:", 6))
user_var.upper_margin=
simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "hslen:", 6))
user_var.hsync_len=simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "vslen:", 6))
user_var.vsync_len=simple_strtoul(options+6, NULL, 0);
else if (!strncmp(options, "pixclock:", 9))
user_var.pixclock=simple_strtoul(options+9, NULL, 0);
else if (!strcmp(options, "+hsync"))
user_var.sync|=FB_SYNC_HOR_HIGH_ACT;
else if (!strcmp(options, "-hsync"))
user_var.sync&=~FB_SYNC_HOR_HIGH_ACT;
else if (!strcmp(options, "+vsync"))
user_var.sync|=FB_SYNC_VERT_HIGH_ACT;
else if (!strcmp(options, "-vsync"))
user_var.sync&=~FB_SYNC_VERT_HIGH_ACT;
else if (!strcmp(options, "+double"))
user_var.vmode|=FB_VMODE_DOUBLE;
else if (!strcmp(options, "-double"))
user_var.vmode&=~FB_VMODE_DOUBLE;
else if (!strcmp(options, "+accel"))
user_var.accel_flags|=FB_ACCELF_TEXT;
else if (!strcmp(options, "-accel"))
user_var.accel_flags&=~FB_ACCELF_TEXT;
options=next;
}
pm2fb_options.flags|=OPTF_USER_VAR;
}
int __init pm2fb_setup(char* options) {
char* next;
while (options) {
......@@ -2131,16 +2384,23 @@ int __init pm2fb_setup(char* options){
pm2fb_font_setup(options+5);
else if (!strncmp(options, "mode:", 5))
pm2fb_mode_setup(options+5);
else if (!strncmp(options, "var:", 4))
pm2fb_var_setup(options+4);
else if (!strcmp(options, "ypan"))
pm2fb_options.flags |= OPTF_YPAN;
else if (!strcmp(options, "oldmem"))
pm2fb_options.flags |= OPTF_OLD_MEM;
else if (!strcmp(options, "virtual"))
pm2fb_options.flags |= OPTF_VIRTUAL;
else if (!strcmp(options, "lowhsync"))
pm2fb_options.flags |= OPTF_LOW_HSYNC;
else if (!strcmp(options, "lowvsync"))
pm2fb_options.flags |= OPTF_LOW_VSYNC;
else if (!strcmp(options, "noblink"))
curblink = 0;
curblink=0;
options=next;
}
user_var.activate=FB_ACTIVATE_NOW;
return 0;
}
......@@ -2156,9 +2416,10 @@ static char *mode = NULL;
MODULE_PARM(mode, "s");
int __init init_module(void) {
int init_module(void) {
if (mode) pm2fb_mode_setup(mode);
if (mode)
pm2fb_mode_setup(mode);
return pm2fb_init();
}
......
/*
* Permedia2 framebuffer driver definitions.
* Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
* --------------------------------------------------------------------------
* $Id: pm2fb.h,v 1.26 2000/09/19 00:11:53 illo Exp $
* --------------------------------------------------------------------------
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#ifndef PM2FB_H
#define PM2FB_H
#define PM2_REFERENCE_CLOCK 14318 /* in KHz */
#define PM2_MAX_PIXCLOCK 230000 /* in KHz */
#define PM2_REGS_SIZE 0x10000
#define PM2TAG(r) (u32 )(((r)-0x8000)>>3)
/*****************************************************************************
* Permedia2 registers used in the framebuffer
*****************************************************************************/
#define PM2R_RESET_STATUS 0x0000
#define PM2R_IN_FIFO_SPACE 0x0018
#define PM2R_OUT_FIFO_WORDS 0x0020
#define PM2R_APERTURE_ONE 0x0050
#define PM2R_APERTURE_TWO 0x0058
#define PM2R_FIFO_DISCON 0x0068
#define PM2R_CHIP_CONFIG 0x0070
#define PM2R_REBOOT 0x1000
#define PM2R_MEM_CONTROL 0x1040
#define PM2R_BOOT_ADDRESS 0x1080
#define PM2R_MEM_CONFIG 0x10c0
#define PM2R_BYPASS_WRITE_MASK 0x1100
#define PM2R_FRAMEBUFFER_WRITE_MASK 0x1140
#define PM2R_OUT_FIFO 0x2000
#define PM2R_SCREEN_BASE 0x3000
#define PM2R_SCREEN_STRIDE 0x3008
#define PM2R_H_TOTAL 0x3010
#define PM2R_HG_END 0x3018
#define PM2R_HB_END 0x3020
#define PM2R_HS_START 0x3028
#define PM2R_HS_END 0x3030
#define PM2R_V_TOTAL 0x3038
#define PM2R_VB_END 0x3040
#define PM2R_VS_START 0x3048
#define PM2R_VS_END 0x3050
#define PM2R_VIDEO_CONTROL 0x3058
#define PM2R_LINE_COUNT 0x3070
#define PM2R_FIFO_CONTROL 0x3078
#define PM2R_RD_PALETTE_WRITE_ADDRESS 0x4000
#define PM2R_RD_PALETTE_DATA 0x4008
#define PM2R_RD_PIXEL_MASK 0x4010
#define PM2R_RD_PALETTE_READ_ADDRESS 0x4018
#define PM2R_RD_INDEXED_DATA 0x4050
#define PM2R_START_X_DOM 0x8000
#define PM2R_D_X_DOM 0x8008
#define PM2R_START_X_SUB 0x8010
#define PM2R_D_X_SUB 0x8018
#define PM2R_START_Y 0x8020
#define PM2R_D_Y 0x8028
#define PM2R_COUNT 0x8030
#define PM2R_RENDER 0x8038
#define PM2R_RASTERIZER_MODE 0x80a0
#define PM2R_RECTANGLE_ORIGIN 0x80d0
#define PM2R_RECTANGLE_SIZE 0x80d8
#define PM2R_PACKED_DATA_LIMITS 0x8150
#define PM2R_SCISSOR_MODE 0x8180
#define PM2R_SCREEN_SIZE 0x8198
#define PM2R_AREA_STIPPLE_MODE 0x81a0
#define PM2R_WINDOW_ORIGIN 0x81c8
#define PM2R_TEXTURE_ADDRESS_MODE 0x8380
#define PM2R_TEXTURE_MAP_FORMAT 0x8588
#define PM2R_TEXTURE_DATA_FORMAT 0x8590
#define PM2R_TEXTURE_READ_MODE 0x8670
#define PM2R_TEXEL_LUT_MODE 0x8678
#define PM2R_TEXTURE_COLOR_MODE 0x8680
#define PM2R_FOG_MODE 0x8690
#define PM2R_COLOR_DDA_MODE 0x87e0
#define PM2R_ALPHA_BLEND_MODE 0x8810
#define PM2R_DITHER_MODE 0x8818
#define PM2R_FB_SOFT_WRITE_MASK 0x8820
#define PM2R_LOGICAL_OP_MODE 0x8828
#define PM2R_LB_READ_MODE 0x8880
#define PM2R_LB_READ_FORMAT 0x8888
#define PM2R_LB_SOURCE_OFFSET 0x8890
#define PM2R_LB_WINDOW_BASE 0x88b8
#define PM2R_LB_WRITE_FORMAT 0x88c8
#define PM2R_STENCIL_MODE 0x8988
#define PM2R_DEPTH_MODE 0x89a0
#define PM2R_FB_READ_MODE 0x8a80
#define PM2R_FB_SOURCE_OFFSET 0x8a88
#define PM2R_FB_PIXEL_OFFSET 0x8a90
#define PM2R_FB_WINDOW_BASE 0x8ab0
#define PM2R_FB_WRITE_MODE 0x8ab8
#define PM2R_FB_HARD_WRITE_MASK 0x8ac0
#define PM2R_FB_BLOCK_COLOR 0x8ac8
#define PM2R_FB_READ_PIXEL 0x8ad0
#define PM2R_FILTER_MODE 0x8c00
#define PM2R_SYNC 0x8c40
#define PM2R_YUV_MODE 0x8f00
#define PM2R_STATISTICS_MODE 0x8c08
#define PM2R_FB_SOURCE_DELTA 0x8d88
#define PM2R_CONFIG 0x8d90
#define PM2R_DELTA_MODE 0x9300
/* Permedia2v */
#define PM2VR_RD_INDEX_LOW 0x4020
#define PM2VR_RD_INDEX_HIGH 0x4028
#define PM2VR_RD_INDEXED_DATA 0x4030
/* Permedia2 RAMDAC indexed registers */
#define PM2I_RD_CURSOR_CONTROL 0x06
#define PM2I_RD_COLOR_MODE 0x18
#define PM2I_RD_MODE_CONTROL 0x19
#define PM2I_RD_MISC_CONTROL 0x1e
#define PM2I_RD_PIXEL_CLOCK_A1 0x20
#define PM2I_RD_PIXEL_CLOCK_A2 0x21
#define PM2I_RD_PIXEL_CLOCK_A3 0x22
#define PM2I_RD_PIXEL_CLOCK_STATUS 0x29
#define PM2I_RD_MEMORY_CLOCK_1 0x30
#define PM2I_RD_MEMORY_CLOCK_2 0x31
#define PM2I_RD_MEMORY_CLOCK_3 0x32
#define PM2I_RD_MEMORY_CLOCK_STATUS 0x33
#define PM2I_RD_COLOR_KEY_CONTROL 0x40
#define PM2I_RD_OVERLAY_KEY 0x41
#define PM2I_RD_RED_KEY 0x42
#define PM2I_RD_GREEN_KEY 0x43
#define PM2I_RD_BLUE_KEY 0x44
/* Permedia2v extensions */
#define PM2VI_RD_MISC_CONTROL 0x000
#define PM2VI_RD_SYNC_CONTROL 0x001
#define PM2VI_RD_DAC_CONTROL 0x002
#define PM2VI_RD_PIXEL_SIZE 0x003
#define PM2VI_RD_COLOR_FORMAT 0x004
#define PM2VI_RD_CURSOR_MODE 0x005
#define PM2VI_RD_CURSOR_X_LOW 0x007
#define PM2VI_RD_CURSOR_X_HIGH 0x008
#define PM2VI_RD_CURSOR_Y_LOW 0x009
#define PM2VI_RD_CURSOR_Y_HIGH 0x00A
#define PM2VI_RD_CURSOR_X_HOT 0x00B
#define PM2VI_RD_CURSOR_Y_HOT 0x00C
#define PM2VI_RD_CLK0_PRESCALE 0x201
#define PM2VI_RD_CLK0_FEEDBACK 0x202
#define PM2VI_RD_CLK0_POSTSCALE 0x203
#define PM2VI_RD_CLK1_PRESCALE 0x204
#define PM2VI_RD_CLK1_FEEDBACK 0x205
#define PM2VI_RD_CLK1_POSTSCALE 0x206
#define PM2VI_RD_CURSOR_PALETTE 0x303
#define PM2VI_RD_CURSOR_PATTERN 0x400
/* Fields and flags */
#define PM2F_RENDER_AREASTIPPLE (1L<<0)
#define PM2F_RENDER_FASTFILL (1L<<3)
#define PM2F_RENDER_PRIMITIVE_MASK (3L<<6)
#define PM2F_RENDER_LINE 0
#define PM2F_RENDER_TRAPEZOID (1L<<6)
#define PM2F_RENDER_POINT (2L<<6)
#define PM2F_RENDER_RECTANGLE (3L<<6)
#define PM2F_SYNCHRONIZATION (1L<<10)
#define PM2F_PLL_LOCKED 0x10
#define PM2F_BEING_RESET (1L<<31)
#define PM2F_DATATYPE_COLOR 0x8000
#define PM2F_VGA_ENABLE 0x02
#define PM2F_VGA_FIXED 0x04
#define PM2F_FB_WRITE_ENABLE 0x01
#define PM2F_FB_READ_SOURCE_ENABLE 0x0200
#define PM2F_RD_PALETTE_WIDTH_8 0x02
#define PM2F_PART_PROD_MASK 0x01ff
#define PM2F_SCREEN_SCISSOR_ENABLE 0x02
#define PM2F_DATA_64_ENABLE 0x00010000
#define PM2F_BLANK_LOW 0x02
#define PM2F_HSYNC_MASK 0x18
#define PM2F_VSYNC_MASK 0x60
#define PM2F_HSYNC_ACT_HIGH 0x08
#define PM2F_HSYNC_FORCED_LOW 0x10
#define PM2F_HSYNC_ACT_LOW 0x18
#define PM2F_VSYNC_ACT_HIGH 0x20
#define PM2F_VSYNC_FORCED_LOW 0x40
#define PM2F_VSYNC_ACT_LOW 0x60
#define PM2F_LINE_DOUBLE 0x04
#define PM2F_VIDEO_ENABLE 0x01
#define PM2F_RD_GUI_ACTIVE 0x10
#define PM2F_RD_COLOR_MODE_RGB 0x20
#define PM2F_DELTA_ORDER_RGB (1L<<18)
#define PM2F_RD_TRUECOLOR 0x80
#define PM2F_NO_ALPHA_BUFFER 0x10
#define PM2F_TEXTEL_SIZE_16 0x00080000
#define PM2F_TEXTEL_SIZE_32 0x00100000
#define PM2F_TEXTEL_SIZE_4 0x00180000
#define PM2F_TEXTEL_SIZE_24 0x00200000
#define PM2F_INCREASE_X (1L<<21)
#define PM2F_INCREASE_Y (1L<<22)
#define PM2F_CONFIG_FB_WRITE_ENABLE (1L<<3)
#define PM2F_CONFIG_FB_PACKED_DATA (1L<<2)
#define PM2F_CONFIG_FB_READ_DEST_ENABLE (1L<<1)
#define PM2F_CONFIG_FB_READ_SOURCE_ENABLE (1L<<0)
#define PM2F_COLOR_KEY_TEST_OFF (1L<<4)
#define PM2F_MEM_CONFIG_RAM_MASK (3L<<29)
#define PM2F_MEM_BANKS_1 0L
#define PM2F_MEM_BANKS_2 (1L<<29)
#define PM2F_MEM_BANKS_3 (2L<<29)
#define PM2F_MEM_BANKS_4 (3L<<29)
typedef enum {
PM2_TYPE_PERMEDIA2,
PM2_TYPE_PERMEDIA2V
} pm2type_t;
#endif /* PM2FB_H */
/*****************************************************************************
* That's all folks!
*****************************************************************************/
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