0,0 → 1,970 |
/* |
NeoMagic chipset driver |
Written by Shigehiro Nomura <s.nomura@mba.nifty.ne.jp> |
|
Does not support external screen. |
|
Remarks: |
Problem: The modes whose width is longer than the width of LCD panel |
are also reported by vgatest, but not displaying properly. |
--> Please do not select such modes :-) |
|
Note: |
When use Toshiba Libretto100,110, please define "LIBRETTO100" at |
line 19 in src/neo.c |
And add the following lines to libvga.config |
------------------------------------------------------------------- |
HorizSync 31.5 70 |
VertRefresh 50 100 |
Modeline "800x480" 50 800 856 976 1024 480 483 490 504 +hsync |
+vsync |
newmode 800 480 256 800 1 |
newmode 800 480 32768 1600 2 |
newmode 800 480 65536 1600 2 |
newmode 800 480 16777216 2400 3 |
------------------------------------------------------------------- |
|
*/ |
#include <stdlib.h> |
#include <stdio.h> |
#include <string.h> |
#include <unistd.h> |
#include "vga.h" |
#include "libvga.h" |
#include "driver.h" |
#include "timing.h" |
#include "vgaregs.h" |
#include "interface.h" |
#include "vgapci.h" |
|
#undef NEO_PCI_BURST |
#undef LIBRETTO100 /* Define if Toshiba Libretto100/110 */ |
|
#define VENDOR_ID 0x10c8 /* NeoMagic */ |
#define PCI_CHIP_NM2070 0x0001 |
#define PCI_CHIP_NM2090 0x0002 |
#define PCI_CHIP_NM2093 0x0003 |
#define PCI_CHIP_NM2097 0x0083 |
#define PCI_CHIP_NM2160 0x0004 |
#define PCI_CHIP_NM2200 0x0005 |
|
#define GRAX 0x3ce |
|
#define NEO_EXT_CR_MAX 0x85 |
#define NEO_EXT_GR_MAX 0xC7 |
|
#define NEOREG_SAVE(i) (VGA_TOTAL_REGS+i) |
#define GeneralLockReg NEOREG_SAVE(0) /* GRAX(0x0a) */ |
#define ExtCRTDispAddr NEOREG_SAVE(1) /* GRAX(0x0e) */ |
#define ExtCRTOffset NEOREG_SAVE(2) /* GRAX(0x0f) */ |
#define SysIfaceCntl1 NEOREG_SAVE(3) /* GRAX(0x10) */ |
#define SysIfaceCntl2 NEOREG_SAVE(4) /* GRAX(0x11) */ |
#define SingleAddrPage NEOREG_SAVE(5) /* GRAX(0x15) */ |
#define DualAddrPage NEOREG_SAVE(6) /* GRAX(0x16) */ |
#define PanelDispCntlReg1 NEOREG_SAVE(7) /* GRAX(0x20) */ |
#define PanelDispCntlReg2 NEOREG_SAVE(8) /* GRAX(0x25) */ |
#define PanelDispCntlReg3 NEOREG_SAVE(9) /* GRAX(0x30) */ |
#define PanelVertCenterReg1 NEOREG_SAVE(10) /* GRAX(0x28) */ |
#define PanelVertCenterReg2 NEOREG_SAVE(11) /* GRAX(0x29) */ |
#define PanelVertCenterReg3 NEOREG_SAVE(12) /* GRAX(0x2a) */ |
#define PanelVertCenterReg4 NEOREG_SAVE(13) /* GRAX(0x32) */ |
#define PanelVertCenterReg5 NEOREG_SAVE(14) /* GRAX(0x37) */ |
#define PanelHorizCenterReg1 NEOREG_SAVE(15) /* GRAX(0x33) */ |
#define PanelHorizCenterReg2 NEOREG_SAVE(16) /* GRAX(0x34) */ |
#define PanelHorizCenterReg3 NEOREG_SAVE(17) /* GRAX(0x35) */ |
#define PanelHorizCenterReg4 NEOREG_SAVE(18) /* GRAX(0x36) */ |
#define PanelHorizCenterReg5 NEOREG_SAVE(19) /* GRAX(0x38) */ |
#define ExtColorModeSelect NEOREG_SAVE(20) /* GRAX(0x90) */ |
#define VCLK3NumeratorLow NEOREG_SAVE(21) /* GRAX(0x9b) */ |
#define VCLK3NumeratorHigh NEOREG_SAVE(22) /* GRAX(0x8f) */ |
#define VCLK3Denominator NEOREG_SAVE(23) /* GRAX(0x9f) */ |
#define VerticalExt NEOREG_SAVE(24) |
#define EXT_SAVED NEOREG_SAVE(25) /* EXT regs. saved ? */ |
#define EXTCR NEOREG_SAVE(26) /* CR(0x00..) */ |
#define EXTGR (EXTCR + NEO_EXT_CR_MAX + 1) /* GR(0x00..) */ |
#define DAC (EXTGR + NEO_EXT_GR_MAX + 1) /* DAC */ |
#define NEO_TOTAL_REGS (DAC + 768) |
|
#define DACDelay \ |
{ \ |
unsigned char temp = port_in(vgaIOBase + 0x0A); \ |
temp = port_in(vgaIOBase + 0x0A); \ |
} |
|
|
static int neo_init(int, int, int); |
static void neo_unlock(void); |
static void neo_lock(void); |
|
static int neo_memory; |
static int NeoChipset; |
static int NeoPanelWidth, NeoPanelHeight; |
static int neo_is_linear, neo_linear_base; |
static int vgaIOBase; |
|
static CardSpecs *cardspecs; |
|
static void neo_setpage(int page) |
{ |
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setpage: %d\n", page); |
#endif |
outb(GRAX, 0x11); |
outw(GRAX, ((port_in(GRAX+1) & 0xfc) << 8) | 0x11); |
outw(GRAX, (page << 10) | 0x15); /* set read/write bank */ |
} |
|
static void neo_setrdpage(int page) |
{ |
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setrdpage: %d\n", page); |
#endif |
outb(GRAX, 0x11); |
outw(GRAX, (((port_in(GRAX+1) & 0xfc) | 0x01) << 8) | 0x11); |
outw(GRAX, (page << 10) | 0x15); /* set read bank */ |
} |
|
static void neo_setwrpage(int page) |
{ |
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setwrpage: %d\n", page); |
#endif |
outb(GRAX, 0x11); |
outw(GRAX, (((port_in(GRAX+1) & 0xfc) | 0x01) << 8) | 0x11); |
outw(GRAX, (page << 10) | 0x16); /* set write bank */ |
} |
|
static int __svgalib_neo_inlinearmode(void) |
{ |
#ifdef DEBUG |
printk(KERN_DEBUG "neo_inlinearmode\n"); |
#endif |
return neo_is_linear; |
} |
|
/* Fill in chipset specific mode information */ |
|
static void neo_getmodeinfo(int mode, vga_modeinfo *modeinfo) |
{ |
#ifdef DEBUG |
printk(KERN_DEBUG "neo_getmodeinfo: %d\n", mode); |
#endif |
|
if(modeinfo->colors==16)return; |
|
modeinfo->maxpixels = neo_memory*1024/modeinfo->bytesperpixel; |
if (NeoChipset == PCI_CHIP_NM2200) |
modeinfo->maxlogicalwidth = 1280; |
else |
modeinfo->maxlogicalwidth = 1024; |
modeinfo->startaddressrange = neo_memory * 1024 - 1; |
modeinfo->haveblit = 0; |
modeinfo->flags |= HAVE_RWPAGE; |
|
#if 1 |
if (modeinfo->bytesperpixel >= 1) { |
if(neo_linear_base)modeinfo->flags |= CAPABLE_LINEAR; |
if (__svgalib_neo_inlinearmode()) |
modeinfo->flags |= IS_LINEAR | LINEAR_MODE; |
} |
#endif |
} |
|
/* Read and save chipset-specific registers */ |
|
static int neo_saveregs(unsigned char regs[]) |
{ |
int i; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_saveregs\n"); |
#endif |
neo_unlock(); |
outw(GRAX, 0x0015); /* bank#0 */ |
|
outb(GRAX, 0x0a); regs[GeneralLockReg] = port_in(GRAX + 1); |
outb(GRAX, 0x0e); regs[ExtCRTDispAddr] = port_in(GRAX + 1); |
outb(GRAX, 0x0f); regs[ExtCRTOffset] = port_in(GRAX + 1); |
outb(GRAX, 0x10); regs[SysIfaceCntl1] = port_in(GRAX + 1); |
outb(GRAX, 0x11); regs[SysIfaceCntl2] = port_in(GRAX + 1); |
outb(GRAX, 0x15); regs[SingleAddrPage] = port_in(GRAX + 1); |
outb(GRAX, 0x16); regs[DualAddrPage] = port_in(GRAX+1); |
outb(GRAX, 0x20); regs[PanelDispCntlReg1] = port_in(GRAX+1); |
outb(GRAX, 0x25); regs[PanelDispCntlReg2] = port_in(GRAX+1); |
outb(GRAX, 0x30); regs[PanelDispCntlReg3] = port_in(GRAX+1); |
outb(GRAX, 0x28); regs[PanelVertCenterReg1] = port_in(GRAX+1); |
outb(GRAX, 0x29); regs[PanelVertCenterReg2] = port_in(GRAX+1); |
outb(GRAX, 0x2a); regs[PanelVertCenterReg3] = port_in(GRAX+1); |
if (NeoChipset != PCI_CHIP_NM2070){ |
outb(GRAX, 0x32); regs[PanelVertCenterReg4] = port_in(GRAX+1); |
outb(GRAX, 0x33); regs[PanelHorizCenterReg1] = port_in(GRAX+1); |
outb(GRAX, 0x34); regs[PanelHorizCenterReg2] = port_in(GRAX+1); |
outb(GRAX, 0x35); regs[PanelHorizCenterReg3] = port_in(GRAX+1); |
} |
if (NeoChipset == PCI_CHIP_NM2160){ |
outb(GRAX, 0x36); regs[PanelHorizCenterReg4] = port_in(GRAX+1); |
} |
if (NeoChipset == PCI_CHIP_NM2200){ |
outb(GRAX, 0x36); regs[PanelHorizCenterReg4] = port_in(GRAX+1); |
outb(GRAX, 0x37); regs[PanelVertCenterReg5] = port_in(GRAX+1); |
outb(GRAX, 0x38); regs[PanelHorizCenterReg5] = port_in(GRAX+1); |
} |
outb(GRAX, 0x90); regs[ExtColorModeSelect] = port_in(GRAX+1); |
outb(GRAX, 0x9B); regs[VCLK3NumeratorLow] = port_in(GRAX+1); |
if (NeoChipset == PCI_CHIP_NM2200){ |
outb(GRAX, 0x8F); regs[VCLK3NumeratorHigh] = port_in(GRAX+1); |
} |
outb(GRAX, 0x9F); regs[VCLK3Denominator] = port_in(GRAX+1); |
|
regs[EXT_SAVED] = TRUE; |
outb(vgaIOBase + 4, 0x25); regs[EXTCR + 0x25] = port_in(vgaIOBase + 5); |
outb(vgaIOBase + 4, 0x2F); regs[EXTCR + 0x2F] = port_in(vgaIOBase + 5); |
for (i = 0x40; i <= 0x59; i++){ |
outb(vgaIOBase + 4, i); regs[EXTCR + i] = port_in(vgaIOBase + 5); |
} |
for (i = 0x60; i <= 0x69; i++){ |
outb(vgaIOBase + 4, i); regs[EXTCR + i] = port_in(vgaIOBase + 5); |
} |
for (i = 0x70; i <= NEO_EXT_CR_MAX; i++){ |
outb(vgaIOBase + 4, i); regs[EXTCR + i] = port_in(vgaIOBase + 5); |
} |
|
for (i = 0x0A; i <= NEO_EXT_GR_MAX; i++){ |
outb(GRAX, i); regs[EXTGR + i] = port_in(GRAX+1); |
} |
|
/* DAC */ |
outb(0x3C6,0xFF); /* mask */ |
outb(0x3C7,0x00); /* read address */ |
for (i = 0; i < 768; i++){ |
regs[DAC + i] = port_in(0x3C9); |
DACDelay; |
} |
|
return NEO_TOTAL_REGS - VGA_TOTAL_REGS; |
} |
|
/* Set chipset-specific registers */ |
|
static void neo_setregs(const unsigned char regs[], int mode) |
{ |
int i; |
unsigned char temp; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setregs\n"); |
#endif |
neo_unlock(); |
outw(GRAX, 0x0015); /* bank#0 */ |
|
outb(GRAX, 0x0a); outb(GRAX+1, regs[GeneralLockReg]); |
|
/* set color mode first */ |
outb(GRAX, 0x90); temp = port_in(GRAX+1); |
switch (NeoChipset){ |
case PCI_CHIP_NM2070: |
temp &= 0xF0; /* Save bits 7:4 */ |
temp |= (regs[ExtColorModeSelect] & ~0xF0); |
break; |
case PCI_CHIP_NM2090: case PCI_CHIP_NM2093: case PCI_CHIP_NM2097: |
case PCI_CHIP_NM2160: case PCI_CHIP_NM2200: |
temp &= 0x70; /* Save bits 6:4 */ |
temp |= (regs[ExtColorModeSelect] & ~0x70); |
break; |
} |
outb(GRAX, 0x90); outb(GRAX+1, temp); |
|
/* Disable horizontal and vertical graphics and text expansions */ |
outb(GRAX, 0x25); |
temp = port_in(GRAX+1); |
outb(GRAX, 0x25); |
temp &= 0x39; |
outb(GRAX+1, temp); |
|
sleep(1); |
|
/* DAC */ |
outb(0x3C6,0xFF); /* mask */ |
outb(0x3C8,0x00); /* write address */ |
for (i = 0; i < 768; i++){ |
outb(0x3C9, regs[DAC + i]); |
DACDelay; |
} |
|
outb(GRAX, 0x0E); outb(GRAX+1, regs[ExtCRTDispAddr]); |
outb(GRAX, 0x0F); outb(GRAX+1, regs[ExtCRTOffset]); |
outb(GRAX, 0x10); temp = port_in(GRAX+1); |
temp &= 0x0F; /* Save bits 3:0 */ |
temp |= (regs[SysIfaceCntl1] & ~0x0F); |
outb(GRAX, 0x10); outb(GRAX+1, temp); |
|
outb(GRAX, 0x11); outb(GRAX+1, regs[SysIfaceCntl2]); |
outb(GRAX, 0x15); outb(GRAX+1, regs[SingleAddrPage]); |
outb(GRAX, 0x16); outb(GRAX+1, regs[DualAddrPage]); |
outb(GRAX, 0x20); temp = port_in(GRAX+1); |
switch (NeoChipset){ |
case PCI_CHIP_NM2070: |
temp &= 0xFC; /* Save bits 7:2 */ |
temp |= (regs[PanelDispCntlReg1] & ~0xFC); |
break; |
case PCI_CHIP_NM2090: case PCI_CHIP_NM2093: case PCI_CHIP_NM2097: |
case PCI_CHIP_NM2160: |
temp &= 0xDC; /* Save bits 7:6,4:2 */ |
temp |= (regs[PanelDispCntlReg1] & ~0xDC); |
break; |
case PCI_CHIP_NM2200: |
temp &= 0x98; /* Save bits 7,4:3 */ |
temp |= (regs[PanelDispCntlReg1] & ~0x98); |
break; |
} |
outb(GRAX, 0x20); outb(GRAX+1, temp); |
outb(GRAX, 0x25); temp = port_in(GRAX+1); |
temp &= 0x38; /* Save bits 5:3 */ |
temp |= (regs[PanelDispCntlReg2] & ~0x38); |
outb(GRAX, 0x25); outb(GRAX+1, temp); |
|
if (NeoChipset != PCI_CHIP_NM2070){ |
outb(GRAX, 0x30); temp = port_in(GRAX+1); |
temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */ |
temp |= (regs[PanelDispCntlReg3] & ~0xEF); |
outb(GRAX, 0x30); outb(GRAX+1, temp); |
} |
|
outb(GRAX, 0x28); outb(GRAX+1, regs[PanelVertCenterReg1]); |
outb(GRAX, 0x29); outb(GRAX+1, regs[PanelVertCenterReg2]); |
outb(GRAX, 0x2a); outb(GRAX+1, regs[PanelVertCenterReg3]); |
|
if (NeoChipset != PCI_CHIP_NM2070){ |
outb(GRAX, 0x32); outb(GRAX+1, regs[PanelVertCenterReg4]); |
outb(GRAX, 0x33); outb(GRAX+1, regs[PanelHorizCenterReg1]); |
outb(GRAX, 0x34); outb(GRAX+1, regs[PanelHorizCenterReg2]); |
outb(GRAX, 0x35); outb(GRAX+1, regs[PanelHorizCenterReg3]); |
} |
|
if (NeoChipset == PCI_CHIP_NM2160){ |
outb(GRAX, 0x36); outb(GRAX+1, regs[PanelHorizCenterReg4]); |
} |
|
if (NeoChipset == PCI_CHIP_NM2200){ |
outb(GRAX, 0x36); outb(GRAX+1, regs[PanelHorizCenterReg4]); |
outb(GRAX, 0x37); outb(GRAX+1, regs[PanelVertCenterReg5]); |
outb(GRAX, 0x38); outb(GRAX+1, regs[PanelHorizCenterReg5]); |
} |
|
#if 0 |
outb(GRAX, 0x9B); outb(GRAX+1, regs[VCLK3NumeratorLow]); |
if (NeoChipset == PCI_CHIP_NM2200){ |
outb(GRAX, 0x8F); temp = port_in(GRAX+1); |
temp &= 0x0F; /* Save bits 3:0 */ |
temp |= (regs[VCLK3NumeratorHigh] & ~0x0F); |
outb(GRAX, 0x8F); outb(GRAX+1, temp); |
} |
outb(GRAX, 0x9F); outb(GRAX+1, regs[VCLK3Denominator]); |
#endif |
|
if (regs[EXT_SAVED]){ |
outb(vgaIOBase + 4, 0x25); outb(vgaIOBase + 5, regs[EXTCR + 0x25]); |
outb(vgaIOBase + 4, 0x2F); outb(vgaIOBase + 5, regs[EXTCR + 0x2F]); |
for (i = 0x40; i <= 0x59; i++){ |
outb(vgaIOBase + 4, i); outb(vgaIOBase + 5, regs[EXTCR + i]); |
} |
for (i = 0x60; i <= 0x69; i++){ |
outb(vgaIOBase + 4, i); outb(vgaIOBase + 5, regs[EXTCR + i]); |
} |
for (i = 0x70; i <= NEO_EXT_CR_MAX; i++){ |
outb(vgaIOBase + 4, i); outb(vgaIOBase + 5, regs[EXTCR + i]); |
} |
|
for (i = 0x0a; i <= 0x3f; i++){ |
outb(GRAX, i); outb(GRAX+1, regs[EXTGR + i]); |
} |
for (i = 0x90; i <= NEO_EXT_GR_MAX; i++){ |
outb(GRAX, i); outb(GRAX+1, regs[EXTGR + i]); |
} |
} |
|
/* Program vertical extension register */ |
if (NeoChipset == PCI_CHIP_NM2200){ |
outb(vgaIOBase + 4, 0x70); outb(vgaIOBase + 5, regs[VerticalExt]); |
} |
} |
|
#if 0 |
/* |
* NeoCalcVCLK -- |
* |
* Determine the closest clock frequency to the one requested. |
*/ |
#define REF_FREQ 14.31818 |
#define MAX_N 127 |
#define MAX_D 31 |
#define MAX_F 1 |
|
static void NeoCalcVCLK(long freq, unsigned char *moderegs) |
{ |
int n, d, f; |
double f_out; |
double f_diff; |
int n_best = 0, d_best = 0, f_best = 0; |
double f_best_diff = 999999.0; |
double f_target = freq/1000.0; |
|
for (f = 0; f <= MAX_F; f++) |
for (n = 0; n <= MAX_N; n++) |
for (d = 0; d <= MAX_D; d++) { |
f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ; |
f_diff = abs(f_out-f_target); |
if (f_diff < f_best_diff) { |
f_best_diff = f_diff; |
n_best = n; |
d_best = d; |
f_best = f; |
} |
} |
|
if (NeoChipset == PCI_CHIP_NM2200){ |
/* NOT_DONE: We are trying the full range of the 2200 clock. |
We should be able to try n up to 2047 */ |
moderegs[VCLK3NumeratorLow] = n_best; |
moderegs[VCLK3NumeratorHigh] = (f_best << 7); |
} else { |
moderegs[VCLK3NumeratorLow] = n_best | (f_best << 7); |
} |
moderegs[VCLK3Denominator] = d_best; |
} |
#endif |
|
|
/* Return nonzero if mode is available */ |
|
static int neo_modeavailable(int mode) |
{ |
struct info *info; |
ModeTiming *modetiming; |
ModeInfo *modeinfo; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_modeavaailable: %d\n", mode); |
#endif |
|
if (IS_IN_STANDARD_VGA_DRIVER(mode)) |
return __svgalib_vga_driverspecs.modeavailable(mode); |
|
info = &__svgalib_infotable[mode]; |
if (neo_memory * 1024 < info->ydim * info->xbytes) |
return 0; |
|
modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); |
modetiming = malloc(sizeof(ModeTiming)); |
if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) { |
free(modetiming); |
free(modeinfo); |
return 0; |
} |
free(modetiming); |
free(modeinfo); |
|
return SVGADRV; |
} |
|
/* Local, called by neo_setmode(). */ |
|
static void neo_initializemode(unsigned char *moderegs, |
ModeTiming * modetiming, ModeInfo * modeinfo, int mode) |
{ |
int i, hoffset, voffset; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_initializemode: %d\n", mode); |
#endif |
neo_saveregs(moderegs); |
__svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo); |
|
moderegs[EXT_SAVED] = FALSE; |
moderegs[VGA_AR10] = 0x01; /* Attribute 0x10 */ |
|
moderegs[0x13] = modeinfo->lineWidth >> 3; |
moderegs[ExtCRTOffset] = modeinfo->lineWidth >> 11; |
switch (modeinfo->bitsPerPixel){ |
case 8: |
moderegs[ExtColorModeSelect] = 0x11; |
break; |
case 15: |
case 16: |
if (modeinfo->greenWeight == 5){ /* 15bpp */ |
for (i = 0; i < 64; i++){ |
moderegs[DAC + i*3+0] = i << 1; |
moderegs[DAC + i*3+1] = i << 1; |
moderegs[DAC + i*3+2] = i << 1; |
} |
moderegs[ExtColorModeSelect] = 0x12; |
} else { /* 16bpp */ |
for (i = 0; i < 64; i++){ |
moderegs[DAC + i*3+0] = i << 1; |
moderegs[DAC + i*3+1] = i; |
moderegs[DAC + i*3+2] = i << 1; |
} |
moderegs[ExtColorModeSelect] = 0x13; |
} |
break; |
case 24: |
for (i = 0; i < 256; i++){ |
moderegs[DAC + i*3+0] = i; |
moderegs[DAC + i*3+1] = i; |
moderegs[DAC + i*3+2] = i; |
} |
moderegs[ExtColorModeSelect] = 0x14; |
break; |
} |
moderegs[ExtCRTDispAddr] = 0x10; |
|
#if 0 |
/* Vertical Extension */ |
moderegs[VerticalExt] = (((modetiming->CrtcVTotal -2) & 0x400) >> 10 ) |
| (((modetiming->CrtcVDisplay -1) & 0x400) >> 9 ) |
| (((modetiming->CrtcVSyncStart) & 0x400) >> 8 ) |
| (((modetiming->CrtcVSyncStart) & 0x400) >> 7 ); |
#endif |
|
/* Disable read/write bursts if requested. */ |
#ifdef NEO_PCI_BURST |
moderegs[SysIfaceCntl1] = 0x30; |
#else /* NEO_PCI_BURST */ |
moderegs[SysIfaceCntl1] = 0x00; |
#endif /* NEO_PCI_BURST */ |
|
/* If they are used, enable linear addressing and/or enable MMIO. */ |
moderegs[SysIfaceCntl2] = 0x00; |
moderegs[SysIfaceCntl2] |= 0x80; /* Linear */ |
#if 0 |
moderegs[SysIfaceCntl2] |= 0x40; /* MMIO */ |
#endif |
|
moderegs[PanelDispCntlReg1] = 0x00; |
moderegs[PanelDispCntlReg1] |= 0x02; /* Enable internal display */ |
#if 0 |
moderegs[PanelDispCntlReg1] |= 0x01; /* Enable external display */ |
#endif |
|
/* If we are using a fixed mode, then tell the chip we are. */ |
switch (modetiming->HDisplay) { |
case 1280: |
moderegs[PanelDispCntlReg1] |= 0x60; |
break; |
case 1024: |
moderegs[PanelDispCntlReg1] |= 0x40; |
break; |
case 800: |
moderegs[PanelDispCntlReg1] |= 0x20; |
break; |
case 640: |
break; |
} |
|
/* Setup shadow register locking. */ |
moderegs[GeneralLockReg] = 0x01; |
|
moderegs[PanelDispCntlReg2] = 0x00; |
moderegs[PanelDispCntlReg3] = 0x00; |
|
/* |
* If the screen is to be centerd, turn on the centering for the |
* various modes. |
*/ |
moderegs[PanelVertCenterReg1] = 0x00; |
moderegs[PanelVertCenterReg2] = 0x00; |
moderegs[PanelVertCenterReg3] = 0x00; |
moderegs[PanelVertCenterReg4] = 0x00; |
moderegs[PanelVertCenterReg5] = 0x00; |
moderegs[PanelHorizCenterReg1] = 0x00; |
moderegs[PanelHorizCenterReg2] = 0x00; |
moderegs[PanelHorizCenterReg3] = 0x00; |
moderegs[PanelHorizCenterReg4] = 0x00; |
moderegs[PanelHorizCenterReg5] = 0x00; |
|
if (moderegs[PanelDispCntlReg1] & 0x02){ |
if (modetiming->HDisplay < NeoPanelWidth){ |
moderegs[PanelDispCntlReg3] |= 0x10; |
hoffset = ((NeoPanelWidth - modetiming->HDisplay) >> 4) - 1; |
moderegs[PanelHorizCenterReg1] = hoffset; |
switch (modetiming->HDisplay){ |
case 320: |
moderegs[PanelHorizCenterReg3] = hoffset; |
break; |
case 400: |
moderegs[PanelHorizCenterReg4] = hoffset; |
break; |
case 640: |
moderegs[PanelHorizCenterReg1] = hoffset; |
break; |
case 800: |
moderegs[PanelHorizCenterReg2] = hoffset; |
break; |
case 1024: |
moderegs[PanelHorizCenterReg5] = hoffset; |
break; |
case 1280: |
/* No centering in these modes. */ |
break; |
} |
} |
if (modetiming->VDisplay < NeoPanelHeight){ |
moderegs[PanelDispCntlReg2] |= 0x01; |
voffset = ((NeoPanelHeight - modetiming->VDisplay) >> 1) - 2; |
moderegs[PanelVertCenterReg2] = voffset; |
switch (modetiming->VDisplay){ |
case 240: |
moderegs[PanelVertCenterReg2] = voffset; |
break; |
case 300: case 384: |
moderegs[PanelVertCenterReg1] = voffset; |
break; |
case 480: |
moderegs[PanelVertCenterReg3] = voffset; |
break; |
case 600: |
moderegs[PanelVertCenterReg4] = voffset; |
break; |
case 768: |
moderegs[PanelVertCenterReg5] = voffset; |
break; |
case 1280: |
/* No centering in these modes. */ |
break; |
} |
} |
} |
|
#if 0 |
/* |
* Calculate the VCLK that most closely matches the requested dot |
* clock. |
*/ |
NeoCalcVCLK(modetiming->pixelClock, moderegs); |
#endif |
/* Since we program the clocks ourselves, always use VCLK3. */ |
moderegs[MIS] |= 0x0C; |
|
return ; |
} |
|
|
static int neo_setmode(int mode, int prv_mode) |
{ |
unsigned char *moderegs; |
ModeTiming *modetiming; |
ModeInfo *modeinfo; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setmode: %d\n", mode); |
#endif |
if (IS_IN_STANDARD_VGA_DRIVER(mode)) { |
|
return __svgalib_vga_driverspecs.setmode(mode, prv_mode); |
} |
if (!neo_modeavailable(mode)) |
return 1; |
|
modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); |
|
modetiming = malloc(sizeof(ModeTiming)); |
if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) { |
free(modetiming); |
free(modeinfo); |
return 1; |
} |
|
moderegs = malloc(NEO_TOTAL_REGS); |
|
neo_initializemode(moderegs, modetiming, modeinfo, mode); |
free(modetiming); |
|
__svgalib_setregs(moderegs); /* Set standard regs. */ |
neo_setregs(moderegs, mode); /* Set extended regs. */ |
free(moderegs); |
|
__svgalib_InitializeAcceleratorInterface(modeinfo); |
|
|
free(modeinfo); |
return 0; |
} |
|
|
/* Unlock chipset-specific registers */ |
|
static void neo_unlock(void) |
{ |
int temp; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_unlock\n"); |
#endif |
outb(vgaIOBase + 4, 0x11); |
temp = port_in(vgaIOBase + 5); |
outb(vgaIOBase + 5, temp & 0x7F); |
outw(GRAX, 0x2609); /* Unlock NeoMagic registers */ |
} |
|
static void neo_lock(void) |
{ |
int temp; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_lock\n"); |
#endif |
outb(vgaIOBase + 4, 0x11); |
temp = port_in(vgaIOBase + 5); |
outb(vgaIOBase + 5, temp | 0x80); |
outw(GRAX, 0x0009); /* Lock NeoMagic registers */ |
} |
|
|
/* Indentify chipset, initialize and return non-zero if detected */ |
|
int neo_test(void) |
{ |
unsigned long buf[64]; |
int found=0; |
|
found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0); |
|
if (found == 0){ /* found */ |
switch ((buf[0] >> 16) & 0xffff){ |
case PCI_CHIP_NM2070: case PCI_CHIP_NM2090: case PCI_CHIP_NM2093: |
case PCI_CHIP_NM2097: case PCI_CHIP_NM2160: case PCI_CHIP_NM2200: |
neo_init(0,0,0); |
return (TRUE); |
} |
} |
return (FALSE); |
} |
|
|
/* Set display start address (not for 16 color modes) */ |
/* Cirrus supports any address in video memory (up to 2Mb) */ |
|
static void neo_setdisplaystart(int address) |
{ |
int oldExtCRTDispAddr; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setdisplaystart: 0x%x\n", address); |
#endif |
address=address >> 2; |
outw(vgaIOBase + 4, (address & 0x00FF00) | 0x0C); |
outw(vgaIOBase + 4, ((address & 0x00FF) << 8) | 0x0D); |
|
outb(GRAX, 0x0E); |
oldExtCRTDispAddr = port_in(GRAX+1); |
outw(GRAX, |
((((address >> 16) & 0x07) | (oldExtCRTDispAddr & 0xf8)) << 8) | 0x0E); |
} |
|
|
/* Set logical scanline length (usually multiple of 8) */ |
/* Cirrus supports multiples of 8, up to 4088 */ |
|
static void neo_setlogicalwidth(int width) |
{ |
int offset = width >> 3; |
|
#ifdef DEBUG |
printk(KERN_DEBUG "neo_setlogicalwidth: %d\n", width); |
#endif |
__svgalib_outCR(0x13,offset&0xff); |
outb(GRAX, 0x0F); |
outb(GRAX+1, width >> 11); |
} |
|
static int neo_linear(int op, int param) |
{ |
#ifdef DEBUG |
printk(KERN_DEBUG "neo_linear: %d\n", op); |
#endif |
if (op==LINEAR_ENABLE){neo_is_linear=1; return 0;}; |
if (op==LINEAR_DISABLE){neo_is_linear=0; return 0;}; |
if (op==LINEAR_QUERY_BASE) return neo_linear_base; |
if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0; /* No granularity or range. */ |
else return -1; /* Unknown function. */ |
} |
|
static int neo_match_programmable_clock(int clock) |
{ |
return clock ; |
} |
|
static int neo_map_clock(int bpp, int clock) |
{ |
return clock ; |
} |
|
static int neo_map_horizontal_crtc(int bpp, int pixelclock, int htiming) |
{ |
return htiming; |
} |
|
/* Function table (exported) */ |
|
DriverSpecs __svgalib_neo_driverspecs = |
{ |
neo_saveregs, |
neo_setregs, |
#if 1 |
neo_unlock, |
neo_lock, |
#else |
0, |
0, |
#endif |
neo_test, |
neo_init, |
neo_setpage, |
neo_setrdpage, |
neo_setwrpage, |
neo_setmode, |
neo_modeavailable, |
neo_setdisplaystart, |
neo_setlogicalwidth, |
neo_getmodeinfo, |
0, /* old blit funcs */ |
0, |
0, |
0, |
0, |
0, /* ext_set */ |
0, /* accel */ |
neo_linear, |
0, /* accelspecs, filled in during init. */ |
NULL, /* Emulation */ |
}; |
|
|
/* Initialize chipset (called after detection) */ |
|
static int neo_init(int force, int par1, int par2) |
{ |
unsigned long buf[64]; |
int found=0; |
int w; |
|
vgaIOBase = (port_in(0x3CC) & 0x01) ? 0x3D0 : 0x3B0; |
neo_unlock(); |
if (force) { |
neo_memory = par1; |
NeoChipset = par2; |
} else { |
neo_memory = -1; |
NeoChipset = -1; |
}; |
|
found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0); |
|
neo_linear_base=0; |
if (!found){ /* found */ |
neo_linear_base=buf[4]&0xffffff00; |
if (NeoChipset < 0) |
NeoChipset = (buf[0] >> 16) & 0xffff; |
if (neo_memory < 0){ |
switch (NeoChipset){ |
case PCI_CHIP_NM2070: |
neo_memory = 896; |
break; |
case PCI_CHIP_NM2090: case PCI_CHIP_NM2093: case PCI_CHIP_NM2097: |
neo_memory = 1152; |
break; |
case PCI_CHIP_NM2160: |
neo_memory = 2048; |
break; |
case PCI_CHIP_NM2200: |
neo_memory = 2560; |
break; |
default: |
neo_memory = 0; |
} |
} |
} |
|
if (__svgalib_driver_report) { |
printk(KERN_INFO "Using NeoMagic driver, %iKB.\n",neo_memory); |
}; |
|
cardspecs = malloc(sizeof(CardSpecs)); |
cardspecs->videoMemory = neo_memory; |
cardspecs->maxPixelClock4bpp = 75000; |
switch (NeoChipset){ |
case PCI_CHIP_NM2070: |
cardspecs->maxPixelClock8bpp = 65000; |
cardspecs->maxPixelClock16bpp = 65000; |
cardspecs->maxPixelClock24bpp = 0; |
cardspecs->maxPixelClock32bpp = 0; |
break; |
case PCI_CHIP_NM2090: case PCI_CHIP_NM2093: case PCI_CHIP_NM2097: |
cardspecs->maxPixelClock8bpp = 80000; |
cardspecs->maxPixelClock16bpp = 80000; |
cardspecs->maxPixelClock24bpp = 80000; |
cardspecs->maxPixelClock32bpp = 0; |
break; |
case PCI_CHIP_NM2160: |
cardspecs->maxPixelClock8bpp = 90000; |
cardspecs->maxPixelClock16bpp = 90000; |
cardspecs->maxPixelClock24bpp = 90000; |
cardspecs->maxPixelClock32bpp = 0; |
break; |
case PCI_CHIP_NM2200: |
cardspecs->maxPixelClock8bpp = 110000; |
cardspecs->maxPixelClock16bpp = 110000; |
cardspecs->maxPixelClock24bpp = 110000; |
cardspecs->maxPixelClock32bpp = 0; |
break; |
} |
|
/* Determine panel width -- used in NeoValidMode. */ |
outb(GRAX, 0x20); |
w = port_in(GRAX+1); |
switch ((w & 0x18) >> 3){ |
case 0x00: |
NeoPanelWidth = 640; |
NeoPanelHeight = 480; |
break; |
case 0x01: |
NeoPanelWidth = 800; |
#ifdef LIBRETTO100 |
NeoPanelHeight = 480; |
#else /* LIBRETTO100 */ |
NeoPanelHeight = 600; |
#endif /* LIBRETTO100 */ |
break; |
case 0x02: |
NeoPanelWidth = 1024; |
NeoPanelHeight = 768; |
break; |
case 0x03: |
NeoPanelWidth = 1280; |
NeoPanelHeight = 1024; |
break; |
default : |
NeoPanelWidth = 640; |
NeoPanelHeight = 480; |
} |
|
__svgalib_modeinfo_linearset |= IS_LINEAR; |
|
cardspecs->flags = INTERLACE_DIVIDE_VERT | CLOCK_PROGRAMMABLE; |
cardspecs->maxHorizontalCrtc = 2040; |
cardspecs->maxPixelClock4bpp = 0; |
cardspecs->nClocks =0; |
cardspecs->mapClock = neo_map_clock; |
cardspecs->mapHorizontalCrtc = neo_map_horizontal_crtc; |
cardspecs->matchProgrammableClock=neo_match_programmable_clock; |
__svgalib_driverspecs = &__svgalib_neo_driverspecs; |
__svgalib_banked_mem_base=0xa0000; |
__svgalib_banked_mem_size=0x10000; |
__svgalib_linear_mem_base=neo_linear_base; |
__svgalib_linear_mem_size=neo_memory*0x400; |
neo_is_linear = FALSE; |
|
sleep(4); |
|
return 0; |
} |