1629 lines · 42.6 KB · C
RawDownload
/* *  linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * *	Copyright (C) 1995 Jay Estabrook *	Copyright (C) 1997 Geert Uytterhoeven *	Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha *	Copyright (C) 2002 Richard Henderson *	Copyright (C) 2006, 2007  Maciej W. Rozycki * *  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/aperture.h>#include <linux/bitrev.h>#include <linux/compiler.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/errno.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/selection.h>#include <linux/string.h>#include <linux/tc.h> #include <asm/io.h> #include <video/tgafb.h> #ifdef CONFIG_TC#define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type)#else#define TGA_BUS_TC(dev) 0#endif /* * Local functions. */ static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *);static int tgafb_set_par(struct fb_info *);static void tgafb_set_pll(struct tga_par *, int);static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned,			   unsigned, struct fb_info *);static int tgafb_blank(int, struct fb_info *);static void tgafb_init_fix(struct fb_info *); static void tgafb_imageblit(struct fb_info *, const struct fb_image *);static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); static int tgafb_register(struct device *dev);static void tgafb_unregister(struct device *dev); static const char *mode_option;static const char *mode_option_pci = "640x480@60";static const char *mode_option_tc = "1280x1024@72";  static struct pci_driver tgafb_pci_driver;static struct tc_driver tgafb_tc_driver; /* *  Frame buffer operations */ static const struct fb_ops tgafb_ops = {	.owner			= THIS_MODULE,	__FB_DEFAULT_IOMEM_OPS_RDWR,	.fb_check_var		= tgafb_check_var,	.fb_set_par		= tgafb_set_par,	.fb_setcolreg		= tgafb_setcolreg,	.fb_blank		= tgafb_blank,	.fb_pan_display		= tgafb_pan_display,	.fb_fillrect		= tgafb_fillrect,	.fb_copyarea		= tgafb_copyarea,	.fb_imageblit		= tgafb_imageblit,	__FB_DEFAULT_IOMEM_OPS_MMAP,};  #ifdef CONFIG_PCI/* *  PCI registration operations */static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);static void tgafb_pci_unregister(struct pci_dev *); static struct pci_device_id const tgafb_pci_table[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) },	{ }};MODULE_DEVICE_TABLE(pci, tgafb_pci_table); static struct pci_driver tgafb_pci_driver = {	.name			= "tgafb",	.id_table		= tgafb_pci_table,	.probe			= tgafb_pci_register,	.remove			= tgafb_pci_unregister,}; static int tgafb_pci_register(struct pci_dev *pdev,			      const struct pci_device_id *ent){	int ret; 	ret = aperture_remove_conflicting_pci_devices(pdev, "tgafb");	if (ret)		return ret; 	return tgafb_register(&pdev->dev);} static void tgafb_pci_unregister(struct pci_dev *pdev){	tgafb_unregister(&pdev->dev);}#endif /* CONFIG_PCI */ #ifdef CONFIG_TC/* *  TC registration operations */static int tgafb_tc_register(struct device *);static int tgafb_tc_unregister(struct device *); static struct tc_device_id const tgafb_tc_table[] = {	{ "DEC     ", "PMAGD-AA" },	{ "DEC     ", "PMAGD   " },	{ }};MODULE_DEVICE_TABLE(tc, tgafb_tc_table); static struct tc_driver tgafb_tc_driver = {	.id_table		= tgafb_tc_table,	.driver			= {		.name		= "tgafb",		.bus		= &tc_bus_type,		.probe		= tgafb_tc_register,		.remove		= tgafb_tc_unregister,	},}; static int tgafb_tc_register(struct device *dev){	int status = tgafb_register(dev);	if (!status)		get_device(dev);	return status;} static int tgafb_tc_unregister(struct device *dev){	put_device(dev);	tgafb_unregister(dev);	return 0;}#endif /* CONFIG_TC */  /** *      tgafb_check_var - Optional function.  Validates a var passed in. *      @var: frame buffer variable screen structure *      @info: frame buffer structure that represents a single frame buffer */static inttgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	struct tga_par *par = (struct tga_par *)info->par; 	if (!var->pixclock)		return -EINVAL; 	if (par->tga_type == TGA_TYPE_8PLANE) {		if (var->bits_per_pixel != 8)			return -EINVAL;	} else {		if (var->bits_per_pixel != 32)			return -EINVAL;	}	var->red.length = var->green.length = var->blue.length = 8;	if (var->bits_per_pixel == 32) {		var->red.offset = 16;		var->green.offset = 8;		var->blue.offset = 0;	} 	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)		return -EINVAL;	if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len)		return -EINVAL;	if (var->nonstd)		return -EINVAL;	if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)		return -EINVAL;	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)		return -EINVAL; 	/* Some of the acceleration routines assume the line width is	   a multiple of 8 bytes.  */	if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 8)		return -EINVAL; 	return 0;} /** *      tgafb_set_par - Optional function.  Alters the hardware state. *      @info: frame buffer structure that represents a single frame buffer */static inttgafb_set_par(struct fb_info *info){	static unsigned int const deep_presets[4] = {		0x00004000,		0x0000440d,		0xffffffff,		0x0000441d	};	static unsigned int const rasterop_presets[4] = {		0x00000003,		0x00000303,		0xffffffff,		0x00000303	};	static unsigned int const mode_presets[4] = {		0x00000000,		0x00000300,		0xffffffff,		0x00000300	};	static unsigned int const base_addr_presets[4] = {		0x00000000,		0x00000001,		0xffffffff,		0x00000001	}; 	struct tga_par *par = (struct tga_par *) info->par;	int tga_bus_pci = dev_is_pci(par->dev);	int tga_bus_tc = TGA_BUS_TC(par->dev);	u32 htimings, vtimings, pll_freq;	u8 tga_type;	int i; 	/* Encode video timings.  */	htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB)		    | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB));	vtimings = (info->var.yres & TGA_VERT_ACTIVE);	htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP;	vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP;	htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC;	vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC;	htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP;	vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP; 	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)		htimings |= TGA_HORIZ_POLARITY;	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)		vtimings |= TGA_VERT_POLARITY; 	par->htimings = htimings;	par->vtimings = vtimings; 	par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN); 	/* Store other useful values in par.  */	par->xres = info->var.xres;	par->yres = info->var.yres;	par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;	par->bits_per_pixel = info->var.bits_per_pixel;	info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); 	tga_type = par->tga_type; 	/* First, disable video.  */	TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); 	/* Write the DEEP register.  */	while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */		continue;	mb();	TGA_WRITE_REG(par, deep_presets[tga_type] |			   (par->sync_on_green ? 0x0 : 0x00010000),		      TGA_DEEP_REG);	while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */		continue;	mb(); 	/* Write some more registers.  */	TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG);	TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG);	TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG); 	/* Calculate & write the PLL.  */	tgafb_set_pll(par, pll_freq); 	/* Write some more registers.  */	TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG);	TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG); 	/* Init video timing regs.  */	TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG);	TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); 	/* Initialise RAMDAC. */	if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) { 		/* Init BT485 RAMDAC registers.  */		BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),			    BT485_CMD_0);		BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE);		BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */		BT485_WRITE(par, 0x40, BT485_CMD_1);		BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */		BT485_WRITE(par, 0xff, BT485_PIXEL_MASK); 		/* Fill palette registers.  */		BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);		TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); 		for (i = 0; i < 256 * 3; i += 4) {			TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8),				      TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),				      TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),				      TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),				      TGA_RAMDAC_REG);		} 	} else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) { 		/* Init BT459 RAMDAC registers.  */		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40);		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00);		BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2,			    (par->sync_on_green ? 0xc0 : 0x40)); 		BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00); 		/* Fill the palette.  */		BT459_LOAD_ADDR(par, 0x0000);		TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG); 		for (i = 0; i < 256 * 3; i += 4) {			TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);		} 	} else { /* 24-plane or 24plusZ */ 		/* Init BT463 RAMDAC registers.  */		BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40);		BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08);		BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2,			    (par->sync_on_green ? 0xc0 : 0x40)); 		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff);		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff);		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff);		BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); 		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00);		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00);		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);		BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); 		/* Fill the palette.  */		BT463_LOAD_ADDR(par, 0x0000);		TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG); #ifdef CONFIG_VT		for (i = 0; i < 16; i++) {			int j = color_table[i]; 			TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG);			TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG);			TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG);		}		for (i = 0; i < 512 * 3; i += 4) {#else		for (i = 0; i < 528 * 3; i += 4) {#endif			TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);		} 		/* Fill window type table after start of vertical retrace.  */		while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))			continue;		TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);		mb();		while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))			continue;		TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); 		BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE);		TGA_WRITE_REG(par, BT463_REG_ACC << 2, TGA_RAMDAC_SETUP_REG); 		for (i = 0; i < 16; i++) {			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x01, TGA_RAMDAC_REG);			TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);		} 	} 	/* Finally, enable video scan (and pray for the monitor... :-) */	TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG); 	return 0;} #define DIFFCHECK(X)							  \do {									  \	if (m <= 0x3f) {						  \		int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \		if (delta < 0)						  \			delta = -delta;					  \		if (delta < min_diff)					  \			min_diff = delta, vm = m, va = a, vr = r;	  \	}								  \} while (0) static voidtgafb_set_pll(struct tga_par *par, int f){	int n, shift, base, min_diff, target;	int r,a,m,vm = 34, va = 1, vr = 30; 	for (r = 0 ; r < 12 ; r++)		TGA_WRITE_REG(par, !r, TGA_CLOCK_REG); 	if (f > TGA_PLL_MAX_FREQ)		f = TGA_PLL_MAX_FREQ; 	if (f >= TGA_PLL_MAX_FREQ / 2)		shift = 0;	else if (f >= TGA_PLL_MAX_FREQ / 4)		shift = 1;	else		shift = 2; 	TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG);	TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG); 	for (r = 0 ; r < 10 ; r++)		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); 	if (f <= 120000) {		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);	}	else if (f <= 200000) {		TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);	}	else {		TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);		TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);	} 	TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);	TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);	TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);	TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);	TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);	TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); 	target = (f << shift) / TGA_PLL_BASE_FREQ;	min_diff = TGA_PLL_MAX_FREQ; 	r = 7 / target;	if (!r) r = 1; 	base = target * r;	while (base < 449) {		for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) {			m = ((n + 3) / 7) - 1;			a = 0;			DIFFCHECK((m + 1) * 7);			m++;			DIFFCHECK((m + 1) * 7);			m = (n / 6) - 1;			if ((a = n % 6))				DIFFCHECK(n);		}

Lines 1–500 of 1629.