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

📄 pvr2fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * drivers/video/pvr2fb.c * * Frame buffer and fbcon support for the NEC PowerVR2 found within the Sega * Dreamcast. * * Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org> * Copyright (c) 2001 - 2008  Paul Mundt <lethal@linux-sh.org> * * This driver is mostly based on the excellent amifb and vfb sources.  It uses * an odd scheme for converting hardware values to/from framebuffer values, * here are some hacked-up formulas: * *  The Dreamcast has screen offsets from each side of its four borders and *  the start offsets of the display window.  I used these values to calculate *  'pseudo' values (think of them as placeholders) for the fb video mode, so *  that when it came time to convert these values back into their hardware *  values, I could just add mode- specific offsets to get the correct mode *  settings: * *      left_margin = diwstart_h - borderstart_h; *      right_margin = borderstop_h - (diwstart_h + xres); *      upper_margin = diwstart_v - borderstart_v; *      lower_margin = borderstop_v - (diwstart_h + yres); * *      hsync_len = borderstart_h + (hsync_total - borderstop_h); *      vsync_len = borderstart_v + (vsync_total - borderstop_v); * *  Then, when it's time to convert back to hardware settings, the only *  constants are the borderstart_* offsets, all other values are derived from *  the fb video mode: * *      // PAL *      borderstart_h = 116; *      borderstart_v = 44; *      ... *      borderstop_h = borderstart_h + hsync_total - hsync_len; *      ... *      diwstart_v = borderstart_v - upper_margin; * *  However, in the current implementation, the borderstart values haven't had *  the benefit of being fully researched, so some modes may be broken. */#undef DEBUG#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#ifdef CONFIG_SH_DREAMCAST#include <asm/machvec.h>#include <mach-dreamcast/mach/sysasic.h>#endif#ifdef CONFIG_SH_DMA#include <linux/pagemap.h>#include <mach/dma.h>#include <asm/dma.h>#endif#ifdef CONFIG_SH_STORE_QUEUES#include <linux/uaccess.h>#include <cpu/sq.h>#endif#ifndef PCI_DEVICE_ID_NEC_NEON250#  define PCI_DEVICE_ID_NEC_NEON250	0x0067#endif/* 2D video registers */#define DISP_BASE	par->mmio_base#define DISP_BRDRCOLR (DISP_BASE + 0x40)#define DISP_DIWMODE (DISP_BASE + 0x44)#define DISP_DIWADDRL (DISP_BASE + 0x50)#define DISP_DIWADDRS (DISP_BASE + 0x54)#define DISP_DIWSIZE (DISP_BASE + 0x5c)#define DISP_SYNCCONF (DISP_BASE + 0xd0)#define DISP_BRDRHORZ (DISP_BASE + 0xd4)#define DISP_SYNCSIZE (DISP_BASE + 0xd8)#define DISP_BRDRVERT (DISP_BASE + 0xdc)#define DISP_DIWCONF (DISP_BASE + 0xe8)#define DISP_DIWHSTRT (DISP_BASE + 0xec)#define DISP_DIWVSTRT (DISP_BASE + 0xf0)#define DISP_PIXDEPTH (DISP_BASE + 0x108)/* Pixel clocks, one for TV output, doubled for VGA output */#define TV_CLK 74239#define VGA_CLK 37119/* This is for 60Hz - the VTOTAL is doubled for interlaced modes */#define PAL_HTOTAL 863#define PAL_VTOTAL 312#define NTSC_HTOTAL 857#define NTSC_VTOTAL 262/* Supported cable types */enum { CT_VGA, CT_NONE, CT_RGB, CT_COMPOSITE };/* Supported video output types */enum { VO_PAL, VO_NTSC, VO_VGA };/* Supported palette types */enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 };struct pvr2_params { unsigned int val; char *name; };static struct pvr2_params cables[] __devinitdata = {	{ CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" },};static struct pvr2_params outputs[] __devinitdata = {	{ VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" },};/* * This describes the current video mode */static struct pvr2fb_par {	unsigned int hsync_total;	/* Clocks/line */	unsigned int vsync_total;	/* Lines/field */	unsigned int borderstart_h;	unsigned int borderstop_h;	unsigned int borderstart_v;	unsigned int borderstop_v;	unsigned int diwstart_h;	/* Horizontal offset of the display field */	unsigned int diwstart_v;	/* Vertical offset of the display field, for				   interlaced modes, this is the long field */	unsigned long disp_start;	/* Address of image within VRAM */	unsigned char is_interlaced;	/* Is the display interlaced? */	unsigned char is_doublescan;	/* Are scanlines output twice? (doublescan) */	unsigned char is_lowres;	/* Is horizontal pixel-doubling enabled? */	unsigned long mmio_base;	/* MMIO base */	u32 palette[16];} *currentpar;static struct fb_info *fb_info;static struct fb_fix_screeninfo pvr2_fix __devinitdata = {	.id =		"NEC PowerVR2",	.type =		FB_TYPE_PACKED_PIXELS,	.visual =	FB_VISUAL_TRUECOLOR,	.ypanstep =	1,	.ywrapstep =	1,	.accel =	FB_ACCEL_NONE,};static struct fb_var_screeninfo pvr2_var __devinitdata = {	.xres =		640,	.yres =		480,	.xres_virtual =	640,	.yres_virtual = 480,	.bits_per_pixel	=16,	.red =		{ 11, 5, 0 },	.green =	{  5, 6, 0 },	.blue =		{  0, 5, 0 },	.activate =	FB_ACTIVATE_NOW,	.height =	-1,	.width =	-1,	.vmode =	FB_VMODE_NONINTERLACED,};static int cable_type = CT_VGA;static int video_output = VO_VGA;static int nopan = 0;static int nowrap = 1;/* * We do all updating, blanking, etc. during the vertical retrace period */static unsigned int do_vmode_full = 0;	/* Change the video mode */static unsigned int do_vmode_pan = 0;	/* Update the video mode */static short do_blank = 0;		/* (Un)Blank the screen */static unsigned int is_blanked = 0;		/* Is the screen blanked? */#ifdef CONFIG_SH_STORE_QUEUESstatic unsigned long pvr2fb_map;#endif#ifdef CONFIG_SH_DMAstatic unsigned int shdma = PVR2_CASCADE_CHAN;static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;#endifstatic int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue,                            unsigned int transp, struct fb_info *info);static int pvr2fb_blank(int blank, struct fb_info *info);static unsigned long get_line_length(int xres_virtual, int bpp);static void set_color_bitfields(struct fb_var_screeninfo *var);static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);static int pvr2fb_set_par(struct fb_info *info);static void pvr2_update_display(struct fb_info *info);static void pvr2_init_display(struct fb_info *info);static void pvr2_do_blank(void);static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id);static int pvr2_init_cable(void);static int pvr2_get_param(const struct pvr2_params *p, const char *s,                            int val, int size);#ifdef CONFIG_SH_DMAstatic ssize_t pvr2fb_write(struct fb_info *info, const char *buf,			    size_t count, loff_t *ppos);#endifstatic struct fb_ops pvr2fb_ops = {	.owner		= THIS_MODULE,	.fb_setcolreg	= pvr2fb_setcolreg,	.fb_blank	= pvr2fb_blank,	.fb_check_var	= pvr2fb_check_var,	.fb_set_par	= pvr2fb_set_par,#ifdef CONFIG_SH_DMA	.fb_write	= pvr2fb_write,#endif	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,};static struct fb_videomode pvr2_modedb[] __devinitdata = {    /*     * Broadcast video modes (PAL and NTSC).  I'm unfamiliar with     * PAL-M and PAL-N, but from what I've read both modes parallel PAL and     * NTSC, so it shouldn't be a problem (I hope).     */    {	/* 640x480 @ 60Hz interlaced (NTSC) */	"ntsc_640x480i", 60, 640, 480, TV_CLK, 38, 33, 0, 18, 146, 26,	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP    }, {	/* 640x240 @ 60Hz (NTSC) */	/* XXX: Broken! Don't use... */	"ntsc_640x240", 60, 640, 240, TV_CLK, 38, 33, 0, 0, 146, 22,	FB_SYNC_BROADCAST, FB_VMODE_YWRAP    }, {	/* 640x480 @ 60hz (VGA) */	"vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26,	0, FB_VMODE_YWRAP    },};#define NUM_TOTAL_MODES  ARRAY_SIZE(pvr2_modedb)#define DEFMODE_NTSC	0#define DEFMODE_PAL	0#define DEFMODE_VGA	2static int defmode = DEFMODE_NTSC;static char *mode_option __devinitdata = NULL;static inline void pvr2fb_set_pal_type(unsigned int type){	struct pvr2fb_par *par = (struct pvr2fb_par *)fb_info->par;	fb_writel(type, par->mmio_base + 0x108);}static inline void pvr2fb_set_pal_entry(struct pvr2fb_par *par,					unsigned int regno,					unsigned int val){	fb_writel(val, par->mmio_base + 0x1000 + (4 * regno));}static int pvr2fb_blank(int blank, struct fb_info *info){	do_blank = blank ? blank : -1;	return 0;}static inline unsigned long get_line_length(int xres_virtual, int bpp){	return (unsigned long)((((xres_virtual*bpp)+31)&~31) >> 3);}static void set_color_bitfields(struct fb_var_screeninfo *var){	switch (var->bits_per_pixel) {	    case 16:        /* RGB 565 */		pvr2fb_set_pal_type(PAL_RGB565);		var->red.offset = 11;    var->red.length = 5;		var->green.offset = 5;   var->green.length = 6;		var->blue.offset = 0;    var->blue.length = 5;		var->transp.offset = 0;  var->transp.length = 0;		break;	    case 24:        /* RGB 888 */		var->red.offset = 16;    var->red.length = 8;		var->green.offset = 8;   var->green.length = 8;		var->blue.offset = 0;    var->blue.length = 8;		var->transp.offset = 0;  var->transp.length = 0;		break;	    case 32:        /* ARGB 8888 */		pvr2fb_set_pal_type(PAL_ARGB8888);		var->red.offset = 16;    var->red.length = 8;		var->green.offset = 8;   var->green.length = 8;		var->blue.offset = 0;    var->blue.length = 8;		var->transp.offset = 24; var->transp.length = 8;		break;	}}static int pvr2fb_setcolreg(unsigned int regno, unsigned int red,			    unsigned int green, unsigned int blue,                            unsigned int transp, struct fb_info *info){	struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;	unsigned int tmp;	if (regno > info->cmap.len)		return 1;	/*	 * We only support the hardware palette for 16 and 32bpp. It's also	 * expected that the palette format has been set by the time we get	 * here, so we don't waste time setting it again.	 */	switch (info->var.bits_per_pixel) {	    case 16: /* RGB 565 */		tmp =  (red   & 0xf800)       |		      ((green & 0xfc00) >> 5) |		      ((blue  & 0xf800) >> 11);		pvr2fb_set_pal_entry(par, regno, tmp);		break;	    case 24: /* RGB 888 */		red >>= 8; green >>= 8; blue >>= 8;		tmp = (red << 16) | (green << 8) | blue;		break;	    case 32: /* ARGB 8888 */		red >>= 8; green >>= 8; blue >>= 8;		tmp = (transp << 24) | (red << 16) | (green << 8) | blue;		pvr2fb_set_pal_entry(par, regno, tmp);		break;	    default:		pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel);		return 1;	}	if (regno < 16)		((u32*)(info->pseudo_palette))[regno] = tmp;	return 0;}static int pvr2fb_set_par(struct fb_info *info){	struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;	struct fb_var_screeninfo *var = &info->var;	unsigned long line_length;	unsigned int vtotal;	/*	 * XXX: It's possible that a user could use a VGA box, change the cable	 * type in hardware (i.e. switch from VGA<->composite), then change	 * modes (i.e. switching to another VT).  If that happens we should	 * automagically change the output format to cope, but currently I	 * don't have a VGA box to make sure this works properly.	 */	cable_type = pvr2_init_cable();	if (cable_type == CT_VGA && video_output != VO_VGA)		video_output = VO_VGA;	var->vmode &= FB_VMODE_MASK;	if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA)		par->is_interlaced = 1;	/*	 * XXX: Need to be more creative with this (i.e. allow doublecan for	 * PAL/NTSC output).	 */	if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA)

⌨️ 快捷键说明

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