Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1334 lines
29 KiB

/*++
Copyright (c) 1995 International Business Machines Corporation
Module Name:
pxp91.c
Abstract:
This module implements the HAL display initialization and output routines
for a PowerPC system using a Weitek P9100 video adapter.
Author:
Jake Oshins
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#include "pxP91.h"
#include "pci.h"
#include "pcip.h"
#define MAP_PCI_CONFIG_PHASE0 \
if (HalpInitPhase == 0) HalpPhase0MapBusConfigSpace()
#define UNMAP_PCI_CONFIG_PHASE0 \
if (HalpInitPhase == 0) HalpPhase0UnMapBusConfigSpace()
#define MAP_FRAMEBUF_PHASE0 \
if (HalpInitPhase == 0) HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo(HalpP9FramebufPhysicalAddress.LowPart, 0x200000)
#define UNMAP_FRAMEBUF_PHASE0 \
if (HalpInitPhase == 0) KePhase0DeleteIoMap(HalpP9FramebufPhysicalAddress.LowPart, 0x200000)
VOID
HalpDisplayPpcP91Setup (
VOID
);
VOID
HalpDisplayCharacterP91 (
IN UCHAR Character
);
VOID
HalpOutputCharacterP91(
IN PUCHAR Glyph
);
VOID
HalpP91RelinquishDisplayOwnership();
VOID
SetupVideoBackend();
VOID
WriteIBM525(
USHORT index,
UCHAR value
);
BOOLEAN
IBM525SetMode();
VOID
P91_WriteTiming();
VOID
P91_SysConf();
VOID
CalcP9100MemConfig ();
VOID
ProgramClockSynth(
USHORT usFrequency,
BOOLEAN bSetMemclk,
BOOLEAN bUseClockDoubler
);
VOID
Write525PLL(
USHORT usFreq
);
VOID P91WriteICD(
ULONG data
);
VOID
Write9100FreqSel(
ULONG cs
);
VOID
WriteP9ConfigRegister(
UCHAR index,
UCHAR value
);
VOID
VLEnableP91();
UCHAR
ReadP9ConfigRegister(
UCHAR index
);
ULONG
Read9100FreqSel();
VOID
IBM525PointerOff();
typedef
VOID
(*PHALP_CONTROLLER_SETUP) (
VOID
);
typedef
VOID
(*PHALP_DISPLAY_CHARACTER) (
UCHAR
);
//
// Define static data.
//
extern BOOLEAN HalpDisplayOwnedByHal;
extern ULONG HalpPciMaxSlots;
extern ULONG HalpInitPhase;
extern volatile PUCHAR HalpVideoMemoryBase;
extern volatile PUCHAR HalpVideoCoprocBase;
extern PHALP_CONTROLLER_SETUP HalpDisplayControllerSetup;
extern PHALP_DISPLAY_CHARACTER HalpDisplayCharacter;
//
// Define OEM font variables.
//
extern USHORT HalpBytesPerRow;
extern USHORT HalpCharacterHeight;
extern USHORT HalpCharacterWidth;
extern ULONG HalpDisplayText;
extern ULONG HalpDisplayWidth;
extern ULONG HalpScrollLength;
extern ULONG HalpScrollLine;
//
// Define display variables.
//
extern ULONG HalpColumn;
extern ULONG HalpRow;
extern ULONG HalpHorizontalResolution;
extern ULONG HalpVerticalResolution;
extern POEM_FONT_FILE_HEADER HalpFontHeader;
//
// PCI slot number
//
UCHAR HalpP9SlotNumber;
UCHAR HalpP9BusNumber;
//
// Framebuffer physical address
//
PHYSICAL_ADDRESS HalpP9FramebufPhysicalAddress = {0,0};
//
// Coprocessor physical address
PHYSICAL_ADDRESS HalpP9CoprocPhysicalAddress = {0,0};
VOID
HalpP91RelinquishDisplayOwnership()
/*++
Routine Description:
This routine unmaps the BATs that allow us to function in Phase0.
It is called when the video miniport takes ownership of the screen.
Arguments:
None.
Return Value:
None.
--*/
{
ASSERT(HalpVideoMemoryBase);
ASSERT(HalpVideoCoprocBase);
ASSERT(HalpP9FramebufPhysicalAddress.LowPart);
ASSERT(HalpP9CoprocPhysicalAddress.LowPart);
//
// Delete the framebuffer
//
KePhase0DeleteIoMap(HalpP9FramebufPhysicalAddress.LowPart,
0x200000);
HalpVideoMemoryBase = NULL;
//
// Unmap the control registers
//
KePhase0DeleteIoMap(HalpP9CoprocPhysicalAddress.LowPart,
0x10000);
HalpVideoCoprocBase = NULL;
}
VOID
HalpDisplayPpcP91Setup (
VOID
)
/*++
Routine Description:
This routine initializes the Weitek P9100 display contoller chip.
Arguments:
None.
Return Value:
None.
--*/
{
PULONG buffer;
ULONG limit, index;
volatile ULONG throwaway = 0;
ULONG i, j;
RGB colors[255];
UCHAR *pData, ucpdata;
ULONG pdata;
ULONG curDACIndex;
ULONG value;
PHYSICAL_ADDRESS busrelative;
if (HalpInitPhase == 0) {
// Discover the PCI slot number, coprocessor physical address, and
// frame buffer physical address
if(HalpPhase0MapBusConfigSpace () == FALSE){
ASSERT(FALSE);
}
else
{
//
// In the case that there are two P9100's in the system, this
// will identify the one that occupies the lowest PCI slot number.
//
HalpP9BusNumber=0;
HalpP9SlotNumber=0;
for (j=0; j < HalpPciMaxBuses; j++) {
for (i=0; i<HalpPciMaxSlots; i++) {
HalpPhase0GetPciDataByOffset (j, i, &value, 0x0, 4);
if(value == ((P91_DEV_ID_WEITEK_PCI << 16) | P91_VEN_ID_WEITEK_PCI)){
HalpP9SlotNumber = (UCHAR)i;
HalpP9BusNumber = (UCHAR)j;
}
}
}
if(i==HalpPciMaxSlots && HalpP9SlotNumber==0){
ASSERT(FALSE);
return;
}
}
HalpPhase0GetPciDataByOffset (HalpP9BusNumber,
HalpP9SlotNumber,
&busrelative.LowPart,
0x10,
4);
HalpPhase0UnMapBusConfigSpace();
HalpP9CoprocPhysicalAddress.LowPart = PCI_MEMORY_PHYSICAL_BASE + busrelative.LowPart;
HalpP9FramebufPhysicalAddress.LowPart = HalpP9CoprocPhysicalAddress.LowPart +
P9100_FRAMEBUF_OFFSET;
//
// Now map everything with BATs
//
if (HalpVideoMemoryBase == NULL) {
HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo(HalpP9FramebufPhysicalAddress.LowPart,
0x200000); // 2 MB
}
if (HalpVideoCoprocBase == NULL) {
HalpVideoCoprocBase = (PUCHAR)KePhase0MapIo(HalpP9CoprocPhysicalAddress.LowPart,
0x100000); //1MB
// I'm pretty sure this covers all the registers we need to hit from
// the HAL.
}
}
else {
//
// Map video memory space via pte's
//
// NT may have moved the video frame buffer since we last used it...
HalGetBusDataByOffset (PCIConfiguration,
HalpP9BusNumber,
HalpP9SlotNumber,
&busrelative.LowPart,
0x10,
4);
HalpP9CoprocPhysicalAddress.LowPart = PCI_MEMORY_PHYSICAL_BASE + busrelative.LowPart;
HalpP9FramebufPhysicalAddress.LowPart = HalpP9CoprocPhysicalAddress.LowPart +
P9100_FRAMEBUF_OFFSET;
ASSERT((HalpP9CoprocPhysicalAddress.LowPart != (ULONG)NULL));
ASSERT((HalpP9FramebufPhysicalAddress.LowPart != (ULONG)NULL));
ASSERT((HalpP9SlotNumber != 0));
HalpVideoMemoryBase = MmMapIoSpace(HalpP9FramebufPhysicalAddress,
0x200000,
FALSE);
HalpVideoCoprocBase = MmMapIoSpace(HalpP9CoprocPhysicalAddress,
0x10000,
FALSE);
}
HalpHorizontalResolution = 640;
HalpVerticalResolution = 480;
//
// Set the video mode to 640x480, 8bits, palette enabled, 60Hz
//
VLEnableP91();
// IBM_JACOBO
// The following section sets the palette so that the HAL writes
// white characters on a blue background. It insures this by setting
// half of the 256-color palette to blue and the other half to white.
//
// ... and now for a little black magic lifted from the ROS/IPL code
throwaway += P9_RD_REG(P91_PU_CONFIG);
throwaway += P9_WR_FB(0x00000200); /* hw bug */
P9_WR_REG(P9100_PalCurRamW ,0x00000000); /* point at beginning of table */
throwaway += P9_RD_REG(P91_PU_CONFIG); /* ensure 5 clocks between DAC accesses */
// Create a 256 color palette. The top half of the colors should all be white
// and the bottom half should all be blue.
for (i = 0; i < 128; i++) {
colors[i].red = 0;
colors[i].green = 0;
colors[i].blue = (char)0x7F;
}
for (i = 128; i < 256; i++) {
colors[i].red = (char)0xFF;
colors[i].green = (char)0xFF;
colors[i].blue = (char)0xFF;
}
pData = (char*)colors;
for (curDACIndex = 0;curDACIndex<(256*3);curDACIndex++){
ucpdata = *pData++;
pdata = (ULONG) ucpdata;
throwaway += P9_WR_FB(0x00000200); /* hw bug */
P9_WR_REG(P9100_PalData,(pdata<< 24 | pdata<<16 | pdata << 8 | pdata));
throwaway += P9_RD_REG(P91_PU_CONFIG); /* ensure 5 clocks between DAC accesses */
}
throwaway += P9_WR_FB(0x00000200); /* hw bug */
P9_WR_REG(P9100_PalCurRamR ,0x00000000);
throwaway += P9_RD_REG(P91_PU_CONFIG); /* ensure 5 clocks between DAC accesses */
/* Wait for Weitek controller not busy */
//IBMLAN Use font file from OS Loader
//
// Compute display variables using using HalpFontHeader which is
// initialized in HalpInitializeDisplay().
//
// N.B. The font information suppled by the OS Loader is used during phase
// 0 initialization. During phase 1 initialization, a pool buffer is
// allocated and the font information is copied from the OS Loader
// heap into pool.
//
// This means that font information is taken from the file VGAOEM.FON,
// which is put in memory by the OSLOADER.
//
//FontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile;
//HalpFontHeader = FontHeader;
HalpBytesPerRow = (HalpFontHeader->PixelWidth + 7) / 8;
HalpCharacterHeight = HalpFontHeader->PixelHeight;
HalpCharacterWidth = HalpFontHeader->PixelWidth;
//
// Compute character output display parameters.
//
HalpDisplayText =
HalpVerticalResolution / HalpCharacterHeight;
HalpScrollLine =
HalpHorizontalResolution * HalpCharacterHeight;
HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1);
HalpDisplayWidth =
HalpHorizontalResolution / HalpCharacterWidth;
//
// Set the video memory to address color one.
//
buffer = (PULONG)HalpVideoMemoryBase;
limit = (HalpHorizontalResolution *
HalpVerticalResolution) / sizeof(ULONG);
for (index = 0; index < limit; index += 1) {
*buffer++ = 0x01010101;
}
//
// Initialize the current display column, row, and ownership values.
//
HalpColumn = 0;
HalpRow = 0;
HalpDisplayOwnedByHal = TRUE;
return;
} //end of HalpDisplayPpcP91Setup
VOID
HalpDisplayCharacterP91 (
IN UCHAR Character
)
/*++
Routine Description:
This routine displays a character at the current x and y positions in
the frame buffer. If a newline is encountered, the frame buffer is
scrolled. If characters extend below the end of line, they are not
displayed.
Arguments:
Character - Supplies a character to be displayed.
Return Value:
None.
--*/
{
PUCHAR Destination;
PUCHAR Source;
ULONG Index;
//
// If the character is a newline, then scroll the screen up, blank the
// bottom line, and reset the x position.
//
if (Character == '\n') {
HalpColumn = 0;
if (HalpRow < (HalpDisplayText - 1)) {
HalpRow += 1;
} else {
//RtlMoveMemory((PVOID)P91_VIDEO_MEMORY_BASE,
// (PVOID)(P91_VIDEO_MEMORY_BASE + HalpScrollLineP9),
// HalpScrollLengthP9);
// Scroll up one line
Destination = HalpVideoMemoryBase;
Source = (PUCHAR) HalpVideoMemoryBase + HalpScrollLine;
for (Index = 0; Index < HalpScrollLength; Index++) {
*Destination++ = *Source++;
}
// Blue the bottom line
Destination = HalpVideoMemoryBase + HalpScrollLength;
for (Index = 0; Index < HalpScrollLine; Index += 1) {
*Destination++ = 1;
}
}
} else if (Character == '\r') {
HalpColumn = 0;
} else {
if ((Character < HalpFontHeader->FirstCharacter) ||
(Character > HalpFontHeader->LastCharacter)) {
Character = HalpFontHeader->DefaultCharacter;
}
Character -= HalpFontHeader->FirstCharacter;
HalpOutputCharacterP91((PUCHAR)HalpFontHeader + HalpFontHeader->Map[Character].Offset);
}
return;
}
VOID
HalpOutputCharacterP91(
IN PUCHAR Glyph
)
/*++
Routine Description:
This routine insert a set of pixels into the display at the current x
cursor position. If the current x cursor position is at the end of the
line, then a newline is displayed before the specified character.
This awful little chunk of code reads a font in the format that it
is stored in VGAOEM.FON and draws it onto the screen by iterating
over the pixels in the position of the cursor.
Arguments:
Character - Supplies a character to be displayed.
Return Value:
None.
--*/
{
PUCHAR Destination;
ULONG FontValue;
ULONG tmp;
ULONG I;
ULONG J;
//
// If the current x cursor position is at the end of the line, then
// output a line feed before displaying the character.
//
if (HalpColumn == HalpDisplayWidth) {
HalpDisplayCharacterP91('\n');
}
//
// Output the specified character and update the x cursor position.
//
Destination = (PUCHAR)(HalpVideoMemoryBase +
(HalpRow * HalpScrollLine) + (HalpColumn * HalpCharacterWidth));
for (I = 0; I < HalpCharacterHeight; I += 1) {
FontValue = 0;
for (J = 0; J < HalpBytesPerRow; J += 1) {
FontValue |= *(Glyph + (J * HalpCharacterHeight)) << (24 - (J * 8));
}
Glyph += 1;
for (J = 0; J < HalpCharacterWidth ; J += 1) {
if (FontValue >> 31 != 0) {
*Destination = 0xFF; //Make this pixel white
} else {
*Destination = 0x00; //Make it black
}
Destination++;
//*Destination++ = (FontValue >> 31) ^ 1;
FontValue <<= 1;
}
Destination +=
(HalpHorizontalResolution - HalpCharacterWidth);
}
HalpColumn += 1;
return;
}
VOID
VLEnableP91()
/*++
Routine Description:
Perform the OEM specific tasks necessary to enable P9100 Video. These
include memory mapping, setting the sync polarities, and enabling the
P9100 video output.
This has been lifted right out of the video miniport driver weitekp9.sys.
I cut it down to the point where it only does what is absolutely
necessary to for setting the screen to 640x480x8bit at 60Hz. -- Jake
Arguments:
Return Value:
None.
--*/
{
//USHORT usMemClkInUse;
//
// Enable native mode to: No RAMDAC shadowing, memory & I/O enabled.
//
UNMAP_FRAMEBUF_PHASE0;
MAP_PCI_CONFIG_PHASE0;
WriteP9ConfigRegister(P91_CONFIG_MODE, 0); // Native mode
UNMAP_PCI_CONFIG_PHASE0;
MAP_FRAMEBUF_PHASE0;
// Program MEMCLK
ProgramClockSynth(0x136f, TRUE, FALSE);
//
// Next setup the pixel clock frequency. We have to handle potential
// clock multiplicaiton by the RAMDAC. On the BT485 if the dotfreq
// is greater than the maximum clock freq then we will adjust the
// dot frequency to program the clock with.
//
//
// Program Pix clk
//
ProgramClockSynth(0x9d5, FALSE, TRUE);
//
// Determine size of Vram (ulFrameBufferSize)...
//
//
// For some reason we are calling P91SizeVideoMemory here, even
// though we've already done this in HwFindAdapter. In order
// to free the frame buffer, I have to remove this seemingly
// redundant call. Sizing the memory, did have the side effect
// of setting one of the coprocessor registers however, so I'll
// add code to do that here.
//
// Assume that we are working with a 2MB card for now...
//
// this simulates the side-effect of P91SizeVideoMemory
//
P9_WR_REG(P91_MEM_CONFIG, 0x00000005);
//
// Init system config & clipping registers...
//
P91_SysConf();
// Since I have deleted the device extention, all that was left
// of CalcP9100MemConfig was this call. It is probably just
// a side effect, but I am preserving it. -- Jake
ProgramClockSynth(4, TRUE, FALSE);
//
// Load the video timing registers...
//
P91_WriteTiming();
//
// Setup the RAMDAC to the current mode...
//
IBM525PointerOff();
IBM525SetMode();
//
// Setup MEMCONFIG and SRTCTL regs
//
SetupVideoBackend();
return;
} // End of VLEnableP91()
VOID
SetupVideoBackend()
{
// I have limited this function to write the values necessary for
// 640x480x256.
// This is taken from the miniport function of the same name. Look
// there for a complete explanation. -- Jake
P9_WR_REG(P91_MEM_CONFIG, 0xc818007d);
P9_WR_REG(P91_SRTCTL, 0x1a3);
P9_WR_REG(P91_SRTCTL2, P91_HSYNC_LOW_TRUE | P91_VSYNC_LOW_TRUE);
return;
} // End of SetupVideoBackend()
BOOLEAN
IBM525SetMode()
{
// This function is a simplified version of the one in the
// miniport. Look there for a good explanation -- Jake.
//
// Set the pixel read mask.
//
P9_WR_BYTE_REG(P9100_PIXELMASK, 0xff);
//
// Select the fast DAC slew rate for the sharpest pixels
//
WriteIBM525(RGB525_DAC_OPER, 0x02);
//
// Enable the 64-bit VRAM pixel port
//
WriteIBM525(RGB525_MISC_CTL1, 0x01);
WriteIBM525(RGB525_MISC_CTL2, 0x45);
//
// Select 8bpp
//
WriteIBM525(RGB525_MISC_CLOCK_CTL, 0x27);
WriteIBM525(RGB525_PIXEL_FORMAT, 0x03);
WriteIBM525(RGB525_8BPP_CTL, 0x00);
return(TRUE);
}
VOID
P91_WriteTiming()
{
ULONG ulValueRead, ulValueWritten;
ULONG ulHRZSR;
ULONG ulHRZBR;
ULONG ulHRZBF;
ULONG ulHRZT;
// These magic numbers come from watching the miniport set the screen to
// 640x480x256. -- Jake
ulHRZSR = 0xa;
ulHRZBR = 0xe;
ulHRZBF = 0x5e;
ulHRZT = 0x63;
//
// 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) 4;
do
{
P9_WR_REG(P91_VRTSR, ulValueWritten);
ulValueRead = (ULONG) P9_RD_REG(P91_VRTSR);
} while (ulValueRead != ulValueWritten);
ulValueWritten = (ULONG) 0x1c;
do
{
P9_WR_REG(P91_VRTBR, ulValueWritten);
ulValueRead = (ULONG) P9_RD_REG(P91_VRTBR);
} while (ulValueRead != ulValueWritten);
ulValueWritten = (ULONG) 0x1fc;
do
{
P9_WR_REG(P91_VRTBF, ulValueWritten);
ulValueRead = (ULONG) P9_RD_REG(P91_VRTBF);
} while (ulValueRead != ulValueWritten);
ulValueWritten = (ULONG) 0x20d;
do
{
P9_WR_REG(P91_VRTT, ulValueWritten);
ulValueRead = (ULONG) P9_RD_REG(P91_VRTT);
} while (ulValueRead != ulValueWritten);
return;
} // End of P91_WriteTimings()
VOID
P91_SysConf()
{
// This function taken and simplified from the miniport.
P9_WR_REG(P91_SYSCONFIG, 0x8563000); // send data to the register
//
// There are two sets of clipping registers. The first takes the
// horizontal diemnsion in pixels and the vertical dimension in
// scanlines.
//
P9_WR_REG(P91_DE_P_W_MIN, 0L);
P9_WR_REG(P91_DE_P_W_MAX, 0x27f1998);
//
// The second set takes the horizontal dimension in bytes and the
// vertical dimension in scanlines.
//
P9_WR_REG(P91_DE_B_W_MIN, 0L);
P9_WR_REG(P91_DE_B_W_MAX, 0x27f1998);
return;
} // End of P91_SysConf()
VOID
ProgramClockSynth(
USHORT usFrequency,
BOOLEAN bSetMemclk,
BOOLEAN bUseClockDoubler
)
{
ULONG clockstring; // IC designs pixel dot rate shift value
if ((!bSetMemclk))
{
Write525PLL(usFrequency);
//
// Set reference frequency to 5000 Mhz...
//
usFrequency = 5000;
}
else
{
usFrequency = 4975;
}
UNMAP_FRAMEBUF_PHASE0;
MAP_PCI_CONFIG_PHASE0;
if (bSetMemclk)
{
clockstring = 0x16fc91;
P91WriteICD(clockstring | IC_MREG); // Memclk
}
else
{
clockstring = 0x1c841;
P91WriteICD(clockstring | IC_REG2); // Pixclk
}
//
// Select custom frequency
//
Write9100FreqSel(ICD2061_EXTSEL9100);
UNMAP_PCI_CONFIG_PHASE0;
MAP_FRAMEBUF_PHASE0;
} // End of ProgramClockSynth()
VOID
WriteIBM525(
USHORT index,
UCHAR value
)
{
IBM525_WR_DAC(P9100_IBM525_INDEX_LOW, (UCHAR) (index & 0x00FF));
IBM525_WR_DAC(P9100_IBM525_INDEX_HIGH, (UCHAR) ((index & 0xFF00) >> 8));
IBM525_WR_DAC(P9100_IBM525_INDEX_DATA, (UCHAR) value);
(void) P9_RD_REG(P91_MEM_CONFIG); // Needed for timinig...
} // End of WriteIBM525()
UCHAR
ReadIBM525(
USHORT index
)
{
UCHAR j;
IBM525_WR_DAC(P9100_IBM525_INDEX_LOW, (UCHAR) (index & 0x00FF));
IBM525_WR_DAC(P9100_IBM525_INDEX_HIGH, (UCHAR) ((index & 0xFF00) >> 8));
IBM525_RD_DAC(P9100_IBM525_INDEX_DATA, j);
return(j);
} // End of ReadIBM525()
VOID
Write525PLL(
USHORT usFreq
)
/*++
Routine Description:
This function programs the IBM RGB525 Ramdac to generate and use the
specified frequency as its pixel clock frequency.
Arguments:
Frequency.
Return Value:
None.
--*/
{
USHORT usRoundedFreq;
USHORT usVCODivCount;
ULONG ulValue;
usRoundedFreq = 2525;
usVCODivCount = 36;
//
// Setup for writing to the PLL Reference Divider register.
//
//
// Program REFCLK to a fixed 50MHz.
//
WriteIBM525(RGB525_FIXED_PLL_REF_DIV, IBM525_PLLD_50MHZ);
//
// Set up for programming frequency register 9.
//
WriteIBM525(RGB525_F9, (UCHAR) (usVCODivCount));
//
// Program PLL Control Register 2.
//
WriteIBM525(RGB525_PLL_CTL2, IBM525_PLL2_F9_REG);
//
// Program PLL Control Register 1.
//
WriteIBM525(RGB525_PLL_CTL1, (IBM525_PLL1_REFCLK_INPUT |
IBM525_PLL1_INT_FS) );
//
// Program DAC Operation Register.
//
WriteIBM525(RGB525_DAC_OPER, IBM525_DO_DSR_FAST);
//
// Program Miscellaneous Control Register 1.
//
WriteIBM525(RGB525_MISC_CTL1, IBM525_MC1_VRAM_64_BITS);
//
// Program Miscellaneous Clock Control Register.
//
ulValue = ReadIBM525(RGB525_MISC_CLOCK_CTL);
//
// At 8 Bpp, divide the clock by 8.
//
ulValue |= IBM525_MCC_PLL_DIV_8 | IBM525_MCC_PLL_ENABLE;
WriteIBM525(RGB525_MISC_CLOCK_CTL,
(UCHAR) ulValue);
return;
} // End of Write525PLL()
VOID P91WriteICD(
ULONG data
)
/*++
Routine Description:
Program the ICD2061a Frequency Synthesizer.
Arguments:
HwDeviceExtension - Pointer to the miniport driver's device extension.
data - Data to be written.
Return Value:
None.
--*/
{
int i;
ULONG savestate;
//
// Note: We might have to disable interrupts to preclude the ICD's
// watchdog timer from expiring resulting in the ICD resetting to the
// idle state.
//
savestate = Read9100FreqSel();
//
// First, send the "Unlock sequence" to the clock chip.
// Raise the data bit and send 5 unlock bits.
//
Write9100FreqSel(ICD2061_DATA9100);
for (i = 0; i < 5; i++) // send at least 5 unlock bits
{
//
// Hold the data while lowering and raising the clock
//
Write9100FreqSel(ICD2061_DATA9100);
Write9100FreqSel( ICD2061_DATA9100 |
ICD2061_CLOCK9100);
}
//
// Then turn the data clock off and turn the clock on one more time...
//
Write9100FreqSel( 0);
Write9100FreqSel( ICD2061_CLOCK9100);
//
// Now send the start bit: Leave data off, adn lower the clock.
//
Write9100FreqSel( 0);
//
// Leave data off and raise the clock.
//
Write9100FreqSel( ICD2061_CLOCK9100);
//
// Localbus position for hacking bits out
// Next, send the 24 data bits.
//
for (i = 0; i < 24; i++)
{
//
// Leaving the clock high, raise the inverse of the data bit
//
Write9100FreqSel(
((~data << ICD2061_DATASHIFT9100) &
ICD2061_DATA9100) | ICD2061_CLOCK9100);
//
// Leaving the inverse data in place, lower the clock.
//
Write9100FreqSel(
(~data << ICD2061_DATASHIFT9100) & ICD2061_DATA9100);
//
// Leaving the clock low, rais the data bit.
//
Write9100FreqSel(
(data << ICD2061_DATASHIFT9100) & ICD2061_DATA9100);
//
// Leaving the data bit in place, raise the clock.
//
Write9100FreqSel(
((data << ICD2061_DATASHIFT9100) & ICD2061_DATA9100)
| ICD2061_CLOCK9100);
data >>= 1; // get the next bit of the data
}
//
// Leaving the clock high, raise the data bit.
//
Write9100FreqSel(
ICD2061_CLOCK9100 | ICD2061_DATA9100);
//
// Leaving the data high, drop the clock low, then high again.
//
Write9100FreqSel( ICD2061_DATA9100);
Write9100FreqSel(
ICD2061_CLOCK9100 | ICD2061_DATA9100);
//
// Note: if interrupts were disabled, enable them here.
// before restoring the
// original value or the ICD
// will freak out.
Write9100FreqSel( savestate); // restore orig register value
return;
} // End of WriteICD()
VOID
Write9100FreqSel(
ULONG cs
)
/*++
Routine Description:
Write to the P9100 clock select register preserving the video coprocessor
enable bit.
Statically:
Bits [1:0] go to frequency select
Dynamically:
Bit 1: data
Bit 0: clock
Arguments:
Clock select value to write.
Return Value:
None.
--*/
{
//
// Set the frequency select bits in the P9100 configuration
//
WriteP9ConfigRegister(P91_CONFIG_CKSEL,
(UCHAR) ((cs << 2)));
return;
} // End of Write9100FreqSel()
ULONG
Read9100FreqSel()
{
return((ULONG)(ReadP9ConfigRegister(P91_CONFIG_CKSEL)
>> 2) & 0x03);
} // End of Read9100FreqSel()
VOID
WriteP9ConfigRegister(
UCHAR index,
UCHAR value
)
{
if (HalpInitPhase == 0) {
HalpPhase0SetPciDataByOffset(HalpP9BusNumber,
HalpP9SlotNumber,
&value,
index,
1);
}
else {
HalSetBusDataByOffset(PCIConfiguration,
HalpP9BusNumber,
HalpP9SlotNumber,
&value,
index,
1);
}
}
UCHAR
ReadP9ConfigRegister(
UCHAR index
)
{
UCHAR retval;
if (HalpInitPhase == 0) {
HalpPhase0GetPciDataByOffset(HalpP9BusNumber,
HalpP9SlotNumber,
&retval,
index,
1);
}
else {
HalGetBusDataByOffset(PCIConfiguration,
HalpP9BusNumber,
HalpP9SlotNumber,
&retval,
index,
1);
}
return ( retval );
}
VOID
IBM525PointerOff(
)
/*++
Routine Description:
Turn off the hardware cursor.
Arguments:
Return Value:
None.
--*/
{
//
// Turn the cursor off only if it was enabled.
//
if (CURS_IS_ON_IBM525())
{
CURS_OFF_IBM525();
}
return;
}