📄 savagefb_driver.c
字号:
/* * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver * * Copyright (c) 2001-2002 Denis Oliver Kropp <dok@directfb.org> * Sven Neumann <neo@directfb.org> * * * Card specific code is based on XFree86's savage driver. * Framebuffer framework code is based on code of cyber2000fb and tdfxfb. * * 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. * * 0.4.0 (neo) * - hardware accelerated clear and move * * 0.3.2 (dok) * - wait for vertical retrace before writing to cr67 * at the beginning of savagefb_set_par * - use synchronization registers cr23 and cr26 * * 0.3.1 (dok) * - reset 3D engine * - don't return alpha bits for 32bit format * * 0.3.0 (dok) * - added WaitIdle functions for all Savage types * - do WaitIdle before mode switching * - code cleanup * * 0.2.0 (dok) * - first working version * * * TODO * - clock validations in decode_var * * BUGS * - white margin on bootup * */#include <linux/config.h>#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/fb.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/console.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#include "savagefb.h"#define SAVAGEFB_VERSION "0.4.0_2.6"/* --------------------------------------------------------------------- */static char *mode_option __initdata = NULL;#ifdef MODULEMODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@directfb.org>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");#endif/* --------------------------------------------------------------------- */static void vgaHWSeqReset (struct savagefb_par *par, int start){ if (start) VGAwSEQ (0x00, 0x01, par); /* Synchronous Reset */ else VGAwSEQ (0x00, 0x03, par); /* End Reset */}static void vgaHWProtect (struct savagefb_par *par, int on){ unsigned char tmp; if (on) { /* * Turn off screen and disable sequencer. */ tmp = VGArSEQ (0x01, par); vgaHWSeqReset (par, 1); /* start synchronous reset */ VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */ VGAenablePalette(par); } else { /* * Reenable sequencer, then turn on screen. */ tmp = VGArSEQ (0x01, par); VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */ vgaHWSeqReset (par, 0); /* clear synchronous reset */ VGAdisablePalette(par); }}static void vgaHWRestore (struct savagefb_par *par){ int i; VGAwMISC (par->MiscOutReg, par); for (i = 1; i < 5; i++) VGAwSEQ (i, par->Sequencer[i], par); /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */ VGAwCR (17, par->CRTC[17] & ~0x80, par); for (i = 0; i < 25; i++) VGAwCR (i, par->CRTC[i], par); for (i = 0; i < 9; i++) VGAwGR (i, par->Graphics[i], par); VGAenablePalette(par); for (i = 0; i < 21; i++) VGAwATTR (i, par->Attribute[i], par); VGAdisablePalette(par);}static void vgaHWInit (struct fb_var_screeninfo *var, struct savagefb_par *par, struct xtimings *timings){ par->MiscOutReg = 0x23; if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) par->MiscOutReg |= 0x40; if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) par->MiscOutReg |= 0x80; /* * Time Sequencer */ par->Sequencer[0x00] = 0x00; par->Sequencer[0x01] = 0x01; par->Sequencer[0x02] = 0x0F; par->Sequencer[0x03] = 0x00; /* Font select */ par->Sequencer[0x04] = 0x0E; /* Misc */ /* * CRTC Controller */ par->CRTC[0x00] = (timings->HTotal >> 3) - 5; par->CRTC[0x01] = (timings->HDisplay >> 3) - 1; par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; par->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80; par->CRTC[0x04] = (timings->HSyncStart >> 3); par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | (((timings->HSyncEnd >> 3)) & 0x1f); par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | (((timings->VDisplay - 1) & 0x100) >> 7) | ((timings->VSyncStart & 0x100) >> 6) | (((timings->VSyncStart - 1) & 0x100) >> 5) | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4) | (((timings->VDisplay - 1) & 0x200) >> 3) | ((timings->VSyncStart & 0x200) >> 2); par->CRTC[0x08] = 0x00; par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; if (timings->dblscan) par->CRTC[0x09] |= 0x80; par->CRTC[0x0a] = 0x00; par->CRTC[0x0b] = 0x00; par->CRTC[0x0c] = 0x00; par->CRTC[0x0d] = 0x00; par->CRTC[0x0e] = 0x00; par->CRTC[0x0f] = 0x00; par->CRTC[0x10] = timings->VSyncStart & 0xff; par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; par->CRTC[0x13] = var->xres_virtual >> 4; par->CRTC[0x14] = 0x00; par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; par->CRTC[0x17] = 0xc3; par->CRTC[0x18] = 0xff; /* * are these unnecessary? * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO); * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO); */ /* * Graphics Display Controller */ par->Graphics[0x00] = 0x00; par->Graphics[0x01] = 0x00; par->Graphics[0x02] = 0x00; par->Graphics[0x03] = 0x00; par->Graphics[0x04] = 0x00; par->Graphics[0x05] = 0x40; par->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */ par->Graphics[0x07] = 0x0F; par->Graphics[0x08] = 0xFF; par->Attribute[0x00] = 0x00; /* standard colormap translation */ par->Attribute[0x01] = 0x01; par->Attribute[0x02] = 0x02; par->Attribute[0x03] = 0x03; par->Attribute[0x04] = 0x04; par->Attribute[0x05] = 0x05; par->Attribute[0x06] = 0x06; par->Attribute[0x07] = 0x07; par->Attribute[0x08] = 0x08; par->Attribute[0x09] = 0x09; par->Attribute[0x0a] = 0x0A; par->Attribute[0x0b] = 0x0B; par->Attribute[0x0c] = 0x0C; par->Attribute[0x0d] = 0x0D; par->Attribute[0x0e] = 0x0E; par->Attribute[0x0f] = 0x0F; par->Attribute[0x10] = 0x41; par->Attribute[0x11] = 0xFF; par->Attribute[0x12] = 0x0F; par->Attribute[0x13] = 0x00; par->Attribute[0x14] = 0x00;}/* -------------------- Hardware specific routines ------------------------- *//* * Hardware Acceleration for SavageFB *//* Wait for fifo space */static voidsavage3D_waitfifo(struct savagefb_par *par, int space){ int slots = MAXFIFO - space; while ((savage_in32(0x48C00, par) & 0x0000ffff) > slots);}static voidsavage4_waitfifo(struct savagefb_par *par, int space){ int slots = MAXFIFO - space; while ((savage_in32(0x48C60, par) & 0x001fffff) > slots);}static voidsavage2000_waitfifo(struct savagefb_par *par, int space){ int slots = MAXFIFO - space; while ((savage_in32(0x48C60, par) & 0x0000ffff) > slots);}/* Wait for idle accelerator */static voidsavage3D_waitidle(struct savagefb_par *par){ while ((savage_in32(0x48C00, par) & 0x0008ffff) != 0x80000);}static voidsavage4_waitidle(struct savagefb_par *par){ while ((savage_in32(0x48C60, par) & 0x00a00000) != 0x00a00000);}static voidsavage2000_waitidle(struct savagefb_par *par){ while ((savage_in32(0x48C60, par) & 0x009fffff));}static voidSavageSetup2DEngine (struct savagefb_par *par){ unsigned long GlobalBitmapDescriptor; GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth); BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth); switch(par->chip) { case S3_SAVAGE3D: case S3_SAVAGE_MX: /* Disable BCI */ savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par); /* Setup BCI command overflow buffer */ savage_out32(0x48C14, (par->cob_offset >> 11) | (par->cob_index << 29), par); /* Program shadow status update. */ savage_out32(0x48C10, 0x78207220, par); savage_out32(0x48C0C, 0, par); /* Enable BCI and command overflow buffer */ savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par); break; case S3_SAVAGE4: case S3_PROSAVAGE: case S3_SUPERSAVAGE: /* Disable BCI */ savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par); /* Program shadow status update */ savage_out32(0x48C10, 0x00700040, par); savage_out32(0x48C0C, 0, par); /* Enable BCI without the COB */ savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x08, par); break; case S3_SAVAGE2000: /* Disable BCI */ savage_out32(0x48C18, 0, par); /* Setup BCI command overflow buffer */ savage_out32(0x48C18, (par->cob_offset >> 7) | (par->cob_index), par); /* Disable shadow status update */ savage_out32(0x48A30, 0, par); /* Enable BCI and command overflow buffer */ savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x00280000, par); break; default: break; } /* Turn on 16-bit register access. */ vga_out8(0x3d4, 0x31, par); vga_out8(0x3d5, 0x0c, par); /* Set stride to use GBD. */ vga_out8 (0x3d4, 0x50, par); vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par); /* Enable 2D engine. */ vga_out8 (0x3d4, 0x40, par); vga_out8 (0x3d5, 0x01, par); savage_out32 (MONO_PAT_0, ~0, par); savage_out32 (MONO_PAT_1, ~0, par); /* Setup plane masks */ savage_out32 (0x8128, ~0, par); /* enable all write planes */ savage_out32 (0x812C, ~0, par); /* enable all read planes */ savage_out16 (0x8134, 0x27, par); savage_out16 (0x8136, 0x07, par); /* Now set the GBD */ par->bci_ptr = 0; par->SavageWaitFifo (par, 4); BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 ); BCI_SEND( 0 ); BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 ); BCI_SEND( GlobalBitmapDescriptor );}static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, int min_n2, int max_n2, long freq_min, long freq_max, unsigned int *mdiv, unsigned int *ndiv, unsigned int *r){ long diff, best_diff; unsigned int m; unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; if (freq < freq_min / (1 << max_n2)) { printk (KERN_ERR "invalid frequency %ld Khz\n", freq); freq = freq_min / (1 << max_n2); } if (freq > freq_max / (1 << min_n2)) { printk (KERN_ERR "invalid frequency %ld Khz\n", freq); freq = freq_max / (1 << min_n2); } /* work out suitable timings */ best_diff = freq; for (n2=min_n2; n2<=max_n2; n2++) { for (n1=min_n1+2; n1<=max_n1+2; n1++) { m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) / BASE_FREQ; if (m < min_m+2 || m > 127+2) continue; if ((m * BASE_FREQ >= freq_min * n1) && (m * BASE_FREQ <= freq_max * n1)) { diff = freq * (1 << n2) * n1 - BASE_FREQ * m; if (diff < 0) diff = -diff; if (diff < best_diff) { best_diff = diff; best_m = m; best_n1 = n1; best_n2 = n2; } } } } *ndiv = best_n1 - 2; *r = best_n2; *mdiv = best_m - 2;}static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, int min_n2, int max_n2, long freq_min, long freq_max, unsigned char *mdiv, unsigned char *ndiv){ long diff, best_diff; unsigned int m; unsigned char n1, n2; unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2; best_diff = freq; for (n2 = min_n2; n2 <= max_n2; n2++) { for (n1 = min_n1+2; n1 <= max_n1+2; n1++) { m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) / BASE_FREQ; if (m < min_m + 2 || m > 127+2) continue; if((m * BASE_FREQ >= freq_min * n1) && (m * BASE_FREQ <= freq_max * n1)) { diff = freq * (1 << n2) * n1 - BASE_FREQ * m; if(diff < 0) diff = -diff; if(diff < best_diff) { best_diff = diff; best_m = m; best_n1 = n1; best_n2 = n2; } } } } if(max_n1 == 63) *ndiv = (best_n1 - 2) | (best_n2 << 6); else *ndiv = (best_n1 - 2) | (best_n2 << 5); *mdiv = best_m - 2; return 0;}#ifdef SAVAGEFB_DEBUG/* This function is used to debug, it prints out the contents of s3 regs */static void SavagePrintRegs(void){ unsigned char i; int vgaCRIndex = 0x3d4; int vgaCRReg = 0x3d5; printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " "xF" ); for( i = 0; i < 0x70; i++ ) { if( !(i % 16) ) printk(KERN_DEBUG "\nSR%xx ", i >> 4 ); vga_out8( 0x3c4, i, par); printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) ); } printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " "xD xE xF" ); for( i = 0; i < 0xB7; i++ ) { if( !(i % 16) ) printk(KERN_DEBUG "\nCR%xx ", i >> 4 ); vga_out8( vgaCRIndex, i, par); printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) ); } printk(KERN_DEBUG "\n\n");}#endif/* --------------------------------------------------------------------- */static void savage_get_default_par(struct savagefb_par *par){ unsigned char cr3a, cr53, cr66; vga_out16 (0x3d4, 0x4838, par); vga_out16 (0x3d4, 0xa039, par); vga_out16 (0x3c4, 0x0608, par); vga_out8 (0x3d4, 0x66, par); cr66 = vga_in8 (0x3d5, par); vga_out8 (0x3d5, cr66 | 0x80, par); vga_out8 (0x3d4, 0x3a, par); cr3a = vga_in8 (0x3d5, par); vga_out8 (0x3d5, cr3a | 0x80, par); vga_out8 (0x3d4, 0x53, par); cr53 = vga_in8 (0x3d5, par); vga_out8 (0x3d5, cr53 & 0x7f, par); vga_out8 (0x3d4, 0x66, par); vga_out8 (0x3d5, cr66, par); vga_out8 (0x3d4, 0x3a, par); vga_out8 (0x3d5, cr3a, par); vga_out8 (0x3d4, 0x66, par); vga_out8 (0x3d5, cr66, par); vga_out8 (0x3d4, 0x3a, par); vga_out8 (0x3d5, cr3a, par); /* unlock extended seq regs */ vga_out8 (0x3c4, 0x08, par); par->SR08 = vga_in8 (0x3c5, par); vga_out8 (0x3c5, 0x06, par); /* now save all the extended regs we need */ vga_out8 (0x3d4, 0x31, par); par->CR31 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x32, par); par->CR32 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x34, par); par->CR34 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x36, par); par->CR36 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x3a, par); par->CR3A = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x40, par); par->CR40 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x42, par); par->CR42 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x45, par); par->CR45 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x50, par); par->CR50 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x51, par); par->CR51 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x53, par); par->CR53 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x58, par); par->CR58 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x60, par); par->CR60 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x66, par); par->CR66 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x67, par); par->CR67 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x68, par); par->CR68 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x69, par); par->CR69 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x6f, par); par->CR6F = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x33, par); par->CR33 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x86, par); par->CR86 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x88, par); par->CR88 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x90, par); par->CR90 = vga_in8 (0x3d5, par); vga_out8 (0x3d4, 0x91, par);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -