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

📄 gxt4500.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Frame buffer device for IBM GXT4500P and GXT6000P display adaptors * * Copyright (C) 2006 Paul Mackerras, IBM Corp. <paulus@samba.org> */#include <linux/kernel.h>#include <linux/module.h>#include <linux/fb.h>#include <linux/console.h>#include <linux/pci.h>#include <linux/pci_ids.h>#include <linux/delay.h>#include <linux/string.h>#define PCI_DEVICE_ID_IBM_GXT4500P	0x21c#define PCI_DEVICE_ID_IBM_GXT6000P	0x170/* GXT4500P registers *//* Registers in PCI config space */#define CFG_ENDIAN0		0x40/* Misc control/status registers */#define STATUS			0x1000#define CTRL_REG0		0x1004#define   CR0_HALT_DMA			0x4#define   CR0_RASTER_RESET		0x8#define   CR0_GEOM_RESET		0x10#define   CR0_MEM_CTRLER_RESET		0x20/* Framebuffer control registers */#define FB_AB_CTRL		0x1100#define FB_CD_CTRL		0x1104#define FB_WID_CTRL		0x1108#define FB_Z_CTRL		0x110c#define FB_VGA_CTRL		0x1110#define REFRESH_AB_CTRL		0x1114#define REFRESH_CD_CTRL		0x1118#define FB_OVL_CTRL		0x111c#define   FB_CTRL_TYPE			0x80000000#define   FB_CTRL_WIDTH_MASK		0x007f0000#define   FB_CTRL_WIDTH_SHIFT		16#define   FB_CTRL_START_SEG_MASK	0x00003fff#define REFRESH_START		0x1098#define REFRESH_SIZE		0x109c/* "Direct" framebuffer access registers */#define DFA_FB_A		0x11e0#define DFA_FB_B		0x11e4#define DFA_FB_C		0x11e8#define DFA_FB_D		0x11ec#define   DFA_FB_ENABLE			0x80000000#define   DFA_FB_BASE_MASK		0x03f00000#define   DFA_FB_STRIDE_1k		0x00000000#define   DFA_FB_STRIDE_2k		0x00000010#define   DFA_FB_STRIDE_4k		0x00000020#define   DFA_PIX_8BIT			0x00000000#define   DFA_PIX_16BIT_565		0x00000001#define   DFA_PIX_16BIT_1555		0x00000002#define   DFA_PIX_24BIT			0x00000004#define   DFA_PIX_32BIT			0x00000005/* maps DFA_PIX_* to pixel size in bytes */static const unsigned char pixsize[] = {	1, 2, 2, 2, 4, 4};/* Display timing generator registers */#define DTG_CONTROL		0x1900#define   DTG_CTL_SCREEN_REFRESH	2#define   DTG_CTL_ENABLE		1#define DTG_HORIZ_EXTENT	0x1904#define DTG_HORIZ_DISPLAY	0x1908#define DTG_HSYNC_START		0x190c#define DTG_HSYNC_END		0x1910#define DTG_HSYNC_END_COMP	0x1914#define DTG_VERT_EXTENT		0x1918#define DTG_VERT_DISPLAY	0x191c#define DTG_VSYNC_START		0x1920#define DTG_VSYNC_END		0x1924#define DTG_VERT_SHORT		0x1928/* PLL/RAMDAC registers */#define DISP_CTL		0x402c#define   DISP_CTL_OFF			2#define SYNC_CTL		0x4034#define   SYNC_CTL_SYNC_ON_RGB		1#define   SYNC_CTL_SYNC_OFF		2#define   SYNC_CTL_HSYNC_INV		8#define   SYNC_CTL_VSYNC_INV		0x10#define   SYNC_CTL_HSYNC_OFF		0x20#define   SYNC_CTL_VSYNC_OFF		0x40#define PLL_M			0x4040#define PLL_N			0x4044#define PLL_POSTDIV		0x4048#define PLL_C			0x404c/* Hardware cursor */#define CURSOR_X		0x4078#define CURSOR_Y		0x407c#define CURSOR_HOTSPOT		0x4080#define CURSOR_MODE		0x4084#define   CURSOR_MODE_OFF		0#define   CURSOR_MODE_4BPP		1#define CURSOR_PIXMAP		0x5000#define CURSOR_CMAP		0x7400/* Window attribute table */#define WAT_FMT			0x4100#define   WAT_FMT_24BIT			0#define   WAT_FMT_16BIT_565		1#define   WAT_FMT_16BIT_1555		2#define   WAT_FMT_32BIT			3	/* 0 vs. 3 is a guess */#define   WAT_FMT_8BIT_332		9#define   WAT_FMT_8BIT			0xa#define   WAT_FMT_NO_CMAP		4	/* ORd in to other values */#define WAT_CMAP_OFFSET		0x4104		/* 4-bit value gets << 6 */#define WAT_CTRL		0x4108#define   WAT_CTRL_SEL_B		1	/* select B buffer if 1 */#define   WAT_CTRL_NO_INC		2#define WAT_GAMMA_CTRL		0x410c#define   WAT_GAMMA_DISABLE		1	/* disables gamma cmap */#define WAT_OVL_CTRL		0x430c		/* controls overlay *//* Indexed by DFA_PIX_* values */static const unsigned char watfmt[] = {	WAT_FMT_8BIT, WAT_FMT_16BIT_565, WAT_FMT_16BIT_1555, 0,	WAT_FMT_24BIT, WAT_FMT_32BIT};/* Colormap array; 1k entries of 4 bytes each */#define CMAP			0x6000#define readreg(par, reg)	readl((par)->regs + (reg))#define writereg(par, reg, val)	writel((val), (par)->regs + (reg))struct gxt4500_par {	void __iomem *regs;	int pixfmt;		/* pixel format, see DFA_PIX_* values */	/* PLL parameters */	int refclk_ps;		/* ref clock period in picoseconds */	int pll_m;		/* ref clock divisor */	int pll_n;		/* VCO divisor */	int pll_pd1;		/* first post-divisor */	int pll_pd2;		/* second post-divisor */	u32 pseudo_palette[16];	/* used in color blits */};/* mode requested by user */static char *mode_option;/* default mode: 1280x1024 @ 60 Hz, 8 bpp */static const struct fb_videomode defaultmode __devinitdata = {	.refresh = 60,	.xres = 1280,	.yres = 1024,	.pixclock = 9295,	.left_margin = 248,	.right_margin = 48,	.upper_margin = 38,	.lower_margin = 1,	.hsync_len = 112,	.vsync_len = 3,	.vmode = FB_VMODE_NONINTERLACED};/* List of supported cards */enum gxt_cards {	GXT4500P,	GXT6000P};/* Card-specific information */static const struct cardinfo {	int	refclk_ps;	/* period of PLL reference clock in ps */	const char *cardname;} cardinfo[] = {	[GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" },	[GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" },};/* * The refclk and VCO dividers appear to use a linear feedback shift * register, which gets reloaded when it reaches a terminal value, at * which point the divider output is toggled.  Thus one can obtain * whatever divisor is required by putting the appropriate value into * the reload register.  For a divisor of N, one puts the value from * the LFSR sequence that comes N-1 places before the terminal value * into the reload register. */static const unsigned char mdivtab[] = {/* 1 */		      0x3f, 0x00, 0x20, 0x10, 0x28, 0x14, 0x2a, 0x15, 0x0a,/* 10 */	0x25, 0x32, 0x19, 0x0c, 0x26, 0x13, 0x09, 0x04, 0x22, 0x11,/* 20 */	0x08, 0x24, 0x12, 0x29, 0x34, 0x1a, 0x2d, 0x36, 0x1b, 0x0d,/* 30 */	0x06, 0x23, 0x31, 0x38, 0x1c, 0x2e, 0x17, 0x0b, 0x05, 0x02,/* 40 */	0x21, 0x30, 0x18, 0x2c, 0x16, 0x2b, 0x35, 0x3a, 0x1d, 0x0e,/* 50 */	0x27, 0x33, 0x39, 0x3c, 0x1e, 0x2f, 0x37, 0x3b, 0x3d, 0x3e,/* 60 */	0x1f, 0x0f, 0x07, 0x03, 0x01,};static const unsigned char ndivtab[] = {/* 2 */		            0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x78, 0xbc, 0x5e,/* 10 */	0x2f, 0x17, 0x0b, 0x85, 0xc2, 0xe1, 0x70, 0x38, 0x9c, 0x4e,/* 20 */	0xa7, 0xd3, 0xe9, 0xf4, 0xfa, 0xfd, 0xfe, 0x7f, 0xbf, 0xdf,/* 30 */	0xef, 0x77, 0x3b, 0x1d, 0x8e, 0xc7, 0xe3, 0x71, 0xb8, 0xdc,/* 40 */	0x6e, 0xb7, 0x5b, 0x2d, 0x16, 0x8b, 0xc5, 0xe2, 0xf1, 0xf8,/* 50 */	0xfc, 0x7e, 0x3f, 0x9f, 0xcf, 0x67, 0xb3, 0xd9, 0x6c, 0xb6,/* 60 */	0xdb, 0x6d, 0x36, 0x9b, 0x4d, 0x26, 0x13, 0x89, 0xc4, 0x62,/* 70 */	0xb1, 0xd8, 0xec, 0xf6, 0xfb, 0x7d, 0xbe, 0x5f, 0xaf, 0x57,/* 80 */	0x2b, 0x95, 0x4a, 0x25, 0x92, 0x49, 0xa4, 0x52, 0x29, 0x94,/* 90 */	0xca, 0x65, 0xb2, 0x59, 0x2c, 0x96, 0xcb, 0xe5, 0xf2, 0x79,/* 100 */	0x3c, 0x1e, 0x0f, 0x07, 0x83, 0x41, 0x20, 0x90, 0x48, 0x24,/* 110 */	0x12, 0x09, 0x84, 0x42, 0xa1, 0x50, 0x28, 0x14, 0x8a, 0x45,/* 120 */	0xa2, 0xd1, 0xe8, 0x74, 0xba, 0xdd, 0xee, 0xf7, 0x7b, 0x3d,/* 130 */	0x9e, 0x4f, 0x27, 0x93, 0xc9, 0xe4, 0x72, 0x39, 0x1c, 0x0e,/* 140 */	0x87, 0xc3, 0x61, 0x30, 0x18, 0x8c, 0xc6, 0x63, 0x31, 0x98,/* 150 */	0xcc, 0xe6, 0x73, 0xb9, 0x5c, 0x2e, 0x97, 0x4b, 0xa5, 0xd2,/* 160 */	0x69,};static int calc_pll(int period_ps, struct gxt4500_par *par){	int m, n, pdiv1, pdiv2, postdiv;	int pll_period, best_error, t, intf;	/* only deal with range 5MHz - 300MHz */	if (period_ps < 3333 || period_ps > 200000)		return -1;	best_error = 1000000;	for (pdiv1 = 1; pdiv1 <= 8; ++pdiv1) {		for (pdiv2 = 1; pdiv2 <= pdiv1; ++pdiv2) {			postdiv = pdiv1 * pdiv2;			pll_period = DIV_ROUND_UP(period_ps, postdiv);			/* keep pll in range 350..600 MHz */			if (pll_period < 1666 || pll_period > 2857)				continue;			for (m = 1; m <= 64; ++m) {				intf = m * par->refclk_ps;				if (intf > 500000)					break;				n = intf * postdiv / period_ps;				if (n < 3 || n > 160)					continue;				t = par->refclk_ps * m * postdiv / n;				t -= period_ps;				if (t >= 0 && t < best_error) {					par->pll_m = m;					par->pll_n = n;					par->pll_pd1 = pdiv1;					par->pll_pd2 = pdiv2;					best_error = t;				}			}		}	}	if (best_error == 1000000)		return -1;	return 0;}static int calc_pixclock(struct gxt4500_par *par){	return par->refclk_ps * par->pll_m * par->pll_pd1 * par->pll_pd2		/ par->pll_n;}static int gxt4500_var_to_par(struct fb_var_screeninfo *var,			      struct gxt4500_par *par){	if (var->xres + var->xoffset > var->xres_virtual ||	    var->yres + var->yoffset > var->yres_virtual ||	    var->xres_virtual > 4096)		return -EINVAL;	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)		return -EINVAL;	if (calc_pll(var->pixclock, par) < 0)		return -EINVAL;	switch (var->bits_per_pixel) {	case 32:		if (var->transp.length)			par->pixfmt = DFA_PIX_32BIT;		else			par->pixfmt = DFA_PIX_24BIT;		break;	case 24:		par->pixfmt = DFA_PIX_24BIT;		break;	case 16:		if (var->green.length == 5)			par->pixfmt = DFA_PIX_16BIT_1555;		else			par->pixfmt = DFA_PIX_16BIT_565;		break;	case 8:		par->pixfmt = DFA_PIX_8BIT;		break;	default:		return -EINVAL;	}	return 0;}static const struct fb_bitfield eightbits = {0, 8};static const struct fb_bitfield nobits = {0, 0};static void gxt4500_unpack_pixfmt(struct fb_var_screeninfo *var,				  int pixfmt){	var->bits_per_pixel = pixsize[pixfmt] * 8;	var->red = eightbits;	var->green = eightbits;	var->blue = eightbits;	var->transp = nobits;	switch (pixfmt) {	case DFA_PIX_16BIT_565:		var->red.length = 5;		var->green.length = 6;		var->blue.length = 5;		break;	case DFA_PIX_16BIT_1555:		var->red.length = 5;		var->green.length = 5;		var->blue.length = 5;		var->transp.length = 1;		break;	case DFA_PIX_32BIT:		var->transp.length = 8;		break;	}	if (pixfmt != DFA_PIX_8BIT) {		var->green.offset = var->red.length;		var->blue.offset = var->green.offset + var->green.length;		if (var->transp.length)			var->transp.offset =				var->blue.offset + var->blue.length;	}}static int gxt4500_check_var(struct fb_var_screeninfo *var,			     struct fb_info *info){	struct gxt4500_par par;	int err;	par = *(struct gxt4500_par *)info->par;	err = gxt4500_var_to_par(var, &par);	if (!err) {		var->pixclock = calc_pixclock(&par);		gxt4500_unpack_pixfmt(var, par.pixfmt);	}	return err;}static int gxt4500_set_par(struct fb_info *info){	struct gxt4500_par *par = info->par;	struct fb_var_screeninfo *var = &info->var;	int err;	u32 ctrlreg, tmp;	unsigned int dfa_ctl, pixfmt, stride;	unsigned int wid_tiles, i;	unsigned int prefetch_pix, htot;	struct gxt4500_par save_par;	save_par = *par;	err = gxt4500_var_to_par(var, par);	if (err) {		*par = save_par;		return err;	}	/* turn off DTG for now */	ctrlreg = readreg(par, DTG_CONTROL);	ctrlreg &= ~(DTG_CTL_ENABLE | DTG_CTL_SCREEN_REFRESH);	writereg(par, DTG_CONTROL, ctrlreg);

⌨️ 快捷键说明

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