|
|
//***************************************************************************
//
// Module Name:
//
// power.c
//
// Abstract:
// This module contains the code that implements the Plug & Play and
// power management features
//
// Environment:
//
// Kernel mode
//
//
// Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
// Copyright (c) 1995-1999 Microsoft Corporation. All Rights Reserved.
//
//***************************************************************************
#include "permedia.h"
#define VESA_POWER_FUNCTION 0x4f10
#define VESA_POWER_ON 0x0000
#define VESA_POWER_STANDBY 0x0100
#define VESA_POWER_SUSPEND 0x0200
#define VESA_POWER_OFF 0x0400
#define VESA_GET_POWER_FUNC 0x0000
#define VESA_SET_POWER_FUNC 0x0001
#define VESA_STATUS_SUCCESS 0x004f
//
// all our IDs begin with 0x1357bd so they are readily identifiable as our own
//
#define P2_DDC_MONITOR (0x1357bd00)
#define P2_NONDDC_MONITOR (0x1357bd01)
BOOLEAN PowerOnReset( PHW_DEVICE_EXTENSION hwDeviceExtension ); VOID SaveDeviceState( PHW_DEVICE_EXTENSION hwDeviceExtension ); VOID RestoreDeviceState( PHW_DEVICE_EXTENSION hwDeviceExtension );
VOID I2CWriteClock(PVOID HwDeviceExtension, UCHAR data); VOID I2CWriteData(PVOID HwDeviceExtension, UCHAR data); BOOLEAN I2CReadClock(PVOID HwDeviceExtension); BOOLEAN I2CReadData(PVOID HwDeviceExtension); VOID I2CWaitVSync(PVOID HwDeviceExtension);
#if defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE, PowerOnReset)
#pragma alloc_text(PAGE, SaveDeviceState)
#pragma alloc_text(PAGE, RestoreDeviceState)
#pragma alloc_text(PAGE, Permedia2GetPowerState)
#pragma alloc_text(PAGE, Permedia2SetPowerState)
#pragma alloc_text(PAGE, Permedia2GetChildDescriptor)
#pragma alloc_text(PAGE, I2CWriteClock)
#pragma alloc_text(PAGE, I2CWriteData)
#pragma alloc_text(PAGE, I2CReadClock)
#pragma alloc_text(PAGE, I2CReadData)
#pragma alloc_text(PAGE, I2CWaitVSync)
#endif
I2C_FNC_TABLE I2CFunctionTable = { sizeof(I2C_FNC_TABLE), I2CWriteClock, I2CWriteData, I2CReadClock, I2CReadData, I2CWaitVSync, NULL };
VP_STATUS Permedia2GetPowerState ( PVOID HwDeviceExtension, ULONG HwId, PVIDEO_POWER_MANAGEMENT VideoPowerControl )
/*++
Routine Description:
Returns power state information.
Arguments:
HwDeviceExtension - Pointer to our hardware device extension structure.
HwId - Private unique 32 bit ID identifing the device.
VideoPowerControl - Points to a VIDEO_POWER_MANAGEMENT structure that specifies the power state for which support is being queried.
Return Value:
VP_STATUS value (NO_ERROR or error value)
--*/
{ VIDEO_X86_BIOS_ARGUMENTS biosArguments; VP_STATUS status; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
DEBUG_PRINT((2, "Permedia2GetPowerState: hwId(%xh) state = %d\n", (int)HwId, (int)VideoPowerControl->PowerState));
switch((int)HwId) { case P2_DDC_MONITOR: case P2_NONDDC_MONITOR:
switch (VideoPowerControl->PowerState) {
case VideoPowerOn: case VideoPowerStandBy: case VideoPowerSuspend: case VideoPowerOff: case VideoPowerHibernate: case VideoPowerShutdown:
status = NO_ERROR; break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown monitor PowerState(%xh)\n", (int)VideoPowerControl->PowerState));
ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; } break;
case DISPLAY_ADAPTER_HW_ID:
//
// only support ON at the moment
//
switch (VideoPowerControl->PowerState) { case VideoPowerOn: case VideoPowerStandBy: case VideoPowerSuspend: case VideoPowerHibernate: case VideoPowerShutdown: status = NO_ERROR; break;
case VideoPowerOff:
if( hwDeviceExtension->HardwiredSubSystemId ) { status = NO_ERROR; } else { //
// If SubSystemId is not hardwired in a read-only way,
// it is possible we'll see a different value when
// system comes back form S3 mode. This will cause
// problem since os will assume this is a different
// device
//
DEBUG_PRINT((2, "Permedia2GetPowerState: VideoPowerOff is not suported by this card!\n")); status = ERROR_INVALID_FUNCTION; }
break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown adapter PowerState(%xh)\n", (int)VideoPowerControl->PowerState));
ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER;
} break;
default:
DEBUG_PRINT((1, "Permedia2GetPowerState: Unknown hwId(%xh)", (int)HwId)); ASSERT(FALSE);
status = ERROR_INVALID_PARAMETER; }
DEBUG_PRINT((2, "Permedia2GetPowerState: returning %xh\n", status));
return(status); }
VP_STATUS Permedia2SetPowerState ( PVOID HwDeviceExtension, ULONG HwId, PVIDEO_POWER_MANAGEMENT VideoPowerControl )
/*++
Routine Description:
Set the power state for a given device.
Arguments:
HwDeviceExtension - Pointer to our hardware device extension structure.
HwId - Private unique 32 bit ID identifing the device.
VideoPowerControl - Points to a VIDEO_POWER_MANAGEMENT structure that specifies the power state to be set.
Return Value:
VP_STATUS value (NO_ERROR, if all's well)
--*/
{ PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG Polarity; VIDEO_X86_BIOS_ARGUMENTS biosArguments; VP_STATUS status; P2_DECL;
DEBUG_PRINT((2, "Permedia2SetPowerState: hwId(%xh) state = %d\n", (int)HwId, (int)VideoPowerControl->PowerState));
switch((int)HwId) {
case P2_DDC_MONITOR: case P2_NONDDC_MONITOR:
Polarity = VideoPortReadRegisterUlong(VIDEO_CONTROL);
Polarity &= ~((1 << 5) | (1 << 3) | 1);
switch (VideoPowerControl->PowerState) {
case VideoPowerHibernate: case VideoPowerShutdown:
//
// Do nothing for hibernate as the monitor must stay on.
//
status = NO_ERROR; break;
case VideoPowerOn:
RestoreDeviceState(hwDeviceExtension); status = NO_ERROR; break;
case VideoPowerStandBy:
//
// hsync low, vsync active high, video disabled
//
SaveDeviceState(hwDeviceExtension); VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | (1 << 5) | (2 << 3) | 0);
status = NO_ERROR; break;
case VideoPowerSuspend:
//
// vsync low, hsync active high, video disabled
//
VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | (2 << 5) | (1 << 3) | 0);
status = NO_ERROR; break;
case VideoPowerOff:
//
// vsync low, hsync low, video disabled
//
VideoPortWriteRegisterUlong(VIDEO_CONTROL, Polarity | (2 << 5) | (2 << 3) | 0);
status = NO_ERROR; break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown monitor PowerState(%xh)\n", (int)VideoPowerControl->PowerState));
ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; }
//
// Track the current monitor power state
//
hwDeviceExtension->bMonitorPoweredOn = (VideoPowerControl->PowerState == VideoPowerOn) || (VideoPowerControl->PowerState == VideoPowerHibernate);
Polarity = VideoPortReadRegisterUlong(VIDEO_CONTROL);
break;
case DISPLAY_ADAPTER_HW_ID:
switch (VideoPowerControl->PowerState) { case VideoPowerHibernate: status = NO_ERROR; break;
case VideoPowerShutdown:
//
// We need to make sure no interrupts will be generated
// after the device being powered down
//
VideoPortWriteRegisterUlong(INT_ENABLE, 0);
status = NO_ERROR; break;
case VideoPowerOn:
if ((hwDeviceExtension->PreviousPowerState == VideoPowerOff) || (hwDeviceExtension->PreviousPowerState == VideoPowerSuspend) || (hwDeviceExtension->PreviousPowerState == VideoPowerHibernate)) { PowerOnReset(hwDeviceExtension); }
status = NO_ERROR; break;
case VideoPowerStandBy:
status = NO_ERROR; break;
case VideoPowerSuspend:
status = NO_ERROR; break; case VideoPowerOff:
status = NO_ERROR; break;
default:
DEBUG_PRINT((2, "Permedia2GetPowerState: Unknown adapter PowerState(%xh)\n", (int)VideoPowerControl->PowerState));
ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; }
hwDeviceExtension->PreviousPowerState = VideoPowerControl->PowerState;
break; default:
DEBUG_PRINT((1, "Permedia2SetPowerState: Unknown hwId(%xh)\n", (int)HwId));
ASSERT(FALSE); status = ERROR_INVALID_PARAMETER; }
return(status);
}
BOOLEAN PowerOnReset( PHW_DEVICE_EXTENSION hwDeviceExtension )
/*++
Routine Description:
Called when the adapter is powered on
--*/
{ int i; ULONG ulValue; BOOLEAN bOK; P2_DECL;
if(!hwDeviceExtension->bVGAEnabled || !hwDeviceExtension->bDMAEnabled) { PCI_COMMON_CONFIG PciData;
//
// in a multi-adapter system we'll need to turn on the DMA and
// memory space for the secondary adapters
//
DEBUG_PRINT((1, "PowerOnReset() enabling memory space access for the secondary card\n"));
VideoPortGetBusData( hwDeviceExtension, PCIConfiguration, 0, &PciData, 0, PCI_COMMON_HDR_LENGTH);
PciData.Command |= PCI_ENABLE_MEMORY_SPACE; PciData.Command |= PCI_ENABLE_BUS_MASTER;
VideoPortSetBusData( hwDeviceExtension, PCIConfiguration, 0, &PciData, 0, PCI_COMMON_HDR_LENGTH );
#if DBG
DumpPCIConfigSpace(hwDeviceExtension, hwDeviceExtension->pciBus, (ULONG)hwDeviceExtension->pciSlot.u.AsULONG); #endif
}
//
// While waking up from hibernation, we usually don't need
// to reset perm2 and call ProcessInitializationTable()
// for the primary card since video bios will get posted.
// We do so here because we saw cases that the perm2 bios
// failed to worked correctly on some machines.
//
//
// reset the device
//
VideoPortWriteRegisterUlong(RESET_STATUS, 0);
for(i = 0; i < 100000; ++i) { ulValue = VideoPortReadRegisterUlong(RESET_STATUS);
if (ulValue == 0) break; }
if(ulValue) { DEBUG_PRINT((1, "PowerOnReset() Read RESET_STATUS(%xh) - failed to reset\n", ulValue));
ASSERT(FALSE); bOK = FALSE; } else { //
// reload registers given in ROM
//
if(hwDeviceExtension->culTableEntries) { ProcessInitializationTable(hwDeviceExtension); }
//
// set-up other registers not set in InitializeVideo
//
VideoPortWriteRegisterUlong(BYPASS_WRITE_MASK, 0xFFFFFFFF); VideoPortWriteRegisterUlong(APERTURE_ONE, 0x0); VideoPortWriteRegisterUlong(APERTURE_TWO, 0x0);
bOK = TRUE;
}
return(bOK);
}
VOID SaveDeviceState(PHW_DEVICE_EXTENSION hwDeviceExtension)
/*++
Routine Description:
Save any registers that will be destroyed when we power down the monitor
--*/
{ P2_DECL;
DEBUG_PRINT((2, "SaveDeviceState() called\n")); //
// hwDeviceExtension->VideoControl should be set in InitializeVideo,
// just in case we get here before InitializeVideo
//
if( !(hwDeviceExtension->VideoControl) ) { hwDeviceExtension->VideoControl = VideoPortReadRegisterUlong(VIDEO_CONTROL); }
hwDeviceExtension->IntEnable = VideoPortReadRegisterUlong(INT_ENABLE);
}
VOID RestoreDeviceState(PHW_DEVICE_EXTENSION hwDeviceExtension)
/*++
Routine Description:
Restore registers saved before monitor power down
--*/
{ P2_DECL;
DEBUG_PRINT((2, "RestoreDeviceState() called\n")); VideoPortWriteRegisterUlong(VIDEO_CONTROL, hwDeviceExtension->VideoControl); VideoPortWriteRegisterUlong(INT_ENABLE, hwDeviceExtension->IntEnable);
}
ULONG Permedia2GetChildDescriptor( PVOID HwDeviceExtension, PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, PVIDEO_CHILD_TYPE pChildType, PVOID pChildDescriptor, PULONG pUId, PULONG pUnused )
/*++
Routine Description:
Enumerate all child devices controlled by the Permedia 2 chip.
This includes DDC monitors attached to the board, as well as other devices which may be connected to a proprietary bus.
Arguments:
HwDeviceExtension - Pointer to our hardware device extension structure.
ChildEnumInfo - Information about the device that should be enumerated.
pChildType - Type of child we are enumerating - monitor, I2C ...
pChildDescriptor - Identification structure of the device (EDID, string)
pUId - Private unique 32 bit ID to passed back to the miniport
pUnused - Do not use
Return Value:
ERROR_NO_MORE_DEVICES - if no more child devices exist.
ERROR_INVALID_NAME - The miniport could not enumerate the child device identified in ChildEnumInfo but does have more devices to be enumerated.
ERROR_MORE_DATA - There are more devices to be enumerated.
Note:
In the event of a failure return, none of the fields are valid except for the return value and the pMoreChildren field.
--*/
{
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
DEBUG_PRINT((2, "Permedia2GetChildDescriptor called\n"));
switch (ChildEnumInfo->ChildIndex) { case 0:
//
// Case 0 is used to enumerate devices found by the ACPI firmware.
// We do not currently support ACPI devices
//
return ERROR_NO_MORE_DEVICES;
case 1:
//
// Treat index 1 as the monitor
//
*pChildType = Monitor;
//
// if it's a DDC monitor we return its EDID in pjBuffer
// (always 128 bytes)
//
if(VideoPortDDCMonitorHelper(HwDeviceExtension, &I2CFunctionTable, pChildDescriptor, ChildEnumInfo->ChildDescriptorSize)) { //
// found a DDC monitor
//
DEBUG_PRINT((2, "Permedia2GetChildDescriptor: found a DDC monitor\n"));
*pUId = P2_DDC_MONITOR; } else { //
// failed: assume non-DDC monitor
//
DEBUG_PRINT((2, "Permedia2GetChildDescriptor: found a non-DDC monitor\n"));
*pUId = P2_NONDDC_MONITOR;
}
return ERROR_MORE_DATA;
default:
return ERROR_NO_MORE_DEVICES; } }
VOID I2CWriteClock(PVOID HwDeviceExtension, UCHAR data) { const ULONG nbitClock = 3; const ULONG Clock = 1 << nbitClock;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= ~Clock; ul |= (data & 1) << nbitClock; VideoPortWriteRegisterUlong(DDC_DATA, ul); }
VOID I2CWriteData(PVOID HwDeviceExtension, UCHAR data) { const ULONG nbitData = 2; const ULONG Data = 1 << nbitData;
PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= ~Data; ul |= ((data & 1) << nbitData); VideoPortWriteRegisterUlong(DDC_DATA, ul); }
BOOLEAN I2CReadClock(PVOID HwDeviceExtension) { const ULONG nbitClock = 1; const ULONG Clock = 1 << nbitClock; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= Clock; ul >>= nbitClock;
return((BOOLEAN)ul); }
BOOLEAN I2CReadData(PVOID HwDeviceExtension) { const ULONG nbitData = 0; const ULONG Data = 1 << nbitData; PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; ULONG ul; P2_DECL;
ul = VideoPortReadRegisterUlong(DDC_DATA); ul &= Data; ul >>= nbitData; return((BOOLEAN)ul); }
VOID I2CWaitVSync(PVOID HwDeviceExtension) { PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension; UCHAR jIndexSaved, jStatus; P2_DECL; if(hwDeviceExtension->bVGAEnabled) {
//
// VGA run on this board, is it currently in VGA or VTG mode?
//
jIndexSaved = VideoPortReadRegisterUchar(PERMEDIA_MMVGA_INDEX_REG);
VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG, PERMEDIA_VGA_CTRL_INDEX);
jStatus = VideoPortReadRegisterUchar(PERMEDIA_MMVGA_DATA_REG);
VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG, jIndexSaved);
} else { //
// VGA not run
//
jStatus = 0;
}
if(jStatus & PERMEDIA_VGA_ENABLE) { //
// in VGA, so check VSync via the VGA registers
// 1. if we're in VSync, wait for it to end
//
while( (VideoPortReadRegisterUchar(PERMEDIA_MMVGA_STAT_REG) & PERMEDIA_VGA_STAT_VSYNC) == 1);
//
// 2. wait for the start of VSync
//
while( (VideoPortReadRegisterUchar(PERMEDIA_MMVGA_STAT_REG) & PERMEDIA_VGA_STAT_VSYNC) == 0); } else { if(!hwDeviceExtension->bVTGRunning) {
//
// time to set-up the VTG - we'll need a valid mode to do this,
// so we;ll choose 640x480x8 we get here (at boot-up only) if
// the secondary card has VGA disabled: GetChildDescriptor is
// called before InitializeVideo so that the VTG hasn't been
// programmed yet
//
DEBUG_PRINT((2, "I2CWaitVSync() - VGA nor VTG running: attempting to setup VTG\n"));
if(hwDeviceExtension->pFrequencyDefault == NULL) { DEBUG_PRINT((1, "I2CWaitVSync() - no valid modes to use: can't set-up VTG\n")); return; }
Permedia2GetClockSpeeds(HwDeviceExtension); ZeroMemAndDac(hwDeviceExtension, 0);
if (!InitializeVideo( HwDeviceExtension, hwDeviceExtension->pFrequencyDefault) ) { DEBUG_PRINT((1, "I2CWaitVSync() - InitializeVideo failed\n")); return; } }
//
// VTG has been set-up: check via the control registers
//
VideoPortWriteRegisterUlong ( INT_FLAGS, INTR_VBLANK_SET );
while (( (VideoPortReadRegisterUlong (INT_FLAGS) ) & INTR_VBLANK_SET ) == 0 ); } }
|