forked from KolibriOS/kolibrios
fb8dc89b4d
git-svn-id: svn://kolibrios.org@1029 a494cfbc-eb01-0410-851d-a64ba20cac60
961 lines
22 KiB
C
961 lines
22 KiB
C
/*
|
|
* Copyright 2007, 2008 Egbert Eich <eich@novell.com>
|
|
* Copyright 2007, 2008 Luc Verhaegen <lverhaegen@novell.com>
|
|
* Copyright 2007, 2008 Matthias Hopf <mhopf@novell.com>
|
|
* Copyright 2007, 2008 Advanced Micro Devices, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef ATOM_BIOS
|
|
# include "xf86.h"
|
|
#include "rhd.h"
|
|
|
|
# include "edid.h"
|
|
|
|
# include "xf86DDC.h"
|
|
|
|
# if HAVE_XF86_ANSIC_H
|
|
# include "xf86_ansic.h"
|
|
# else
|
|
# include <unistd.h>
|
|
# include <string.h>
|
|
# include <stdio.h>
|
|
# endif
|
|
|
|
|
|
|
|
# include "rhd_atombios.h"
|
|
|
|
# include "rhd_connector.h"
|
|
# include "rhd_output.h"
|
|
# include "rhd_biosscratch.h"
|
|
# include "rhd_crtc.h"
|
|
# include "rhd_card.h"
|
|
|
|
# ifdef ATOM_BIOS_PARSER
|
|
# define INT8 INT8
|
|
# define INT16 INT16
|
|
# define INT32 INT32
|
|
# include "CD_Common_Types.h"
|
|
# else
|
|
# ifndef ULONG
|
|
typedef unsigned int ULONG;
|
|
# define ULONG ULONG
|
|
# endif
|
|
# ifndef UCHAR
|
|
typedef unsigned char UCHAR;
|
|
# define UCHAR UCHAR
|
|
# endif
|
|
# ifndef USHORT
|
|
typedef unsigned short USHORT;
|
|
# define USHORT USHORT
|
|
# endif
|
|
# endif
|
|
|
|
# include "atombios.h"
|
|
|
|
struct rhdOutputDevices {
|
|
enum atomDevice DeviceId;
|
|
enum rhdConnectorType ConnectorType;
|
|
};
|
|
|
|
#if defined (ATOM_BIOS_PARSER)
|
|
/*
|
|
*
|
|
*/
|
|
static enum rhdSensedOutput
|
|
rhdAtomBIOSScratchDACSenseResults(struct rhdOutput *Output, enum atomDAC DAC, enum atomDevice Device)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
|
CARD32 BIOS_0;
|
|
Bool TV = FALSE;
|
|
|
|
RHDFUNC(Output);
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
BIOS_0 = RHDRegRead(Output, 0x10);
|
|
else
|
|
BIOS_0 = RHDRegRead(Output, 0x1724);
|
|
|
|
switch (Device) {
|
|
case atomNone:
|
|
case atomCRT2:
|
|
case atomCRT1:
|
|
case atomLCD1:
|
|
case atomLCD2:
|
|
case atomDFP1:
|
|
case atomDFP2:
|
|
case atomDFP3:
|
|
case atomDFP4:
|
|
case atomDFP5:
|
|
TV = FALSE;
|
|
break;
|
|
case atomTV1:
|
|
case atomTV2:
|
|
case atomCV:
|
|
TV = TRUE;
|
|
break;
|
|
}
|
|
|
|
RHDDebug(Output->scrnIndex, "BIOSScratch_0: 0x%4.4x\n",BIOS_0);
|
|
|
|
switch (DAC) {
|
|
case atomDACA:
|
|
break;
|
|
case atomDACB:
|
|
BIOS_0 >>= 8;
|
|
break;
|
|
case atomDACExt:
|
|
return RHD_SENSED_NONE;
|
|
}
|
|
|
|
if (!TV) {
|
|
if (BIOS_0 & ATOM_S0_CRT1_MASK) {
|
|
RHDDebug(Output->scrnIndex, "%s sensed RHD_SENSED_VGA\n",__func__);
|
|
return RHD_SENSED_VGA;
|
|
}
|
|
} else {
|
|
if (BIOS_0 & ATOM_S0_TV1_COMPOSITE_A) {
|
|
RHDDebug(Output->scrnIndex, "%s: RHD_SENSED_TV_COMPOSITE\n",__func__);
|
|
return RHD_SENSED_TV_COMPOSITE;
|
|
} else if (BIOS_0 & ATOM_S0_TV1_SVIDEO_A) {
|
|
RHDDebug(Output->scrnIndex, "%s: RHD_SENSED_TV_SVIDE\n",__func__);
|
|
return RHD_SENSED_TV_SVIDEO;
|
|
} else if (BIOS_0 & ATOM_S0_CV_MASK_A) {
|
|
RHDDebug(Output->scrnIndex, "%s: RHD_SENSED_TV_COMPONENT\n",__func__);
|
|
return RHD_SENSED_TV_COMPONENT;
|
|
}
|
|
}
|
|
|
|
RHDDebug(Output->scrnIndex, "%s: RHD_SENSED_NONE\n",__func__);
|
|
return RHD_SENSED_NONE;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
enum rhdSensedOutput
|
|
RHDBIOSScratchDACSense(struct rhdOutput *Output, struct rhdConnector *Connector)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
|
enum atomDAC DAC;
|
|
Bool ret;
|
|
Bool TV;
|
|
enum atomDevice Device;
|
|
enum rhdSensedOutput retVal;
|
|
int i = 0;
|
|
|
|
RHDFUNC(Output);
|
|
|
|
if (!Output->OutputDriverPrivate)
|
|
return RHD_SENSED_NONE;
|
|
|
|
switch (Output->Id) {
|
|
case RHD_OUTPUT_DACA:
|
|
RHDDebug(Output->scrnIndex, "Sensing DACA on Output %s\n",Output->Name);
|
|
DAC = atomDACA;
|
|
break;
|
|
case RHD_OUTPUT_DACB:
|
|
RHDDebug(Output->scrnIndex, "Sensing DACB on Output %s\n",Output->Name);
|
|
DAC = atomDACB;
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
switch (Connector->Type) {
|
|
case RHD_CONNECTOR_DVI:
|
|
case RHD_CONNECTOR_DVI_SINGLE:
|
|
case RHD_CONNECTOR_VGA:
|
|
TV = FALSE;
|
|
break;
|
|
default:
|
|
TV = TRUE;
|
|
}
|
|
|
|
while ((Device = Output->OutputDriverPrivate->OutputDevices[i++].DeviceId) != atomNone) {
|
|
switch (Device) {
|
|
case atomCRT1:
|
|
case atomCRT2:
|
|
if (TV)
|
|
continue;
|
|
break;
|
|
case atomTV1:
|
|
case atomTV2:
|
|
case atomCV:
|
|
if (!TV)
|
|
continue;
|
|
break;
|
|
default: /* should not get here */
|
|
return RHD_SENSED_NONE;
|
|
}
|
|
|
|
ret = AtomDACLoadDetection(rhdPtr->atomBIOS, Device, DAC);
|
|
|
|
if (!ret)
|
|
continue;
|
|
|
|
if ((retVal = rhdAtomBIOSScratchDACSenseResults(Output, DAC, Device)) != RHD_SENSED_NONE)
|
|
return retVal;
|
|
}
|
|
return RHD_SENSED_NONE;
|
|
}
|
|
# endif /* ATOM_BIOS_PARSER */
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdAtomBIOSScratchUpdateAttachedState(RHDPtr rhdPtr, enum atomDevice dev, Bool attached)
|
|
{
|
|
CARD32 BIOS_0;
|
|
CARD32 Addr;
|
|
CARD32 Mask;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x10;
|
|
else
|
|
Addr = 0x1724;
|
|
|
|
BIOS_0 = RHDRegRead(rhdPtr, Addr);
|
|
|
|
switch (dev) {
|
|
case atomDFP1:
|
|
Mask = ATOM_S0_DFP1;
|
|
break;
|
|
case atomDFP2:
|
|
Mask = ATOM_S0_DFP2;
|
|
break;
|
|
case atomLCD1:
|
|
Mask = ATOM_S0_LCD1;
|
|
break;
|
|
case atomLCD2:
|
|
Mask = ATOM_S0_LCD2;
|
|
break;
|
|
case atomTV2:
|
|
Mask = ATOM_S0_TV2;
|
|
break;
|
|
case atomDFP3:
|
|
Mask = ATOM_S0_DFP3;
|
|
break;
|
|
case atomDFP4:
|
|
Mask = ATOM_S0_DFP4;
|
|
break;
|
|
case atomDFP5:
|
|
Mask = ATOM_S0_DFP5;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
if (attached)
|
|
BIOS_0 |= Mask;
|
|
else
|
|
BIOS_0 &= ~Mask;
|
|
|
|
RHDRegWrite(rhdPtr, Addr, BIOS_0);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdAtomBIOSScratchUpdateOnState(RHDPtr rhdPtr, enum atomDevice dev, Bool on)
|
|
{
|
|
CARD32 BIOS_3;
|
|
CARD32 Addr;
|
|
CARD32 Mask = 0;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x1C;
|
|
else
|
|
Addr = 0x1730;
|
|
|
|
BIOS_3 = RHDRegRead(rhdPtr, Addr);
|
|
|
|
switch (dev) {
|
|
case atomCRT1:
|
|
Mask = ATOM_S3_CRT1_ACTIVE;
|
|
break;
|
|
case atomLCD1:
|
|
Mask = ATOM_S3_LCD1_ACTIVE;
|
|
break;
|
|
case atomTV1:
|
|
Mask = ATOM_S3_TV1_ACTIVE;
|
|
break;
|
|
case atomDFP1:
|
|
Mask = ATOM_S3_DFP1_ACTIVE;
|
|
break;
|
|
case atomCRT2:
|
|
Mask = ATOM_S3_CRT2_ACTIVE;
|
|
break;
|
|
case atomLCD2:
|
|
Mask = ATOM_S3_LCD2_ACTIVE;
|
|
break;
|
|
case atomTV2:
|
|
Mask = ATOM_S3_TV2_ACTIVE;
|
|
break;
|
|
case atomDFP2:
|
|
Mask = ATOM_S3_DFP2_ACTIVE;
|
|
break;
|
|
case atomCV:
|
|
Mask = ATOM_S3_CV_ACTIVE;
|
|
break;
|
|
case atomDFP3:
|
|
Mask = ATOM_S3_DFP3_ACTIVE;
|
|
break;
|
|
case atomDFP4:
|
|
Mask = ATOM_S3_DFP4_ACTIVE;
|
|
break;
|
|
case atomDFP5:
|
|
Mask = ATOM_S3_DFP5_ACTIVE;
|
|
break;
|
|
case atomNone:
|
|
return;
|
|
}
|
|
if (on)
|
|
BIOS_3 |= Mask;
|
|
else
|
|
BIOS_3 &= ~Mask;
|
|
|
|
RHDRegWrite(rhdPtr, Addr, BIOS_3);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void
|
|
RHDAtomBIOSScratchSetAccelratorMode(RHDPtr rhdPtr, Bool on)
|
|
{
|
|
CARD32 Addr;
|
|
CARD32 Mask = ATOM_S6_ACC_MODE | ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x10 + (6 << 2);
|
|
else
|
|
Addr = 0x1724 + (6 << 2);
|
|
|
|
RHDRegMask(rhdPtr, Addr, on ? Mask : 0, Mask);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdAtomBIOSScratchSetAcceleratorModeForDevice(RHDPtr rhdPtr,
|
|
enum atomDevice Device, Bool on)
|
|
{
|
|
CARD32 Addr;
|
|
CARD32 Mask = 0;
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x10 + (6 << 2);
|
|
else
|
|
Addr = 0x1724 + (6 << 2);
|
|
|
|
switch (Device) {
|
|
case atomCRT1:
|
|
Mask = ATOM_S6_ACC_REQ_CRT1;
|
|
break;
|
|
case atomLCD1:
|
|
Mask = ATOM_S6_ACC_REQ_LCD1;
|
|
break;
|
|
case atomTV1:
|
|
Mask = ATOM_S6_ACC_REQ_TV1;
|
|
break;
|
|
case atomDFP1:
|
|
Mask = ATOM_S6_ACC_REQ_DFP1;
|
|
break;
|
|
case atomCRT2:
|
|
Mask = ATOM_S6_ACC_REQ_CRT2;
|
|
break;
|
|
case atomLCD2:
|
|
Mask = ATOM_S6_ACC_REQ_LCD2;
|
|
break;
|
|
case atomTV2:
|
|
Mask = ATOM_S6_ACC_REQ_TV2;
|
|
break;
|
|
case atomDFP2:
|
|
Mask = ATOM_S6_ACC_REQ_DFP2;
|
|
break;
|
|
case atomCV:
|
|
Mask = ATOM_S6_ACC_REQ_CV;
|
|
break;
|
|
case atomDFP3:
|
|
Mask = ATOM_S6_ACC_REQ_DFP3;
|
|
break;
|
|
case atomDFP4:
|
|
Mask = ATOM_S6_ACC_REQ_DFP4;
|
|
break;
|
|
case atomDFP5:
|
|
Mask = ATOM_S6_ACC_REQ_DFP5;
|
|
break;
|
|
case atomNone:
|
|
return;
|
|
}
|
|
RHDRegMask(rhdPtr, Addr, on ? Mask : 0, Mask);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdAtomBIOSScratchSetCrtcState(RHDPtr rhdPtr, enum atomDevice dev, enum atomCrtc Crtc)
|
|
{
|
|
CARD32 BIOS_3;
|
|
CARD32 Addr;
|
|
CARD32 Mask = 0;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x1C;
|
|
else
|
|
Addr = 0x1730;
|
|
|
|
BIOS_3 = RHDRegRead(rhdPtr, Addr);
|
|
|
|
switch (dev) {
|
|
case atomCRT1:
|
|
Mask = ATOM_S3_CRT1_CRTC_ACTIVE;
|
|
break;
|
|
case atomLCD1:
|
|
Mask = ATOM_S3_LCD1_CRTC_ACTIVE;
|
|
break;
|
|
case atomTV1:
|
|
Mask = ATOM_S3_TV1_CRTC_ACTIVE;
|
|
break;
|
|
case atomDFP1:
|
|
Mask = ATOM_S3_DFP1_CRTC_ACTIVE;
|
|
break;
|
|
case atomCRT2:
|
|
Mask = ATOM_S3_CRT2_CRTC_ACTIVE;
|
|
break;
|
|
case atomLCD2:
|
|
Mask = ATOM_S3_LCD2_CRTC_ACTIVE;
|
|
break;
|
|
case atomTV2:
|
|
Mask = ATOM_S3_TV2_CRTC_ACTIVE;
|
|
break;
|
|
case atomDFP2:
|
|
Mask = ATOM_S3_DFP2_CRTC_ACTIVE;
|
|
break;
|
|
case atomCV:
|
|
Mask = ATOM_S3_CV_CRTC_ACTIVE;
|
|
break;
|
|
case atomDFP3:
|
|
Mask = ATOM_S3_DFP3_CRTC_ACTIVE;
|
|
break;
|
|
case atomDFP4:
|
|
Mask = ATOM_S3_DFP4_CRTC_ACTIVE;
|
|
break;
|
|
case atomDFP5:
|
|
Mask = ATOM_S3_DFP5_CRTC_ACTIVE;
|
|
break;
|
|
case atomNone:
|
|
return;
|
|
}
|
|
if (Crtc == atomCrtc2)
|
|
BIOS_3 |= Mask;
|
|
else
|
|
BIOS_3 &= ~Mask;
|
|
|
|
RHDRegWrite(rhdPtr, Addr, BIOS_3);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void
|
|
RHDAtomBIOSScratchPMState(RHDPtr rhdPtr, struct rhdOutput *Output, int PowerManagementMode)
|
|
{
|
|
CARD32 Addr;
|
|
CARD32 Mask = 0, Mask1;
|
|
enum atomDevice Device = Output->OutputDriverPrivate->Device;
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x10 + (2 << 2);
|
|
else
|
|
Addr = 0x1724 + (2 << 2);
|
|
|
|
switch (Device) {
|
|
case atomCRT1:
|
|
Mask = ATOM_S2_CRT1_DPMS_STATE;
|
|
break;
|
|
case atomLCD1:
|
|
Mask = ATOM_S2_LCD1_DPMS_STATE;
|
|
break;
|
|
case atomTV1:
|
|
Mask = ATOM_S2_TV1_DPMS_STATE;
|
|
break;
|
|
case atomDFP1:
|
|
Mask = ATOM_S2_DFP1_DPMS_STATE;
|
|
break;
|
|
case atomCRT2:
|
|
Mask = ATOM_S2_CRT2_DPMS_STATE;
|
|
break;
|
|
case atomLCD2:
|
|
Mask = ATOM_S2_LCD2_DPMS_STATE;
|
|
break;
|
|
case atomTV2:
|
|
Mask = ATOM_S2_TV2_DPMS_STATE;
|
|
break;
|
|
case atomDFP2:
|
|
Mask = ATOM_S2_DFP2_DPMS_STATE;
|
|
break;
|
|
case atomCV:
|
|
Mask = ATOM_S2_CV_DPMS_STATE;
|
|
break;
|
|
case atomDFP3:
|
|
Mask = ATOM_S2_DFP3_DPMS_STATE;
|
|
break;
|
|
case atomDFP4:
|
|
Mask = ATOM_S2_DFP4_DPMS_STATE;
|
|
break;
|
|
case atomDFP5:
|
|
Mask = ATOM_S2_DFP5_DPMS_STATE;
|
|
break;
|
|
case atomNone:
|
|
return;
|
|
}
|
|
switch (PowerManagementMode) {
|
|
case DPMSModeOn:
|
|
Mask1 = 0;
|
|
break;
|
|
case DPMSModeStandby:
|
|
case DPMSModeSuspend:
|
|
case DPMSModeOff:
|
|
default:
|
|
Mask1 = Mask;
|
|
break;
|
|
}
|
|
|
|
RHDRegMask(rhdPtr, Addr, Mask1, Mask);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void
|
|
RHDAtomBIOSScratchBlLevel(RHDPtr rhdPtr, enum rhdBIOSScratchBlAction action, int *val)
|
|
{
|
|
CARD32 Addr;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x18;
|
|
else
|
|
Addr = 0x172C;
|
|
|
|
switch (action) {
|
|
case rhdBIOSScratchBlGet:
|
|
*val = (RHDRegRead(rhdPtr, Addr) >> 8) & 0xFF;
|
|
RHDDebug(rhdPtr->scrnIndex, "Get BL level: 0x%x\n",*val);
|
|
break;
|
|
case rhdBIOSScratchBlSet:
|
|
RHDDebug(rhdPtr->scrnIndex, "Set BL level: 0x%x\n",*val);
|
|
RHDRegMask(rhdPtr, Addr, (*val) << 8, 0xFF00);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function finds the AtomBIOS device ID of the device that we currently
|
|
* want to drive with a specific output. It contains a logic to deal with CRTC vs. TV
|
|
* on DACs.
|
|
* This function preferrably gets called from within the function that also updates
|
|
* the BIOS scratch registers.
|
|
*/
|
|
static enum atomDevice
|
|
rhdBIOSScratchSetDeviceForOutput(struct rhdOutput *Output)
|
|
{
|
|
int i = 0;
|
|
|
|
RHDFUNC(Output);
|
|
|
|
if (!Output->Connector) {
|
|
RHDDebug(Output->scrnIndex,"%s: No connector assigned to output %s\n",__func__,Output->Name);
|
|
return atomNone;
|
|
}
|
|
|
|
if (!Output->OutputDriverPrivate) {
|
|
RHDDebug(Output->scrnIndex,"%s: Output %s has no DriverPrivate\n",__func__,Output->Name);
|
|
return atomNone;
|
|
}
|
|
|
|
while (Output->OutputDriverPrivate->OutputDevices[i].DeviceId != atomNone) {
|
|
if (Output->OutputDriverPrivate->OutputDevices[i].ConnectorType == Output->Connector->Type){
|
|
|
|
switch (Output->OutputDriverPrivate->OutputDevices[i].DeviceId) {
|
|
case atomCrtc1:
|
|
case atomCrtc2:
|
|
if (Output->SensedType == RHD_SENSED_VGA
|
|
|| Output->SensedType == RHD_SENSED_NONE) /* if nothing was sensed default to VGA */
|
|
break;
|
|
i++;
|
|
continue;
|
|
case atomTV1:
|
|
case atomTV2:
|
|
if (Output->SensedType == RHD_SENSED_TV_SVIDEO
|
|
|| Output->SensedType == RHD_SENSED_TV_COMPOSITE)
|
|
break;
|
|
i++;
|
|
continue;
|
|
case atomCV:
|
|
if (Output->SensedType == RHD_SENSED_TV_COMPONENT)
|
|
break;
|
|
i++;
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
Output->OutputDriverPrivate->Device = Output->OutputDriverPrivate->OutputDevices[i].DeviceId;
|
|
|
|
return Output->OutputDriverPrivate->Device;
|
|
}
|
|
i++;
|
|
}
|
|
RHDDebugVerb(Output->scrnIndex,1,"%s: No device found: ConnectorType: %2.2x SensedType: %2.2x\n",
|
|
__func__, Output->Connector->Type, Output->SensedType);
|
|
return atomNone;
|
|
}
|
|
|
|
/*
|
|
* This function is public as it is used from within other outputs, too.
|
|
*/
|
|
static enum atomDevice
|
|
rhdBIOSScratchUpdateBIOSScratchForOutput(struct rhdOutput *Output)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTRI(Output);
|
|
struct rhdOutputDevices *devList;
|
|
enum atomDevice Device;
|
|
int i = 0;
|
|
|
|
RHDFUNC(Output);
|
|
|
|
if (!Output->OutputDriverPrivate) {
|
|
RHDDebug(Output->scrnIndex,"%s: no output driver private present\n",__func__);
|
|
return atomNone;
|
|
}
|
|
devList = Output->OutputDriverPrivate->OutputDevices;
|
|
|
|
if (Output->Connector) {
|
|
/* connected - enable */
|
|
Device = rhdBIOSScratchSetDeviceForOutput(Output);
|
|
|
|
if (Device == atomNone && rhdPtr->Card->ConnectorInfo[0].Type != RHD_CONNECTOR_NONE) {
|
|
xf86DrvMsg(Output->scrnIndex, X_WARNING, "%s: AtomBIOS DeviceID unknown\n",__func__);
|
|
return Device;
|
|
}
|
|
|
|
ASSERT(Device != atomNone);
|
|
|
|
if (Output->Crtc)
|
|
rhdAtomBIOSScratchSetCrtcState(rhdPtr, Device,
|
|
Output->Crtc->Id == 1 ? atomCrtc2 : atomCrtc1);
|
|
rhdAtomBIOSScratchUpdateOnState(rhdPtr, Device, Output->Active);
|
|
rhdAtomBIOSScratchSetAcceleratorModeForDevice(rhdPtr, Device, Output->Active);
|
|
rhdAtomBIOSScratchUpdateAttachedState(rhdPtr, Device, TRUE);
|
|
|
|
while (devList[i].DeviceId != atomNone) {
|
|
if (devList[i].DeviceId != Device)
|
|
rhdAtomBIOSScratchUpdateOnState(rhdPtr, devList[i].DeviceId, FALSE);
|
|
i++;
|
|
}
|
|
|
|
} else {
|
|
/* not connected - just disable everything */
|
|
Device = atomNone;
|
|
Output->OutputDriverPrivate->Device = Device;
|
|
|
|
while (devList[i].DeviceId != atomNone) {
|
|
rhdAtomBIOSScratchUpdateOnState(rhdPtr, devList[i].DeviceId, FALSE);
|
|
rhdAtomBIOSScratchSetAcceleratorModeForDevice(rhdPtr,
|
|
devList[i].DeviceId, FALSE);
|
|
rhdAtomBIOSScratchUpdateAttachedState(rhdPtr, devList[i].DeviceId, FALSE);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return Device;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdBIOSScratchPower(struct rhdOutput *Output, int Power)
|
|
{
|
|
rhdBIOSScratchUpdateBIOSScratchForOutput(Output);
|
|
Output->OutputDriverPrivate->Power(Output, Power);
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdBIOSScratchMode(struct rhdOutput *Output, DisplayModePtr Mode)
|
|
{
|
|
rhdBIOSScratchUpdateBIOSScratchForOutput(Output);
|
|
Output->OutputDriverPrivate->Mode(Output, Mode);
|
|
}
|
|
|
|
/*
|
|
* This destroys the privates again. It is implemented as an output destroy wrapper.
|
|
*/
|
|
static void
|
|
rhdBIOSScratchDestroyOutputDriverPrivate(struct rhdOutput *Output)
|
|
{
|
|
RHDFUNC(Output);
|
|
|
|
if (Output->OutputDriverPrivate) {
|
|
void (*Destroy) (struct rhdOutput *Output) = Output->OutputDriverPrivate->Destroy;
|
|
|
|
xfree(Output->OutputDriverPrivate->OutputDevices);
|
|
xfree(Output->OutputDriverPrivate);
|
|
Output->OutputDriverPrivate = NULL;
|
|
if (Destroy)
|
|
Destroy(Output);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This sets up the AtomBIOS driver output private.
|
|
* It allocates the data structure and sets up the list of devices
|
|
* including the connector they are associated with.
|
|
*/
|
|
Bool
|
|
RHDAtomSetupOutputDriverPrivate(struct rhdAtomOutputDeviceList *Devices, struct rhdOutput *Output)
|
|
{
|
|
struct rhdOutputDevices *od = NULL;
|
|
struct BIOSScratchOutputPrivate *OutputDriverPrivate;
|
|
int i = 0, cnt = 0;
|
|
|
|
RHDFUNC(Output);
|
|
|
|
if (!Devices) {
|
|
RHDDebug(Output->scrnIndex, "%s: Device list doesn't exist.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
RHDDebugVerb(Output->scrnIndex, 1, " Output: %s[0x%2.2x] - adding devices:\n", Output->Name, Output->Id);
|
|
|
|
while (Devices[i].DeviceId != atomNone) {
|
|
RHDDebugVerb(Output->scrnIndex,1," Looking at DeviceID: 0x%2.2x OutputType: 0x%2.2x ConnectorType: 0x%2.2x\n",
|
|
Devices[i].DeviceId,Devices[i].OutputType,Devices[i].ConnectorType);
|
|
if (Devices[i].OutputType == Output->Id) {
|
|
if (!(od = (struct rhdOutputDevices *)xrealloc(od, sizeof(struct rhdOutputDevices) * (cnt + 1))))
|
|
return FALSE;
|
|
RHDDebugVerb(Output->scrnIndex,1," >> 0x%2.2x\n", Devices[i].DeviceId);
|
|
od[cnt].DeviceId = Devices[i].DeviceId;
|
|
od[cnt].ConnectorType = Devices[i].ConnectorType;
|
|
cnt++;
|
|
}
|
|
i++;
|
|
}
|
|
if (!(od = (struct rhdOutputDevices *)xrealloc(od, sizeof(struct rhdOutputDevices) * (cnt + 1))))
|
|
return FALSE;
|
|
od[cnt].DeviceId = atomNone;
|
|
|
|
if (!(OutputDriverPrivate = (struct BIOSScratchOutputPrivate *)xalloc(sizeof(struct BIOSScratchOutputPrivate)))) {
|
|
xfree(od);
|
|
return FALSE;
|
|
}
|
|
OutputDriverPrivate->OutputDevices = od;
|
|
OutputDriverPrivate->Destroy = Output->Destroy;
|
|
Output->Destroy = rhdBIOSScratchDestroyOutputDriverPrivate;
|
|
OutputDriverPrivate->Power = Output->Power;
|
|
Output->Power = rhdBIOSScratchPower;
|
|
OutputDriverPrivate->Mode = Output->Mode;
|
|
Output->Mode = rhdBIOSScratchMode;
|
|
Output->OutputDriverPrivate = OutputDriverPrivate;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Find the connector and output type for a specific atom device.
|
|
* This information is kept in the output lists.
|
|
*/
|
|
Bool
|
|
RHDFindConnectorAndOutputTypesForDevice(RHDPtr rhdPtr, enum atomDevice Device, enum rhdOutputType *ot, enum rhdConnectorType *ct)
|
|
{
|
|
struct rhdOutput *Output;
|
|
|
|
*ot = RHD_OUTPUT_NONE;
|
|
*ct = RHD_CONNECTOR_NONE;
|
|
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next) {
|
|
struct rhdOutputDevices *DeviceList;
|
|
int i = 0;
|
|
|
|
if (!Output->OutputDriverPrivate)
|
|
continue;
|
|
|
|
DeviceList = Output->OutputDriverPrivate->OutputDevices;
|
|
while (DeviceList[i].DeviceId != atomNone) {
|
|
if (DeviceList[i].DeviceId == Device) {
|
|
*ot = Output->Id;
|
|
*ct = DeviceList[i].ConnectorType;
|
|
return TRUE;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
enum atomDevice
|
|
RHDGetDeviceOnCrtc(RHDPtr rhdPtr, enum atomCrtc Crtc)
|
|
{
|
|
CARD32 BIOS_3;
|
|
CARD32 Addr;
|
|
CARD32 Mask = 0;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
Addr = 0x1C;
|
|
else
|
|
Addr = 0x1730;
|
|
|
|
if (Crtc == atomCrtc1)
|
|
Mask = ~Mask;
|
|
|
|
BIOS_3 = RHDRegRead(rhdPtr, Addr);
|
|
RHDDebug(rhdPtr->scrnIndex, "%s: BIOS_3 = 0x%x\n",__func__,BIOS_3);
|
|
|
|
if (BIOS_3 & ATOM_S3_CRT1_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_CRT1_CRTC_ACTIVE))
|
|
return atomCRT1;
|
|
else if (BIOS_3 & ATOM_S3_LCD1_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_LCD1_CRTC_ACTIVE))
|
|
return atomLCD1;
|
|
else if (BIOS_3 & ATOM_S3_DFP1_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_DFP1_CRTC_ACTIVE))
|
|
return atomDFP1;
|
|
else if (BIOS_3 & ATOM_S3_CRT2_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_CRT2_CRTC_ACTIVE))
|
|
return atomCRT2;
|
|
else if (BIOS_3 & ATOM_S3_LCD2_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_LCD2_CRTC_ACTIVE))
|
|
return atomLCD2;
|
|
else if (BIOS_3 & ATOM_S3_TV2_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_TV2_CRTC_ACTIVE))
|
|
return atomTV2;
|
|
else if (BIOS_3 & ATOM_S3_DFP2_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_DFP2_CRTC_ACTIVE))
|
|
return atomDFP2;
|
|
else if (BIOS_3 & ATOM_S3_CV_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_CV_CRTC_ACTIVE))
|
|
return atomCV;
|
|
else if (BIOS_3 & ATOM_S3_DFP3_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_DFP3_CRTC_ACTIVE))
|
|
return atomDFP3;
|
|
else if (BIOS_3 & ATOM_S3_DFP4_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_DFP4_CRTC_ACTIVE))
|
|
return atomDFP4;
|
|
else if (BIOS_3 & ATOM_S3_DFP5_ACTIVE
|
|
&& ((BIOS_3 ^ Mask) & ATOM_S3_DFP5_CRTC_ACTIVE))
|
|
return atomDFP5;
|
|
else
|
|
return atomNone;
|
|
}
|
|
|
|
struct rhdBiosScratchRegisters {
|
|
CARD32 Scratch0;
|
|
CARD32 Scratch2;
|
|
CARD32 Scratch3;
|
|
CARD32 Scratch6;
|
|
};
|
|
|
|
struct rhdBiosScratchRegisters *
|
|
RHDSaveBiosScratchRegisters(RHDPtr rhdPtr)
|
|
{
|
|
struct rhdBiosScratchRegisters *regs;
|
|
CARD32 S0Addr, S2Addr, S3Addr, S6Addr;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (!(regs = (struct rhdBiosScratchRegisters *)xalloc(sizeof(struct rhdBiosScratchRegisters))))
|
|
return NULL;
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600) {
|
|
S0Addr = 0x10;
|
|
S2Addr = 0x18;
|
|
S3Addr = 0x1C;
|
|
S6Addr = 0x10 + (6 << 2);
|
|
} else {
|
|
S0Addr = 0x1724;
|
|
S2Addr = 0x172C;
|
|
S3Addr = 0x1730;
|
|
S6Addr = 0x1724 + (6 << 2);
|
|
}
|
|
regs->Scratch0 = RHDRegRead(rhdPtr, S0Addr);
|
|
regs->Scratch2 = RHDRegRead(rhdPtr, S2Addr);
|
|
regs->Scratch3 = RHDRegRead(rhdPtr, S3Addr);
|
|
regs->Scratch6 = RHDRegRead(rhdPtr, S6Addr);
|
|
|
|
return regs;
|
|
}
|
|
|
|
void
|
|
RHDRestoreBiosScratchRegisters(RHDPtr rhdPtr, struct rhdBiosScratchRegisters *regs)
|
|
{
|
|
CARD32 S0Addr, S2Addr, S3Addr, S6Addr;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
if (!regs)
|
|
return;
|
|
|
|
if (rhdPtr->ChipSet < RHD_R600) {
|
|
S0Addr = 0x10;
|
|
S2Addr = 0x18;
|
|
S3Addr = 0x1C;
|
|
S6Addr = 0x10 + (6 << 2);
|
|
} else {
|
|
S0Addr = 0x1724;
|
|
S2Addr = 0x172C;
|
|
S3Addr = 0x1730;
|
|
S6Addr = 0x1724 + (6 << 2);
|
|
}
|
|
RHDRegWrite(rhdPtr, S0Addr, regs->Scratch0);
|
|
RHDRegWrite(rhdPtr, S2Addr, regs->Scratch2);
|
|
RHDRegWrite(rhdPtr, S3Addr, regs->Scratch3);
|
|
RHDRegWrite(rhdPtr, S6Addr, regs->Scratch6);
|
|
|
|
xfree(regs);
|
|
}
|
|
|
|
#endif /* ATOM_BIOS */
|
|
|