diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/virgefb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video/virgefb.c')
-rw-r--r-- | drivers/video/virgefb.c | 2513 |
1 files changed, 2513 insertions, 0 deletions
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c new file mode 100644 index 00000000000..ed78747487e --- /dev/null +++ b/drivers/video/virgefb.c @@ -0,0 +1,2513 @@ +/* + * linux/drivers/video/virgefb.c -- CyberVision64/3D frame buffer device + * + * Copyright (C) 1997 André Heynatz + * + * + * This file is based on the CyberVision frame buffer device (cyberfb.c): + * + * Copyright (C) 1996 Martin Apel + * Geert Uytterhoeven + * + * Zorro II additions : + * + * Copyright (C) 1998-2000 Christian T. Steigies + * + * Initialization additions : + * + * Copyright (C) 1998-2000 Ken Tyler + * + * Parts of the Initialization code are based on Cyberfb.c by Allan Bair, + * and on the NetBSD CyberVision64 frame buffer driver by Michael Teske who gave + * permission for its use. + * + * Many thanks to Frank Mariak for his assistance with ZORRO 2 access and other + * mysteries. + * + * + * + * 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. + */ + +#undef VIRGEFBDEBUG +#undef VIRGEFBDUMP + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/zorro.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/amigahw.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <video/fbcon.h> +#include <video/fbcon-cfb8.h> +#include <video/fbcon-cfb16.h> +#include <video/fbcon-cfb32.h> + +#include "virgefb.h" + +#ifdef VIRGEFBDEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#ifdef VIRGEFBDUMP +static void cv64_dump(void); +#define DUMP cv64_dump() +#else +#define DUMP +#endif + +/* + * Macros for register access and zorro control + */ + +static inline void mb_inline(void) { mb(); } /* for use in comma expressions */ + +/* Set zorro 2 map */ + +#define SelectIO \ + mb(); \ + if (on_zorro2) { \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x01); \ + mb(); \ + } + +#define SelectMMIO \ + mb(); \ + if (on_zorro2) { \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x02); \ + mb(); \ + } + +#define SelectCFG \ + mb(); \ + if (on_zorro2) { \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x04)) = 0x03); \ + mb(); \ + } + +/* Set pass through, 0 = amiga, !=0 = cv64/3d */ + +#define SetVSwitch(x) \ + mb(); \ + (*(volatile u16 *)((u8 *)(vcode_switch_base)) = \ + (u16)(x ? 0 : 1)); \ + mb(); + +/* Zorro2 endian 'aperture' */ + +#define ENDIAN_BYTE 2 +#define ENDIAN_WORD 1 +#define ENDIAN_LONG 0 + +#define Select_Zorro2_FrameBuffer(x) \ + do { \ + if (on_zorro2) { \ + mb(); \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x08)) = \ + (x * 0x40)); \ + mb(); \ + } \ + } while (0) + +/* SetPortVal - only used for interrupt enable (not yet implemented) */ + +#if 0 +#define SetPortVal(x) \ + mb(); \ + (*(volatile u16 *)((u8 *)(vcode_switch_base + 0x0c)) = \ + (u16)x); \ + mb(); +#endif + +/* IO access */ + +#define byte_access_io(x) (((x) & 0x3ffc) | (((x) & 3)^3) | (((x) & 3) <<14)) +#define byte_access_mmio(x) (((x) & 0xfffc) | (((x) & 3)^3)) + +/* Write 8 bit VGA register - used once for chip wakeup */ + +#define wb_vgaio(reg, dat) \ + SelectIO; \ + (*(volatile u8 *)(vgaio_regs + ((u32)byte_access_io(reg) & 0xffff)) = \ + (dat & 0xff)); \ + SelectMMIO; + +/* Read 8 bit VGA register - only used in dump (SelectIO not needed on read ?) */ + +#ifdef VIRGEFBDUMP +#define rb_vgaio(reg) \ + ({ \ + u8 __zzyzx; \ + SelectIO; \ + __zzyzx = (*(volatile u8 *)((vgaio_regs)+(u32)byte_access_io(reg))); \ + SelectMMIO; \ + __zzyzx; \ + }) +#endif + +/* MMIO access */ + +/* Read 8 bit MMIO register */ + +#define rb_mmio(reg) \ + (mb_inline(), \ + (*(volatile u8 *)(mmio_regs + 0x8000 + (u32)byte_access_mmio(reg)))) + +/* Write 8 bit MMIO register */ + +#define wb_mmio(reg,dat) \ + mb(); \ + (*(volatile u8 *)(mmio_regs + 0x8000 + (byte_access_mmio((reg) & 0xffff))) = \ + (dat & 0xff)); \ + mb(); + +/* Read 32 bit MMIO register */ + +#define rl_mmio(reg) \ + (mb_inline(), \ + (*((volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))))) + +/* Write 32 bit MMIO register */ + +#define wl_mmio(reg,dat) \ + mb(); \ + ((*(volatile u32 *)((u8 *)((mmio_regs + (on_zorro2 ? 0x20000 : 0)) + (reg)))) = \ + (u32)(dat)); \ + mb(); + +/* Write to virge graphics register */ + +#define wgfx(reg, dat) do { wb_mmio(GCT_ADDRESS, (reg)); wb_mmio(GCT_ADDRESS_W, (dat)); } while (0) + +/* Write to virge sequencer register */ + +#define wseq(reg, dat) do { wb_mmio(SEQ_ADDRESS, (reg)); wb_mmio(SEQ_ADDRESS_W, (dat)); } while (0) + +/* Write to virge CRT controller register */ + +#define wcrt(reg, dat) do { wb_mmio(CRT_ADDRESS, (reg)); wb_mmio(CRT_ADDRESS_W, (dat)); } while (0) + +/* Write to virge attribute register */ + +#define watr(reg, dat) \ + do { \ + volatile unsigned char watr_tmp; \ + watr_tmp = rb_mmio(ACT_ADDRESS_RESET); \ + wb_mmio(ACT_ADDRESS_W, (reg)); \ + wb_mmio(ACT_ADDRESS_W, (dat)); \ + udelay(10); \ + } while (0) + +/* end of macros */ + +struct virgefb_par { + struct fb_var_screeninfo var; + __u32 type; + __u32 type_aux; + __u32 visual; + __u32 line_length; +}; + +static struct virgefb_par current_par; + +static int current_par_valid = 0; + +static struct display disp; +static struct fb_info fb_info; + +static union { +#ifdef FBCON_HAS_CFB16 + u16 cfb16[16]; +#endif +#ifdef FBCON_HAS_CFB32 + u32 cfb32[16]; +#endif +} fbcon_cmap; + +/* + * Switch for Chipset Independency + */ + +static struct fb_hwswitch { + + /* Initialisation */ + + int (*init)(void); + + /* Display Control */ + + int (*encode_fix)(struct fb_fix_screeninfo *fix, struct virgefb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, struct virgefb_par *par); + int (*getcolreg)(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); + void (*blank)(int blank); +} *fbhw; + +static unsigned char blit_maybe_busy = 0; + +/* + * Frame Buffer Name + */ + +static char virgefb_name[16] = "CyberVision/3D"; + +/* + * CyberVision64/3d Graphics Board + */ + +static unsigned char virgefb_colour_table [256][3]; +static unsigned long v_ram; +static unsigned long v_ram_size; +static volatile unsigned char *mmio_regs; +static volatile unsigned char *vgaio_regs; + +static unsigned long v_ram_phys; +static unsigned long mmio_regs_phys; +static unsigned long vcode_switch_base; +static unsigned char on_zorro2; + +/* + * Offsets from start of video ram to appropriate ZIII aperture + */ + +#ifdef FBCON_HAS_CFB8 +#define CYBMEM_OFFSET_8 0x800000 /* BGRX */ +#endif +#ifdef FBCON_HAS_CFB16 +#define CYBMEM_OFFSET_16 0x400000 /* GBXR */ +#endif +#ifdef FBCON_HAS_CFB32 +#define CYBMEM_OFFSET_32 0x000000 /* XRGB */ +#endif + +/* + * MEMCLOCK was 32MHz, 64MHz works, 72MHz doesn't (on my board) + */ + +#define MEMCLOCK 50000000 + +/* + * Predefined Video Modes + */ + +static struct { + const char *name; + struct fb_var_screeninfo var; +} virgefb_predefined[] __initdata = { +#ifdef FBCON_HAS_CFB8 + { + "640x480-8", { /* Cybervision 8 bpp */ + 640, 480, 640, 480, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "768x576-8", { /* Cybervision 8 bpp */ + 768, 576, 768, 576, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "800x600-8", { /* Cybervision 8 bpp */ + 800, 600, 800, 600, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + #if 0 + "1024x768-8", { /* Cybervision 8 bpp */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_NONINTERLACED + } + #else + "1024x768-8", { + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + #if 0 + 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #else + 0, 0, -1, -1, FB_ACCELF_TEXT, 12699, 176, 16, 28, 1, 96, 3, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #endif + #endif + }, { + "1152x886-8", { /* Cybervision 8 bpp */ + 1152, 886, 1152, 886, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1280x1024-8", { /* Cybervision 8 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + #if 0 + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + } + #else + 0, 0, -1, -1, FB_ACCELF_TEXT, 7414, 232, 64, 38, 1, 112, 3, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #endif + }, { + "1600x1200-8", { /* Cybervision 8 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + #if 0 + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + #else + 0, 0, -1, -1, FB_ACCELF_TEXT, 6411, 256, 32, 52, 10, 160, 8, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } + #endif + }, +#endif + +#ifdef FBCON_HAS_CFB16 + { + "640x480-16", { /* Cybervision 16 bpp */ + 640, 480, 640, 480, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 152, 144, 82, 61, 88, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "768x576-16", { /* Cybervision 16 bpp */ + 768, 576, 768, 576, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "800x600-16", { /* Cybervision 16 bpp */ + 800, 600, 800, 600, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { +#if 0 + "1024x768-16", { /* Cybervision 16 bpp */ + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_NONINTERLACED + } +#else + "1024x768-16", { + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 12500, 184, 40, 40, 2, 96, 1, + FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + } +#endif + }, { + "1152x886-16", { /* Cybervision 16 bpp */ + 1152, 886, 1152, 886, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1280x1024-16", { /* Cybervision 16 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1600x1200-16", { /* Cybervision 16 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, +#endif + +#ifdef FBCON_HAS_CFB32 + { + "640x480-32", { /* Cybervision 32 bpp */ + 640, 480, 640, 480, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 31250, 160, 136, 82, 61, 88, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "768x576-32", { /* Cybervision 32 bpp */ + 768, 576, 768, 576, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 29411, 144, 112, 32, 15, 64, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "800x600-32", { /* Cybervision 32 bpp */ + 800, 600, 800, 600, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 28571, 168, 104, 22, 1, 48, 2, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1024x768-32", { /* Cybervision 32 bpp */ + 1024, 768, 1024, 768, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1152x886-32", { /* Cybervision 32 bpp */ + 1152, 886, 1152, 886, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 19230, 280, 168, 45, 1, 64, 10, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1280x1024-32", { /* Cybervision 32 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, { + "1600x1200-32", { /* Cybervision 32 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_NONINTERLACED + } + }, +#endif + +/* interlaced modes */ + +#ifdef FBCON_HAS_CFB8 + { + "1024x768-8i", { /* Cybervision 8 bpp */ + 1024, 768, 1024, 768, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_INTERLACED + } + }, { + "1280x1024-8i", { /* Cybervision 8 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, { + "1600x1200-8i", { /* Cybervision 8 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, +#endif + +#ifdef FBCON_HAS_CFB16 + { + "1024x768-16i", { /* Cybervision 16 bpp */ + 1024, 768, 1024, 768, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 20833, 272, 168, 39, 2, 72, 1, + 0, FB_VMODE_INTERLACED + } + }, { + "1280x1024-16i", { /* Cybervision 16 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, { + "1600x1200-16i", { /* Cybervision 16 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, +#endif + +#ifdef FBCON_HAS_CFB32 + { + "1024x768-32i", { /* Cybervision 32 bpp */ + 1024, 768, 1024, 768, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 22222, 216, 144, 39, 2, 72, 1, + 0, FB_VMODE_INTERLACED + } + }, { + "1280x1024-32i", { /* Cybervision 32 bpp */ + 1280, 1024, 1280, 1024, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {23, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 17857, 232, 232, 71, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, { + "1600x1200-32i", { /* Cybervision 32 bpp */ + 1600, 1200, 1600, 1200, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 13698, 336, 224, 77, 15, 176, 12, + 0, FB_VMODE_INTERLACED + } + }, +#endif + +/* doublescan modes */ + +#ifdef FBCON_HAS_CFB8 + { + "320x240-8d", { /* Cybervision 8 bpp */ + 320, 240, 320, 240, 0, 0, 8, 0, + {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, + 0, FB_VMODE_DOUBLE + } + }, +#endif + +#ifdef FBCON_HAS_CFB16 + { + "320x240-16d", { /* Cybervision 16 bpp */ + 320, 240, 320, 240, 0, 0, 16, 0, + {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, + 0, FB_VMODE_DOUBLE + } + }, +#endif + +#ifdef FBCON_HAS_CFB32 + { + "320x240-32d", { /* Cybervision 32 bpp */ + 320, 240, 320, 240, 0, 0, 32, 0, + {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {24, 0, 0}, + 0, 0, -1, -1, FB_ACCELF_TEXT, 59259, 80, 80, 45, 26, 32, 1, + 0, FB_VMODE_DOUBLE + } + }, +#endif +}; + +#define arraysize(x) (sizeof(x)/sizeof(*(x))) +#define NUM_TOTAL_MODES arraysize(virgefb_predefined) + +/* + * Default to 800x600 for video=virge8:, virge16: or virge32: + */ + +#ifdef FBCON_HAS_CFB8 +#define VIRGE8_DEFMODE (2) +#endif + +#ifdef FBCON_HAS_CFB16 +#define VIRGE16_DEFMODE (9) +#endif + +#ifdef FBCON_HAS_CFB32 +#define VIRGE32_DEFMODE (16) +#endif + +static struct fb_var_screeninfo virgefb_default; +static int virgefb_inverse = 0; + +/* + * Interface used by the world + */ + +int virgefb_setup(char*); +static int virgefb_get_fix(struct fb_fix_screeninfo *fix, int con, + struct fb_info *info); +static int virgefb_get_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int virgefb_set_var(struct fb_var_screeninfo *var, int con, + struct fb_info *info); +static int virgefb_get_cmap(struct fb_cmap *cmap, int kspc, int con, + struct fb_info *info); +static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info); +static int virgefb_blank(int blank, struct fb_info *info); + +/* + * Interface to the low level console driver + */ + +int virgefb_init(void); +static int virgefb_switch(int con, struct fb_info *info); +static int virgefb_updatevar(int con, struct fb_info *info); + +/* + * Text console acceleration + */ + +#ifdef FBCON_HAS_CFB8 +static struct display_switch fbcon_virge8; +#endif + +#ifdef FBCON_HAS_CFB16 +static struct display_switch fbcon_virge16; +#endif + +#ifdef FBCON_HAS_CFB32 +static struct display_switch fbcon_virge32; +#endif + +/* + * Hardware Specific Routines + */ + +static int virge_init(void); +static int virgefb_encode_fix(struct fb_fix_screeninfo *fix, + struct virgefb_par *par); +static int virgefb_decode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par); +static int virgefb_encode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par); +static int virgefb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, + u_int *transp, struct fb_info *info); +static void virgefb_gfx_on_off(int blank); +static inline void virgefb_wait_for_idle(void); +static void virgefb_BitBLT(u_short curx, u_short cury, u_short destx, u_short desty, + u_short width, u_short height, u_short stride, u_short depth); +static void virgefb_RectFill(u_short x, u_short y, u_short width, u_short height, + u_short color, u_short stride, u_short depth); + +/* + * Internal routines + */ + +static void virgefb_get_par(struct virgefb_par *par); +static void virgefb_set_par(struct virgefb_par *par); +static int virgefb_do_fb_set_var(struct fb_var_screeninfo *var, int isactive); +static void virgefb_set_disp(int con, struct fb_info *info); +static int virgefb_get_video_mode(const char *name); +static void virgefb_set_video(struct fb_var_screeninfo *var); + +/* + * Additions for Initialization + */ + +static void virgefb_load_video_mode(struct fb_var_screeninfo *video_mode); +static int cv3d_has_4mb(void); +static unsigned short virgefb_compute_clock(unsigned long freq); +static inline unsigned char rattr(short); +static inline unsigned char rseq(short); +static inline unsigned char rcrt(short); +static inline unsigned char rgfx(short); +static inline void gfx_on_off(int toggle); +static void virgefb_pci_init(void); + +/* -------------------- Hardware specific routines ------------------------- */ + +/* + * Functions for register access + */ + +/* Read attribute controller register */ + +static inline unsigned char rattr(short idx) +{ + volatile unsigned char rattr_tmp; + + rattr_tmp = rb_mmio(ACT_ADDRESS_RESET); + wb_mmio(ACT_ADDRESS_W, idx); + return (rb_mmio(ACT_ADDRESS_R)); +} + +/* Read sequencer register */ + +static inline unsigned char rseq(short idx) +{ + wb_mmio(SEQ_ADDRESS, idx); + return (rb_mmio(SEQ_ADDRESS_R)); +} + +/* Read CRT controller register */ + +static inline unsigned char rcrt(short idx) +{ + wb_mmio(CRT_ADDRESS, idx); + return (rb_mmio(CRT_ADDRESS_R)); +} + +/* Read graphics controller register */ + +static inline unsigned char rgfx(short idx) +{ + wb_mmio(GCT_ADDRESS, idx); + return (rb_mmio(GCT_ADDRESS_R)); +} + + +/* + * Initialization + */ + +/* PCI init */ + +void virgefb_pci_init(void) { + + DPRINTK("ENTER\n"); + + SelectCFG; + + if (on_zorro2) { + *((short *)(vgaio_regs + 0x00000010)) = 0; + *((long *)(vgaio_regs + 0x00000004)) = 0x02000003; + } else { + *((short *)(vgaio_regs + 0x000e0010)) = 0; + *((long *)(vgaio_regs + 0x000e0004)) = 0x02000003; + } + + /* SelectIO is in wb_vgaio macro */ + wb_vgaio(SREG_VIDEO_SUBS_ENABLE, 0x01); + /* SelectMMIO is in wb_vgaio macro */ + + DPRINTK("EXIT\n"); + + return; +} + +/* + * Initalize all mode independent regs, find mem size and clear mem +*/ + +static int virge_init(void) +{ + int i; + unsigned char tmp; + + DPRINTK("ENTER\n"); + + virgefb_pci_init(); + + wb_mmio(GREG_MISC_OUTPUT_W, 0x07); /* colour, ram enable, clk sel */ + + wseq(SEQ_ID_UNLOCK_EXT, 0x06); /* unlock extensions */ + tmp = rb_mmio(GREG_MISC_OUTPUT_R); + wcrt(CRT_ID_REGISTER_LOCK_1, 0x48); /* unlock CR2D to CR3F */ + + wcrt(CRT_ID_BACKWAD_COMP_1, 0x00); /* irq disable */ + + wcrt(CRT_ID_REGISTER_LOCK_2, 0xa5); /* unlock CR40 to CRFF and more */ + wcrt(CRT_ID_REGISTER_LOCK,0x00); /* unlock h and v timing */ + wcrt(CRT_ID_SYSTEM_CONFIG, 0x01); /* unlock enhanced programming registers */ + + wb_mmio(GREG_FEATURE_CONTROL_W, 0x00); + + wcrt(CRT_ID_EXT_MISC_CNTL, 0x00); /* b2 = 0 to allow VDAC mmio access */ +#if 0 + /* write strap options ... ? */ + wcrt(CRT_ID_CONFIG_1, 0x08); + wcrt(CRT_ID_CONFIG_2, 0xff); /* 0x0x2 bit needs to be set ?? */ + wcrt(CRT_ID_CONFIG_3, 0x0f); + wcrt(CRT_ID_CONFIG_4, 0x1a); +#endif + wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x82); /* PCI DE and software reset S3D engine */ + /* EXT_MISC_CNTL_1, CR66 bit 0 should be the same as bit 0 MR_ADVANCED_FUNCTION_CONTROL - check */ + wl_mmio(MR_ADVANCED_FUNCTION_CONTROL, 0x00000011); /* enhanced mode, linear addressing */ + +/* crtc registers */ + + wcrt(CRT_ID_PRESET_ROW_SCAN, 0x00); + + /* Disable h/w cursor */ + + wcrt(CRT_ID_CURSOR_START, 0x00); + wcrt(CRT_ID_CURSOR_END, 0x00); + wcrt(CRT_ID_START_ADDR_HIGH, 0x00); + wcrt(CRT_ID_START_ADDR_LOW, 0x00); + wcrt(CRT_ID_CURSOR_LOC_HIGH, 0x00); + wcrt(CRT_ID_CURSOR_LOC_LOW, 0x00); + wcrt(CRT_ID_EXT_MODE, 0x00); + wcrt(CRT_ID_HWGC_MODE, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_X_HI, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_X_LO, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_Y_HI, 0x00); + wcrt(CRT_ID_HWGC_ORIGIN_Y_LO, 0x00); + i = rcrt(CRT_ID_HWGC_MODE); + wcrt(CRT_ID_HWGC_FG_STACK, 0x00); + wcrt(CRT_ID_HWGC_FG_STACK, 0x00); + wcrt(CRT_ID_HWGC_FG_STACK, 0x00); + wcrt(CRT_ID_HWGC_BG_STACK, 0x00); + wcrt(CRT_ID_HWGC_BG_STACK, 0x00); + wcrt(CRT_ID_HWGC_BG_STACK, 0x00); + wcrt(CRT_ID_HWGC_START_AD_HI, 0x00); + wcrt(CRT_ID_HWGC_START_AD_LO, 0x00); + wcrt(CRT_ID_HWGC_DSTART_X, 0x00); + wcrt(CRT_ID_HWGC_DSTART_Y, 0x00); + + wcrt(CRT_ID_UNDERLINE_LOC, 0x00); + + wcrt(CRT_ID_MODE_CONTROL, 0xe3); + wcrt(CRT_ID_BACKWAD_COMP_2, 0x22); /* blank bdr bit 5 blanking only on 8 bit */ + + wcrt(CRT_ID_EX_SYNC_1, 0x00); + + /* memory */ + + wcrt(CRT_ID_EXT_SYS_CNTL_3, 0x00); + wcrt(CRT_ID_MEMORY_CONF, 0x08); /* config enhanced map */ + wcrt(CRT_ID_EXT_MEM_CNTL_1, 0x08); /* MMIO Select (0x0c works as well)*/ + wcrt(CRT_ID_EXT_MEM_CNTL_2, 0x02); /* why 02 big endian 00 works ? */ + wcrt(CRT_ID_EXT_MEM_CNTL_4, 0x9f); /* config big endian - 0x00 ? */ + wcrt(CRT_ID_LAW_POS_HI, 0x00); + wcrt(CRT_ID_LAW_POS_LO, 0x00); + wcrt(CRT_ID_EXT_MISC_CNTL_1, 0x81); + wcrt(CRT_ID_MISC_1, 0x90); /* must follow CRT_ID_EXT_MISC_CNTL_1 */ + wcrt(CRT_ID_LAW_CNTL, 0x13); /* force 4 Meg for test */ + if (cv3d_has_4mb()) { + v_ram_size = 0x00400000; + wcrt(CRT_ID_LAW_CNTL, 0x13); /* 4 MB */ + } else { + v_ram_size = 0x00200000; + wcrt(CRT_ID_LAW_CNTL, 0x12); /* 2 MB */ + } + + if (on_zorro2) + v_ram_size -= 0x60000; /* we need some space for the registers */ + + wcrt(CRT_ID_EXT_SYS_CNTL_4, 0x00); + wcrt(CRT_ID_EXT_DAC_CNTL, 0x00); /* 0x10 for X11 cursor mode */ + +/* sequencer registers */ + + wseq(SEQ_ID_CLOCKING_MODE, 0x01); /* 8 dot clock */ + wseq(SEQ_ID_MAP_MASK, 0xff); + wseq(SEQ_ID_CHAR_MAP_SELECT, 0x00); + wseq(SEQ_ID_MEMORY_MODE, 0x02); + wseq(SEQ_ID_RAMDAC_CNTL, 0x00); + wseq(SEQ_ID_SIGNAL_SELECT, 0x00); + wseq(SEQ_ID_EXT_SEQ_REG9, 0x00); /* MMIO and PIO reg access enabled */ + wseq(SEQ_ID_EXT_MISC_SEQ, 0x00); + wseq(SEQ_ID_CLKSYN_CNTL_1, 0x00); + wseq(SEQ_ID_EXT_SEQ, 0x00); + +/* graphic registers */ + + wgfx(GCT_ID_SET_RESET, 0x00); + wgfx(GCT_ID_ENABLE_SET_RESET, 0x00); + wgfx(GCT_ID_COLOR_COMPARE, 0x00); + wgfx(GCT_ID_DATA_ROTATE, 0x00); + wgfx(GCT_ID_READ_MAP_SELECT, 0x00); + wgfx(GCT_ID_GRAPHICS_MODE, 0x40); + wgfx(GCT_ID_MISC, 0x01); + wgfx(GCT_ID_COLOR_XCARE, 0x0f); + wgfx(GCT_ID_BITMASK, 0xff); + +/* attribute registers */ + + for(i = 0; i <= 15; i++) + watr(ACT_ID_PALETTE0 + i, i); + watr(ACT_ID_ATTR_MODE_CNTL, 0x41); + watr(ACT_ID_OVERSCAN_COLOR, 0xff); + watr(ACT_ID_COLOR_PLANE_ENA, 0x0f); + watr(ACT_ID_HOR_PEL_PANNING, 0x00); + watr(ACT_ID_COLOR_SELECT, 0x00); + + wb_mmio(VDAC_MASK, 0xff); + +/* init local cmap as greyscale levels */ + + for (i = 0; i < 256; i++) { + virgefb_colour_table [i][0] = i; + virgefb_colour_table [i][1] = i; + virgefb_colour_table [i][2] = i; + } + +/* clear framebuffer memory */ + + memset((char*)v_ram, 0x00, v_ram_size); + + DPRINTK("EXIT\n"); + return 0; +} + + +/* + * This function should fill in the `fix' structure based on the + * values in the `par' structure. + */ + +static int virgefb_encode_fix(struct fb_fix_screeninfo *fix, + struct virgefb_par *par) +{ + DPRINTK("ENTER set video phys addr\n"); + + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strcpy(fix->id, virgefb_name); + if (on_zorro2) + fix->smem_start = v_ram_phys; + switch (par->var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + if (on_zorro2) + Select_Zorro2_FrameBuffer(ENDIAN_BYTE); + else + fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_8); + break; +#endif +#ifdef FBCON_HAS_CFB16 + case 16: + if (on_zorro2) + Select_Zorro2_FrameBuffer(ENDIAN_WORD); + else + fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_16); + break; +#endif +#ifdef FBCON_HAS_CFB32 + case 32: + if (on_zorro2) + Select_Zorro2_FrameBuffer(ENDIAN_LONG); + else + fix->smem_start = (v_ram_phys + CYBMEM_OFFSET_32); + break; +#endif + } + + fix->smem_len = v_ram_size; + fix->mmio_start = mmio_regs_phys; + fix->mmio_len = 0x10000; /* TODO: verify this for the CV64/3D */ + + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + if (par->var.bits_per_pixel == 8) + fix->visual = FB_VISUAL_PSEUDOCOLOR; + else + fix->visual = FB_VISUAL_TRUECOLOR; + + fix->xpanstep = 0; + fix->ypanstep = 0; + fix->ywrapstep = 0; + fix->line_length = par->var.xres_virtual*par->var.bits_per_pixel/8; + fix->accel = FB_ACCEL_S3_VIRGE; + DPRINTK("EXIT v_ram_phys = 0x%8.8lx\n", (unsigned long)fix->smem_start); + return 0; +} + + +/* + * Fill the `par' structure based on the values in `var'. + * TODO: Verify and adjust values, return -EINVAL if bad. + */ + +static int virgefb_decode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par) +{ + DPRINTK("ENTER\n"); + par->var.xres = var->xres; + par->var.yres = var->yres; + par->var.xres_virtual = var->xres_virtual; + par->var.yres_virtual = var->yres_virtual; + /* roundup and validate */ + par->var.xres = (par->var.xres+7) & ~7; + par->var.xres_virtual = (par->var.xres_virtual+7) & ~7; + if (par->var.xres_virtual < par->var.xres) + par->var.xres_virtual = par->var.xres; + if (par->var.yres_virtual < par->var.yres) + par->var.yres_virtual = par->var.yres; + par->var.xoffset = var->xoffset; + par->var.yoffset = var->yoffset; + par->var.bits_per_pixel = var->bits_per_pixel; + if (par->var.bits_per_pixel <= 8) + par->var.bits_per_pixel = 8; + else if (par->var.bits_per_pixel <= 16) + par->var.bits_per_pixel = 16; + else + par->var.bits_per_pixel = 32; +#ifndef FBCON_HAS_CFB32 + if (par->var.bits_per_pixel == 32) + par->var.bits_per_pixel = 16; +#endif +#ifndef FBCON_HAS_CFB16 + if (par->var.bits_per_pixel == 16) + par->var.bits_per_pixel = 8; +#endif + par->var.grayscale = var->grayscale; + par->var.red = var->red; + par->var.green = var->green; + par->var.blue = var->blue; + par->var.transp = var->transp; + par->var.nonstd = var->nonstd; + par->var.activate = var->activate; + par->var.height = var->height; + par->var.width = var->width; + if (var->accel_flags & FB_ACCELF_TEXT) { + par->var.accel_flags = FB_ACCELF_TEXT; + } else { + par->var.accel_flags = 0; + } + par->var.pixclock = var->pixclock; + par->var.left_margin = var->left_margin; + par->var.right_margin = var->right_margin; + par->var.upper_margin = var->upper_margin; + par->var.lower_margin = var->lower_margin; + par->var.hsync_len = var->hsync_len; + par->var.vsync_len = var->vsync_len; + par->var.sync = var->sync; + par->var.vmode = var->vmode; + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Fill the `var' structure based on the values in `par' and maybe + * other values read out of the hardware. + */ + +static int virgefb_encode_var(struct fb_var_screeninfo *var, + struct virgefb_par *par) +{ + DPRINTK("ENTER\n"); + memset(var, 0, sizeof(struct fb_var_screeninfo)); /* need this ? */ + var->xres = par->var.xres; + var->yres = par->var.yres; + var->xres_virtual = par->var.xres_virtual; + var->yres_virtual = par->var.yres_virtual; + var->xoffset = par->var.xoffset; + var->yoffset = par->var.yoffset; + var->bits_per_pixel = par->var.bits_per_pixel; + var->grayscale = par->var.grayscale; + var->red = par->var.red; + var->green = par->var.green; + var->blue = par->var.blue; + var->transp = par->var.transp; + var->nonstd = par->var.nonstd; + var->activate = par->var.activate; + var->height = par->var.height; + var->width = par->var.width; + var->accel_flags = par->var.accel_flags; + var->pixclock = par->var.pixclock; + var->left_margin = par->var.left_margin; + var->right_margin = par->var.right_margin; + var->upper_margin = par->var.upper_margin; + var->lower_margin = par->var.lower_margin; + var->hsync_len = par->var.hsync_len; + var->vsync_len = par->var.vsync_len; + var->sync = par->var.sync; + var->vmode = par->var.vmode; + DPRINTK("EXIT\n"); + return 0; +} + +/* + * Set a single color register. The values supplied are already + * rounded down to the hardware's capabilities (according to the + * entries in the var structure). Return != 0 for invalid regno. + */ + +static int virgefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + DPRINTK("ENTER\n"); + if (((current_par.var.bits_per_pixel==8) && (regno>255)) || + ((current_par.var.bits_per_pixel!=8) && (regno>15))) { + DPRINTK("EXIT\n"); + return 1; + } + if (((current_par.var.bits_per_pixel==8) && (regno<256)) || + ((current_par.var.bits_per_pixel!=8) && (regno<16))) { + virgefb_colour_table [regno][0] = red >> 10; + virgefb_colour_table [regno][1] = green >> 10; + virgefb_colour_table [regno][2] = blue >> 10; + } + + switch (current_par.var.bits_per_pixel) { +#ifdef FBCON_HAS_CFB8 + case 8: + wb_mmio(VDAC_ADDRESS_W, (unsigned char)regno); + wb_mmio(VDAC_DATA, ((unsigned char)(red >> 10))); + wb_mmio(VDAC_DATA, ((unsigned char)(green >> 10))); + wb_mmio(VDAC_DATA, ((unsigned char)(blue >> |