⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 retz3fb.c

📁 S3C44B0X下的LCD (framebuffer)驱动资料与相关代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 + -