📄 gbefb.c
字号:
/* * SGI GBE frame buffer driver * * Copyright (C) 1999 Silicon Graphics, Inc. - Jeffrey Newquist * Copyright (C) 2002 Vivien Chappelier <vivien.chappelier@linux-mips.org> * * 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/delay.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <linux/errno.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/module.h>#ifdef CONFIG_X86#include <asm/mtrr.h>#endif#ifdef CONFIG_MIPS#include <asm/addrspace.h>#endif#include <asm/byteorder.h>#include <asm/io.h>#include <asm/tlbflush.h>#include <video/gbe.h>static struct sgi_gbe *gbe;struct gbefb_par { struct fb_var_screeninfo var; struct gbe_timing_info timing; int valid;};#ifdef CONFIG_SGI_IP32#define GBE_BASE 0x16000000 /* SGI O2 */#endif#ifdef CONFIG_X86_VISWS#define GBE_BASE 0xd0000000 /* SGI Visual Workstation */#endif/* macro for fastest write-though access to the framebuffer */#ifdef CONFIG_MIPS#ifdef CONFIG_CPU_R10000#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_UNCACHED_ACCELERATED)#else#define pgprot_fb(_prot) (((_prot) & (~_CACHE_MASK)) | _CACHE_CACHABLE_NO_WA)#endif#endif#ifdef CONFIG_X86#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)#endif/* * RAM we reserve for the frame buffer. This defines the maximum screen * size */#if CONFIG_FB_GBE_MEM > 8#error GBE Framebuffer cannot use more than 8MB of memory#endif#define TILE_SHIFT 16#define TILE_SIZE (1 << TILE_SHIFT)#define TILE_MASK (TILE_SIZE - 1)static unsigned int gbe_mem_size = CONFIG_FB_GBE_MEM * 1024*1024;static void *gbe_mem;static dma_addr_t gbe_dma_addr;unsigned long gbe_mem_phys;static struct { uint16_t *cpu; dma_addr_t dma;} gbe_tiles;static int gbe_revision;static struct fb_info fb_info;static int ypan, ywrap;static uint32_t pseudo_palette[256];static char *mode_option __initdata = NULL;/* default CRT mode */static struct fb_var_screeninfo default_var_CRT __initdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ .xres = 640, .yres = 480, .xres_virtual = 640, .yres_virtual = 480, .xoffset = 0, .yoffset = 0, .bits_per_pixel = 8, .grayscale = 0, .red = { 0, 8, 0 }, .green = { 0, 8, 0 }, .blue = { 0, 8, 0 }, .transp = { 0, 0, 0 }, .nonstd = 0, .activate = 0, .height = -1, .width = -1, .accel_flags = 0, .pixclock = 39722, /* picoseconds */ .left_margin = 48, .right_margin = 16, .upper_margin = 33, .lower_margin = 10, .hsync_len = 96, .vsync_len = 2, .sync = 0, .vmode = FB_VMODE_NONINTERLACED,};/* default LCD mode */static struct fb_var_screeninfo default_var_LCD __initdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, .xres_virtual = 1600, .yres_virtual = 1024, .xoffset = 0, .yoffset = 0, .bits_per_pixel = 8, .grayscale = 0, .red = { 0, 8, 0 }, .green = { 0, 8, 0 }, .blue = { 0, 8, 0 }, .transp = { 0, 0, 0 }, .nonstd = 0, .activate = 0, .height = -1, .width = -1, .accel_flags = 0, .pixclock = 9353, .left_margin = 20, .right_margin = 30, .upper_margin = 37, .lower_margin = 3, .hsync_len = 20, .vsync_len = 3, .sync = 0, .vmode = FB_VMODE_NONINTERLACED};/* default modedb mode *//* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */static struct fb_videomode default_mode_CRT __initdata = { .refresh = 60, .xres = 640, .yres = 480, .pixclock = 39722, .left_margin = 48, .right_margin = 16, .upper_margin = 33, .lower_margin = 10, .hsync_len = 96, .vsync_len = 2, .sync = 0, .vmode = FB_VMODE_NONINTERLACED,};/* 1600x1024 SGI flatpanel 1600sw */static struct fb_videomode default_mode_LCD __initdata = { /* 1600x1024, 8 bpp */ .xres = 1600, .yres = 1024, .pixclock = 9353, .left_margin = 20, .right_margin = 30, .upper_margin = 37, .lower_margin = 3, .hsync_len = 20, .vsync_len = 3, .vmode = FB_VMODE_NONINTERLACED,};struct fb_videomode *default_mode = &default_mode_CRT;struct fb_var_screeninfo *default_var = &default_var_CRT;static int flat_panel_enabled = 0;static struct gbefb_par par_current;static void gbe_reset(void){ /* Turn on dotclock PLL */ gbe->ctrlstat = 0x300aa000;}/* * Function: gbe_turn_off * Parameters: (None) * Description: This should turn off the monitor and gbe. This is used * when switching between the serial console and the graphics * console. */void gbe_turn_off(void){ int i; unsigned int val, x, y, vpixen_off; /* check if pixel counter is on */ val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 1) return; /* turn off DMA */ val = gbe->ovr_control; SET_GBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, val, 0); gbe->ovr_control = val; udelay(1000); val = gbe->frm_control; SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 0); gbe->frm_control = val; udelay(1000); val = gbe->did_control; SET_GBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, val, 0); gbe->did_control = val; udelay(1000); /* We have to wait through two vertical retrace periods before * the pixel DMA is turned off for sure. */ for (i = 0; i < 10000; i++) { val = gbe->frm_inhwctrl; if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val)) { udelay(10); } else { val = gbe->ovr_inhwctrl; if (GET_GBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, val)) { udelay(10); } else { val = gbe->did_inhwctrl; if (GET_GBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, val)) { udelay(10); } else break; } } } if (i == 10000) printk(KERN_ERR "gbefb: turn off DMA timed out\n"); /* wait for vpixen_off */ val = gbe->vt_vpixen; vpixen_off = GET_GBE_FIELD(VT_VPIXEN, VPIXEN_OFF, val); for (i = 0; i < 100000; i++) { val = gbe->vt_xy; x = GET_GBE_FIELD(VT_XY, X, val); y = GET_GBE_FIELD(VT_XY, Y, val); if (y < vpixen_off) break; udelay(1); } if (i == 100000) printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n"); for (i = 0; i < 10000; i++) { val = gbe->vt_xy; x = GET_GBE_FIELD(VT_XY, X, val); y = GET_GBE_FIELD(VT_XY, Y, val); if (y > vpixen_off) break; udelay(1); } if (i == 10000) printk(KERN_ERR "gbefb: wait for vpixen_off timed out\n"); /* turn off pixel counter */ val = 0; SET_GBE_FIELD(VT_XY, FREEZE, val, 1); gbe->vt_xy = val; udelay(10000); for (i = 0; i < 10000; i++) { val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val) != 1) udelay(10); else break; } if (i == 10000) printk(KERN_ERR "gbefb: turn off pixel clock timed out\n"); /* turn off dot clock */ val = gbe->dotclock; SET_GBE_FIELD(DOTCLK, RUN, val, 0); gbe->dotclock = val; udelay(10000); for (i = 0; i < 10000; i++) { val = gbe->dotclock; if (GET_GBE_FIELD(DOTCLK, RUN, val)) udelay(10); else break; } if (i == 10000) printk(KERN_ERR "gbefb: turn off dotclock timed out\n"); /* reset the frame DMA FIFO */ val = gbe->frm_size_tile; SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 1); gbe->frm_size_tile = val; SET_GBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, val, 0); gbe->frm_size_tile = val;}static void gbe_turn_on(void){ unsigned int val, i; /* * Check if pixel counter is off, for unknown reason this * code hangs Visual Workstations */ if (gbe_revision < 2) { val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val) == 0) return; } /* turn on dot clock */ val = gbe->dotclock; SET_GBE_FIELD(DOTCLK, RUN, val, 1); gbe->dotclock = val; udelay(10000); for (i = 0; i < 10000; i++) { val = gbe->dotclock; if (GET_GBE_FIELD(DOTCLK, RUN, val) != 1) udelay(10); else break; } if (i == 10000) printk(KERN_ERR "gbefb: turn on dotclock timed out\n"); /* turn on pixel counter */ val = 0; SET_GBE_FIELD(VT_XY, FREEZE, val, 0); gbe->vt_xy = val; udelay(10000); for (i = 0; i < 10000; i++) { val = gbe->vt_xy; if (GET_GBE_FIELD(VT_XY, FREEZE, val)) udelay(10); else break; } if (i == 10000) printk(KERN_ERR "gbefb: turn on pixel clock timed out\n"); /* turn on DMA */ val = gbe->frm_control; SET_GBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, val, 1); gbe->frm_control = val; udelay(1000); for (i = 0; i < 10000; i++) { val = gbe->frm_inhwctrl; if (GET_GBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, val) != 1) udelay(10); else break; } if (i == 10000) printk(KERN_ERR "gbefb: turn on DMA timed out\n");}/* * Blank the display. */static int gbefb_blank(int blank, struct fb_info *info){ /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ switch (blank) { case 0: /* unblank */ gbe_turn_on(); break; case 1: /* blank */ gbe_turn_off(); break; default: /* Nothing */ break; } return 0;}/* * Setup flatpanel related registers. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -