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.
 
 
 
 
 
 

1475 lines
40 KiB

#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/ddk351/src/hal/halsni4x/mips/RCS/snidisp.c,v 1.3 1995/10/06 09:43:09 flo Exp $")
/*++
Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG
Copyright (c) 1991-93 Microsoft Corporation
Module Name:
SNIdisp.c
Abstract:
This module implements the HAL display initialization and output routines
for the different SNI machines.
Because we have no full working Configuration management (yet), we try to
identitify some graphic boards ourself.
CHANGE CHANGE CHANGE now we have a working display configuration entry
Thanx to Mr. Pierre Sanguard, the firmware people from SNI France (Plaisir)
At the moment we know about the following boards:
P9000 based Cards: Orchid P9000 VLB / Diamond Viper
Standard S3 based ISA/VLB cards ( 80x50 Alpha Mode)
Standard Cirrus ISA/VLB cards ( 80x50 Alpha Mode)
Standard (unknown) VGA on ISA/VLB( 80x50 Alpha Mode)
If we can not identify the board, we don't initialise the display and we call
the vendor printf to display strings.
At the boot phase all I/O is done via the unmapped uncached Segment (KSEG1) of the
R4000 (HalpEisaControlBase); later with the mapped value of HalpEisaControlBase
Memory is always accessed via unmapped/uncached (KSEG1) area
Environment:
Kernel mode
Revision History:
Removed HalpInitializeDisplay1, because we do no longer use the P9000 in graphic mode ...
NOTE:
We did use our own ...MoveMemory() instead of RtlMoveMemory(),
as there is a Hardware bug in our machine and RtlMoveMemory uses
the floating point registers for fast 64 bit move and on our bus
only 32 bit can be found ... :-)
--*/
#include "halp.h"
#include "string.h"
#include "vgadata.h"
#define MEGA_MOVE_MEMORY(D,S,L) MegaMoveMemory(D,S,L) // orig. RtlMoveMemory()
//
// supported VGA text modi
//
typedef enum _TEXT_MODE {
TEXT_80x50,
TEXT_132x50
} TEXT_MODE;
//
// Define forward referenced procedure prototypes.
//
BOOLEAN ICD2061LoadClockgen (PUCHAR port, ULONG data, LONG bitpos);
BOOLEAN Bt485InitRamdac (VOID);
LONG ICD2061CalcClockgen (LONG freq);
VOID HalpDisplaySmallCharacter (IN UCHAR Character);
VOID HalpOutputSmallCharacter (IN PUCHAR Font);
VOID HalpInitializeVGADisplay(TEXT_MODE TextMode);
VOID HalpClearVGADisplay (VOID);
VOID HalpDisplayVGAString (PUCHAR String);
VOID HalpPutVGACharacter (UCHAR Character);
VOID HalpNextVGALine (VOID);
VOID HalpScrollVGADisplay (VOID);
VOID DownLoadVGAFont (VOID);
VOID HalpResetS3Chip (VOID);
VOID HalpResetCirrusChip (VOID);
VOID HalpResetP9000 (VOID);
VOID HalpResetP9100 (VOID);
VOID HalpVGASetup (VOID);
VOID HalpDoNoSetup (VOID);
typedef
VOID
(*PHALP_CONTROLLER_SETUP) (
VOID
);
//
// Supported board definitions.
//
typedef enum _VIDEO_BOARD {
P9000_RM400 = 0, // SNI specific Video Board for the RM400-10
P9000_ORCHID, // Orchid P9000 VLB (Vesa Local Bus)
P9000_VIPER, // Diamond Viper (Vesa Local Bus P9000)
S3_GENERIC, // Standard S3 based Card (miro crystal 8s)
S3_GENERIC_VLB, // Standard S3 based Card (Local Bus)
CIRRUS_GENERIC, // Generic Cirrus VGA (Cirrus CL54xx)
CIRRUS_GENERIC_VLB, // Generic Cirrus VGA (Cirrus CL54xx) (Local Bus)
CIRRUS_ONBOARD, // The Desktop onboard VGA (Cirrus CL5434)
VGA_GENERIC, // generic (unknown) VGA
VGA_GENERIC_VLB, // generic (unknown) VGA on the Vesa Local BUS
P9100_WEITEK, // Diamond (Vesa Local Bus P9100)
VIDEO_BOARD_UNKNOWN // unknown Display Adapter
} VIDEO_BOARD;
//
// some supported VGA chips
//
typedef enum _VIDEO_CHIP {
P9000 = 0,
S3,
CIRRUS,
VGA, // generic (unknown) VGA
VGA_P9000,
VGA_P9100,
VIDEO_CHIP_UNKNOWN
} VIDEO_CHIP;
typedef struct _VIDEO_BOARD_INFO {
PUCHAR FirmwareString;
PHALP_CONTROLLER_SETUP ControllerSetup;
VIDEO_BOARD VideoBoard;
VIDEO_CHIP VideoChip;
} VIDEO_BOARD_INFO, *PVIDEO_BOARD_INFO;
VIDEO_BOARD_INFO KnownVideoBoards[] = {
{"ORCHID P9000 VLBUS", HalpVGASetup , P9000_ORCHID , VGA_P9000 },
{"DIAMOND P9000 VLBUS", HalpVGASetup , P9000_VIPER , VGA_P9000 },
{"VGA ON ATBUS", HalpVGASetup , VGA_GENERIC , VGA },
{"S3 BASED VLBUS", HalpVGASetup , S3_GENERIC_VLB, S3 },
{"CIRRUS BASED VLBUS", HalpVGASetup , CIRRUS_GENERIC_VLB, CIRRUS},
{"CIRRUS ON BOARD", HalpVGASetup , CIRRUS_ONBOARD, CIRRUS},
{"CIRRUS ONBOARD", HalpVGASetup , CIRRUS_ONBOARD, CIRRUS},
{"VGA ON VLBUS", HalpVGASetup , VGA_GENERIC_VLB, VGA },
{"DIAMOND P9100 VLBUS", HalpVGASetup , P9100_WEITEK , VGA_P9100 }
};
LONG numVideoBoards = sizeof (KnownVideoBoards) / sizeof(VIDEO_BOARD_INFO);
//
// Define static data.
//
VIDEO_BOARD HalpVideoBoard = VIDEO_BOARD_UNKNOWN;
VIDEO_CHIP HalpVideoChip = VIDEO_CHIP_UNKNOWN;
PHALP_CONTROLLER_SETUP HalpDisplayControllerSetup = HalpDoNoSetup;
ULONG HalpColumn;
ULONG HalpRow;
ULONG HalpDisplayText;
ULONG HalpDisplayWidth;
ULONG HalpScrollLength;
ULONG HalpScrollLine;
ULONG HalpBytesPerRow;
PVOID HalpVGAControlBase=( PVOID)( EISA_IO); // Base Address for VGA register access
PUSHORT VideoBuffer = ( PUSHORT)( EISA_MEMORY_BASE + 0xb8000);
PUCHAR FontBuffer = ( PUCHAR )( EISA_MEMORY_BASE + 0xa0000);
BOOLEAN HalpFirstBoot = TRUE;
//
// Declare externally defined data.
//
BOOLEAN HalpDisplayOwnedByHal;
//
// Put all code for HAL initialization in the INIT section. It will be
// deallocated by memory management when phase 1 initialization is
// completed.
//
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(INIT, HalpInitializeDisplay0)
#pragma alloc_text(INIT, HalpInitializeDisplay1)
#endif
VOID MegaMoveMemory(
OUT PVOID Destination,
IN PVOID Source,
IN ULONG Length
)
/*++
Our private function written to substitute the RtlMoveMemory()
function (64 bit problem).
--*/
{
ULONG lo_index_ul;
PULONG Dst, Src;
Dst = (PULONG)Destination;
Src = (PULONG)Source;
for (lo_index_ul=0; lo_index_ul < Length/sizeof(ULONG); lo_index_ul++)
*Dst++ = *Src++;
}
BOOLEAN
HalpInitializeDisplay0 (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine maps the video memory and control registers into the user
part of the idle process address space, initializes the video control
registers, and clears the video screen.
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
Return Value:
If the initialization is successfully completed, than a value of TRUE
is returned. Otherwise, a value of FALSE is returned.
--*/
{
PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
PVIDEO_BOARD_INFO VideoBoard;
LONG Index;
ULONG MatchKey;
//
// Find the configuration entry for the first display controller.
//
MatchKey = 0;
ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
ControllerClass,
DisplayController,
&MatchKey);
if (ConfigurationEntry == NULL) {
return FALSE;
}
//
// Determine which video controller is present in the system.
// N.B. Be carefull with debug prints during Phase 0, it
// will kill the initial break point request from the debugger ...
//
for( Index=0, VideoBoard = KnownVideoBoards; Index < numVideoBoards; Index++, VideoBoard++) {
if (!strcmp( ConfigurationEntry->ComponentEntry.Identifier,
VideoBoard->FirmwareString
)) {
HalpVideoBoard = VideoBoard->VideoBoard;
HalpVideoChip = VideoBoard->VideoChip;
HalpDisplayControllerSetup = VideoBoard->ControllerSetup;
break;
}
}
if (Index >= numVideoBoards) {
HalpVideoBoard = VIDEO_BOARD_UNKNOWN;
HalpVideoChip = VIDEO_CHIP_UNKNOWN;
HalpDisplayControllerSetup = HalpDoNoSetup;
//
// let's see, if the bios emulator can initialize the card ....
//
HalpDisplayWidth = 80;
HalpDisplayText = 25;
return TRUE;
}
//
// Initialize the display controller.
//
HalpDisplayControllerSetup();
HalpFirstBoot = FALSE;
return TRUE;
}
BOOLEAN
HalpInitializeDisplay1 (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This routine normally allocates pool for the OEM font file, but
in this version we use only VGA facilities of the Grapgic boards
so we simply return TRUE
Arguments:
LoaderBlock - Supplies a pointer to the loader parameter block.
Return Value:
TRUE
--*/
{
return TRUE;
}
VOID
HalAcquireDisplayOwnership (
IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
/*++
Routine Description:
This routine switches ownership of the display away from the HAL to
the system display driver. It is called when the system has reached
a point during bootstrap where it is self supporting and can output
its own messages. Once ownership has passed to the system display
driver any attempts to output messages using HalDisplayString must
result in ownership of the display reverting to the HAL and the
display hardware reinitialized for use by the HAL.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Set HAL ownership of the display to false.
//
HalpDisplayOwnedByHal = FALSE;
return;
}
VOID
HalpDoNoSetup(
VOID
)
/*++
Routine Description:
This routine does nothing...
Arguments:
None.
Return Value:
None.
--*/
{
HalpDisplayOwnedByHal = TRUE;
return;
}
VOID
HalpVGASetup(
VOID
)
/*++
Routine Description:
This routine initializes a VGA based Graphic card
Arguments:
None.
Return Value:
None.
--*/
{
UCHAR byte;
switch (HalpVideoBoard){
case S3_GENERIC_VLB:
case CIRRUS_GENERIC_VLB:
case VGA_GENERIC_VLB:
case P9100_WEITEK:
//
// N.B.
// on an SNI desktop model the VL I/O space is transparent, so
// acces in the normal Backplane area results in correct values
// the minitower instead, does not decode all VL signals correct,
// so ther is an EXTRA I/O space for accessing VL I/O (0x1exxxxxx)
// this is handled in the definition of VESA_IO in SNIdef.h
//
HalpVGAControlBase = (HalpIsRM200) ? (PVOID)HalpEisaControlBase : (PVOID)VESA_IO;
VideoBuffer = ( PUSHORT)( VESA_BUS + 0xb8000);
FontBuffer = ( PUCHAR )( VESA_BUS + 0xa0000);
break;
case CIRRUS_ONBOARD:
HalpVGAControlBase = (PVOID)HalpOnboardControlBase;
VideoBuffer = ( PUSHORT)( RM200_ONBOARD_MEMORY + 0xb8000);
FontBuffer = ( PUCHAR )( RM200_ONBOARD_MEMORY + 0xa0000);
break;
case S3_GENERIC:
case CIRRUS_GENERIC:
case VGA_GENERIC:
default:
HalpVGAControlBase = (PVOID)HalpEisaControlBase;
VideoBuffer = ( PUSHORT)( EISA_MEMORY_BASE + 0xb8000);
FontBuffer = ( PUCHAR )( EISA_MEMORY_BASE + 0xa0000);
break;
}
//
// if "only" VGA is detected look for an S3 or cirrus chip (VGA ON ATBUS)
// if the firmware detects an S3 chip, look if this is an 805i (interleave)
//
if ((HalpVideoChip == VGA) || (HalpVideoChip == S3)){
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x1206); // look for Cirrus chips
byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA); // read it back
if (byte != 0x12) { // no cirrus
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x4838); // unlock the S3 regs
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa539); // Unlock the SC regs
WRITE_REGISTER_UCHAR(VGA_CRT_IDX, 0x30); // look for s3 chip id
byte = READ_REGISTER_UCHAR(VGA_CRT_DATA) ; // look only for major id
switch (byte & 0xf0){
case 0xa0: // 801/805 chipset
if (byte == 0xa8) { // the new 805i (interleave)
// DebugPrint(("HAL: Found the new 805i Chip resetting to 805 mode\n"));
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0053);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0067);
}
case 0x80:
case 0x90:
// DebugPrint(("HAL: Found S3 Chip set - Chip id 0x%x\n",byte));
HalpVideoChip = S3;
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0038); // lock s3 regs
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0039); // lock more s3 regs
break;
default: DebugPrint(("HAL: This seems to be no S3 Chip\n"));
}
} else { // this may be an cirrus
WRITE_REGISTER_UCHAR(VGA_CRT_IDX, 0x27); // cirrus id reg
byte = READ_REGISTER_UCHAR(VGA_CRT_DATA);
if ((byte & 0xe0) == 0x80) { // look for 100xxxxx
// DebugPrint(("HAL: Found Cirrus Chip set - Chip id 0x%x\n",byte));
HalpVideoChip = CIRRUS;
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0006); // lock Cirrus extensions
}
}
}
switch (HalpVideoChip) {
case VGA_P9000:
HalpResetP9000();
//
// we have programmed the clock into register 0 of the ICD2061, so
// select it via the VGA_MISC register
//
// WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0xa3);
break;
case S3: HalpResetS3Chip();
break;
case CIRRUS: HalpResetCirrusChip();
break;
case VGA_P9100:
HalpResetP9100();
break;
default: ;
}
HalpInitializeVGADisplay(TEXT_80x50);
//
// Initialize the current display column, row, and ownership values.
//
HalpColumn = 0;
HalpRow = 0;
HalpDisplayOwnedByHal = TRUE;
return;
}
VOID
HalQueryDisplayParameters (
OUT PULONG WidthInCharacters,
OUT PULONG HeightInLines,
OUT PULONG CursorColumn,
OUT PULONG CursorRow
)
/*++
Routine Description:
This routine return information about the display area and current
cursor position.
Arguments:
WidthInCharacter - Supplies a pointer to a varible that receives
the width of the display area in characters.
HeightInLines - Supplies a pointer to a variable that receives the
height of the display area in lines.
CursorColumn - Supplies a pointer to a variable that receives the
current display column position.
CursorRow - Supplies a pointer to a variable that receives the
current display row position.
Return Value:
None.
--*/
{
//
// Set the display parameter values and return.
//
*WidthInCharacters = HalpDisplayWidth;
*HeightInLines = HalpDisplayText;
*CursorColumn = HalpColumn;
*CursorRow = HalpRow;
return;
}
VOID
HalSetDisplayParameters (
IN ULONG CursorColumn,
IN ULONG CursorRow
)
/*++
Routine Description:
This routine set the current cursor position on the display area.
Arguments:
CursorColumn - Supplies the new display column position.
CursorRow - Supplies a the new display row position.
Return Value:
None.
--*/
{
//
// Set the display parameter values and return.
//
if (CursorColumn > HalpDisplayWidth) {
CursorColumn = HalpDisplayWidth;
}
if (CursorRow > HalpDisplayText) {
CursorRow = HalpDisplayText;
}
HalpColumn = CursorColumn;
HalpRow = CursorRow;
return;
}
VOID
HalDisplayString (
PUCHAR String
)
/*++
Routine Description:
This routine displays a character string on the display screen.
Arguments:
String - Supplies a pointer to the characters that are to be displayed.
Return Value:
None.
--*/
{
KIRQL OldIrql;
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
if(HalpIsMulti) KiAcquireSpinLock(&HalpDisplayAdapterLock);
//
// If ownership of the display has been switched to the system display
// driver, then reinitialize the display controller and revert ownership
// to the HAL.
//
if (HalpDisplayOwnedByHal == FALSE) {
HalpDisplayControllerSetup();
}
// display the string
if( HalpVideoChip == VIDEO_CHIP_UNKNOWN) {
((SNI_PRIVATE_VECTOR *)(SYSTEM_BLOCK->VendorVector))->printf(String);
} else {
HalpDisplayVGAString(String);
}
if(HalpIsMulti) KiReleaseSpinLock(&HalpDisplayAdapterLock);
KeLowerIrql(OldIrql);
return;
}
VOID
HalpDisplayVGAString (
PUCHAR String
)
{
while (*String) {
switch (*String) {
case '\n':
HalpNextVGALine();
break;
case '\r':
HalpColumn = 0;
break;
default:
HalpPutVGACharacter(*String);
if (++HalpColumn == HalpDisplayWidth) {
HalpNextVGALine();
}
}
++String;
}
return;
}
VOID
HalpNextVGALine(
VOID
)
{
if (HalpRow==HalpDisplayText-1) {
HalpScrollVGADisplay();
} else {
++HalpRow;
}
HalpColumn = 0;
}
VOID
HalpScrollVGADisplay(
VOID
)
/*++
Routine Description:
Scrolls the text on the display up one line.
Arguments:
None
Return Value:
None.
--*/
{
PUSHORT NewStart;
ULONG i;
NewStart = VideoBuffer+HalpDisplayWidth;
MegaMoveMemory((PVOID)VideoBuffer, (PVOID)NewStart, (HalpDisplayText-1)*HalpDisplayWidth*sizeof(USHORT));
for (i=(HalpDisplayText-1)*HalpDisplayWidth; i<HalpDisplayText*HalpDisplayWidth; i++) {
VideoBuffer[i] = (REVERSE_ATTRIBUTE << 8) | ' ';
}
}
VOID
HalpPutVGACharacter(
UCHAR Character
)
{
PUSHORT cp = (PUSHORT)VideoBuffer;
int x = HalpColumn;
int y = HalpRow;
cp[y*HalpDisplayWidth + x] = (USHORT)((REVERSE_ATTRIBUTE << 8) | (Character ));
}
VOID
HalpClearVGADisplay(
VOID
)
{
ULONG i;
PUSHORT cp = (PUSHORT)VideoBuffer;
USHORT Attribute = (REVERSE_ATTRIBUTE << 8) | ' ';
for(i=0; i < HalpDisplayText*HalpDisplayWidth; i++) {
VideoBuffer[i] = Attribute;
}
HalpColumn=0;
HalpColumn=0;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HARDWARE specific Part of Display routines
this part of this file deals with special Hardware parts of some
graphic adapters (RamDac, Clock Generator, VGA Chipsets etc.
-------------------------------------------------------------------*/
VOID
DownLoadVGAFont(
VOID
)
/*+++
The Space occupied for 1 caracter in the charackter generator memory of an VGA
is 0x20 bytes, The font itself uses only 8 bytes, so we skip over the difference
---*/
{
PUCHAR dst = (PUCHAR)FontBuffer;
PUCHAR src = (PUCHAR)font_8x8;
long i, count = 256;
INIT_VGA_FONT();
while(count--){
for (i=0; i<8; i++)
*dst++ = *src++;
dst += 0x18;
}
EXIT_VGA_FONT() ;
}
VOID
HalpInitializeVGADisplay(
TEXT_MODE TextMode
)
{
static UCHAR _80x50_crt_regs [MAX_CRT] = { // 80x50 text mode
0x5f, 0x4f, 0x50, 0x82, 0x55, // cr0 - cr4
0x81, 0xBF, 0x1f, 0x0, 0x47, // cr9 - 7 lines per char
0x20, 0x00, 0x00, 0x00, 0x00, // cra - cursor off
0x00, 0x9c, 0x8e, 0x8f, 0x28,
0x1f, 0x96, 0xb9, 0xa3, 0xff
};
static UCHAR _132x50_crt_regs [MAX_CRT] = { // 132x50 text mode
0xa0, 0x83, 0x84, 0x83, 0x8a, // cr0 - cr4
0x9e, 0xBF, 0x1f, 0x0, 0x47, // cr9 - 7 lines per char
0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x9c, 0x85, 0x8f, 0x42,
0x1f, 0x95, 0xa5, 0xa3, 0xff
};
static UCHAR default_graph_regs[GRAPH_MAX] =
{
0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x0e, 0x00, 0xff
};
static UCHAR default_pal_regs[MAX_PALETTE] = {
0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x14, 0x7, 0x38, 0x39,
0x3A, 0x3B, 0x3C, 0x3d, 0x3e,
0x3f, 0x08, 0x00, 0x0f, 0x00,
0x00
};
int i;
UCHAR byte;
// reset ATC FlipFlop
byte = READ_REGISTER_UCHAR(VGA_ATC_FF);
WRITE_REGISTER_UCHAR(VGA_ATC_DATA, 0); // Disable palette
// stop the sequencer
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0100);
if (TextMode == TEXT_132x50) {
// external clock (40MHz)
WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0xAF);
} else {
// COLOR registers , enable RAM, 25 MHz (???) 400 Lines,
if (HalpVideoChip == VGA_P9100) {
WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // 28.322 Mhz
} else {
WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x63) ; // 25,175 MHz (don't use with P9100).
}
}
// Select the timing sequencer values
// 8 dot/char
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0101);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0302);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0003);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0204);
// start the sequencer
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0300);
// Unprotect CRT regs and program them
WRITE_REGISTER_USHORT(VGA_CRT_IDX , 0x0011);
for(i=0; i<MAX_CRT; i++) {
WRITE_REGISTER_UCHAR(VGA_CRT_IDX, i);
if (TextMode == TEXT_132x50){
WRITE_REGISTER_UCHAR(VGA_CRT_DATA, _132x50_crt_regs[i]);
} else {
WRITE_REGISTER_UCHAR(VGA_CRT_DATA, _80x50_crt_regs[i]);
}
}
DownLoadVGAFont();
HalpDisplayWidth = (TextMode == TEXT_132x50) ? 132 : 80;
HalpDisplayText = 50;
HalpClearVGADisplay();
i = READ_REGISTER_UCHAR(VGA_ATC_FF); // Reset attr FF
if (!HalpFirstBoot) {
//
// if this is not the First Boot
// i.e. an Bugcheck; we have to setup
// the Attribute and colors of the VGA PART
//
for(i=0; i<GRAPH_MAX; i++) {
WRITE_REGISTER_UCHAR(VGA_GRAPH_IDX , i);
WRITE_REGISTER_UCHAR(VGA_GRAPH_DATA, default_graph_regs[i]);
}
for(i=0; i<MAX_PALETTE; i++) { // PALETTE (ATC)
WRITE_REGISTER_UCHAR(VGA_ATC_IDX , i);
WRITE_REGISTER_UCHAR(VGA_ATC_DATA, default_pal_regs[i]);
}
}
WRITE_REGISTER_UCHAR(VGA_DAC_MASK , 0xff);
//
// set the 16 base colors for text mode in the DAC
//
WRITE_REGISTER_UCHAR(VGA_DAC_WRITE_INDEX, 0x00);
for(i=0; i<48; i++) {
WRITE_REGISTER_UCHAR(VGA_DAC_DATA, base_colors[i]);
}
WRITE_REGISTER_UCHAR(VGA_ATC_IDX, 0x20);
WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen on
byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA);
WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte & 0xdf)); // in the sequencer
}
VOID
HalpResetP9100(
VOID
)
/*++
Routine Description:
This routine initializes the VGA part of an Orchid P9000VLB or Diamond Viper card
Arguments:
None.
Return Value:
None.
--*/
{
LONG IcdVal;
int i;
//
// First, reprogram register broken by the p9100 driver
//
switch (HalpMainBoard) {
case M8036:
WRITE_REGISTER_UCHAR (0xbfcc0000, 0x00); // RM200
break;
case M8042 :
WRITE_REGISTER_UCHAR (0xbc010000, 0xff); // RM400 MT
break;
case M8032 :
WRITE_REGISTER_UCHAR (0xbc0c0000, 0xff); // RM400 T
break;
}
//
// unlock and disable the P9000 on the board
//
WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x11);
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00); // unlock extended SEQ reg
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x12); // select extended reg 0x12
if (HalpVideoBoard == P9000_ORCHID) {
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x08);
} else {
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x88);
}
//
// init the clock generator, we use use the 80x50 Text mode
// so we need a 25.175Mhz clock
//
// if(( IcdVal = ICD2061CalcClockgen(25175)) == -1){
// DebugPrint(("HAL: Error calculating ICD Value for 25.175Mhz\n"));
// }
// byte = READ_REGISTER_UCHAR((PUCHAR) VGA_MISC_WRITE);
IcdVal = 0x7170a0;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
IcdVal = 0x01a8bc;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
IcdVal = 0x2560ac;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
IcdVal = 0x4560ac;ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
// WRITE_REGISTER_UCHAR((PUCHAR) VGA_MISC_WRITE,byte);
WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // 28.322 Mhz - crt ad = 3dx
//
// if this is the first initialisation i.e. Systemboot,
// the firmware has initialized the VGA part properly
//
if (HalpFirstBoot) return;
WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_CONFIG_REG); // enable VGA
WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x02);
WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_COMMAND_REG); // enable I/O space - ctl VGA palette snoop
WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x83);
WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_MEM_BASE_ADDR_REG); // why not...
WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x00);
// init ramdac (bug workaround + other unknown things...)
WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_CONFIG_REG); // enable VGA
WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x00);
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x90909090);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x03030303);
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x70707070);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x40404040);
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x0a0a0a0a);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x02020202);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x40404040);
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x71717171);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x40404040);
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x71717171);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x02020202);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x01010101);
for(i=2;i <= 0x72; ++i) {
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x00000000);
}
WRITE_REGISTER_ULONG( P9100_RAMDAC_HIGH_ADDR, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_CTRL, 0x00000000);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x02020202);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x01010101);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x0a0a0a0a);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x03030303);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x14141414);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x0e0e0e0e);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x20202020);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x24242424);
WRITE_REGISTER_ULONG( P9100_RAMDAC_LOW_ADDR, 0x21212121);
WRITE_REGISTER_ULONG( P9100_RAMDAC_DATA, 0x30303030);
WRITE_REGISTER_UCHAR( P9100_CFG_IDX, P9100_CONFIG_REG); // enable VGA
WRITE_REGISTER_UCHAR( P9100_CFG_DATA, 0x02);
WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x67) ; // 28.322 Mhz - crt ad = 3dx
}
VOID
HalpResetP9000(
VOID
)
/*++
Routine Description:
This routine initializes the VGA part of an Orchid P9000VLB or Diamond Viper card
Arguments:
None.
Return Value:
None.
--*/
{
LONG IcdVal;
//
// unlock and disable the P9000 on the board
//
WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x11);
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00); // unlock extended SEQ reg
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA,0x00);
WRITE_REGISTER_UCHAR (VGA_SEQ_IDX, 0x12); // select extended reg 0x12
if (HalpVideoBoard == P9000_ORCHID) {
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x08);
} else {
WRITE_REGISTER_UCHAR (VGA_SEQ_DATA, 0x88);
}
//
// init the clock generator, we use use the 80x50 Text mode
// so we need a 25.175Mhz clock
//
if(( IcdVal = ICD2061CalcClockgen(25175)) == -1){
DebugPrint(("HAL: Error calculating ICD Value for 25.175Mhz\n"));
}
ICD2061LoadClockgen((PUCHAR) VGA_MISC_WRITE , IcdVal, 2);
//
// if this is the first initialisation i.e. Systemboot,
// the firmware has initialized the VGA part properly
//
if (HalpFirstBoot) return;
//
// reset the RamDac (Bt485) to VGA mode, no clock doubler
//
WRITE_REGISTER_UCHAR( Bt485_CR0, 0xa0); // 6 bit operations, no sync on colors
WRITE_REGISTER_UCHAR( Bt485_CR1, 0x00); //
// WRITE_REGISTER_UCHAR( Bt485_CR1, 0x40); //
WRITE_REGISTER_UCHAR( Bt485_CR2, 0x00); // select VGA port
// enable CR3 via CR0
WRITE_REGISTER_UCHAR( Bt485_ADDR, 0x01);
WRITE_REGISTER_UCHAR( Bt485_CR3, 0x00); // disable clock multiplier
WRITE_REGISTER_UCHAR( Bt485_MASK, 0xff);
}
VOID
HalpResetS3Chip(
VOID
)
/*+++
This function resets/loads default values to the S3 Chip
extended registers
this code is borrowed/derived from the s3 miniport driver
---*/
{
UCHAR byte;
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x4838); // unlock the S3 regs
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa539); // Unlock the SC regs
WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen off
byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA);
WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte | 0x20)); // stop the sequencer
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0140); // Enable the enhanced 8514 registers
WRITE_REGISTER_USHORT(S3_ADVFUNC_CNTL, 0x02); // reset to normal VGA operation
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0032); // Backward Compat 3
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0035); // CRTC Lock
WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x00); // async reset
WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x01); //
WRITE_REGISTER_UCHAR(VGA_FEAT_CNTRL, 0x00); // normal sync
WRITE_REGISTER_UCHAR(VGA_MISC_READ, 0x00); //
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x8531);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x2033); // Backward Compat 2
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0034); // Backward Compat 3
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x853a); // S3 Misc 1
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x5a3b); // Data Transfer Exec Pos
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x103c); // Interlace Retrace start
WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x00); // start the sequencer
WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, 0x03); //
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa640); // VLB: 3Wait
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x1841);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0050);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0051);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff52);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0053);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x3854);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0055);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0056);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0057);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x8058); // ISA Latch ? (bit 3)
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x005c);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x005d);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x005e);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0760);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x8061);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xa162);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0043); // Extended Mode
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0045); // HW graphics Cursor Mode
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0046); // HW graphics Cursor Orig x
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff47); // HW graphics Cursor Orig x
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xfc48); // HW graphics Cursor Orig y
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff49); // HW graphics Cursor Orig y
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4a); // HW graphics Cursor Orig y
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4b); // HW graphics Cursor Orig y
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4c); // HW graphics Cursor Orig y
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4d); // HW graphics Cursor Orig y
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xff4e); // Dsp Start x pixel pos
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0xdf4f); // Dsp Start y pixel pos
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0042); // select default clock
WRITE_REGISTER_UCHAR(VGA_MISC_WRITE, 0x63); // Clock select
/*
// this should be done in the InitializeVGA code ...
WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen on
byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA);
WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte & 0xdf)); // in the sequencer
*/
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0038); // lock s3 regs
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x0039); // lock more s3 regs
}
VOID
HalpResetCirrusChip(
VOID
)
/*+++
This function resets/loads default values to the Cirrus Chip
extended registers for use with extended text mode (80x50)
Register values found in the cirrus manual, appendix D5
---*/
{
UCHAR byte;
WRITE_REGISTER_UCHAR(VGA_SEQ_IDX, 0x01); // Screen off
byte = READ_REGISTER_UCHAR(VGA_SEQ_DATA);
WRITE_REGISTER_UCHAR(VGA_SEQ_DATA, (byte | 0x20)); // stop the sequencer
// extended sequencer and crtc regs for cirrus
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x1206); // unlock the extended registers
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0007);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x4008);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x5709);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x180a);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x660b);
// new modifs
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x3b1b);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x000f);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0016);
WRITE_REGISTER_USHORT(VGA_CRT_IDX, 0x001b);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0007);
WRITE_REGISTER_USHORT(VGA_GRAPH_IDX, 0x0009);
WRITE_REGISTER_USHORT(VGA_GRAPH_IDX, 0x000a);
WRITE_REGISTER_USHORT(VGA_GRAPH_IDX, 0x000b);
// end new modifs
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0010);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0011);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0012);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0013);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0018);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x0119);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x001a);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x3b1b);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x2f1c);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x301d);
WRITE_REGISTER_USHORT(VGA_SEQ_IDX, 0x331e);
}
BOOLEAN
ICD2061LoadClockgen(
PUCHAR port,
ULONG data,
LONG bitpos
)
/*++
Routine Description:
The ICD2061LoadClockgen() routine.
This routine loads the ICD206x Clock Generator with the given data
The circuit is programmed serial over 2 data Lines lines; clock and data
On an Plaisir Graphics board clock bit is bit 0
data bit is bit 1
On most VGA with an ICD2061 the lines are connected over the VGA_MISC Register
clock bit is bit 2
data bit is bit 3
Arguments:
Arguments: the port for programming
the value
the BitPosition of the output port for clock and data line
Return Value:
TRUE on success
--*/
{
#define w_icd(x) WRITE_REGISTER_UCHAR(port, mask & (x))
ULONG tmp;
LONG i;
UCHAR mask = 0x3; // 00000011
UCHAR ck0 = 0x0; // Clock Bit = low
UCHAR ck1 = 0x1; // Clock Bit = high
UCHAR dat0 = 0x0; // Data Bit = low
UCHAR dat1 = 0x2; // Data Bit = high
ULONG shift = bitpos + 1; // Data bit
mask = mask << bitpos;
ck1 = ck1 << bitpos;
dat1 = dat1 << bitpos;
tmp = 0;
for (i=0; i<5; i++) {
w_icd(ck0 | dat1); // unlock bit 1-5
w_icd(ck1 | dat1);
}
w_icd(ck0 | dat0); // end of unlock sequence
w_icd(ck1 | dat0);
w_icd(ck0 | dat0); // start bit falling
w_icd(ck1 | dat0); // start bit rising
for (i=0; i<24; i++) { // write the 24 bits of data
w_icd(ck1 | (UCHAR)(((~data)&1)<<shift));
w_icd(ck0 | (UCHAR)(((~data)&1)<<shift));
w_icd(ck0 | (UCHAR)((data&1)<<shift));
w_icd(ck1 | (UCHAR)((data&1)<<shift));
data >>= 1;
}
w_icd(ck1 | dat1);
w_icd(ck0 | dat1); // stop bit
w_icd(ck1 | dat1); // stop bit
w_icd(0); // select REG0 video frequency
return (TRUE);
}
#undef w_icd
LONG
ICD2061CalcClockgen(
LONG freq
)
/*++
Routine Description:
The ICD2061CalcClockgen() routine.
This routine calculates the data for the ICD2062/ ICD2061 Clock Generator from the
given pixel frequency (in kHz).
The frequency in is kHz rather than MHz because the kernel does not support
floating point, and this routine had to be converted to integer.
Arguments:
requested frequency.
Return Value:
(-1), on error
the calculated data word, otherwise
--*/
{
int p, q, qlow, qhigh, bestp, bestq, mux, index;
int diff, bestdiff;
int fref = 14318;
int fvco, fcalc, qoverp;
// check that frequency is derivable
if (freq < 625) return (-1);
else if (freq < 1250) mux = 6;
else if (freq < 2500) mux = 5;
else if (freq < 5000) mux = 4;
else if (freq < 10000) mux = 3;
else if (freq < 20000) mux = 2;
else if (freq < 40000) mux = 1;
else if (freq < 160000) mux = 0;
else return (-1);
// calculate the index field
fvco = (1 << mux) * freq;
if (fvco < 40000) index = 0;
else if (fvco < 47500) index = 1;
else if (fvco < 52200) index = 2;
else if (fvco < 56300) index = 3;
else if (fvco < 61900) index = 4;
else if (fvco < 65000) index = 5;
else if (fvco < 68100) index = 6;
else if (fvco < 82300) index = 7;
else if (fvco < 86000) index = 8;
else if (fvco < 88000) index = 9;
else if (fvco < 90500) index = 10;
else if (fvco < 95000) index = 11;
else if (fvco < 100000) index = 12;
else index = 13;
qoverp = 1000 * 2 * fref / fvco;
qlow = (fref + 500)/1000;
qhigh = (fref * 5 - 500)/1000;
bestp = bestq = 0;
bestdiff = 10000;
for (p = 130; p >= 4; p--) {
q = (int)((qoverp * p + 500)/1000);
if ((q < qlow) || (q > qhigh)) continue;
fcalc = 2 * fref * p / q;
if (fcalc > fvco) diff = fcalc - fvco;
else diff = fvco - fcalc;
if (diff < bestdiff) {
bestdiff = diff;
bestp = p;
bestq = q;
}
}
if ((bestp == 0) || (bestq == 0)) return (-1);
return ( (index << 17) |
((~(130 - bestp) & 0x7f) << 10) |
(mux << 7) |
(~(129 - bestq) & 0x7f) );
}