pm2fb.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,289 行 · 第 1/3 页

C
1,289
字号
/* * Permedia2 framebuffer driver. * * 2.5/2.6 driver: * Copyright (c) 2003 Jim Hague (jim.hague@acm.org) * * based on 2.4 driver: * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com) * * and additional input from James Simmon's port of Hannu Mallat's tdfx * driver. * * $Id$ * * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. * I have no access to other pm2fb implementations, and cannot test * on them. Therefore for now I am omitting Sparc and CVision code. * * Multiple boards support has been on the TODO list for ages. * Don't expect this to change. * * 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/config.h>#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/init.h>#include <linux/pci.h>#include <video/permedia2.h>#include <video/cvisionppc.h>#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)#error	"The endianness of the target host has not been defined."#endif#if defined(__BIG_ENDIAN) && !defined(__sparc__)#define PM2FB_BE_APERTURE#endif#if !defined(CONFIG_PCI)#error "Only generic PCI cards supported."#endif#undef PM2FB_MASTER_DEBUG#ifdef PM2FB_MASTER_DEBUG#define DPRINTK(a,b...)	printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)#else#define DPRINTK(a,b...)#endif/* * The 2.4 driver calls reset_card() at init time, where it also sets the * initial mode. I don't think the driver should touch the chip until * the console sets a video mode. So I was calling this at the start * of setting a mode. However, certainly on 1280x1024 depth 16 on my * PCI Graphics Blaster Exxtreme this causes the display to smear * slightly.  I don't know why. Guesses to jim.hague@acm.org. */#undef RESET_CARD_ON_MODE_SET/* * Driver data  */static char *mode __initdata = NULL;/* * The XFree GLINT driver will (I think to implement hardware cursor * support on TVP4010 and similar where there is no RAMDAC - see * comment in set_video) always request +ve sync regardless of what * the mode requires. This screws me because I have a Sun * fixed-frequency monitor which absolutely has to have -ve sync. So * these flags allow the user to specify that requests for +ve sync * should be silently turned in -ve sync. */static int lowhsync __initdata = 0;static int lowvsync __initdata = 0;	/* * The hardware state of the graphics card that isn't part of the * screeninfo. */struct pm2fb_par{	pm2type_t	type;		/* Board type */	u32		fb_size;	/* framebuffer memory size */	unsigned char*	v_fb;		/* virtual address of frame buffer */	unsigned char*	v_regs;		/* virtual address of p_regs */	u32 	   	memclock;	/* memclock */	u32		video;		/* video flags before blanking */};/* * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo * if we don't use modedb. */static struct fb_fix_screeninfo pm2fb_fix __initdata = {	.id =		"", 	.type =		FB_TYPE_PACKED_PIXELS,	.visual =	FB_VISUAL_PSEUDOCOLOR,	.xpanstep =	1,	.ypanstep =	1,	.ywrapstep =	0, 	.accel =	FB_ACCEL_NONE,};/* * Default video mode. In case the modedb doesn't work, or we're * a module (in which case modedb doesn't really work). */static struct fb_var_screeninfo pm2fb_var __initdata = {	/* "640x480, 8 bpp @ 60 Hz */	.xres =		640,	.yres =		480,	.xres_virtual =	640,	.yres_virtual =	480,	.bits_per_pixel =8,	.red =		{0, 8, 0},	.blue =		{0, 8, 0},	.green =	{0, 8, 0},	.activate =	FB_ACTIVATE_NOW,	.height =	-1,	.width =	-1,	.accel_flags =	0,	.pixclock =	39721,	.left_margin =	40,	.right_margin =	24,	.upper_margin =	32,	.lower_margin =	11,	.hsync_len =	96,	.vsync_len =	2,	.vmode =	FB_VMODE_NONINTERLACED};/* * Utility functions */inline static u32 RD32(unsigned char* base, s32 off){	return fb_readl(base + off);}inline static void WR32(unsigned char* base, s32 off, u32 v){	fb_writel(v, base + off);}inline static u32 pm2_RD(struct pm2fb_par* p, s32 off){	return RD32(p->v_regs, off);}inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v){	WR32(p->v_regs, off, v);}inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx){	int index = PM2R_RD_INDEXED_DATA;	switch (p->type) {	case PM2_TYPE_PERMEDIA2:		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);		break;	case PM2_TYPE_PERMEDIA2V:		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);		index = PM2VR_RD_INDEXED_DATA;		break;	}		mb();	return pm2_RD(p, index);}inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v){	int index = PM2R_RD_INDEXED_DATA;	switch (p->type) {	case PM2_TYPE_PERMEDIA2:		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);		break;	case PM2_TYPE_PERMEDIA2V:		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);		index = PM2VR_RD_INDEXED_DATA;		break;	}		mb();	pm2_WR(p, index, v);}inline static u32 pm2v_RDAC_RD(struct pm2fb_par* p, s32 idx){	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);	mb();	return pm2_RD(p, PM2VR_RD_INDEXED_DATA);}inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v){	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);	mb();	pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);}#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT#define WAIT_FIFO(p,a)#elseinline static void WAIT_FIFO(struct pm2fb_par* p, u32 a){	while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a );	mb();}#endif/* * partial products for the supported horizontal resolutions. */#define PACKPP(p0,p1,p2)	(((p2) << 6) | ((p1) << 3) | (p0))static const struct {	u16 width;	u16 pp;} pp_table[] = {	{ 32,	PACKPP(1, 0, 0) }, { 64,	PACKPP(1, 1, 0) },	{ 96,	PACKPP(1, 1, 1) }, { 128,	PACKPP(2, 1, 1) },	{ 160,	PACKPP(2, 2, 1) }, { 192,	PACKPP(2, 2, 2) },	{ 224,	PACKPP(3, 2, 1) }, { 256,	PACKPP(3, 2, 2) },	{ 288,	PACKPP(3, 3, 1) }, { 320,	PACKPP(3, 3, 2) },	{ 384,	PACKPP(3, 3, 3) }, { 416,	PACKPP(4, 3, 1) },	{ 448,	PACKPP(4, 3, 2) }, { 512,	PACKPP(4, 3, 3) },	{ 544,	PACKPP(4, 4, 1) }, { 576,	PACKPP(4, 4, 2) },	{ 640,	PACKPP(4, 4, 3) }, { 768,	PACKPP(4, 4, 4) },	{ 800,	PACKPP(5, 4, 1) }, { 832,	PACKPP(5, 4, 2) },	{ 896,	PACKPP(5, 4, 3) }, { 1024,	PACKPP(5, 4, 4) },	{ 1056,	PACKPP(5, 5, 1) }, { 1088,	PACKPP(5, 5, 2) },	{ 1152,	PACKPP(5, 5, 3) }, { 1280,	PACKPP(5, 5, 4) },	{ 1536,	PACKPP(5, 5, 5) }, { 1568,	PACKPP(6, 5, 1) },	{ 1600,	PACKPP(6, 5, 2) }, { 1664,	PACKPP(6, 5, 3) },	{ 1792,	PACKPP(6, 5, 4) }, { 2048,	PACKPP(6, 5, 5) },	{ 0,	0 } };static u32 partprod(u32 xres){	int i;	for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)		;	if ( pp_table[i].width == 0 )		DPRINTK("invalid width %u\n", xres);	return pp_table[i].pp;}static u32 to3264(u32 timing, int bpp, int is64){	switch (bpp) {	case 8:		timing >>= 2 + is64;		break;	case 16:		timing >>= 1 + is64;		break;	case 24:		timing = (timing * 3) >> (2 + is64);		break;	case 32:		if (is64)			timing >>= 1;		break;	}	return timing;}static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,		    unsigned char* pp){	unsigned char m;	unsigned char n;	unsigned char p;	u32 f;	s32 curr;	s32 delta = 100000;	*mm = *nn = *pp = 0;	for (n = 2; n < 15; n++) {		for (m = 2; m; m++) {			f = PM2_REFERENCE_CLOCK * m / n;			if (f >= 150000 && f <= 300000) {				for ( p = 0; p < 5; p++, f >>= 1) {					curr = ( clk > f ) ? clk - f : f - clk;					if ( curr < delta ) {						delta=curr;						*mm=m;						*nn=n;						*pp=p;					}				}			}		}	}}static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,		     unsigned char* pp){	unsigned char m;	unsigned char n;	unsigned char p;	u32 f;	s32 delta = 1000;	*mm = *nn = *pp = 0;	for (n = 1; n; n++) {		for ( m = 1; m; m++) {			for ( p = 0; p < 2; p++) {				f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1)));				if ( clk > f - delta && clk < f + delta ) {					delta = ( clk > f ) ? clk - f : f - clk;					*mm=m;					*nn=n;					*pp=p;				}			}		}	}}static void clear_palette(struct pm2fb_par* p) {	int i=256;	WAIT_FIFO(p, 1);	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);	wmb();	while (i--) {		WAIT_FIFO(p, 3);		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);	}}#ifdef RESET_CARD_ON_MODE_SETstatic void reset_card(struct pm2fb_par* p){	if (p->type == PM2_TYPE_PERMEDIA2V)		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);	pm2_WR(p, PM2R_RESET_STATUS, 0);	mb();	while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)		;	mb();#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT	DPRINTK("FIFO disconnect enabled\n");	pm2_WR(p, PM2R_FIFO_DISCON, 1);	mb();#endif}#endifstatic void reset_config(struct pm2fb_par* p){	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_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_FB_WINDOW_BASE, 0);	pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);	pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));	pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));	pm2_WR(p, PM2R_FB_READ_PIXEL, 0);	pm2_WR(p, PM2R_DITHER_MODE, 0);	pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);	pm2_WR(p, PM2R_DEPTH_MODE, 0);	pm2_WR(p, PM2R_STENCIL_MODE, 0);	pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);	pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);	pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);	pm2_WR(p, PM2R_YUV_MODE, 0);	pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);	pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);	pm2_WR(p, PM2R_FOG_MODE, 0);	pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);	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 */		pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);		break;	case PM2_TYPE_PERMEDIA2V:		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */		break;	}	pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);	pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);	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 set_aperture(struct pm2fb_par* p, u32 depth){	WAIT_FIFO(p, 4);#ifdef __LITTLE_ENDIAN

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?