diff options
Diffstat (limited to 'drivers/video/dnfb.c')
-rw-r--r-- | drivers/video/dnfb.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c new file mode 100644 index 000000000..db0a6172f --- /dev/null +++ b/drivers/video/dnfb.c @@ -0,0 +1,381 @@ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/config.h> +#include <linux/interrupt.h> +#include <asm/setup.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/apollohw.h> +#include <linux/fb.h> +#include <linux/module.h> + +#include "fbcon-mfb.h" + + +/* apollo video HW definitions */ + +/* + * Control Registers. IOBASE + $x + * + * Note: these are the Memory/IO BASE definitions for a mono card set to the + * alternate address + * + * Control 3A and 3B serve identical functions except that 3A + * deals with control 1 and 3b deals with Color LUT reg. + */ + +#define AP_IOBASE 0x5d80 /* Base address of 1 plane board. */ +#define AP_STATUS 0x5d80 /* Status register. Read */ +#define AP_WRITE_ENABLE 0x5d80 /* Write Enable Register Write */ +#define AP_DEVICE_ID 0x5d81 /* Device ID Register. Read */ +#define AP_ROP_1 0x5d82 /* Raster Operation reg. Write Word */ +#define AP_DIAG_MEM_REQ 0x5d84 /* Diagnostic Memory Request. Write Word */ +#define AP_CONTROL_0 0x5d88 /* Control Register 0. Read/Write */ +#define AP_CONTROL_1 0x5d8a /* Control Register 1. Read/Write */ +#define AP_CONTROL_3A 0x5d8e /* Control Register 3a. Read/Write */ +#define AP_CONTROL_2 0x5d8c /* 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 */ + +/* 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_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 BLANK_DISP 0x00 /* xxxx.xxx0 */ +#define ENAB_DISP 0x01 /* xxxx.xxx1 */ + +#define NORM_CREG1 (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */ + +/* CREG 2 */ + +/* + * 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 */ + +/* CREG 3A/CREG 3B */ +# define RESET_CREG 0x80 /* 1000.0000 */ + +/* ROP REG - all one nibble */ +/* ********* NOTE : this is used r0,r1,r2,r3 *********** */ +#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) ) +#define DEST_ZERO 0x0 +#define SRC_AND_DEST 0x1 +#define SRC_AND_nDEST 0x2 +#define SRC 0x3 +#define nSRC_AND_DEST 0x4 +#define DEST 0x5 +#define SRC_XOR_DEST 0x6 +#define SRC_OR_DEST 0x7 +#define SRC_NOR_DEST 0x8 +#define SRC_XNOR_DEST 0x9 +#define nDEST 0xA +#define SRC_OR_nDEST 0xB +#define nSRC 0xC +#define nSRC_OR_DEST 0xD +#define SRC_NAND_DEST 0xE +#define DEST_ONE 0xF + +#define SWAP(A) ((A>>8) | ((A&0xff) <<8)) + +#if 0 +#define outb(a,d) *(char *)(a)=(d) +#define outw(a,d) *(unsigned short *)a=d +#endif + + +/* frame buffer operations */ + +static int dnfb_open(struct fb_info *info); +static int dnfb_release(struct fb_info *info); +static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int dnfb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int dnfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int dnfb_get_cmap(struct fb_cmap *cmap,int kspc,int con, + struct fb_info *info); +static int dnfb_set_cmap(struct fb_cmap *cmap,int kspc,int con, + struct fb_info *info); +static int dnfb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int dnfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + 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 void dnfbcon_blank(int blank, struct fb_info *info); + +static void dnfb_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 dnfb_ops = { + dnfb_open,dnfb_release, dnfb_get_fix, dnfb_get_var, dnfb_set_var, + dnfb_get_cmap, dnfb_set_cmap, dnfb_pan_display, NULL, dnfb_ioctl +}; + +static int currcon=0; + +static char dnfb_name[]="Apollo"; + +static int dnfb_open(struct fb_info *info) +{ + /* + * Nothing, only a usage count for the moment + */ + + MOD_INC_USE_COUNT; + return(0); +} + +static int dnfb_release(struct fb_info *info) +{ + MOD_DEC_USE_COUNT; + return(0); +} + +static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info) +{ + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id,"Apollo Mono"); + fix->smem_start=(char*)(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 dnfb_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; + var->accel=FB_ACCEL_NONE; + + return 0; + +} + +static int dnfb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + 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; + if(var->accel!=FB_ACCEL_NONE) + return -EINVAL; + + return 0; + +} + +static int dnfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + printk("get cmap not supported\n"); + + return -EINVAL; +} + +static int dnfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info) +{ + printk("set cmap not supported\n"); + + return -EINVAL; + +} + +static int dnfb_pan_display(struct fb_var_screeninfo *var, int con, + struct fb_info *info) +{ + printk("panning not supported\n"); + + return -EINVAL; + +} + +static int dnfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, int con, + struct fb_info *info) +{ + return -EINVAL; +} + +static void dnfb_set_disp(int con, struct fb_info *info) +{ + struct fb_fix_screeninfo fix; + + dnfb_get_fix(&fix, con, info); + if(con==-1) + con=0; + + disp[con].screen_base = (u_char *)fix.smem_start; + disp[con].visual = fix.visual; + disp[con].type = fix.type; + disp[con].type_aux = fix.type_aux; + disp[con].ypanstep = fix.ypanstep; + disp[con].ywrapstep = fix.ywrapstep; + disp[con].can_soft_blank = 1; + disp[con].inverse = 0; + disp[con].line_length = fix.line_length; +#ifdef CONFIG_FBCON_MFB + disp[con].dispsw = &fbcon_mfb; +#else + disp[con].dispsw = NULL; +#endif +} + +unsigned long dnfb_init(unsigned long mem_start) +{ + int err; + + fb_info.changevar=NULL; + strcpy(&fb_info.modename[0],dnfb_name); + fb_info.fontname[0]=0; + fb_info.disp=disp; + fb_info.switch_con=&dnfbcon_switch; + fb_info.updatevar=&dnfbcon_updatevar; + fb_info.blank=&dnfbcon_blank; + fb_info.node = -1; + fb_info.fbops = &dnfb_ops; + + 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("fb%d: apollo frame buffer alive and kicking !\n", + GET_FB_IDX(fb_info.node)); + + + dnfb_get_var(&disp[0].var, 0, &fb_info); + + dnfb_set_disp(-1, &fb_info); + + return mem_start; + +} + + +static int dnfbcon_switch(int con, struct fb_info *info) +{ + currcon=con; + + return 0; + +} + +static int dnfbcon_updatevar(int con, struct fb_info *info) +{ + return 0; +} + +static void dnfbcon_blank(int blank, struct fb_info *info) +{ + if(blank) { + outb(0, AP_CONTROL_3A); + outb((AD_BLT | DST_EQ_SRC | NORM_CREG1) & ~ENAB_DISP, + AP_CONTROL_1); + } + else { + outb(1, AP_CONTROL_3A); + outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1); + } +} |