📄 retz3fb.c
字号:
/* * Linux/drivers/video/retz3fb.c -- RetinaZ3 frame buffer device * * Copyright (C) 1997 Jes Sorensen * * This file is based on the CyberVision64 frame buffer device and * the generic Cirrus Logic driver. * * cyberfb.c: Copyright (C) 1996 Martin Apel, * Geert Uytterhoeven * clgen.c: Copyright (C) 1996 Frank Neumann * * History: * - 22 Jan 97: Initial work * - 14 Feb 97: Screen initialization works somewhat, still only * 8-bit packed pixel is supported. * * 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. */#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/fb.h>#include <linux/zorro.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/io.h>#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include "retz3fb.h"/* #define DEBUG if(1) */#define DEBUG if(0)/* * Reserve space for one pattern line. * * For the time being we only support 4MB boards! */#define PAT_MEM_SIZE 16*3#define PAT_MEM_OFF (4*1024*1024 - PAT_MEM_SIZE)struct retz3fb_par { int xres; int yres; int xres_vir; int yres_vir; int xoffset; int yoffset; int bpp; struct fb_bitfield red; struct fb_bitfield green; struct fb_bitfield blue; struct fb_bitfield transp; int pixclock; int left_margin; /* time from sync to picture */ int right_margin; /* time from picture to sync */ int upper_margin; /* time from sync to picture */ int lower_margin; int hsync_len; /* length of horizontal sync */ int vsync_len; /* length of vertical sync */ int vmode; int accel;};struct display_data { long h_total; /* Horizontal Total */ long h_sstart; /* Horizontal Sync Start */ long h_sstop; /* Horizontal Sync Stop */ long h_bstart; /* Horizontal Blank Start */ long h_bstop; /* Horizontal Blank Stop */ long h_dispend; /* Horizontal Display End */ long v_total; /* Vertical Total */ long v_sstart; /* Vertical Sync Start */ long v_sstop; /* Vertical Sync Stop */ long v_bstart; /* Vertical Blank Start */ long v_bstop; /* Vertical Blank Stop */ long v_dispend; /* Horizontal Display End */};struct retz3_fb_info { struct fb_info info; unsigned char *base; unsigned char *fbmem; unsigned long fbsize; volatile unsigned char *regs; unsigned long physfbmem; unsigned long physregs; int currcon; int current_par_valid; /* set to 0 by memset */ int blitbusy; struct display disp; struct retz3fb_par current_par; unsigned char color_table [256][3];};static char fontname[40] __initdata = { 0 };#define retz3info(info) ((struct retz3_fb_info *)(info))#define fbinfo(info) ((struct fb_info *)(info))/* * Frame Buffer Name */static char retz3fb_name[16] = "RetinaZ3";/* * A small info on how to convert XFree86 timing values into fb * timings - by Frank Neumann: *An XFree86 mode line consists of the following fields: "800x600" 50 800 856 976 1040 600 637 643 666 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFLThe fields in the fb_var_screeninfo structure are: unsigned long pixclock; * pixel clock in ps (pico seconds) * unsigned long left_margin; * time from sync to picture * unsigned long right_margin; * time from picture to sync * unsigned long upper_margin; * time from sync to picture * unsigned long lower_margin; unsigned long hsync_len; * length of horizontal sync * unsigned long vsync_len; * length of vertical sync *1) Pixelclock: xfree: in MHz fb: In Picoseconds (ps) pixclock = 1000000 / DCF2) horizontal timings: left_margin = HFL - SH2 right_margin = SH1 - HR hsync_len = SH2 - SH13) vertical timings: upper_margin = VFL - SV2 lower_margin = SV1 - VR vsync_len = SV2 - SV1Good examples for VESA timings can be found in the XFree86 source tree,under "programs/Xserver/hw/xfree86/doc/modeDB.txt".*//* * Predefined Video Modes */static struct { const char *name; struct fb_var_screeninfo var;} retz3fb_predefined[] __initdata = { /* * NB: it is very important to adjust the pixel-clock to the color-depth. */ { "640x480", { /* 640x480, 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_ACCEL_NONE, 39722, 48, 16, 33, 10, 96, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED } }, /* ModeLine "800x600" 36 800 824 896 1024 600 601 603 625 < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL */ { "800x600", { /* 800x600, 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, 27778, 64, 24, 22, 1, 120, 2, FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED } }, { "800x600-60", { /* 800x600, 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, 25000, 88, 40, 23, 1, 128, 4, FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED } }, { "800x600-70", { /* 800x600, 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, 22272, 40, 24, 15, 9, 144, 12, FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED } }, /* ModeLine "1024x768i" 45 1024 1064 1224 1264 768 777 785 817 interlace < name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL */ { "1024x768i", { /* 1024x768, 8 bpp, interlaced */ 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, 22222, 40, 40, 32, 9, 160, 8, FB_SYNC_COMP_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED } }, { "1024x768", { 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_ACCEL_NONE, 12500, 92, 112, 31, 2, 204, 4, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED } }, { "640x480-16", { /* 640x480, 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, 0, 38461/2, 28, 32, 12, 10, 96, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED } }, { "640x480-24", { /* 640x480, 24 bpp */ 640, 480, 640, 480, 0, 0, 24, 0, {8, 8, 8}, {8, 8, 8}, {8, 8, 8}, {0, 0, 0}, 0, 0, -1, -1, 0, 38461/3, 28, 32, 12, 10, 96, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,FB_VMODE_NONINTERLACED } },};#define NUM_TOTAL_MODES ARRAY_SIZE(retz3fb_predefined)static struct fb_var_screeninfo retz3fb_default;static int z3fb_inverse = 0;static int z3fb_mode __initdata = 0;/* * Interface used by the world */int retz3fb_setup(char *options);static int retz3fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int retz3fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int retz3fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int retz3fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int retz3fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);/* * Interface to the low level console driver */int retz3fb_init(void);static int z3fb_switch(int con, struct fb_info *info);static int z3fb_updatevar(int con, struct fb_info *info);static void z3fb_blank(int blank, struct fb_info *info);/* * Text console acceleration */#ifdef FBCON_HAS_CFB8static struct display_switch fbcon_retz3_8;#endif/* * Accelerated Functions used by the low level console driver */static void retz3_bitblt(struct display *p, unsigned short curx, unsigned short cury, unsigned short destx, unsigned short desty, unsigned short width, unsigned short height, unsigned short cmd, unsigned short mask);/* * Hardware Specific Routines */static int retz3_encode_fix(struct fb_info *info, struct fb_fix_screeninfo *fix, struct retz3fb_par *par);static int retz3_decode_var(struct fb_var_screeninfo *var, struct retz3fb_par *par);static int retz3_encode_var(struct fb_var_screeninfo *var, struct retz3fb_par *par);static int retz3_getcolreg(unsigned int regno, unsigned int *red, unsigned int *green, unsigned int *blue, unsigned int *transp, struct fb_info *info);static int retz3_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info);/* * Internal routines */static void retz3fb_get_par(struct fb_info *info, struct retz3fb_par *par);static void retz3fb_set_par(struct fb_info *info, struct retz3fb_par *par);static int do_fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var, int isactive);static void do_install_cmap(int con, struct fb_info *info);static void retz3fb_set_disp(int con, struct fb_info *info);static int get_video_mode(const char *name);/* -------------------- Hardware specific routines ------------------------- */static unsigned short find_fq(unsigned int freq){ unsigned long f; long tmp; long prev = 0x7fffffff; long n2, n1 = 3; unsigned long m; unsigned short res = 0; if (freq <= 31250000) n2 = 3; else if (freq <= 62500000) n2 = 2; else if (freq <= 125000000) n2 = 1; else if (freq <= 250000000) n2 = 0; else return 0; do { f = freq >> (10 - n2); m = (f * n1) / (14318180/1024); if (m > 129) break; tmp = (((m * 14318180) >> n2) / n1) - freq; if (tmp < 0) tmp = -tmp; if (tmp < prev) { prev = tmp; res = (((n2 << 5) | (n1-2)) << 8) | (m-2); } } while ( (++n1) <= 21); return res;}static int retz3_set_video(struct fb_info *info, struct fb_var_screeninfo *var, struct retz3fb_par *par){ volatile unsigned char *regs = retz3info(info)->regs; unsigned int freq; int xres, hfront, hsync, hback; int yres, vfront, vsync, vback; unsigned char tmp; unsigned short best_freq; struct display_data data; short clocksel = 0; /* Apparantly this is always zero */ int bpp = var->bits_per_pixel; /* * XXX */ if (bpp == 24) return 0; if ((bpp != 8) && (bpp != 16) && (bpp != 24)) return -EFAULT; par->xoffset = 0; par->yoffset = 0; xres = var->xres * bpp / 4; hfront = var->right_margin * bpp / 4; hsync = var->hsync_len * bpp / 4; hback = var->left_margin * bpp / 4; if (var->vmode & FB_VMODE_DOUBLE) { yres = var->yres * 2; vfront = var->lower_margin * 2; vsync = var->vsync_len * 2; vback = var->upper_margin * 2; } else if (var->vmode & FB_VMODE_INTERLACED) { yres = (var->yres + 1) / 2; vfront = (var->lower_margin + 1) / 2; vsync = (var->vsync_len + 1) / 2; vback = (var->upper_margin + 1) / 2; } else { yres = var->yres; /* -1 ? */ vfront = var->lower_margin; vsync = var->vsync_len; vback = var->upper_margin; } data.h_total = (hback / 8) + (xres / 8) + (hfront / 8) + (hsync / 8) - 1 /* + 1 */; data.h_dispend = ((xres + bpp - 1)/ 8) - 1; data.h_bstart = xres / 8 - 1 /* + 1 */; data.h_bstop = data.h_total+1 + 2 + 1; data.h_sstart = (xres / 8) + (hfront / 8) + 1; data.h_sstop = (xres / 8) + (hfront / 8) + (hsync / 8) + 1; data.v_total = yres + vfront + vsync + vback - 1; data.v_dispend = yres - 1; data.v_bstart = yres - 1; data.v_bstop = data.v_total; data.v_sstart = yres + vfront - 1 - 2; data.v_sstop = yres + vfront + vsync - 1;#if 0 /* testing */ printk("HBS: %i\n", data.h_bstart); printk("HSS: %i\n", data.h_sstart); printk("HSE: %i\n", data.h_sstop); printk("HBE: %i\n", data.h_bstop); printk("HT: %i\n", data.h_total); printk("hsync: %i\n", hsync); printk("hfront: %i\n", hfront); printk("hback: %i\n", hback); printk("VBS: %i\n", data.v_bstart); printk("VSS: %i\n", data.v_sstart); printk("VSE: %i\n", data.v_sstop); printk("VBE: %i\n", data.v_bstop); printk("VT: %i\n", data.v_total); printk("vsync: %i\n", vsync); printk("vfront: %i\n", vfront); printk("vback: %i\n", vback);#endif if (data.v_total >= 1024) printk(KERN_ERR "MAYDAY: v_total >= 1024; bailing out!\n"); reg_w(regs, GREG_MISC_OUTPUT_W, 0xe3 | ((clocksel & 3) * 0x04)); reg_w(regs, GREG_FEATURE_CONTROL_W, 0x00); seq_w(regs, SEQ_RESET, 0x00); seq_w(regs, SEQ_RESET, 0x03); /* reset sequencer logic */ /* * CLOCKING_MODE bits: * 2: This one is only set for certain text-modes, wonder if * it may be for EGA-lines? (it was referred to as CLKDIV2) * (The CL drivers sets it to 0x21 with the comment: * FullBandwidth (video off) and 8/9 dot clock) */ seq_w(regs, SEQ_CLOCKING_MODE, 0x01 | 0x00 /* 0x08 */); seq_w(regs, SEQ_MAP_MASK, 0x0f); /* enable writing to plane 0-3 */ seq_w(regs, SEQ_CHAR_MAP_SELECT, 0x00); /* doesn't matter in gfx-mode */ seq_w(regs, SEQ_MEMORY_MODE, 0x06); /* CL driver says 0x0e for 256 col mode*/ seq_w(regs, SEQ_RESET, 0x01); seq_w(regs, SEQ_RESET, 0x03); seq_w(regs, SEQ_EXTENDED_ENABLE, 0x05); seq_w(regs, SEQ_CURSOR_CONTROL, 0x00); /* disable cursor */ seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); seq_w(regs, SEQ_PRIM_HOST_OFF_HI, 0x00); seq_w(regs, SEQ_LINEAR_0, 0x4a); seq_w(regs, SEQ_LINEAR_1, 0x00); seq_w(regs, SEQ_SEC_HOST_OFF_HI, 0x00); seq_w(regs, SEQ_SEC_HOST_OFF_LO, 0x00); seq_w(regs, SEQ_EXTENDED_MEM_ENA, 0x3 | 0x4 | 0x10 | 0x40); /* * The lower 4 bits (0-3) are used to set the font-width for * text-mode - DON'T try to set this for gfx-mode. */ seq_w(regs, SEQ_EXT_CLOCK_MODE, 0x10); seq_w(regs, SEQ_EXT_VIDEO_ADDR, 0x03); /* * Extended Pixel Control: * bit 0: text-mode=0, gfx-mode=1 (Graphics Byte ?) * bit 1: (Packed/Nibble Pixel Format ?) * bit 4-5: depth, 0=1-8bpp, 1=9-16bpp, 2=17-24bpp */ seq_w(regs, SEQ_EXT_PIXEL_CNTL, 0x01 | (((bpp / 8) - 1) << 4)); seq_w(regs, SEQ_BUS_WIDTH_FEEDB, 0x04); seq_w(regs, SEQ_COLOR_EXP_WFG, 0x01); seq_w(regs, SEQ_COLOR_EXP_WBG, 0x00); seq_w(regs, SEQ_EXT_RW_CONTROL, 0x00); seq_w(regs, SEQ_MISC_FEATURE_SEL, (0x51 | (clocksel & 8))); seq_w(regs, SEQ_COLOR_KEY_CNTL, 0x40); seq_w(regs, SEQ_COLOR_KEY_MATCH0, 0x00); seq_w(regs, SEQ_COLOR_KEY_MATCH1, 0x00); seq_w(regs, SEQ_COLOR_KEY_MATCH2, 0x00); seq_w(regs, SEQ_CRC_CONTROL, 0x00); seq_w(regs, SEQ_PERF_SELECT, 0x10); seq_w(regs, SEQ_ACM_APERTURE_1, 0x00); seq_w(regs, SEQ_ACM_APERTURE_2, 0x30); seq_w(regs, SEQ_ACM_APERTURE_3, 0x00); seq_w(regs, SEQ_MEMORY_MAP_CNTL, 0x03);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -