|
|
/*++
Copyright (c) 1993, 1994 Weitek Corporation
Module Name:
p9100.c
Abstract:
This module contains the code specific to the Weitek P9100.
Environment:
Kernel mode
Revision History may be found at the end of this file.
--*/
#include "p9.h"
#include "p9gbl.h"
#include "p91regs.h"
#include "vga.h"
#include "wtkp9xvl.h"
VOID InitP9100( PHW_DEVICE_EXTENSION HwDeviceExtension )
/*++
Routine Description:
Initialize the P9100.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/ { VideoDebugPrint((2, "InitP9100------\n"));
P9_WR_REG(P91_INTERRUPT_EN, 0x00000080L); //INTERRUPT-EN = disabled
P9_WR_REG(P91_PREHRZC, 0x00000000L); //PREHRZC = 0
P9_WR_REG(P91_PREVRTC, 0x00000000L); //PREVRTC = 0
//
// Initialize the P9100 registers.
//
P9_WR_REG(P91_RFPERIOD, 0x00000186L); //RFPERIOD =
P9_WR_REG(P91_RLMAX, 0x000000FAL); //RLMAX =
P9_WR_REG(P91_DE_PMASK, 0xFFFFFFFFL); //allow writing in all 8 planes
P9_WR_REG(P91_DE_DRAW_MODE, P91_WR_INSIDE_WINDOW | P91_DE_DRAW_BUFF_0); P9_WR_REG(P91_PE_W_OFF_XY, 0x00000000L); //disable any co-ord offset
return; }
VOID P91_WriteTiming( PHW_DEVICE_EXTENSION HwDeviceExtension )
/*++
Routine Description:
Initializes the P9100 Crtc timing registers.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/
{ int num, den, bpp; ULONG ulValueRead, ulValueWritten; ULONG ulHRZSR; ULONG ulHRZBR; ULONG ulHRZBF; ULONG ulHRZT;
VideoDebugPrint((2, "P91_WriteTiming - Entry\n"));
bpp = HwDeviceExtension->usBitsPixel / 8; // Need bytes per pixel
//
// 24-bit color
//
if (bpp == 3) { num = 3; den = HwDeviceExtension->Dac.usRamdacWidth/8; } else { num = 1; den = HwDeviceExtension->Dac.usRamdacWidth/(bpp * 8); }
//
// Calculate HRZSR.
//
ulHRZSR = (ULONG) (HwDeviceExtension->VideoData.hsyncp / (ULONG) den) * (ULONG) num;
ulHRZSR -= HwDeviceExtension->p91State.ulBlnkDlyAdj;
//
// Calculate HRZBR.
//
ulHRZBR = (ULONG) ((HwDeviceExtension->VideoData.hsyncp + HwDeviceExtension->VideoData.hbp) / (ULONG) den) * (ULONG) num;
ulHRZBR -= HwDeviceExtension->p91State.ulBlnkDlyAdj;
// ulHRZBR -= 4;
ulHRZBF = (ULONG) ( (HwDeviceExtension->VideoData.hsyncp+ HwDeviceExtension->VideoData.hbp+ HwDeviceExtension->VideoData.XSize) / (ULONG) den) * (ULONG) num;
//
// Calculate HRZBF.
//
ulHRZBF -= HwDeviceExtension->p91State.ulBlnkDlyAdj;
// ulHRZBF -= 4;
ulHRZT = (ULONG) ( (HwDeviceExtension->VideoData.hsyncp+ HwDeviceExtension->VideoData.hbp+ HwDeviceExtension->VideoData.XSize+ HwDeviceExtension->VideoData.hfp) / (ULONG) den) * (ULONG) num; --ulHRZT;
//
// Changes requested by Rober Embry, Jan 26 Spec.
//
if (HwDeviceExtension->Dac.ulDacId == DAC_ID_BT489) { //
// Fix for fussy screen problem, Per Sam Jenson
//
ulHRZT = 2 * (ulHRZT>>1) + 1; }
if ((HwDeviceExtension->Dac.ulDacId == DAC_ID_BT489) || (HwDeviceExtension->Dac.ulDacId == DAC_ID_BT485)) { if (bpp == 1) { ulHRZBR -= 12 * num / den; ulHRZBF -= 12 * num / den; } else { ulHRZBR -= 9 * num / den; ulHRZBF -= 9 * num / den; } }
//
// By robert embry 12/1/94
//
// The hardware configuration (Power 9100 version and DAC type) affects
// the minimum horizontal back porch timing that a board can support.
// The most flexible (able to support the smallest back porch)
// configuration is with Power 9100 A4 with the IBM or ATT DAC.
//
// The Power 9100 A2 increases the front porch minimum by one.
// The Brooktree DAC increases the front porch minimum by one, also.
//
// Configuration Min. Back Porch
// ----------------- ---------------
// P9100 A4, IBM/ATT DAC 40 pixels (5 CRTC clocks)
// P9100 A2, IBM/ATT DAC 48 pixels (6 CRTC clocks)
// P9100 A4, BT485/9 DAC 48 pixels (6 CRTC clocks)
// P9100 A2, BT485/9 DAC 56 pixels (7 CRTC clocks)
//
// Since we want one P9x00RES.DAT file AND we don't want to penalize the
// most common configuration, the driver needs to choose the best fit
// when the P9x00RES.DAT file specifies a set of parameters that are not
// supported.
//
// Algorithm for BEST FIT:
//
// First, time must be taken from something else. Either by shortening
// the pulse width or the front porch (shifts line to right.) The
// largest value of the two is decreased, sync pulse if equal.
//
// A given P9x00RES.DAT file will result in valid register values
// in one hardware configuration, but not in another. This code
// adjusts these register values so the P9x00RES.DAT file parameters
// work for all boards, but not necesarily giving the requested timing.
// The P9100 A4 silicon with an IBM or ATT DAC is the best case.
// When the P9100 A2 or a Brooktree DAC is present then the
// minimum supportable horizontal back porch is enlarged.
//
// psuedo BASIC code:
//
// This is parameter checking code for the Power 9100's hrzSR and hrzBR
// registers. The following equation must be satisfied: hrzSR < hrzBR.
//
// If this equation is violated in the presence of the Power 9100 A2
// silicon or a non-pipelined DAC (BT485/9) then these register values
// are modified.
//
// This code should go just before the registers are written.
// The register values may need to be modified by up to 2 counts.
//
// IF (DacType=BT485 OR DacType=BT485A OR DacType=BT489 OR _
// SiliconVerion=A2) THEN {
// WHILE hrzSR >= hrzBR {
// IF hsp>hfp THEN DECR hrzSR _ ;shrink sync pulse width
// ELSE INCR hrzBR :INCR hrzBF ;shorten front porch
// } }
//
if ((HwDeviceExtension->Dac.ulDacId == DAC_ID_BT489) || (HwDeviceExtension->Dac.ulDacId == DAC_ID_BT485) || (HwDeviceExtension->p91State.usRevisionID < WTK_9100_REV3)) { while (ulHRZSR >= ulHRZBR) { if (HwDeviceExtension->VideoData.hsyncp > HwDeviceExtension->VideoData.hfp) { ulHRZSR--; } else { ulHRZBR++; ulHRZBF++; } } }
//
// Write to the video timing registers
//
do { P9_WR_REG(P91_HRZSR, ulHRZSR); ulValueRead = (ULONG) P9_RD_REG(P91_HRZSR); } while (ulValueRead != ulHRZSR);
do { P9_WR_REG(P91_HRZBR, ulHRZBR); ulValueRead = (ULONG) P9_RD_REG(P91_HRZBR); } while (ulValueRead != ulHRZBR);
do { P9_WR_REG(P91_HRZBF, ulHRZBF); ulValueRead = (ULONG) P9_RD_REG(P91_HRZBF); } while (ulValueRead != ulHRZBF);
do { P9_WR_REG(P91_HRZT, ulHRZT); ulValueRead = (ULONG) P9_RD_REG(P91_HRZT); } while (ulValueRead != ulHRZT);
ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp;
do { P9_WR_REG(P91_VRTSR, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTSR); } while (ulValueRead != ulValueWritten);
ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp+ HwDeviceExtension->VideoData.vbp; do { P9_WR_REG(P91_VRTBR, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTBR); } while (ulValueRead != ulValueWritten);
ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp+ HwDeviceExtension->VideoData.vbp+ HwDeviceExtension->VideoData.YSize; do { P9_WR_REG(P91_VRTBF, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTBF); } while (ulValueRead != ulValueWritten);
ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp+ HwDeviceExtension->VideoData.vbp+ HwDeviceExtension->VideoData.YSize+ HwDeviceExtension->VideoData.vfp; do { P9_WR_REG(P91_VRTT, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTT); } while (ulValueRead != ulValueWritten);
VideoDebugPrint((2, "P91_WriteTiming - Exit\n"));
return;
} // End of P91_WriteTimings()
VOID P91_SysConf( PHW_DEVICE_EXTENSION HwDeviceExtension )
/*++
Routine Description:
Syscon converts the ->XSize value into the correct bits in the System Configuration Register and writes the register (This register contains the XSize of the display.)
Half-word and byte swapping are set via bits: 12 & 13; The shift control fields are set to the size of the scanline in bytes; And pixel size is set to bits per pixel.
XSize and ulFrameBufferSize must be set prior to entering this routine. This routine also initializes the clipping registers.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
Return Value:
None.
--*/
{ int i, j, iBytesPerPixel; // loop counters
long sysval; // swap bytes and words for little endian PC
int xtem = (int) HwDeviceExtension->VideoData.XSize; long ClipMax; // clipping register value for NotBusy to restore
iBytesPerPixel = (int) HwDeviceExtension->usBitsPixel / 8; // Calc Bytes/pixel
xtem *= iBytesPerPixel;
VideoDebugPrint((2, "P91_SysConf------\n"));
//
// The following sets up the System Configuration Register
// for BPP with byte and half-word swapping. This swapping
// is usually what is needed since the frame-buffer is stored
// in big endian pixel format and the 80x86 software usually
// expects little endian pixel format.
//
if (iBytesPerPixel == 1) sysval = SYSCFG_BPP_8; else if (iBytesPerPixel == 2) sysval = SYSCFG_BPP_16; else if (iBytesPerPixel == 3) sysval = SYSCFG_BPP_24; else // if (iBytesPerPixel == 4)
sysval = SYSCFG_BPP_32;
//
// Now set the Shift3, Shift0, Shift1 & Shift2 multipliers.
//
// Each field in the sysconfig can only set a limited
// range of bits in the size.
//
if (xtem & 0x1c00) // 7168
{ //
// Look at all the bits for shift control 3
//
j=3; for (i=4096;i>=1024;i>>=1) { //
// If this bit is on...
//
if (i & xtem) { //
// Use this field to set it and
// remove the bit from the size. Each
// field can only set one bit.
//
sysval |= ((long)j)<<29; xtem &= ~i; break; } j=j-1; } }
if (xtem & 0xf80) // each field in the sysconreg can only set
{ // a limited range of bits in the size
j = 7; // each field is 3 bits wide
//
// Look at all the bits for shift control 0
//
for (i = 2048; i >= 128;i >>= 1) // look at all the bits field 3 can effect
{ if (i & xtem) // if this bit is on,
{ sysval |= ((long) j) << 20; // use this field to set it
xtem &= ~i; // and remove the bit from the size
break; // each field can only set one bit
} j -= 1; } }
if (xtem & 0x7C0) // do the same thing for field 2
{ //
// Do the same thing for shift control 1
//
j = 6; // each field is 3 bits wide
for (i = 1024; i >= 64; i >>= 1) // look at all the bits field 2 can effect
{ if (i & xtem) // if this bit is on,
{ sysval |= ((long)j)<<17; // use this field to set it
xtem &= ~i; // and remove the bit from the size
break; // each field can only set one bit
} j -= 1; } }
if (xtem & 0x3E0) // do the same thing for field 1
{ j = 5; // each field is 3 bits wide
//
// do the same thing for shift control 2
//
for (i = 512; i >= 32;i >>= 1) // look at all the bits field 1 can effect
{ if (i & xtem) // if this bit is on,
{ sysval |= ((long) j) << 14; // use this field to set it
xtem &= ~i; // and remove the bit from the size
break; // each field can only set one bit
} j -= 1; } }
//
// If there are bits left, it is an illegal x size. This just means
// that we cannot handle it because we have not implemented a
// full multiplier. However, the vast majority of screen sizes can be
// expressed as a sum of few powers of two.
//
if (xtem != 0) // if there are bits left, it is an
return; // illegal x size.
VideoDebugPrint((2, "P91_SysConf:sysval = 0x%lx\n", sysval));
P9_WR_REG(P91_SYSCONFIG, sysval); // send data to the register
xtem = (int) (HwDeviceExtension->VideoData.XSize * (ULONG) iBytesPerPixel); //
// Now calculate and set the max clipping to allow access to all of
// the extra memory.
//
// There are two sets of clipping registers. The first takes the
// horizontal diemnsion in pixels and the vertical dimension in
// scanlines.
//
ClipMax=((long) HwDeviceExtension->VideoData.XSize - 1L) << 16 | (div32(HwDeviceExtension->FrameLength, (USHORT) xtem) - 1L);
P9_WR_REG(P91_DE_P_W_MIN, 0L); P9_WR_REG(P91_DE_P_W_MAX, ClipMax);
//
// The second set takes the horizontal dimension in bytes and the
// vertical dimension in scanlines.
//
ClipMax=((long) xtem -1L) << 16 | (div32(HwDeviceExtension->FrameLength, (USHORT) xtem) - 1L); // calc and set max
P9_WR_REG(P91_DE_B_W_MIN, 0L); P9_WR_REG(P91_DE_B_W_MAX, ClipMax);
return;
} // End of P91_SysConf()
#define RESTORE_DAC 1
//#define SAVE_INDEX_REGS 1
/***************************************************************************\
* * * Save & Restore VGA registers routines * * * * this is to avoid "blind" boot end * * * \***************************************************************************/
void P91SaveVGARegs(PHW_DEVICE_EXTENSION HwDeviceExtension,VGA_REGS * SaveVGARegisters) { UCHAR ucIndex ; ULONG ulIndex ; UCHAR temp;
#ifdef SAVE_INDEX_REGS
// Save index registers.
temp = VGA_RD_REG(0x004); VideoDebugPrint((1, "Save, 3c4:%x\n", temp));
temp = VGA_RD_REG(0x00e); VideoDebugPrint((1, "Save, 3ce:%x\n", temp));
temp = VGA_RD_REG(0x014); VideoDebugPrint((1, "Save, 3d4:%x\n", temp)); #endif
/* Miscellaneous Output Register: [3C2]w, [3CC]r */ SaveVGARegisters->MiscOut = VGA_RD_REG(0x00C) ;
/* CRT Controller Registers 0-18: index [3D4], data [3D5] */ for (ucIndex = 0 ; ucIndex < 0x18 ; ucIndex ++) { VGA_WR_REG(0x014 ,ucIndex) ; SaveVGARegisters->CR[ucIndex] = VGA_RD_REG(0x015) ; }
/* Sequencer Registers 1-4: index [3C4], data [3C5] */ for (ucIndex = 1 ; ucIndex < 4 ; ucIndex ++) { VGA_WR_REG(0x004 ,ucIndex) ; SaveVGARegisters->SR[ucIndex] = VGA_RD_REG(0x005) ; }
/* Graphics Controller Registers 0-8: index [3CE], data [3CF] */ for (ucIndex = 0 ; ucIndex < 8 ; ucIndex ++) { VGA_WR_REG(0x00E ,ucIndex) ; SaveVGARegisters->GR[ucIndex] = VGA_RD_REG(0x00F) ; }
/* Attribute Controller Registers 0-14: index and data [3C0]w, [3C1]r */ VGA_RD_REG(0x01A) ; /* set toggle to index mode */ for (ucIndex = 0 ; ucIndex < 0x14 ; ucIndex ++) { VGA_WR_REG(0x000 ,ucIndex) ; /* write index */ SaveVGARegisters->AR[ucIndex] = VGA_RD_REG(0x001) ; /* read data */ VGA_WR_REG(0x000 ,SaveVGARegisters->AR[ucIndex]) ; /* toggle */ }
#ifdef RESTORE_DAC
//Look-Up Table: Read Index [3C7]w, Write Index [3C8], Data [3C9]
VGA_WR_REG(0x007 ,0) ; //set read index to 0
for (ulIndex = 0 ; ulIndex < (3 * 256) ; ulIndex ++) { SaveVGARegisters->LUT[ulIndex] = VGA_RD_REG(0x009) ; } #endif //RESTORE_DAC
}
void P91RestoreVGAregs(PHW_DEVICE_EXTENSION HwDeviceExtension,VGA_REGS * SaveVGARegisters) { UCHAR ucIndex ; ULONG ulIndex ; UCHAR temp;
WriteP9ConfigRegister(HwDeviceExtension,P91_CONFIG_MODE,0x2); /* Put the VGA back in color mode for our PROM */ VGA_WR_REG(MISCOUT ,1) ;
/* Enable VGA Registers: [3C3] = 1 */ VGA_WR_REG(0x003 ,1) ;
/* Miscellaneous Output Register: [3C2]w, [3CC]r */ VGA_WR_REG(0x002 ,SaveVGARegisters->MiscOut) ;
/* Enable CR0-CR7: CR11[7] = 0 */ VGA_WR_REG(0x014 ,0x11) ; VGA_WR_REG(0x015 ,SaveVGARegisters->CR[0x11] & 0x7F) ;
/* CRT Controller Registers 0-18: index [3D4], data [3D5] */ for (ucIndex = 0 ; ucIndex < 0x18 ; ucIndex ++) { VGA_WR_REG(0x014 ,ucIndex) ; VGA_WR_REG(0x015 ,SaveVGARegisters->CR[ucIndex]) ; }
/* Synchronous Reset: SR0 = 1 */ VGA_WR_REG(0x004 ,0) ; VGA_WR_REG(0x005 ,1) ;
/* ClockMode: SR1 */ VGA_WR_REG(0x004 ,1) ; VGA_WR_REG(0x005 ,SaveVGARegisters->SR[1]) ;
/* Non Reset Mode: SR0 = 0 */ VGA_WR_REG(0x004 ,0) ; VGA_WR_REG(0x005 ,0) ;
/* Sequencer Registers 2-4: index [3C4], data [3C5] */ for (ucIndex = 2 ; ucIndex < 4 ; ucIndex ++) { VGA_WR_REG(0x004 ,ucIndex) ; VGA_WR_REG(0x005 ,SaveVGARegisters->SR[ucIndex]) ; }
/* Graphics Controller Regs 0-8: index [3CE], data [3CF] */ VGA_WR_REG(0x00E ,1) ; VGA_WR_REG(0x00F ,0x0F) ; /* enable all 4 planes for GR0 */ for (ucIndex = 0 ; ucIndex < 8 ; ucIndex ++) { VGA_WR_REG(0x00E ,ucIndex) ; VGA_WR_REG(0x00F ,SaveVGARegisters->GR[ucIndex]) ; }
/* Attrib Controller Regs 0-14:index and data [3C0]w,[3C1]r */ VGA_RD_REG(0x01A) ; /* set toggle to index mode */ for (ucIndex = 0 ; ucIndex < 0x14 ; ucIndex ++) { VGA_WR_REG(0x000 ,ucIndex) ; /* write index */ VGA_WR_REG(0x000 ,SaveVGARegisters->AR[ucIndex]) ; /* write data */ } VGA_WR_REG(0x000 ,0x20) ; /* set index[5] to 1 */
#ifdef SAVE_INDEX_REGS
// Restore index registers.
VGA_WR_REG(0x004, 0x002); temp = VGA_RD_REG(0x004); VideoDebugPrint((1, "Restore: 3c4:%x\n", temp));
VGA_WR_REG(0x00e, 0x005); temp = VGA_RD_REG(0x00e); VideoDebugPrint((1, "Restore: 3ce:%x\n", temp));
VGA_WR_REG(0x014, 0x0011); temp = VGA_RD_REG(0x014); VideoDebugPrint((1, "Restore: 3d4:%x\n", temp)); #endif
#ifdef RESTORE_DAC
//Look-Up Table:
//Read Index [3C7]w, Write Index [3C8], Data [3C9]
VGA_WR_REG(0x008 ,0) ; // set write index to 0
for (ulIndex = 0 ; ulIndex < (3 * 256) ; ulIndex ++) { VGA_WR_REG(0x009 ,SaveVGARegisters->LUT[ulIndex]) ; } #endif //RESTORE_DAC
}
|