📄 pvr2fb.c
字号:
/* 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 Paul Mundt <lethal@chaoticdreams.org> * * This file is part of the LinuxDC project (linuxdc.sourceforge.net). * *//* * 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 it's 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. */#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/config.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/console.h>#ifdef CONFIG_SH_DREAMCAST#include <asm/io.h>#include <asm/machvec.h>#include <asm/dc_sysasic.h>#endif#ifdef CONFIG_MTRR #include <asm/mtrr.h>#endif#include <video/fbcon.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>#include <video/fbcon-cfb32.h>#ifdef CONFIG_FB_PVR2_DEBUG# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)#else# define DPRINTK(fmt, args...)#endif/* 2D video registers */#define DISP_BASE 0xa05f8000#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)/* 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 262enum { CT_VGA, CT_NONE, CT_RGB, CT_COMPOSITE };enum { VO_PAL, VO_NTSC, VO_VGA };struct pvr2_params { u_short val; char *name; };static struct pvr2_params cables[] __initdata = { { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" },};static struct pvr2_params outputs[] __initdata = { { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" },};/* * This describes the current video mode */static struct pvr2fb_par { int xres; int yres; int vxres; int vyres; int xoffset; int yoffset; u_short bpp; u_long pixclock; u_short hsync_total; /* Clocks/line */ u_short vsync_total; /* Lines/field */ u_short borderstart_h; u_short borderstop_h; u_short borderstart_v; u_short borderstop_v; u_short diwstart_h; /* Horizontal offset of the display field */ u_short diwstart_v; /* Vertical offset of the display field, for interlaced modes, this is the long field */ u_long disp_start; /* Address of image within VRAM */ u_long next_line; /* Modulo for next line */ u_char is_interlaced; /* Is the display interlaced? */ u_char is_doublescan; /* Are scanlines output twice? (doublescan) */ u_char is_lowres; /* Is horizontal pixel-doubling enabled? */ u_long bordercolor; /* RGB888 format border color */ u_long vmode; } currentpar;static int currcon = 0;static int currbpp;static struct display disp;static struct fb_info fb_info;static int pvr2fb_inverse = 0;static struct { u_short red, green, blue, alpha; } palette[256];static union {#ifdef FBCON_HAS_CFB16 u16 cfb16[16];#endif#ifdef FBCON_HAS_CFB24 u32 cfb24[16];#endif#ifdef FBCON_HAS_CFB32 u32 cfb32[16];#endif} fbcon_cmap;static char pvr2fb_name[16] = "NEC PowerVR2";#define VIDEOMEMSIZE (8*1024*1024)static u_long videomemory = 0xa5000000, videomemorysize = VIDEOMEMSIZE;static int cable_type = -1;static int video_output = -1;#ifdef CONFIG_MTRRstatic int enable_mtrr = 1;static int mtrr_handle;#endif/* * We do all updating, blanking, etc. during the vertical retrace period */static u_short do_vmode_full = 0; /* Change the video mode */static u_short do_vmode_pan = 0; /* Update the video mode */static short do_blank = 0; /* (Un)Blank the screen */static u_short is_blanked = 0; /* Is the screen blanked? *//* Interface used by the world */int pvr2fb_setup(char*);static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); /* * Interface to the low level console driver */static int pvr2fbcon_switch(int con, struct fb_info *info);static int pvr2fbcon_updatevar(int con, struct fb_info *info);static void pvr2fbcon_blank(int blank, struct fb_info *info); /* * Internal/hardware-specific routines */static void do_install_cmap(int con, struct fb_info *info);static u_long get_line_length(int xres_virtual, int bpp);static void set_color_bitfields(struct fb_var_screeninfo *var);static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *info);static int pvr2_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info);static int pvr2_encode_fix(struct fb_fix_screeninfo *fix, struct pvr2fb_par *par);static int pvr2_decode_var(struct fb_var_screeninfo *var, struct pvr2fb_par *par);static int pvr2_encode_var(struct fb_var_screeninfo *var, struct pvr2fb_par *par);static void pvr2_get_par(struct pvr2fb_par *par);static void pvr2_set_var(struct fb_var_screeninfo *var);static void pvr2_pan_var(struct fb_var_screeninfo *var);static int pvr2_update_par(void);static void pvr2_update_display(void);static void pvr2_init_display(void);static void pvr2_do_blank(void);static void pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);static int pvr2_init_cable(void);static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val, int size);static struct fb_ops pvr2fb_ops = { owner: THIS_MODULE, fb_get_fix: pvr2fb_get_fix, fb_get_var: pvr2fb_get_var, fb_set_var: pvr2fb_set_var, fb_get_cmap: pvr2fb_get_cmap, fb_set_cmap: pvr2fb_set_cmap, fb_pan_display: pvr2fb_pan_display,};static struct fb_videomode pvr2_modedb[] __initdata = { /* * 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 __initdata = NULL;/* Get the fixed part of the display */static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ struct pvr2fb_par par; if (con == -1) pvr2_get_par(&par); else { int err; if ((err = pvr2_decode_var(&fb_display[con].var, &par))) return err; } return pvr2_encode_fix(fix, &par);}/* Get the user-defined part of the display */static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ int err = 0; if (con == -1) { struct pvr2fb_par par; pvr2_get_par(&par); err = pvr2_encode_var(var, &par); } else *var = fb_display[con].var; return err;}/* Set the user-defined part of the display */static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ int err, activate = var->activate; int oldxres, oldyres, oldvxres, oldvyres, oldbpp; struct pvr2fb_par par; struct display *display; if (con >= 0) display = &fb_display[con]; else display = &disp; /* used during initialization */ /* * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! * as FB_VMODE_SMOOTH_XPAN is only used internally */ if (var->vmode & FB_VMODE_CONUPDATE) { var->vmode |= FB_VMODE_YWRAP; var->xoffset = display->var.xoffset; var->yoffset = display->var.yoffset; } if ((err = pvr2_decode_var(var, &par))) return err; pvr2_encode_var(var, &par); /* Do memory check and bitfield set here?? */ if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { oldxres = display->var.xres; oldyres = display->var.yres; oldvxres = display->var.xres_virtual; oldvyres = display->var.yres_virtual; oldbpp = display->var.bits_per_pixel; display->var = *var; if (oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || oldbpp != var->bits_per_pixel) { struct fb_fix_screeninfo fix; pvr2_encode_fix(&fix, &par); display->screen_base = (char *)fix.smem_start; display->scrollmode = SCROLL_YREDRAW; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; display->ypanstep = fix.ypanstep; display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->can_soft_blank = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -