Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 132 → Rev 133

/shark/trunk/drivers/svga/neo.c
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;
}