diff --git a/programs/system/drivers/rhd/AtomBios/CD_Operations.c b/programs/system/drivers/rhd/AtomBios/CD_Operations.c new file mode 100644 index 000000000..1e48f815a --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/CD_Operations.c @@ -0,0 +1,954 @@ +/* + * Copyright 2006-2007 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. + */ + +/** + +Module Name: + + CD_Operations.c + +Abstract: + + Functions Implementing Command Operations and other common functions + +Revision History: + + NEG:27.09.2002 Initiated. +--*/ +#define __SW_4 + +#include "Decoder.h" +#include "atombios.h" + + + +VOID PutDataRegister(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID PutDataPS(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID PutDataWS(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID PutDataFB(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID PutDataPLL(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID PutDataMC(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +UINT32 GetParametersDirect32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersDirect16(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersDirect8(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +UINT32 GetParametersRegister(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersPS(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersWS(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersFB(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersPLL(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersMC(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +VOID SkipParameters16(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID SkipParameters8(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +UINT32 GetParametersIndirect(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +UINT32 GetParametersDirect(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +UINT16* GetDataMasterTablePointer(DEVICE_DATA STACK_BASED* pDeviceData); +UINT8 GetTrueIndexInMasterTable(PARSER_TEMP_DATA STACK_BASED * pParserTempData, UINT8 IndexInMasterTable); + + +WRITE_IO_FUNCTION WritePCIFunctions[8] = { + WritePCIReg32, + WritePCIReg16, WritePCIReg16, WritePCIReg16, + WritePCIReg8,WritePCIReg8,WritePCIReg8,WritePCIReg8 +}; +WRITE_IO_FUNCTION WriteIOFunctions[8] = { + WriteSysIOReg32, + WriteSysIOReg16,WriteSysIOReg16,WriteSysIOReg16, + WriteSysIOReg8,WriteSysIOReg8,WriteSysIOReg8,WriteSysIOReg8 +}; +READ_IO_FUNCTION ReadPCIFunctions[8] = { + (READ_IO_FUNCTION)ReadPCIReg32, + (READ_IO_FUNCTION)ReadPCIReg16, + (READ_IO_FUNCTION)ReadPCIReg16, + (READ_IO_FUNCTION)ReadPCIReg16, + (READ_IO_FUNCTION)ReadPCIReg8, + (READ_IO_FUNCTION)ReadPCIReg8, + (READ_IO_FUNCTION)ReadPCIReg8, + (READ_IO_FUNCTION)ReadPCIReg8 +}; +READ_IO_FUNCTION ReadIOFunctions[8] = { + (READ_IO_FUNCTION)ReadSysIOReg32, + (READ_IO_FUNCTION)ReadSysIOReg16, + (READ_IO_FUNCTION)ReadSysIOReg16, + (READ_IO_FUNCTION)ReadSysIOReg16, + (READ_IO_FUNCTION)ReadSysIOReg8, + (READ_IO_FUNCTION)ReadSysIOReg8, + (READ_IO_FUNCTION)ReadSysIOReg8, + (READ_IO_FUNCTION)ReadSysIOReg8 +}; +READ_IO_FUNCTION GetParametersDirectArray[8]={ + GetParametersDirect32, + GetParametersDirect16,GetParametersDirect16,GetParametersDirect16, + GetParametersDirect8,GetParametersDirect8,GetParametersDirect8, + GetParametersDirect8 +}; + +COMMANDS_DECODER PutDataFunctions[6] = { + PutDataRegister, + PutDataPS, + PutDataWS, + PutDataFB, + PutDataPLL, + PutDataMC +}; +CD_GET_PARAMETERS GetDestination[6] = { + GetParametersRegister, + GetParametersPS, + GetParametersWS, + GetParametersFB, + GetParametersPLL, + GetParametersMC +}; + +COMMANDS_DECODER SkipDestination[6] = { + SkipParameters16, + SkipParameters8, + SkipParameters8, + SkipParameters8, + SkipParameters8, + SkipParameters8 +}; + +CD_GET_PARAMETERS GetSource[8] = { + GetParametersRegister, + GetParametersPS, + GetParametersWS, + GetParametersFB, + GetParametersIndirect, + GetParametersDirect, + GetParametersPLL, + GetParametersMC +}; + +UINT32 AlignmentMask[8] = {0xFFFFFFFF,0xFFFF,0xFFFF,0xFFFF,0xFF,0xFF,0xFF,0xFF}; +UINT8 SourceAlignmentShift[8] = {0,0,8,16,0,8,16,24}; +UINT8 DestinationAlignmentShift[4] = {0,8,16,24}; + +#define INDIRECTIO_ID 1 +#define INDIRECTIO_END_OF_ID 9 + +VOID IndirectIOCommand(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID IndirectIOCommand_MOVE(PARSER_TEMP_DATA STACK_BASED * pParserTempData, UINT32 temp); +VOID IndirectIOCommand_MOVE_INDEX(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID IndirectIOCommand_MOVE_ATTR(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID IndirectIOCommand_MOVE_DATA(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID IndirectIOCommand_SET(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +VOID IndirectIOCommand_CLEAR(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + +INDIRECT_IO_PARSER_COMMANDS IndirectIOParserCommands[10]={ + {IndirectIOCommand,1}, + {IndirectIOCommand,2}, + {ReadIndReg32,3}, + {WriteIndReg32,3}, + {IndirectIOCommand_CLEAR,3}, + {IndirectIOCommand_SET,3}, + {IndirectIOCommand_MOVE_INDEX,4}, + {IndirectIOCommand_MOVE_ATTR,4}, + {IndirectIOCommand_MOVE_DATA,4}, + {IndirectIOCommand,3} +}; + + +VOID IndirectIOCommand(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ +} + + +VOID IndirectIOCommand_MOVE_INDEX(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->IndirectData &= ~((0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1])) << pParserTempData->IndirectIOTablePointer[3]); + pParserTempData->IndirectData |=(((pParserTempData->Index >> pParserTempData->IndirectIOTablePointer[2]) & + (0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1]))) << pParserTempData->IndirectIOTablePointer[3]); +} + +VOID IndirectIOCommand_MOVE_ATTR(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->IndirectData &= ~((0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1])) << pParserTempData->IndirectIOTablePointer[3]); + pParserTempData->IndirectData |=(((pParserTempData->AttributesData >> pParserTempData->IndirectIOTablePointer[2]) + & (0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1]))) << pParserTempData->IndirectIOTablePointer[3]); +} + +VOID IndirectIOCommand_MOVE_DATA(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->IndirectData &= ~((0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1])) << pParserTempData->IndirectIOTablePointer[3]); + pParserTempData->IndirectData |=(((pParserTempData->DestData32 >> pParserTempData->IndirectIOTablePointer[2]) + & (0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1]))) << pParserTempData->IndirectIOTablePointer[3]); +} + + +VOID IndirectIOCommand_SET(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->IndirectData |= ((0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1])) << pParserTempData->IndirectIOTablePointer[2]); +} + +VOID IndirectIOCommand_CLEAR(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->IndirectData &= ~((0xFFFFFFFF >> (32-pParserTempData->IndirectIOTablePointer[1])) << pParserTempData->IndirectIOTablePointer[2]); +} + + +UINT32 IndirectInputOutput(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + // if ((pParserTempData->IndirectData & 0x7f)==INDIRECT_IO_MM) pParserTempData->IndirectData|=pParserTempData->CurrentPortID; +// pParserTempData->IndirectIOTablePointer=pParserTempData->IndirectIOTable; + while (*pParserTempData->IndirectIOTablePointer) + { + if ((pParserTempData->IndirectIOTablePointer[0] == INDIRECTIO_ID) && + (pParserTempData->IndirectIOTablePointer[1] == pParserTempData->IndirectData)) + { + pParserTempData->IndirectIOTablePointer+=IndirectIOParserCommands[*pParserTempData->IndirectIOTablePointer].csize; + while (*pParserTempData->IndirectIOTablePointer != INDIRECTIO_END_OF_ID) + { + IndirectIOParserCommands[*pParserTempData->IndirectIOTablePointer].func(pParserTempData); + pParserTempData->IndirectIOTablePointer+=IndirectIOParserCommands[*pParserTempData->IndirectIOTablePointer].csize; + } + pParserTempData->IndirectIOTablePointer-=*(UINT16*)(pParserTempData->IndirectIOTablePointer+1); + pParserTempData->IndirectIOTablePointer++; + return pParserTempData->IndirectData; + } else pParserTempData->IndirectIOTablePointer+=IndirectIOParserCommands[*pParserTempData->IndirectIOTablePointer].csize; + } + return 0; +} + + + +VOID PutDataRegister(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=(UINT32)pParserTempData->pCmd->Parameters.WordXX.PA_Destination; + pParserTempData->Index+=pParserTempData->CurrentRegBlock; + switch(pParserTempData->Multipurpose.CurrentPort){ + case ATI_RegsPort: + if (pParserTempData->CurrentPortID == INDIRECT_IO_MM) + { + if (pParserTempData->Index==0) pParserTempData->DestData32 <<= 2; + WriteReg32( pParserTempData); + } else + { + pParserTempData->IndirectData=pParserTempData->CurrentPortID+INDIRECT_IO_WRITE; + IndirectInputOutput(pParserTempData); + } + break; + case PCI_Port: + WritePCIFunctions[pParserTempData->pCmd->Header.Attribute.SourceAlignment](pParserTempData); + break; + case SystemIO_Port: + WriteIOFunctions[pParserTempData->pCmd->Header.Attribute.SourceAlignment](pParserTempData); + break; + } +} + +VOID PutDataPS(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + *(pParserTempData->pDeviceData->pParameterSpace+pParserTempData->pCmd->Parameters.ByteXX.PA_Destination)= + pParserTempData->DestData32; +} + +VOID PutDataWS(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + if (pParserTempData->pCmd->Parameters.ByteXX.PA_Destination < WS_QUOTIENT_C) + *(pParserTempData->pWorkingTableData->pWorkSpace+pParserTempData->pCmd->Parameters.ByteXX.PA_Destination) = pParserTempData->DestData32; + else + switch (pParserTempData->pCmd->Parameters.ByteXX.PA_Destination) + { + case WS_REMINDER_C: + pParserTempData->MultiplicationOrDivision.Division.Reminder32=pParserTempData->DestData32; + break; + case WS_QUOTIENT_C: + pParserTempData->MultiplicationOrDivision.Division.Quotient32=pParserTempData->DestData32; + break; + case WS_DATAPTR_C: +#ifndef UEFI_BUILD + pParserTempData->CurrentDataBlock=(UINT16)pParserTempData->DestData32; +#else + pParserTempData->CurrentDataBlock=(UINTN)pParserTempData->DestData32; +#endif + break; + case WS_SHIFT_C: + pParserTempData->Shift2MaskConverter=(UINT8)pParserTempData->DestData32; + break; + case WS_FB_WINDOW_C: + pParserTempData->CurrentFB_Window=pParserTempData->DestData32; + break; + case WS_ATTRIBUTES_C: + pParserTempData->AttributesData=(UINT16)pParserTempData->DestData32; + break; + } + +} + +VOID PutDataFB(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=(UINT32)pParserTempData->pCmd->Parameters.ByteXX.PA_Destination; + //Make an Index from address first, then add to the Index + pParserTempData->Index+=(pParserTempData->CurrentFB_Window>>2); + WriteFrameBuffer32(pParserTempData); +} + +VOID PutDataPLL(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=(UINT32)pParserTempData->pCmd->Parameters.ByteXX.PA_Destination; + WritePLL32( pParserTempData ); +} + +VOID PutDataMC(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=(UINT32)pParserTempData->pCmd->Parameters.ByteXX.PA_Destination; + WriteMC32( pParserTempData ); +} + + +VOID SkipParameters8(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); +} + +VOID SkipParameters16(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->pWorkingTableData->IP+=sizeof(UINT16); +} + + +UINT32 GetParametersRegister(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*(UINT16*)pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT16); + pParserTempData->Index+=pParserTempData->CurrentRegBlock; + switch(pParserTempData->Multipurpose.CurrentPort) + { + case PCI_Port: + return ReadPCIFunctions[pParserTempData->pCmd->Header.Attribute.SourceAlignment](pParserTempData); + case SystemIO_Port: + return ReadIOFunctions[pParserTempData->pCmd->Header.Attribute.SourceAlignment](pParserTempData); + case ATI_RegsPort: + default: + if (pParserTempData->CurrentPortID == INDIRECT_IO_MM) return ReadReg32( pParserTempData ); + else + { + pParserTempData->IndirectData=pParserTempData->CurrentPortID+INDIRECT_IO_READ; + return IndirectInputOutput(pParserTempData); + } + } +} + +UINT32 GetParametersPS(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); + return *(pParserTempData->pDeviceData->pParameterSpace+pParserTempData->Index); +} + +UINT32 GetParametersWS(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); + if (pParserTempData->Index < WS_QUOTIENT_C) + return *(pParserTempData->pWorkingTableData->pWorkSpace+pParserTempData->Index); + else + switch (pParserTempData->Index) + { + case WS_REMINDER_C: + return pParserTempData->MultiplicationOrDivision.Division.Reminder32; + case WS_QUOTIENT_C: + return pParserTempData->MultiplicationOrDivision.Division.Quotient32; + case WS_DATAPTR_C: + return (UINT32)pParserTempData->CurrentDataBlock; + case WS_OR_MASK_C: + return ((UINT32)1) << pParserTempData->Shift2MaskConverter; + case WS_AND_MASK_C: + return ~(((UINT32)1) << pParserTempData->Shift2MaskConverter); + case WS_FB_WINDOW_C: + return pParserTempData->CurrentFB_Window; + case WS_ATTRIBUTES_C: + return pParserTempData->AttributesData; + } + return 0; + +} + +UINT32 GetParametersFB(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); + pParserTempData->Index+=(pParserTempData->CurrentFB_Window>>2); + return ReadFrameBuffer32(pParserTempData); +} + +UINT32 GetParametersPLL(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); + return ReadPLL32( pParserTempData ); +} + +UINT32 GetParametersMC(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); + return ReadMC32( pParserTempData ); +} + + +UINT32 GetParametersIndirect(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Index=*(UINT16*)pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT16); + return *(UINT32*)(RELATIVE_TO_BIOS_IMAGE(pParserTempData->Index)+pParserTempData->CurrentDataBlock); +} + +UINT32 GetParametersDirect8(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->CD_Mask.SrcAlignment=alignmentByte0; + pParserTempData->Index=*(UINT8*)pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT8); + return pParserTempData->Index; +} + +UINT32 GetParametersDirect16(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->CD_Mask.SrcAlignment=alignmentLowerWord; + pParserTempData->Index=*(UINT16*)pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT16); + return pParserTempData->Index; +} + +UINT32 GetParametersDirect32(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->CD_Mask.SrcAlignment=alignmentDword; + pParserTempData->Index=*(UINT32*)pParserTempData->pWorkingTableData->IP; + pParserTempData->pWorkingTableData->IP+=sizeof(UINT32); + return pParserTempData->Index; +} + + +UINT32 GetParametersDirect(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + return GetParametersDirectArray[pParserTempData->pCmd->Header.Attribute.SourceAlignment](pParserTempData); +} + + +VOID CommonSourceDataTransformation(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->SourceData32 >>= SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->SourceData32 &= AlignmentMask[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->SourceData32 <<= DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]; +} + +VOID CommonOperationDataTransformation(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->SourceData32 >>= SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->SourceData32 &= AlignmentMask[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->DestData32 >>= DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]; + pParserTempData->DestData32 &= AlignmentMask[pParserTempData->CD_Mask.SrcAlignment]; +} + +VOID ProcessMove(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + if (pParserTempData->CD_Mask.SrcAlignment!=alignmentDword) + { + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + } else + { + SkipDestination[pParserTempData->ParametersType.Destination](pParserTempData); + } + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + + if (pParserTempData->CD_Mask.SrcAlignment!=alignmentDword) + { + pParserTempData->DestData32 &= ~(AlignmentMask[pParserTempData->CD_Mask.SrcAlignment] << DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 |= pParserTempData->SourceData32; + } else + { + pParserTempData->DestData32=pParserTempData->SourceData32; + } + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessMask(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetParametersDirect(pParserTempData); + pParserTempData->Index=GetParametersDirect(pParserTempData); + pParserTempData->SourceData32 <<= DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]; + pParserTempData->SourceData32 |= ~(AlignmentMask[pParserTempData->CD_Mask.SrcAlignment] << DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]); + pParserTempData->DestData32 &= pParserTempData->SourceData32; + pParserTempData->Index &= AlignmentMask[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->Index <<= DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]; + pParserTempData->DestData32 |= pParserTempData->Index; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessAnd(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + pParserTempData->SourceData32 >>= SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->SourceData32 <<= DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]; + pParserTempData->SourceData32 |= ~(AlignmentMask[pParserTempData->CD_Mask.SrcAlignment] << DestinationAlignmentShift[pParserTempData->CD_Mask.DestAlignment]); + pParserTempData->DestData32 &= pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessOr(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 |= pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessXor(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 ^= pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessShl(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 <<= pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessShr(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 >>= pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + + +VOID ProcessADD(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 += pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessSUB(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonSourceDataTransformation(pParserTempData); + pParserTempData->DestData32 -= pParserTempData->SourceData32; + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessMUL(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonOperationDataTransformation(pParserTempData); + pParserTempData->MultiplicationOrDivision.Multiplication.Low32Bit=pParserTempData->DestData32 * pParserTempData->SourceData32; +} + +VOID ProcessDIV(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + + CommonOperationDataTransformation(pParserTempData); + pParserTempData->MultiplicationOrDivision.Division.Quotient32= + pParserTempData->DestData32 / pParserTempData->SourceData32; + pParserTempData->MultiplicationOrDivision.Division.Reminder32= + pParserTempData->DestData32 % pParserTempData->SourceData32; +} + + +VOID ProcessCompare(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + + CommonOperationDataTransformation(pParserTempData); + + // Here we just set flags based on evaluation + if (pParserTempData->DestData32==pParserTempData->SourceData32) + pParserTempData->CompareFlags = Equal; + else + pParserTempData->CompareFlags = + (UINT8)((pParserTempData->DestData32SourceData32) ? Below : Above); + +} + +VOID ProcessClear(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->DestData32 &= ~(AlignmentMask[pParserTempData->CD_Mask.SrcAlignment] << SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]); + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); + +} + +VOID ProcessShift(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + UINT32 mask = AlignmentMask[pParserTempData->CD_Mask.SrcAlignment] << SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetParametersDirect8(pParserTempData); + + // save original value of the destination + pParserTempData->Index = pParserTempData->DestData32 & ~mask; + pParserTempData->DestData32 &= mask; + + if (pParserTempData->pCmd->Header.Opcode < SHIFT_RIGHT_REG_OPCODE) + pParserTempData->DestData32 <<= pParserTempData->SourceData32; else + pParserTempData->DestData32 >>= pParserTempData->SourceData32; + + // Clear any bits shifted out of masked area... + pParserTempData->DestData32 &= mask; + // ... and restore the area outside of masked with original values + pParserTempData->DestData32 |= pParserTempData->Index; + + // write data back + PutDataFunctions[pParserTempData->ParametersType.Destination](pParserTempData); +} + +VOID ProcessTest(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->DestData32=GetDestination[pParserTempData->ParametersType.Destination](pParserTempData); + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + CommonOperationDataTransformation(pParserTempData); + pParserTempData->CompareFlags = + (UINT8)((pParserTempData->DestData32 & pParserTempData->SourceData32) ? NotEqual : Equal); + +} + +VOID ProcessSetFB_Base(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + pParserTempData->SourceData32 >>= SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->SourceData32 &= AlignmentMask[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->CurrentFB_Window=pParserTempData->SourceData32; +} + +VOID ProcessSwitch(PARSER_TEMP_DATA STACK_BASED * pParserTempData){ + pParserTempData->SourceData32=GetSource[pParserTempData->ParametersType.Source](pParserTempData); + pParserTempData->SourceData32 >>= SourceAlignmentShift[pParserTempData->CD_Mask.SrcAlignment]; + pParserTempData->SourceData32 &= AlignmentMask[pParserTempData->CD_Mask.SrcAlignment]; + while ( *(UINT16*)pParserTempData->pWorkingTableData->IP != (((UINT16)NOP_OPCODE << 8)+NOP_OPCODE)) + { + if (*pParserTempData->pWorkingTableData->IP == 'c') + { + pParserTempData->pWorkingTableData->IP++; + pParserTempData->DestData32=GetParametersDirect(pParserTempData); + pParserTempData->Index=GetParametersDirect16(pParserTempData); + if (pParserTempData->SourceData32 == pParserTempData->DestData32) + { + pParserTempData->pWorkingTableData->IP= RELATIVE_TO_TABLE(pParserTempData->Index); + return; + } + } + } + pParserTempData->pWorkingTableData->IP+=sizeof(UINT16); +} + + +VOID cmdSetDataBlock(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + UINT8 value; + UINT16* pMasterDataTable; + value=((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.ByteXX.PA_Destination; + if (value == 0) pParserTempData->CurrentDataBlock=0; else + { + if (value == DB_CURRENT_COMMAND_TABLE) + { + pParserTempData->CurrentDataBlock= (UINT16)(pParserTempData->pWorkingTableData->pTableHead-pParserTempData->pDeviceData->pBIOS_Image); + } else + { + pMasterDataTable = GetDataMasterTablePointer(pParserTempData->pDeviceData); + pParserTempData->CurrentDataBlock= (TABLE_UNIT_TYPE)((PTABLE_UNIT_TYPE)pMasterDataTable)[value]; + } + } + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_VALUE_BYTE); +} + +VOID cmdSet_ATI_Port(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Multipurpose.CurrentPort=ATI_RegsPort; + pParserTempData->CurrentPortID = (UINT8)((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.WordXX.PA_Destination; + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_OFFSET16); +} + +VOID cmdSet_Reg_Block(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->CurrentRegBlock = ((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.WordXX.PA_Destination; + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_OFFSET16); +} + + +//Atavism!!! Review!!! +VOID cmdSet_X_Port(PARSER_TEMP_DATA STACK_BASED * pParserTempData){ + pParserTempData->Multipurpose.CurrentPort=pParserTempData->ParametersType.Destination; + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_ONLY); + +} + +VOID cmdDelay_Millisec(PARSER_TEMP_DATA STACK_BASED * pParserTempData){ + pParserTempData->SourceData32 = + ((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.ByteXX.PA_Destination; + DelayMilliseconds(pParserTempData); + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_VALUE_BYTE); +} +VOID cmdDelay_Microsec(PARSER_TEMP_DATA STACK_BASED * pParserTempData){ + pParserTempData->SourceData32 = + ((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.ByteXX.PA_Destination; + DelayMicroseconds(pParserTempData); + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_VALUE_BYTE); +} + +VOID ProcessPostChar(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->SourceData32 = + ((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.ByteXX.PA_Destination; + PostCharOutput(pParserTempData); + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_VALUE_BYTE); +} + +VOID ProcessDebug(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->SourceData32 = + ((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.ByteXX.PA_Destination; + CallerDebugFunc(pParserTempData); + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_VALUE_BYTE); +} + + +VOID ProcessDS(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->pWorkingTableData->IP+=((COMMAND_TYPE_1*)pParserTempData->pWorkingTableData->IP)->Parameters.WordXX.PA_Destination+sizeof(COMMAND_TYPE_OPCODE_OFFSET16); +} + + +VOID cmdCall_Table(PARSER_TEMP_DATA STACK_BASED * pParserTempData){ + UINT16* MasterTableOffset; + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_VALUE_BYTE); + MasterTableOffset = GetCommandMasterTablePointer(pParserTempData->pDeviceData); + if(((PTABLE_UNIT_TYPE)MasterTableOffset)[((COMMAND_TYPE_OPCODE_VALUE_BYTE*)pParserTempData->pCmd)->Value]!=0 ) // if the offset is not ZERO + { + pParserTempData->CommandSpecific.IndexInMasterTable=GetTrueIndexInMasterTable(pParserTempData,((COMMAND_TYPE_OPCODE_VALUE_BYTE*)pParserTempData->pCmd)->Value); + pParserTempData->Multipurpose.PS_SizeInDwordsUsedByCallingTable = + (((ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)pParserTempData->pWorkingTableData->pTableHead)->TableAttribute.PS_SizeInBytes>>2); + pParserTempData->pDeviceData->pParameterSpace+= + pParserTempData->Multipurpose.PS_SizeInDwordsUsedByCallingTable; + pParserTempData->Status=CD_CALL_TABLE; + pParserTempData->pCmd=(GENERIC_ATTRIBUTE_COMMAND*)MasterTableOffset; + } +} + + +VOID cmdNOP_(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ +} + + +static VOID NotImplemented(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + pParserTempData->Status = CD_NOT_IMPLEMENTED; +} + + +VOID ProcessJump(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + if ((pParserTempData->ParametersType.Destination == NoCondition) || + (pParserTempData->ParametersType.Destination == pParserTempData->CompareFlags )) + { + + pParserTempData->pWorkingTableData->IP= RELATIVE_TO_TABLE(((COMMAND_TYPE_OPCODE_OFFSET16*)pParserTempData->pWorkingTableData->IP)->CD_Offset16); + } else + { + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_OFFSET16); + } +} + +VOID ProcessJumpE(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + if ((pParserTempData->CompareFlags == Equal) || + (pParserTempData->CompareFlags == pParserTempData->ParametersType.Destination)) + { + + pParserTempData->pWorkingTableData->IP= RELATIVE_TO_TABLE(((COMMAND_TYPE_OPCODE_OFFSET16*)pParserTempData->pWorkingTableData->IP)->CD_Offset16); + } else + { + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_OFFSET16); + } +} + +VOID ProcessJumpNE(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + if (pParserTempData->CompareFlags != Equal) + { + + pParserTempData->pWorkingTableData->IP= RELATIVE_TO_TABLE(((COMMAND_TYPE_OPCODE_OFFSET16*)pParserTempData->pWorkingTableData->IP)->CD_Offset16); + } else + { + pParserTempData->pWorkingTableData->IP+=sizeof(COMMAND_TYPE_OPCODE_OFFSET16); + } +} + + + +COMMANDS_PROPERTIES CallTable[] = +{ + { NULL, 0,0}, + { ProcessMove, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessMove, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessMove, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessMove, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessMove, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessMove, destMC, sizeof(COMMAND_HEADER)}, + { ProcessAnd, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessAnd, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessAnd, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessAnd, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessAnd, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessAnd, destMC, sizeof(COMMAND_HEADER)}, + { ProcessOr, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessOr, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessOr, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessOr, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessOr, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessOr, destMC, sizeof(COMMAND_HEADER)}, + { ProcessShift, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessShift, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessShift, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessShift, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessShift, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessShift, destMC, sizeof(COMMAND_HEADER)}, + { ProcessShift, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessShift, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessShift, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessShift, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessShift, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessShift, destMC, sizeof(COMMAND_HEADER)}, + { ProcessMUL, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessMUL, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessMUL, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessMUL, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessMUL, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessMUL, destMC, sizeof(COMMAND_HEADER)}, + { ProcessDIV, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessDIV, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessDIV, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessDIV, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessDIV, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessDIV, destMC, sizeof(COMMAND_HEADER)}, + { ProcessADD, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessADD, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessADD, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessADD, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessADD, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessADD, destMC, sizeof(COMMAND_HEADER)}, + { ProcessSUB, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessSUB, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessSUB, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessSUB, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessSUB, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessSUB, destMC, sizeof(COMMAND_HEADER)}, + { cmdSet_ATI_Port, ATI_RegsPort, 0}, + { cmdSet_X_Port, PCI_Port, 0}, + { cmdSet_X_Port, SystemIO_Port, 0}, + { cmdSet_Reg_Block, 0, 0}, + { ProcessSetFB_Base,0, sizeof(COMMAND_HEADER)}, + { ProcessCompare, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessCompare, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessCompare, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessCompare, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessCompare, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessCompare, destMC, sizeof(COMMAND_HEADER)}, + { ProcessSwitch, 0, sizeof(COMMAND_HEADER)}, + { ProcessJump, NoCondition, 0}, + { ProcessJump, Equal, 0}, + { ProcessJump, Below, 0}, + { ProcessJump, Above, 0}, + { ProcessJumpE, Below, 0}, + { ProcessJumpE, Above, 0}, + { ProcessJumpNE, 0, 0}, + { ProcessTest, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessTest, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessTest, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessTest, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessTest, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessTest, destMC, sizeof(COMMAND_HEADER)}, + { cmdDelay_Millisec,0, 0}, + { cmdDelay_Microsec,0, 0}, + { cmdCall_Table, 0, 0}, + /*cmdRepeat*/ { NotImplemented, 0, 0}, + { ProcessClear, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessClear, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessClear, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessClear, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessClear, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessClear, destMC, sizeof(COMMAND_HEADER)}, + { cmdNOP_, 0, sizeof(COMMAND_TYPE_OPCODE_ONLY)}, + /*cmdEOT*/ { cmdNOP_, 0, sizeof(COMMAND_TYPE_OPCODE_ONLY)}, + { ProcessMask, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessMask, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessMask, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessMask, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessMask, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessMask, destMC, sizeof(COMMAND_HEADER)}, + /*cmdPost_Card*/ { ProcessPostChar, 0, 0}, + /*cmdBeep*/ { NotImplemented, 0, 0}, + /*cmdSave_Reg*/ { NotImplemented, 0, 0}, + /*cmdRestore_Reg*/{ NotImplemented, 0, 0}, + { cmdSetDataBlock, 0, 0}, + { ProcessXor, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessXor, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessXor, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessXor, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessXor, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessXor, destMC, sizeof(COMMAND_HEADER)}, + + { ProcessShl, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessShl, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessShl, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessShl, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessShl, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessShl, destMC, sizeof(COMMAND_HEADER)}, + + { ProcessShr, destRegister, sizeof(COMMAND_HEADER)}, + { ProcessShr, destParamSpace, sizeof(COMMAND_HEADER)}, + { ProcessShr, destWorkSpace, sizeof(COMMAND_HEADER)}, + { ProcessShr, destFrameBuffer, sizeof(COMMAND_HEADER)}, + { ProcessShr, destPLL, sizeof(COMMAND_HEADER)}, + { ProcessShr, destMC, sizeof(COMMAND_HEADER)}, + /*cmdDebug*/ { ProcessDebug, 0, 0}, + { ProcessDS, 0, 0}, + +}; + +// EOF diff --git a/programs/system/drivers/rhd/AtomBios/Decoder.c b/programs/system/drivers/rhd/AtomBios/Decoder.c new file mode 100644 index 000000000..95908d5fe --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/Decoder.c @@ -0,0 +1,235 @@ +/* + * Copyright 2006-2007 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. + */ + +/** + +Module Name: + + Decoder.c + +Abstract: + + Commands Decoder + +Revision History: + + NEG:24.09.2002 Initiated. +--*/ +//#include "AtomBios.h" +#include "Decoder.h" +#include "atombios.h" +#include "CD_binding.h" +#include "CD_Common_Types.h" + +#ifndef DISABLE_EASF + #include "easf.h" +#endif + + + +#define INDIRECT_IO_TABLE (((UINT16)&((ATOM_MASTER_LIST_OF_DATA_TABLES*)0)->IndirectIOAccess)/sizeof(TABLE_UNIT_TYPE) ) +extern COMMANDS_PROPERTIES CallTable[]; + + +UINT8 ProcessCommandProperties(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ + UINT8 opcode=((COMMAND_HEADER*)pParserTempData->pWorkingTableData->IP)->Opcode; + pParserTempData->pWorkingTableData->IP+=CallTable[opcode].headersize; + pParserTempData->ParametersType.Destination=CallTable[opcode].destination; + pParserTempData->ParametersType.Source = pParserTempData->pCmd->Header.Attribute.Source; + pParserTempData->CD_Mask.SrcAlignment=pParserTempData->pCmd->Header.Attribute.SourceAlignment; + pParserTempData->CD_Mask.DestAlignment=pParserTempData->pCmd->Header.Attribute.DestinationAlignment; + return opcode; +} + +UINT16* GetCommandMasterTablePointer(DEVICE_DATA STACK_BASED* pDeviceData) +{ + UINT16 *MasterTableOffset; +#ifndef DISABLE_EASF + if (pDeviceData->format == TABLE_FORMAT_EASF) + { + /* + make MasterTableOffset point to EASF_ASIC_SETUP_TABLE structure, including usSize. + */ + MasterTableOffset = (UINT16 *) (pDeviceData->pBIOS_Image+((EASF_ASIC_DESCRIPTOR*)pDeviceData->pBIOS_Image)->usAsicSetupTable_Offset); + } else +#endif + { +#ifndef UEFI_BUILD + MasterTableOffset = (UINT16 *)(*(UINT16 *)(pDeviceData->pBIOS_Image+OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER) + pDeviceData->pBIOS_Image); + MasterTableOffset = (UINT16 *)((ULONG)((ATOM_ROM_HEADER *)MasterTableOffset)->usMasterCommandTableOffset + pDeviceData->pBIOS_Image ); + MasterTableOffset =(UINT16 *) &(((ATOM_MASTER_COMMAND_TABLE *)MasterTableOffset)->ListOfCommandTables); +#else + MasterTableOffset = (UINT16 *)(&(GetCommandMasterTable( )->ListOfCommandTables)); +#endif + } + return MasterTableOffset; +} + +UINT16* GetDataMasterTablePointer(DEVICE_DATA STACK_BASED* pDeviceData) +{ + UINT16 *MasterTableOffset; + +#ifndef UEFI_BUILD + MasterTableOffset = (UINT16 *)(*(UINT16 *)(pDeviceData->pBIOS_Image+OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER) + pDeviceData->pBIOS_Image); + MasterTableOffset = (UINT16 *)((ULONG)((ATOM_ROM_HEADER *)MasterTableOffset)->usMasterDataTableOffset + pDeviceData->pBIOS_Image ); + MasterTableOffset =(UINT16 *) &(((ATOM_MASTER_DATA_TABLE *)MasterTableOffset)->ListOfDataTables); +#else + MasterTableOffset = (UINT16 *)(&(GetDataMasterTable( )->ListOfDataTables)); +#endif + return MasterTableOffset; +} + + +UINT8 GetTrueIndexInMasterTable(PARSER_TEMP_DATA STACK_BASED * pParserTempData, UINT8 IndexInMasterTable) +{ +#ifndef DISABLE_EASF + UINT16 i; + if ( pParserTempData->pDeviceData->format == TABLE_FORMAT_EASF) + { +/* + Consider EASF_ASIC_SETUP_TABLE structure pointed by pParserTempData->pCmd as UINT16[] + ((UINT16*)pParserTempData->pCmd)[0] = EASF_ASIC_SETUP_TABLE.usSize; + ((UINT16*)pParserTempData->pCmd)[1+n*4] = usFunctionID; + usFunctionID has to be shifted left by 2 before compare it to the value provided by caller. +*/ + for (i=1; (i < ((UINT16*)pParserTempData->pCmd)[0] >> 1);i+=4) + if ((UINT8)(((UINT16*)pParserTempData->pCmd)[i] << 2)==(IndexInMasterTable & EASF_TABLE_INDEX_MASK)) return (i+1+(IndexInMasterTable & EASF_TABLE_ATTR_MASK)); + return 1; + } else +#endif + { + return IndexInMasterTable; + } +} + +CD_STATUS ParseTable(DEVICE_DATA STACK_BASED* pDeviceData, UINT8 IndexInMasterTable) +{ + PARSER_TEMP_DATA ParserTempData; + WORKING_TABLE_DATA STACK_BASED* prevWorkingTableData; + + ParserTempData.pDeviceData=(DEVICE_DATA*)pDeviceData; +#ifndef DISABLE_EASF + if (pDeviceData->format == TABLE_FORMAT_EASF) + { + ParserTempData.IndirectIOTablePointer = 0; + } else +#endif + { + ParserTempData.pCmd=(GENERIC_ATTRIBUTE_COMMAND*)GetDataMasterTablePointer(pDeviceData); + ParserTempData.IndirectIOTablePointer=(UINT8*)((ULONG)(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[INDIRECT_IO_TABLE]) + pDeviceData->pBIOS_Image); + ParserTempData.IndirectIOTablePointer+=sizeof(ATOM_COMMON_TABLE_HEADER); + } + + ParserTempData.pCmd=(GENERIC_ATTRIBUTE_COMMAND*)GetCommandMasterTablePointer(pDeviceData); + IndexInMasterTable=GetTrueIndexInMasterTable((PARSER_TEMP_DATA STACK_BASED *)&ParserTempData,IndexInMasterTable); + if(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]!=0 ) // if the offset is not ZERO + { + ParserTempData.CommandSpecific.IndexInMasterTable=IndexInMasterTable; + ParserTempData.Multipurpose.CurrentPort=ATI_RegsPort; + ParserTempData.CurrentPortID=INDIRECT_IO_MM; + ParserTempData.CurrentRegBlock=0; + ParserTempData.CurrentFB_Window=0; + prevWorkingTableData=NULL; + ParserTempData.Status=CD_CALL_TABLE; + + do{ + + if (ParserTempData.Status==CD_CALL_TABLE) + { + IndexInMasterTable=ParserTempData.CommandSpecific.IndexInMasterTable; + if(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]!=0) // if the offset is not ZERO + { +#ifndef UEFI_BUILD + ParserTempData.pWorkingTableData =(WORKING_TABLE_DATA STACK_BASED*) AllocateWorkSpace(pDeviceData, + ((ATOM_COMMON_ROM_COMMAND_TABLE_HEADER*)(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]+pDeviceData->pBIOS_Image))->TableAttribute.WS_SizeInBytes+sizeof(WORKING_TABLE_DATA)); +#else + ParserTempData.pWorkingTableData =(WORKING_TABLE_DATA STACK_BASED*) AllocateWorkSpace(pDeviceData, + ((ATOM_COMMON_ROM_COMMAND_TABLE_HEADER*)(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]))->TableAttribute.WS_SizeInBytes+sizeof(WORKING_TABLE_DATA)); +#endif + if (ParserTempData.pWorkingTableData!=NULL) + { + ParserTempData.pWorkingTableData->pWorkSpace=(WORKSPACE_POINTER STACK_BASED*)((UINT8*)ParserTempData.pWorkingTableData+sizeof(WORKING_TABLE_DATA)); +#ifndef UEFI_BUILD + ParserTempData.pWorkingTableData->pTableHead = (UINT8 *)(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]+pDeviceData->pBIOS_Image); +#else + ParserTempData.pWorkingTableData->pTableHead = (UINT8 *)(((PTABLE_UNIT_TYPE)ParserTempData.pCmd)[IndexInMasterTable]); +#endif + ParserTempData.pWorkingTableData->IP=((UINT8*)ParserTempData.pWorkingTableData->pTableHead)+sizeof(ATOM_COMMON_ROM_COMMAND_TABLE_HEADER); + ParserTempData.pWorkingTableData->prevWorkingTableData=prevWorkingTableData; + prevWorkingTableData=ParserTempData.pWorkingTableData; + ParserTempData.Status = CD_SUCCESS; + } else ParserTempData.Status = CD_UNEXPECTED_BEHAVIOR; + } else ParserTempData.Status = CD_EXEC_TABLE_NOT_FOUND; + } + if (!CD_ERROR(ParserTempData.Status)) + { + ParserTempData.Status = CD_SUCCESS; + while (!CD_ERROR_OR_COMPLETED(ParserTempData.Status)) + { + + if (IS_COMMAND_VALID(((COMMAND_HEADER*)ParserTempData.pWorkingTableData->IP)->Opcode)) + { + ParserTempData.pCmd = (GENERIC_ATTRIBUTE_COMMAND*)ParserTempData.pWorkingTableData->IP; + + if (IS_END_OF_TABLE(((COMMAND_HEADER*)ParserTempData.pWorkingTableData->IP)->Opcode)) + { + ParserTempData.Status=CD_COMPLETED; + prevWorkingTableData=ParserTempData.pWorkingTableData->prevWorkingTableData; + + FreeWorkSpace(pDeviceData, ParserTempData.pWorkingTableData); + ParserTempData.pWorkingTableData=prevWorkingTableData; + if (prevWorkingTableData!=NULL) + { + ParserTempData.pDeviceData->pParameterSpace-= + (((ATOM_COMMON_ROM_COMMAND_TABLE_HEADER*)ParserTempData.pWorkingTableData-> + pTableHead)->TableAttribute.PS_SizeInBytes>>2); + } + // if there is a parent table where to return, then restore PS_pointer to the original state + } + else + { + IndexInMasterTable=ProcessCommandProperties((PARSER_TEMP_DATA STACK_BASED *)&ParserTempData); + (*CallTable[IndexInMasterTable].function)((PARSER_TEMP_DATA STACK_BASED *)&ParserTempData); +#if (PARSER_TYPE!=DRIVER_TYPE_PARSER) + BIOS_STACK_MODIFIER(); +#endif + } + } + else + { + ParserTempData.Status=CD_INVALID_OPCODE; + break; + } + + } // while + } // if + else + break; + } while (prevWorkingTableData!=NULL); + if (ParserTempData.Status == CD_COMPLETED) return CD_SUCCESS; + return ParserTempData.Status; + } else return CD_SUCCESS; +} + +// EOF + diff --git a/programs/system/drivers/rhd/AtomBios/hwserv_drv.c b/programs/system/drivers/rhd/AtomBios/hwserv_drv.c new file mode 100644 index 000000000..a5f5a5b80 --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/hwserv_drv.c @@ -0,0 +1,348 @@ +/* + * Copyright 2006-2007 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. + */ + +/** + +Module Name: + + hwserv_drv.c + +Abstract: + + Functions defined in the Command Decoder Specification document + +Revision History: + + NEG:27.09.2002 Initiated. +--*/ +#include "CD_binding.h" +#include "CD_hw_services.h" + +//trace settings +#if DEBUG_OUTPUT_DEVICE & 1 + #define TRACE_USING_STDERR //define it to use stderr as trace output, +#endif +#if DEBUG_OUTPUT_DEVICE & 2 + #define TRACE_USING_RS232 +#endif +#if DEBUG_OUTPUT_DEVICE & 4 + #define TRACE_USING_LPT +#endif + + +#if DEBUG_PARSER == 4 + #define IO_TRACE //IO access trace switch, undefine it to turn off + #define PCI_TRACE //PCI access trace switch, undefine it to turn off + #define MEM_TRACE //MEM access trace switch, undefine it to turn off +#endif + +UINT32 CailReadATIRegister(VOID*,UINT32); +VOID CailWriteATIRegister(VOID*,UINT32,UINT32); +VOID* CailAllocateMemory(VOID*,UINT16); +VOID CailReleaseMemory(VOID *,VOID *); +VOID CailDelayMicroSeconds(VOID *,UINT32 ); +VOID CailReadPCIConfigData(VOID*,VOID*,UINT32,UINT16); +VOID CailWritePCIConfigData(VOID*,VOID*,UINT32,UINT16); +UINT32 CailReadFBData(VOID*,UINT32); +VOID CailWriteFBData(VOID*,UINT32,UINT32); +ULONG CailReadPLL(VOID *Context ,ULONG Address); +VOID CailWritePLL(VOID *Context,ULONG Address,ULONG Data); +ULONG CailReadMC(VOID *Context ,ULONG Address); +VOID CailWriteMC(VOID *Context ,ULONG Address,ULONG Data); + + +#if DEBUG_PARSER>0 +VOID CailVideoDebugPrint(VOID*,ULONG_PTR, UINT16); +#endif +// Delay function +#if ( defined ENABLE_PARSER_DELAY || defined ENABLE_ALL_SERVICE_FUNCTIONS ) + +VOID DelayMilliseconds(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailDelayMicroSeconds(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->SourceData32*1000); +} + +VOID DelayMicroseconds(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailDelayMicroSeconds(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->SourceData32); +} +#endif + +VOID PostCharOutput(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ +} + +VOID CallerDebugFunc(PARSER_TEMP_DATA STACK_BASED * pParserTempData) +{ +} + + +// PCI READ Access + +#if ( defined ENABLE_PARSER_PCIREAD8 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT8 ReadPCIReg8(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + UINT8 rvl; + CailReadPCIConfigData(pWorkingTableData->pDeviceData->CAIL,&rvl,pWorkingTableData->Index,sizeof(UINT8)); + return rvl; +} +#endif + + +#if ( defined ENABLE_PARSER_PCIREAD16 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT16 ReadPCIReg16(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + UINT16 rvl; + CailReadPCIConfigData(pWorkingTableData->pDeviceData->CAIL,&rvl,pWorkingTableData->Index,sizeof(UINT16)); + return rvl; + +} +#endif + + + +#if ( defined ENABLE_PARSER_PCIREAD32 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT32 ReadPCIReg32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + UINT32 rvl; + CailReadPCIConfigData(pWorkingTableData->pDeviceData->CAIL,&rvl,pWorkingTableData->Index,sizeof(UINT32)); + return rvl; +} +#endif + + +// PCI WRITE Access + +#if ( defined ENABLE_PARSER_PCIWRITE8 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +VOID WritePCIReg8 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + CailWritePCIConfigData(pWorkingTableData->pDeviceData->CAIL,&(pWorkingTableData->DestData32),pWorkingTableData->Index,sizeof(UINT8)); + +} + +#endif + + +#if ( defined ENABLE_PARSER_PCIWRITE16 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +VOID WritePCIReg16 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + CailWritePCIConfigData(pWorkingTableData->pDeviceData->CAIL,&(pWorkingTableData->DestData32),pWorkingTableData->Index,sizeof(UINT16)); +} + +#endif + + +#if ( defined ENABLE_PARSER_PCIWRITE32 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +VOID WritePCIReg32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailWritePCIConfigData(pWorkingTableData->pDeviceData->CAIL,&(pWorkingTableData->DestData32),pWorkingTableData->Index,sizeof(UINT32)); +} +#endif + + + + +// System IO Access +#if ( defined ENABLE_PARSER_SYS_IOREAD8 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT8 ReadSysIOReg8 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + UINT8 rvl; + rvl=0; + //rvl= (UINT8) ReadGenericPciCfg(dev,reg,sizeof(UINT8)); + return rvl; +} +#endif + + +#if ( defined ENABLE_PARSER_SYS_IOREAD16 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT16 ReadSysIOReg16(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + UINT16 rvl; + rvl=0; + //rvl= (UINT16) ReadGenericPciCfg(dev,reg,sizeof(UINT16)); + return rvl; + +} +#endif + + + +#if ( defined ENABLE_PARSER_SYS_IOREAD32 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT32 ReadSysIOReg32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + UINT32 rvl; + rvl=0; + //rvl= (UINT32) ReadGenericPciCfg(dev,reg,sizeof(UINT32)); + return rvl; +} +#endif + + +// PCI WRITE Access + +#if ( defined ENABLE_PARSER_SYS_IOWRITE8 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +VOID WriteSysIOReg8 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + //WriteGenericPciCfg(dev,reg,sizeof(UINT8),(UINT32)value); +} + +#endif + + +#if ( defined ENABLE_PARSER_SYS_IOWRITE16 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +VOID WriteSysIOReg16 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + //WriteGenericPciCfg(dev,reg,sizeof(UINT16),(UINT32)value); +} + +#endif + + +#if ( defined ENABLE_PARSER_SYS_IOWRITE32 || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +VOID WriteSysIOReg32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + //WriteGenericPciCfg(dev,reg,sizeof(UINT32),(UINT32)value); +} +#endif + +// ATI Registers Memory Mapped Access + +#if ( defined ENABLE_PARSER_REGISTERS_MEMORY_ACCESS || defined ENABLE_ALL_SERVICE_FUNCTIONS) + +UINT32 ReadReg32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + return CailReadATIRegister(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index); +} + +VOID WriteReg32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailWriteATIRegister(pWorkingTableData->pDeviceData->CAIL,(UINT16)pWorkingTableData->Index,pWorkingTableData->DestData32 ); +} + + +VOID ReadIndReg32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + pWorkingTableData->IndirectData = CailReadATIRegister(pWorkingTableData->pDeviceData->CAIL,*(UINT16*)(pWorkingTableData->IndirectIOTablePointer+1)); +} + +VOID WriteIndReg32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailWriteATIRegister(pWorkingTableData->pDeviceData->CAIL,*(UINT16*)(pWorkingTableData->IndirectIOTablePointer+1),pWorkingTableData->IndirectData ); +} + +#endif + +// ATI Registers IO Mapped Access + +#if ( defined ENABLE_PARSER_REGISTERS_IO_ACCESS || defined ENABLE_ALL_SERVICE_FUNCTIONS ) +UINT32 ReadRegIO (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + //return CailReadATIRegister(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index); + return 0; +} +VOID WriteRegIO(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + // return CailWriteATIRegister(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index,pWorkingTableData->DestData32 ); +} +#endif + +// access to Frame buffer, dummy function, need more information to implement it +UINT32 ReadFrameBuffer32 (PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + + return CailReadFBData(pWorkingTableData->pDeviceData->CAIL, (pWorkingTableData->Index <<2 )); + +} + +VOID WriteFrameBuffer32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailWriteFBData(pWorkingTableData->pDeviceData->CAIL,(pWorkingTableData->Index <<2), pWorkingTableData->DestData32); + +} + + +VOID *AllocateMemory(DEVICE_DATA *pDeviceData , UINT16 MemSize) +{ + if(MemSize) + return(CailAllocateMemory(pDeviceData->CAIL,MemSize)); + else + return NULL; +} + + +VOID ReleaseMemory(DEVICE_DATA *pDeviceData , WORKING_TABLE_DATA* pWorkingTableData) +{ + if( pWorkingTableData) + CailReleaseMemory(pDeviceData->CAIL, pWorkingTableData); +} + + +UINT32 ReadMC32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + UINT32 ReadData; + ReadData=(UINT32)CailReadMC(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index); + return ReadData; +} + +VOID WriteMC32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailWriteMC(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index,pWorkingTableData->DestData32); +} + +UINT32 ReadPLL32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + UINT32 ReadData; + ReadData=(UINT32)CailReadPLL(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index); + return ReadData; + +} + +VOID WritePLL32(PARSER_TEMP_DATA STACK_BASED * pWorkingTableData) +{ + CailWritePLL(pWorkingTableData->pDeviceData->CAIL,pWorkingTableData->Index,pWorkingTableData->DestData32); + +} + + + +#if DEBUG_PARSER>0 +VOID CD_print_string (DEVICE_DATA *pDeviceData, UINT8 *str) +{ + CailVideoDebugPrint( pDeviceData->CAIL, (ULONG_PTR) str, PARSER_STRINGS); +} + +VOID CD_print_value (DEVICE_DATA *pDeviceData, ULONG_PTR value, UINT16 value_type ) +{ + CailVideoDebugPrint( pDeviceData->CAIL, (ULONG_PTR)value, value_type); +} + +#endif + +// EOF diff --git a/programs/system/drivers/rhd/AtomBios/includes/CD_Common_Types.h b/programs/system/drivers/rhd/AtomBios/includes/CD_Common_Types.h new file mode 100644 index 000000000..32d01ef9f --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/CD_Common_Types.h @@ -0,0 +1,156 @@ +/* + * Copyright 2006-2007 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. + */ + +/*++ + +Module Name: + + CD_Common_Types.h + +Abstract: + + Defines common data types to use across platforms/SW components + +Revision History: + + NEG:17.09.2002 Initiated. +--*/ +#ifndef _COMMON_TYPES_H_ + #define _COMMON_TYPES_H_ + + #ifndef LINUX + #if _MSC_EXTENSIONS + + // + // use Microsoft* C complier dependent interger width types + // + // typedef unsigned __int64 uint64_t; + // typedef __int64 int64_t; + typedef unsigned __int32 uint32_t; + typedef __int32 int32_t; +#elif defined (__linux__) || defined (__NetBSD__) \ + || defined(__sun) || defined(__OpenBSD__) \ + || defined (__FreeBSD__) || defined(__DragonFly__) || defined(__GLIBC__) + typedef unsigned int uint32_t; + typedef int int32_t; + #else + typedef unsigned long uint32_t; + typedef signed long int32_t; + #endif + typedef unsigned char uint8_t; +#if (defined(__sun) && defined(_CHAR_IS_SIGNED)) + typedef char int8_t; +#else + typedef signed char int8_t; +#endif + typedef unsigned short uint16_t; + typedef signed short int16_t; + #endif +#ifndef UEFI_BUILD + typedef signed int intn_t; + typedef unsigned int uintn_t; +#else +#ifndef EFIX64 + typedef signed int intn_t; + typedef unsigned int uintn_t; +#endif +#endif +#ifndef FGL_LINUX +#pragma warning ( disable : 4142 ) +#endif + + +#ifndef VOID +typedef void VOID; +#endif +#ifndef UEFI_BUILD + typedef intn_t INTN; + typedef uintn_t UINTN; +#else +#ifndef EFIX64 + typedef intn_t INTN; + typedef uintn_t UINTN; +#endif +#endif +#ifndef BOOLEAN +typedef uint8_t BOOLEAN; +#endif +#ifndef INT8 +typedef int8_t INT8; +#endif +#ifndef UINT8 +typedef uint8_t UINT8; +#endif +#ifndef INT16 +typedef int16_t INT16; +#endif +#ifndef UINT16 +typedef uint16_t UINT16; +#endif +#ifndef INT32 +typedef int32_t INT32; +#endif +#ifndef UINT32 +typedef uint32_t UINT32; +#endif +//typedef int64_t INT64; +//typedef uint64_t UINT64; +typedef uint8_t CHAR8; +typedef uint16_t CHAR16; +#ifndef USHORT +typedef UINT16 USHORT; +#endif +#ifndef UCHAR +typedef UINT8 UCHAR; +#endif +#ifndef ULONG +typedef UINT32 ULONG; +#endif + +#ifndef _WIN64 +#ifndef ULONG_PTR +typedef unsigned long ULONG_PTR; +#endif // ULONG_PTR +#endif // _WIN64 + +//#define FAR __far +#ifndef TRUE + #define TRUE ((BOOLEAN) 1 == 1) +#endif + +#ifndef FALSE + #define FALSE ((BOOLEAN) 0 == 1) +#endif + +#ifndef NULL + #define NULL ((VOID *) 0) +#endif + +//typedef UINTN CD_STATUS; + + +#ifndef FGL_LINUX +#pragma warning ( default : 4142 ) +#endif +#endif // _COMMON_TYPES_H_ + +// EOF diff --git a/programs/system/drivers/rhd/AtomBios/includes/CD_Definitions.h b/programs/system/drivers/rhd/AtomBios/includes/CD_Definitions.h new file mode 100644 index 000000000..98fd49546 --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/CD_Definitions.h @@ -0,0 +1,49 @@ +/* + * Copyright 2006-2007 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. + */ + +/*++ + +Module Name: + +CD_Definitions.h + +Abstract: + +Defines Script Language commands + +Revision History: + +NEG:27.08.2002 Initiated. +--*/ + +#include "CD_Structs.h" +#ifndef _CD_DEFINITIONS_H +#define _CD_DEFINITIONS_H_ +#ifdef DRIVER_PARSER +VOID *AllocateMemory(VOID *, UINT16); +VOID ReleaseMemory(DEVICE_DATA * , WORKING_TABLE_DATA* ); +#endif +CD_STATUS ParseTable(DEVICE_DATA* pDeviceData, UINT8 IndexInMasterTable); +//CD_STATUS CD_MainLoop(PARSER_TEMP_DATA_POINTER pParserTempData); +CD_STATUS Main_Loop(DEVICE_DATA* pDeviceData,UINT16 *MasterTableOffset,UINT8 IndexInMasterTable); +UINT16* GetCommandMasterTablePointer(DEVICE_DATA* pDeviceData); +#endif //CD_DEFINITIONS diff --git a/programs/system/drivers/rhd/AtomBios/includes/CD_Opcodes.h b/programs/system/drivers/rhd/AtomBios/includes/CD_Opcodes.h new file mode 100644 index 000000000..2f3bec5fa --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/CD_Opcodes.h @@ -0,0 +1,181 @@ +/* + * Copyright 2006-2007 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. + */ + +/*++ + +Module Name: + +CD_OPCODEs.h + +Abstract: + +Defines Command Decoder OPCODEs + +Revision History: + +NEG:24.09.2002 Initiated. +--*/ +#ifndef _CD_OPCODES_H_ +#define _CD_OPCODES_H_ + +typedef enum _OPCODE { + Reserved_00= 0, // 0 = 0x00 + // MOVE_ group + MOVE_REG_OPCODE, // 1 = 0x01 + FirstValidCommand=MOVE_REG_OPCODE, + MOVE_PS_OPCODE, // 2 = 0x02 + MOVE_WS_OPCODE, // 3 = 0x03 + MOVE_FB_OPCODE, // 4 = 0x04 + MOVE_PLL_OPCODE, // 5 = 0x05 + MOVE_MC_OPCODE, // 6 = 0x06 + // Logic group + AND_REG_OPCODE, // 7 = 0x07 + AND_PS_OPCODE, // 8 = 0x08 + AND_WS_OPCODE, // 9 = 0x09 + AND_FB_OPCODE, // 10 = 0x0A + AND_PLL_OPCODE, // 11 = 0x0B + AND_MC_OPCODE, // 12 = 0x0C + OR_REG_OPCODE, // 13 = 0x0D + OR_PS_OPCODE, // 14 = 0x0E + OR_WS_OPCODE, // 15 = 0x0F + OR_FB_OPCODE, // 16 = 0x10 + OR_PLL_OPCODE, // 17 = 0x11 + OR_MC_OPCODE, // 18 = 0x12 + SHIFT_LEFT_REG_OPCODE, // 19 = 0x13 + SHIFT_LEFT_PS_OPCODE, // 20 = 0x14 + SHIFT_LEFT_WS_OPCODE, // 21 = 0x15 + SHIFT_LEFT_FB_OPCODE, // 22 = 0x16 + SHIFT_LEFT_PLL_OPCODE, // 23 = 0x17 + SHIFT_LEFT_MC_OPCODE, // 24 = 0x18 + SHIFT_RIGHT_REG_OPCODE, // 25 = 0x19 + SHIFT_RIGHT_PS_OPCODE, // 26 = 0x1A + SHIFT_RIGHT_WS_OPCODE, // 27 = 0x1B + SHIFT_RIGHT_FB_OPCODE, // 28 = 0x1C + SHIFT_RIGHT_PLL_OPCODE, // 29 = 0x1D + SHIFT_RIGHT_MC_OPCODE, // 30 = 0x1E + // Arithmetic group + MUL_REG_OPCODE, // 31 = 0x1F + MUL_PS_OPCODE, // 32 = 0x20 + MUL_WS_OPCODE, // 33 = 0x21 + MUL_FB_OPCODE, // 34 = 0x22 + MUL_PLL_OPCODE, // 35 = 0x23 + MUL_MC_OPCODE, // 36 = 0x24 + DIV_REG_OPCODE, // 37 = 0x25 + DIV_PS_OPCODE, // 38 = 0x26 + DIV_WS_OPCODE, // 39 = 0x27 + DIV_FB_OPCODE, // 40 = 0x28 + DIV_PLL_OPCODE, // 41 = 0x29 + DIV_MC_OPCODE, // 42 = 0x2A + ADD_REG_OPCODE, // 43 = 0x2B + ADD_PS_OPCODE, // 44 = 0x2C + ADD_WS_OPCODE, // 45 = 0x2D + ADD_FB_OPCODE, // 46 = 0x2E + ADD_PLL_OPCODE, // 47 = 0x2F + ADD_MC_OPCODE, // 48 = 0x30 + SUB_REG_OPCODE, // 49 = 0x31 + SUB_PS_OPCODE, // 50 = 0x32 + SUB_WS_OPCODE, // 51 = 0x33 + SUB_FB_OPCODE, // 52 = 0x34 + SUB_PLL_OPCODE, // 53 = 0x35 + SUB_MC_OPCODE, // 54 = 0x36 + // Control grouop + SET_ATI_PORT_OPCODE, // 55 = 0x37 + SET_PCI_PORT_OPCODE, // 56 = 0x38 + SET_SYS_IO_PORT_OPCODE, // 57 = 0x39 + SET_REG_BLOCK_OPCODE, // 58 = 0x3A + SET_FB_BASE_OPCODE, // 59 = 0x3B + COMPARE_REG_OPCODE, // 60 = 0x3C + COMPARE_PS_OPCODE, // 61 = 0x3D + COMPARE_WS_OPCODE, // 62 = 0x3E + COMPARE_FB_OPCODE, // 63 = 0x3F + COMPARE_PLL_OPCODE, // 64 = 0x40 + COMPARE_MC_OPCODE, // 65 = 0x41 + SWITCH_OPCODE, // 66 = 0x42 + JUMP__OPCODE, // 67 = 0x43 + JUMP_EQUAL_OPCODE, // 68 = 0x44 + JUMP_BELOW_OPCODE, // 69 = 0x45 + JUMP_ABOVE_OPCODE, // 70 = 0x46 + JUMP_BELOW_OR_EQUAL_OPCODE, // 71 = 0x47 + JUMP_ABOVE_OR_EQUAL_OPCODE, // 72 = 0x48 + JUMP_NOT_EQUAL_OPCODE, // 73 = 0x49 + TEST_REG_OPCODE, // 74 = 0x4A + TEST_PS_OPCODE, // 75 = 0x4B + TEST_WS_OPCODE, // 76 = 0x4C + TEST_FB_OPCODE, // 77 = 0x4D + TEST_PLL_OPCODE, // 78 = 0x4E + TEST_MC_OPCODE, // 79 = 0x4F + DELAY_MILLISEC_OPCODE, // 80 = 0x50 + DELAY_MICROSEC_OPCODE, // 81 = 0x51 + CALL_TABLE_OPCODE, // 82 = 0x52 + REPEAT_OPCODE, // 83 = 0x53 + // Miscellaneous group + CLEAR_REG_OPCODE, // 84 = 0x54 + CLEAR_PS_OPCODE, // 85 = 0x55 + CLEAR_WS_OPCODE, // 86 = 0x56 + CLEAR_FB_OPCODE, // 87 = 0x57 + CLEAR_PLL_OPCODE, // 88 = 0x58 + CLEAR_MC_OPCODE, // 89 = 0x59 + NOP_OPCODE, // 90 = 0x5A + EOT_OPCODE, // 91 = 0x5B + MASK_REG_OPCODE, // 92 = 0x5C + MASK_PS_OPCODE, // 93 = 0x5D + MASK_WS_OPCODE, // 94 = 0x5E + MASK_FB_OPCODE, // 95 = 0x5F + MASK_PLL_OPCODE, // 96 = 0x60 + MASK_MC_OPCODE, // 97 = 0x61 + // BIOS dedicated group + POST_CARD_OPCODE, // 98 = 0x62 + BEEP_OPCODE, // 99 = 0x63 + SAVE_REG_OPCODE, // 100 = 0x64 + RESTORE_REG_OPCODE, // 101 = 0x65 + SET_DATA_BLOCK_OPCODE, // 102 = 0x66 + + XOR_REG_OPCODE, // 103 = 0x67 + XOR_PS_OPCODE, // 104 = 0x68 + XOR_WS_OPCODE, // 105 = 0x69 + XOR_FB_OPCODE, // 106 = 0x6a + XOR_PLL_OPCODE, // 107 = 0x6b + XOR_MC_OPCODE, // 108 = 0x6c + + SHL_REG_OPCODE, // 109 = 0x6d + SHL_PS_OPCODE, // 110 = 0x6e + SHL_WS_OPCODE, // 111 = 0x6f + SHL_FB_OPCODE, // 112 = 0x70 + SHL_PLL_OPCODE, // 113 = 0x71 + SHL_MC_OPCODE, // 114 = 0x72 + + SHR_REG_OPCODE, // 115 = 0x73 + SHR_PS_OPCODE, // 116 = 0x74 + SHR_WS_OPCODE, // 117 = 0x75 + SHR_FB_OPCODE, // 118 = 0x76 + SHR_PLL_OPCODE, // 119 = 0x77 + SHR_MC_OPCODE, // 120 = 0x78 + + DEBUG_OPCODE, // 121 = 0x79 + CTB_DS_OPCODE, // 122 = 0x7A + + LastValidCommand = CTB_DS_OPCODE, + // Extension specificaTOR + Extension = 0x80, // 128 = 0x80 // Next byte is an OPCODE as well + Reserved_FF = 255 // 255 = 0xFF +}OPCODE; +#endif // _CD_OPCODES_H_ diff --git a/programs/system/drivers/rhd/AtomBios/includes/CD_Structs.h b/programs/system/drivers/rhd/AtomBios/includes/CD_Structs.h new file mode 100644 index 000000000..c43f81dbf --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/CD_Structs.h @@ -0,0 +1,464 @@ +/* + * Copyright 2006-2007 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. + */ + +/*++ + +Module Name: + +CD_Struct.h + +Abstract: + +Defines Script Language commands + +Revision History: + +NEG:26.08.2002 Initiated. +--*/ + +#include "CD_binding.h" +#ifndef _CD_STRUCTS_H_ +#define _CD_STRUCTS_H_ + +#ifdef UEFI_BUILD +typedef UINT16** PTABLE_UNIT_TYPE; +typedef UINTN TABLE_UNIT_TYPE; +#else +typedef UINT16* PTABLE_UNIT_TYPE; +typedef UINT16 TABLE_UNIT_TYPE; +#endif + +#include //This important file is dynamically generated based on the ASIC!!!! + +#define PARSER_MAJOR_REVISION 5 +#define PARSER_MINOR_REVISION 0 + +//#include "atombios.h" +#if (PARSER_TYPE==DRIVER_TYPE_PARSER) +#ifdef FGL_LINUX +#pragma pack(push,1) +#else +#pragma pack(push) +#pragma pack(1) +#endif +#endif + +#include "CD_Common_Types.h" +#include "CD_Opcodes.h" +typedef UINT16 WORK_SPACE_SIZE; +typedef enum _CD_STATUS{ + CD_SUCCESS, + CD_CALL_TABLE, + CD_COMPLETED=0x10, + CD_GENERAL_ERROR=0x80, + CD_INVALID_OPCODE, + CD_NOT_IMPLEMENTED, + CD_EXEC_TABLE_NOT_FOUND, + CD_EXEC_PARAMETER_ERROR, + CD_EXEC_PARSER_ERROR, + CD_INVALID_DESTINATION_TYPE, + CD_UNEXPECTED_BEHAVIOR, + CD_INVALID_SWITCH_OPERAND_SIZE +}CD_STATUS; + +#define PARSER_STRINGS 0 +#define PARSER_DEC 1 +#define PARSER_HEX 2 + +#define DB_CURRENT_COMMAND_TABLE 0xFF + +#define TABLE_FORMAT_BIOS 0 +#define TABLE_FORMAT_EASF 1 + +#define EASF_TABLE_INDEX_MASK 0xfc +#define EASF_TABLE_ATTR_MASK 0x03 + +#define CD_ERROR(a) (((INTN) (a)) > CD_COMPLETED) +#define CD_ERROR_OR_COMPLETED(a) (((INTN) (a)) > CD_SUCCESS) + + +#if (BIOS_PARSER==1) +#ifdef _H2INC +#define STACK_BASED +#else +extern __segment farstack; +#define STACK_BASED __based(farstack) +#endif +#else +#define STACK_BASED +#endif + +typedef enum _COMPARE_FLAGS{ + Below, + Equal, + Above, + NotEqual, + Overflow, + NoCondition +}COMPARE_FLAGS; + +typedef UINT16 IO_BASE_ADDR; + +typedef struct _BUS_DEV_FUNC_PCI_ADDR{ + UINT8 Register; + UINT8 Function; + UINT8 Device; + UINT8 Bus; +} BUS_DEV_FUNC_PCI_ADDR; + +typedef struct _BUS_DEV_FUNC{ + UINT8 Function : 3; + UINT8 Device : 5; + UINT8 Bus; +} BUS_DEV_FUNC; + +#ifndef UEFI_BUILD +typedef struct _PCI_CONFIG_ACCESS_CF8{ + UINT32 Reg : 8; + UINT32 Func : 3; + UINT32 Dev : 5; + UINT32 Bus : 8; + UINT32 Reserved: 7; + UINT32 Enable : 1; +} PCI_CONFIG_ACCESS_CF8; +#endif + +typedef enum _MEM_RESOURCE { + Stack_Resource, + FrameBuffer_Resource, + BIOS_Image_Resource +}MEM_RESOURCE; + +typedef enum _PORTS{ + ATI_RegsPort, + PCI_Port, + SystemIO_Port +}PORTS; + +typedef enum _OPERAND_TYPE { + typeRegister, + typeParamSpace, + typeWorkSpace, + typeFrameBuffer, + typeIndirect, + typeDirect, + typePLL, + typeMC +}OPERAND_TYPE; + +typedef enum _DESTINATION_OPERAND_TYPE { + destRegister, + destParamSpace, + destWorkSpace, + destFrameBuffer, + destPLL, + destMC +}DESTINATION_OPERAND_TYPE; + +typedef enum _SOURCE_OPERAND_TYPE { + sourceRegister, + sourceParamSpace, + sourceWorkSpace, + sourceFrameBuffer, + sourceIndirect, + sourceDirect, + sourcePLL, + sourceMC +}SOURCE_OPERAND_TYPE; + +typedef enum _ALIGNMENT_TYPE { + alignmentDword, + alignmentLowerWord, + alignmentMiddleWord, + alignmentUpperWord, + alignmentByte0, + alignmentByte1, + alignmentByte2, + alignmentByte3 +}ALIGNMENT_TYPE; + + +#define INDIRECT_IO_READ 0 +#define INDIRECT_IO_WRITE 0x80 +#define INDIRECT_IO_MM 0 +#define INDIRECT_IO_PLL 1 +#define INDIRECT_IO_MC 2 + +typedef struct _PARAMETERS_TYPE{ + UINT8 Destination; + UINT8 Source; +}PARAMETERS_TYPE; +/* The following structures don't used to allocate any type of objects(variables). + they are serve the only purpose: Get proper access to data(commands), found in the tables*/ +typedef struct _PA_BYTE_BYTE{ + UINT8 PA_Destination; + UINT8 PA_Source; + UINT8 PA_Padding[8]; +}PA_BYTE_BYTE; +typedef struct _PA_BYTE_WORD{ + UINT8 PA_Destination; + UINT16 PA_Source; + UINT8 PA_Padding[7]; +}PA_BYTE_WORD; +typedef struct _PA_BYTE_DWORD{ + UINT8 PA_Destination; + UINT32 PA_Source; + UINT8 PA_Padding[5]; +}PA_BYTE_DWORD; +typedef struct _PA_WORD_BYTE{ + UINT16 PA_Destination; + UINT8 PA_Source; + UINT8 PA_Padding[7]; +}PA_WORD_BYTE; +typedef struct _PA_WORD_WORD{ + UINT16 PA_Destination; + UINT16 PA_Source; + UINT8 PA_Padding[6]; +}PA_WORD_WORD; +typedef struct _PA_WORD_DWORD{ + UINT16 PA_Destination; + UINT32 PA_Source; + UINT8 PA_Padding[4]; +}PA_WORD_DWORD; +typedef struct _PA_WORD_XX{ + UINT16 PA_Destination; + UINT8 PA_Padding[8]; +}PA_WORD_XX; +typedef struct _PA_BYTE_XX{ + UINT8 PA_Destination; + UINT8 PA_Padding[9]; +}PA_BYTE_XX; +/*The following 6 definitions used for Mask operation*/ +typedef struct _PA_BYTE_BYTE_BYTE{ + UINT8 PA_Destination; + UINT8 PA_AndMaskByte; + UINT8 PA_OrMaskByte; + UINT8 PA_Padding[7]; +}PA_BYTE_BYTE_BYTE; +typedef struct _PA_BYTE_WORD_WORD{ + UINT8 PA_Destination; + UINT16 PA_AndMaskWord; + UINT16 PA_OrMaskWord; + UINT8 PA_Padding[5]; +}PA_BYTE_WORD_WORD; +typedef struct _PA_BYTE_DWORD_DWORD{ + UINT8 PA_Destination; + UINT32 PA_AndMaskDword; + UINT32 PA_OrMaskDword; + UINT8 PA_Padding; +}PA_BYTE_DWORD_DWORD; +typedef struct _PA_WORD_BYTE_BYTE{ + UINT16 PA_Destination; + UINT8 PA_AndMaskByte; + UINT8 PA_OrMaskByte; + UINT8 PA_Padding[6]; +}PA_WORD_BYTE_BYTE; +typedef struct _PA_WORD_WORD_WORD{ + UINT16 PA_Destination; + UINT16 PA_AndMaskWord; + UINT16 PA_OrMaskWord; + UINT8 PA_Padding[4]; +}PA_WORD_WORD_WORD; +typedef struct _PA_WORD_DWORD_DWORD{ + UINT16 PA_Destination; + UINT32 PA_AndMaskDword; + UINT32 PA_OrMaskDword; +}PA_WORD_DWORD_DWORD; + + +typedef union _PARAMETER_ACCESS { + PA_BYTE_XX ByteXX; + PA_BYTE_BYTE ByteByte; + PA_BYTE_WORD ByteWord; + PA_BYTE_DWORD ByteDword; + PA_WORD_BYTE WordByte; + PA_WORD_WORD WordWord; + PA_WORD_DWORD WordDword; + PA_WORD_XX WordXX; +/*The following 6 definitions used for Mask operation*/ + PA_BYTE_BYTE_BYTE ByteByteAndByteOr; + PA_BYTE_WORD_WORD ByteWordAndWordOr; + PA_BYTE_DWORD_DWORD ByteDwordAndDwordOr; + PA_WORD_BYTE_BYTE WordByteAndByteOr; + PA_WORD_WORD_WORD WordWordAndWordOr; + PA_WORD_DWORD_DWORD WordDwordAndDwordOr; +}PARAMETER_ACCESS; + +typedef struct _COMMAND_ATTRIBUTE { + UINT8 Source:3; + UINT8 SourceAlignment:3; + UINT8 DestinationAlignment:2; +}COMMAND_ATTRIBUTE; + +typedef struct _SOURCE_DESTINATION_ALIGNMENT{ + UINT8 DestAlignment; + UINT8 SrcAlignment; +}SOURCE_DESTINATION_ALIGNMENT; +typedef struct _MULTIPLICATION_RESULT{ + UINT32 Low32Bit; + UINT32 High32Bit; +}MULTIPLICATION_RESULT; +typedef struct _DIVISION_RESULT{ + UINT32 Quotient32; + UINT32 Reminder32; +}DIVISION_RESULT; +typedef union _DIVISION_MULTIPLICATION_RESULT{ + MULTIPLICATION_RESULT Multiplication; + DIVISION_RESULT Division; +}DIVISION_MULTIPLICATION_RESULT; +typedef struct _COMMAND_HEADER { + UINT8 Opcode; + COMMAND_ATTRIBUTE Attribute; +}COMMAND_HEADER; + +typedef struct _GENERIC_ATTRIBUTE_COMMAND{ + COMMAND_HEADER Header; + PARAMETER_ACCESS Parameters; +} GENERIC_ATTRIBUTE_COMMAND; + +typedef struct _COMMAND_TYPE_1{ + UINT8 Opcode; + PARAMETER_ACCESS Parameters; +} COMMAND_TYPE_1; + +typedef struct _COMMAND_TYPE_OPCODE_OFFSET16{ + UINT8 Opcode; + UINT16 CD_Offset16; +} COMMAND_TYPE_OPCODE_OFFSET16; + +typedef struct _COMMAND_TYPE_OPCODE_OFFSET32{ + UINT8 Opcode; + UINT32 CD_Offset32; +} COMMAND_TYPE_OPCODE_OFFSET32; + +typedef struct _COMMAND_TYPE_OPCODE_VALUE_BYTE{ + UINT8 Opcode; + UINT8 Value; +} COMMAND_TYPE_OPCODE_VALUE_BYTE; + +typedef union _COMMAND_SPECIFIC_UNION{ + UINT8 ContinueSwitch; + UINT8 ControlOperandSourcePosition; + UINT8 IndexInMasterTable; +} COMMAND_SPECIFIC_UNION; + + +typedef struct _CD_GENERIC_BYTE{ + UINT16 CommandType:3; + UINT16 CurrentParameterSize:3; + UINT16 CommandAccessType:3; + UINT16 CurrentPort:2; + UINT16 PS_SizeInDwordsUsedByCallingTable:5; +}CD_GENERIC_BYTE; + +typedef UINT8 COMMAND_TYPE_OPCODE_ONLY; + +typedef UINT8 COMMAND_HEADER_POINTER; + + +#if (PARSER_TYPE==BIOS_TYPE_PARSER) + +typedef struct _DEVICE_DATA { + UINT32 STACK_BASED *pParameterSpace; + UINT8 *pBIOS_Image; + UINT8 format; +#if (IO_INTERFACE==PARSER_INTERFACE) + IO_BASE_ADDR IOBase; +#endif +} DEVICE_DATA; + +#else + +typedef struct _DEVICE_DATA { + UINT32 *pParameterSpace; + VOID *CAIL; + UINT8 *pBIOS_Image; + UINT32 format; +} DEVICE_DATA; + +#endif + +struct _PARSER_TEMP_DATA; +typedef UINT32 WORKSPACE_POINTER; + +struct _WORKING_TABLE_DATA{ + UINT8 * pTableHead; + COMMAND_HEADER_POINTER * IP; // Commands pointer + WORKSPACE_POINTER STACK_BASED * pWorkSpace; + struct _WORKING_TABLE_DATA STACK_BASED * prevWorkingTableData; +}; + + + +typedef struct _PARSER_TEMP_DATA{ + DEVICE_DATA STACK_BASED *pDeviceData; + struct _WORKING_TABLE_DATA STACK_BASED *pWorkingTableData; + UINT32 SourceData32; + UINT32 DestData32; + DIVISION_MULTIPLICATION_RESULT MultiplicationOrDivision; + UINT32 Index; + UINT32 CurrentFB_Window; + UINT32 IndirectData; + UINT16 CurrentRegBlock; + TABLE_UNIT_TYPE CurrentDataBlock; + UINT16 AttributesData; +// UINT8 *IndirectIOTable; + UINT8 *IndirectIOTablePointer; + GENERIC_ATTRIBUTE_COMMAND *pCmd; //CurrentCommand; + SOURCE_DESTINATION_ALIGNMENT CD_Mask; + PARAMETERS_TYPE ParametersType; + CD_GENERIC_BYTE Multipurpose; + UINT8 CompareFlags; + COMMAND_SPECIFIC_UNION CommandSpecific; + CD_STATUS Status; + UINT8 Shift2MaskConverter; + UINT8 CurrentPortID; +} PARSER_TEMP_DATA; + + +typedef struct _WORKING_TABLE_DATA WORKING_TABLE_DATA; + + + +typedef VOID (*COMMANDS_DECODER)(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +typedef VOID (*WRITE_IO_FUNCTION)(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +typedef UINT32 (*READ_IO_FUNCTION)(PARSER_TEMP_DATA STACK_BASED * pParserTempData); +typedef UINT32 (*CD_GET_PARAMETERS)(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +typedef struct _COMMANDS_PROPERTIES +{ + COMMANDS_DECODER function; + UINT8 destination; + UINT8 headersize; +} COMMANDS_PROPERTIES; + +typedef struct _INDIRECT_IO_PARSER_COMMANDS +{ + COMMANDS_DECODER func; + UINT8 csize; +} INDIRECT_IO_PARSER_COMMANDS; + +#if (PARSER_TYPE==DRIVER_TYPE_PARSER) +#pragma pack(pop) +#endif + +#endif diff --git a/programs/system/drivers/rhd/AtomBios/includes/CD_binding.h b/programs/system/drivers/rhd/AtomBios/includes/CD_binding.h new file mode 100644 index 000000000..7b021d3ed --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/CD_binding.h @@ -0,0 +1,46 @@ +/* + * Copyright 2006-2007 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 NT_BUILD +#ifdef LH_BUILD +#include +#else +#include +#endif // LH_BUILD +#endif // NT_BUILD + + +#if ((defined DBG) || (defined DEBUG)) +#define DEBUG_PARSER 1 // enable parser debug output +#endif + +#define USE_SWITCH_COMMAND 1 +#define DRIVER_TYPE_PARSER 0x48 + +#define PARSER_TYPE DRIVER_TYPE_PARSER + +#define AllocateWorkSpace(x,y) AllocateMemory(pDeviceData,y) +#define FreeWorkSpace(x,y) ReleaseMemory(x,y) + +#define RELATIVE_TO_BIOS_IMAGE( x ) ((ULONG_PTR)x + (ULONG_PTR)((DEVICE_DATA*)pParserTempData->pDeviceData->pBIOS_Image)) +#define RELATIVE_TO_TABLE( x ) (x + (UCHAR *)(pParserTempData->pWorkingTableData->pTableHead)) + diff --git a/programs/system/drivers/rhd/AtomBios/includes/CD_hw_services.h b/programs/system/drivers/rhd/AtomBios/includes/CD_hw_services.h new file mode 100644 index 000000000..529fde590 --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/CD_hw_services.h @@ -0,0 +1,318 @@ +/* + * Copyright 2006-2007 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. + */ + +#ifndef _HW_SERVICES_INTERFACE_ +#define _HW_SERVICES_INTERFACE_ + +#include "CD_Common_Types.h" +#include "CD_Structs.h" + + +// CD - from Command Decoder +typedef UINT16 CD_REG_INDEX; +typedef UINT8 CD_PCI_OFFSET; +typedef UINT16 CD_FB_OFFSET; +typedef UINT16 CD_SYS_IO_PORT; +typedef UINT8 CD_MEM_TYPE; +typedef UINT8 CD_MEM_SIZE; + +typedef VOID * CD_VIRT_ADDR; +typedef UINT32 CD_PHYS_ADDR; +typedef UINT32 CD_IO_ADDR; + +/***********************ATI Registers access routines**************************/ + + VOID ReadIndReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteIndReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT32 ReadReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT32 ReadPLL32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WritePLL32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT32 ReadMC32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteMC32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +/************************PCI Registers access routines*************************/ + + UINT8 ReadPCIReg8(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT16 ReadPCIReg16(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT32 ReadPCIReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WritePCIReg8(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WritePCIReg16(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WritePCIReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +/***************************Frame buffer access routines************************/ + + UINT32 ReadFrameBuffer32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteFrameBuffer32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +/******************System IO Registers access routines********************/ + + UINT8 ReadSysIOReg8(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT16 ReadSysIOReg16(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + UINT32 ReadSysIOReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteSysIOReg8(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteSysIOReg16(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID WriteSysIOReg32(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + +/****************************Delay routines****************************************/ + + VOID DelayMicroseconds(PARSER_TEMP_DATA STACK_BASED * pParserTempData); // take WORKING_TABLE_DATA->SourceData32 as a delay value + + VOID DelayMilliseconds(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID PostCharOutput(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + VOID CallerDebugFunc(PARSER_TEMP_DATA STACK_BASED * pParserTempData); + + +//************************Tracing/Debugging routines and macroses******************/ +#define KEYPRESSED -1 + +#if (DEBUG_PARSER != 0) + +#ifdef DRIVER_PARSER + +VOID CD_print_string (DEVICE_DATA STACK_BASED *pDeviceData, UINT8 *str); +VOID CD_print_value (DEVICE_DATA STACK_BASED *pDeviceData, ULONG_PTR value, UINT16 value_type ); + +// Level 1 : can use WorkingTableData or pDeviceData +#define CD_TRACE_DL1(string) CD_print_string(pDeviceData, string); +#define CD_TRACETAB_DL1(string) CD_TRACE_DL1("\n");CD_TRACE_DL1(string) +#define CD_TRACEDEC_DL1(value) CD_print_value( pDeviceData, (ULONG_PTR)value, PARSER_DEC); +#define CD_TRACEHEX_DL1(value) CD_print_value( pDeviceData, (ULONG_PTR)value, PARSER_HEX); + +// Level 2:can use pWorkingTableData +#define CD_TRACE_DL2(string) CD_print_string( pWorkingTableData->pParserTempData->pDeviceData, string); +#define CD_TRACETAB_DL2(string) CD_TRACE_DL2("\n");CD_TRACE_DL2(string) +#define CD_TRACEDEC_DL2(value) CD_print_value( pWorkingTableData->pParserTempData->pDeviceData, (ULONG_PTR)value, PARSER_DEC); +#define CD_TRACEHEX_DL2(value) CD_print_value( pWorkingTableData->pParserTempData->pDeviceData, (ULONG_PTR)value, PARSER_HEX); + +// Level 3:can use pWorkingTableData +#define CD_TRACE_DL3(string) CD_print_string( pWorkingTableData->pParserTempData->pDeviceData, string); +#define CD_TRACETAB_DL3(string) CD_TRACE_DL3("\n");CD_TRACE_DL3(string) +#define CD_TRACEDEC_DL3(value) CD_print_value( pWorkingTableData->pParserTempData->pDeviceData, value, PARSER_DEC); +#define CD_TRACEHEX_DL3(value) CD_print_value( pWorkingTableData->pParserTempData->pDeviceData, value, PARSER_HEX); + +#define CD_TRACE(string) +#define CD_WAIT(what) +#define CD_BREAKPOINT() + +#else + + +VOID CD_assert (UINT8 *file, INTN lineno); //output file/line to debug console +VOID CD_postcode(UINT8 value); //output post code to debug console +VOID CD_print (UINT8 *str); //output text to debug console +VOID CD_print_dec(UINTN value); //output value in decimal format to debug console +VOID CD_print_hex(UINT32 value, UINT8 len); //output value in hexadecimal format to debug console +VOID CD_print_buf(UINT8 *p, UINTN len); //output dump of memory to debug console +VOID CD_wait(INT32 what); //wait for KEYPRESSED=-1 or Delay value expires +VOID CD_breakpoint(); //insert int3 opcode or 0xF1 (for American Arium) + +#define CD_ASSERT(condition) if(!(condition)) CD_assert(__FILE__, __LINE__) +#define CD_POSTCODE(value) CD_postcode(value) +#define CD_TRACE(string) CD_print(string) +#define CD_TRACETAB(string) CD_print(string) +#define CD_TRACEDEC(value) CD_print_dec( (UINTN)(value)) +#define CD_TRACEHEX(value) CD_print_hex( (UINT32)(value), sizeof(value) ) +#define CD_TRACEBUF(pointer, len) CD_print_buf( (UINT8 *)(pointer), (UINTN) len) +#define CD_WAIT(what) CD_wait((INT32)what) +#define CD_BREAKPOINT() CD_breakpoint() + +#if (DEBUG_PARSER == 4) +#define CD_ASSERT_DL4(condition) if(!(condition)) CD_assert(__FILE__, __LINE__) +#define CD_POSTCODE_DL4(value) CD_postcode(value) +#define CD_TRACE_DL4(string) CD_print(string) +#define CD_TRACETAB_DL4(string) CD_print("\n\t\t");CD_print(string) +#define CD_TRACEDEC_DL4(value) CD_print_dec( (UINTN)(value)) +#define CD_TRACEHEX_DL4(value) CD_print_hex( (UINT32)(value), sizeof(value) ) +#define CD_TRACEBUF_DL4(pointer, len) CD_print_buf( (UINT8 *)(pointer), (UINTN) len) +#define CD_WAIT_DL4(what) CD_wait((INT32)what) +#define CD_BREAKPOINT_DL4() CD_breakpoint() +#else +#define CD_ASSERT_DL4(condition) +#define CD_POSTCODE_DL4(value) +#define CD_TRACE_DL4(string) +#define CD_TRACETAB_DL4(string) +#define CD_TRACEDEC_DL4(value) +#define CD_TRACEHEX_DL4(value) +#define CD_TRACEBUF_DL4(pointer, len) +#define CD_WAIT_DL4(what) +#define CD_BREAKPOINT_DL4() +#endif + +#if (DEBUG_PARSER >= 3) +#define CD_ASSERT_DL3(condition) if(!(condition)) CD_assert(__FILE__, __LINE__) +#define CD_POSTCODE_DL3(value) CD_postcode(value) +#define CD_TRACE_DL3(string) CD_print(string) +#define CD_TRACETAB_DL3(string) CD_print("\n\t\t");CD_print(string) +#define CD_TRACEDEC_DL3(value) CD_print_dec( (UINTN)(value)) +#define CD_TRACEHEX_DL3(value) CD_print_hex( (UINT32)(value), sizeof(value) ) +#define CD_TRACEBUF_DL3(pointer, len) CD_print_buf( (UINT8 *)(pointer), (UINTN) len) +#define CD_WAIT_DL3(what) CD_wait((INT32)what) +#define CD_BREAKPOINT_DL3() CD_breakpoint() +#else +#define CD_ASSERT_DL3(condition) +#define CD_POSTCODE_DL3(value) +#define CD_TRACE_DL3(string) +#define CD_TRACETAB_DL3(string) +#define CD_TRACEDEC_DL3(value) +#define CD_TRACEHEX_DL3(value) +#define CD_TRACEBUF_DL3(pointer, len) +#define CD_WAIT_DL3(what) +#define CD_BREAKPOINT_DL3() +#endif + + +#if (DEBUG_PARSER >= 2) +#define CD_ASSERT_DL2(condition) if(!(condition)) CD_assert(__FILE__, __LINE__) +#define CD_POSTCODE_DL2(value) CD_postcode(value) +#define CD_TRACE_DL2(string) CD_print(string) +#define CD_TRACETAB_DL2(string) CD_print("\n\t");CD_print(string) +#define CD_TRACEDEC_DL2(value) CD_print_dec( (UINTN)(value)) +#define CD_TRACEHEX_DL2(value) CD_print_hex( (UINT32)(value), sizeof(value) ) +#define CD_TRACEBUF_DL2(pointer, len) CD_print_buf( (UINT8 *)(pointer), (UINTN) len) +#define CD_WAIT_DL2(what) CD_wait((INT32)what) +#define CD_BREAKPOINT_DL2() CD_breakpoint() +#else +#define CD_ASSERT_DL2(condition) +#define CD_POSTCODE_DL2(value) +#define CD_TRACE_DL2(string) +#define CD_TRACETAB_DL2(string) +#define CD_TRACEDEC_DL2(value) +#define CD_TRACEHEX_DL2(value) +#define CD_TRACEBUF_DL2(pointer, len) +#define CD_WAIT_DL2(what) +#define CD_BREAKPOINT_DL2() +#endif + + +#if (DEBUG_PARSER >= 1) +#define CD_ASSERT_DL1(condition) if(!(condition)) CD_assert(__FILE__, __LINE__) +#define CD_POSTCODE_DL1(value) CD_postcode(value) +#define CD_TRACE_DL1(string) CD_print(string) +#define CD_TRACETAB_DL1(string) CD_print("\n");CD_print(string) +#define CD_TRACEDEC_DL1(value) CD_print_dec( (UINTN)(value)) +#define CD_TRACEHEX_DL1(value) CD_print_hex( (UINT32)(value), sizeof(value) ) +#define CD_TRACEBUF_DL1(pointer, len) CD_print_buf( (UINT8 *)(pointer), (UINTN) len) +#define CD_WAIT_DL1(what) CD_wait((INT32)what) +#define CD_BREAKPOINT_DL1() CD_breakpoint() +#else +#define CD_ASSERT_DL1(condition) +#define CD_POSTCODE_DL1(value) +#define CD_TRACE_DL1(string) +#define CD_TRACETAB_DL1(string) +#define CD_TRACEDEC_DL1(value) +#define CD_TRACEHEX_DL1(value) +#define CD_TRACEBUF_DL1(pointer, len) +#define CD_WAIT_DL1(what) +#define CD_BREAKPOINT_DL1() +#endif + +#endif //#ifdef DRIVER_PARSER + + +#else + +#define CD_ASSERT(condition) +#define CD_POSTCODE(value) +#define CD_TRACE(string) +#define CD_TRACEDEC(value) +#define CD_TRACEHEX(value) +#define CD_TRACEBUF(pointer, len) +#define CD_WAIT(what) +#define CD_BREAKPOINT() + +#define CD_ASSERT_DL4(condition) +#define CD_POSTCODE_DL4(value) +#define CD_TRACE_DL4(string) +#define CD_TRACETAB_DL4(string) +#define CD_TRACEDEC_DL4(value) +#define CD_TRACEHEX_DL4(value) +#define CD_TRACEBUF_DL4(pointer, len) +#define CD_WAIT_DL4(what) +#define CD_BREAKPOINT_DL4() + +#define CD_ASSERT_DL3(condition) +#define CD_POSTCODE_DL3(value) +#define CD_TRACE_DL3(string) +#define CD_TRACETAB_DL3(string) +#define CD_TRACEDEC_DL3(value) +#define CD_TRACEHEX_DL3(value) +#define CD_TRACEBUF_DL3(pointer, len) +#define CD_WAIT_DL3(what) +#define CD_BREAKPOINT_DL3() + +#define CD_ASSERT_DL2(condition) +#define CD_POSTCODE_DL2(value) +#define CD_TRACE_DL2(string) +#define CD_TRACETAB_DL2(string) +#define CD_TRACEDEC_DL2(value) +#define CD_TRACEHEX_DL2(value) +#define CD_TRACEBUF_DL2(pointer, len) +#define CD_WAIT_DL2(what) +#define CD_BREAKPOINT_DL2() + +#define CD_ASSERT_DL1(condition) +#define CD_POSTCODE_DL1(value) +#define CD_TRACE_DL1(string) +#define CD_TRACETAB_DL1(string) +#define CD_TRACEDEC_DL1(value) +#define CD_TRACEHEX_DL1(value) +#define CD_TRACEBUF_DL1(pointer, len) +#define CD_WAIT_DL1(what) +#define CD_BREAKPOINT_DL1() + + +#endif //#if (DEBUG_PARSER > 0) + + +#ifdef CHECKSTACK +VOID CD_fillstack(UINT16 size); +UINT16 CD_checkstack(UINT16 size); +#define CD_CHECKSTACK(stacksize) CD_checkstack(stacksize) +#define CD_FILLSTACK(stacksize) CD_fillstack(stacksize) +#else +#define CD_CHECKSTACK(stacksize) 0 +#define CD_FILLSTACK(stacksize) +#endif + + +#endif diff --git a/programs/system/drivers/rhd/AtomBios/includes/Decoder.h b/programs/system/drivers/rhd/AtomBios/includes/Decoder.h new file mode 100644 index 000000000..24c25fc29 --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/Decoder.h @@ -0,0 +1,86 @@ +/* + * Copyright 2006-2007 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. + */ + +/*++ + +Module Name: + +Decoder.h + +Abstract: + +Includes all helper headers + +Revision History: + +NEG:27.08.2002 Initiated. +--*/ +#ifndef _DECODER_H_ +#define _DECODER_H_ +#define WS_QUOTIENT_C 64 +#define WS_REMINDER_C (WS_QUOTIENT_C+1) +#define WS_DATAPTR_C (WS_REMINDER_C+1) +#define WS_SHIFT_C (WS_DATAPTR_C+1) +#define WS_OR_MASK_C (WS_SHIFT_C+1) +#define WS_AND_MASK_C (WS_OR_MASK_C+1) +#define WS_FB_WINDOW_C (WS_AND_MASK_C+1) +#define WS_ATTRIBUTES_C (WS_FB_WINDOW_C+1) +#define PARSER_VERSION_MAJOR 0x00000000 +#define PARSER_VERSION_MINOR 0x0000000E +#define PARSER_VERSION (PARSER_VERSION_MAJOR | PARSER_VERSION_MINOR) +#include "CD_binding.h" +#include "CD_Common_Types.h" +#include "CD_hw_services.h" +#include "CD_Structs.h" +#include "CD_Definitions.h" +#include "CD_Opcodes.h" + +#define SOURCE_ONLY_CMD_TYPE 0//0xFE +#define SOURCE_DESTINATION_CMD_TYPE 1//0xFD +#define DESTINATION_ONLY_CMD_TYPE 2//0xFC + +#define ACCESS_TYPE_BYTE 0//0xF9 +#define ACCESS_TYPE_WORD 1//0xF8 +#define ACCESS_TYPE_DWORD 2//0xF7 +#define SWITCH_TYPE_ACCESS 3//0xF6 + +#define CD_CONTINUE 0//0xFB +#define CD_STOP 1//0xFA + + +#define IS_END_OF_TABLE(cmd) ((cmd) == EOT_OPCODE) +#define IS_COMMAND_VALID(cmd) (((cmd)<=LastValidCommand)&&((cmd)>=FirstValidCommand)) +#define IS_IT_SHIFT_COMMAND(Opcode) ((Opcode<=SHIFT_RIGHT_MC_OPCODE)&&(Opcode>=SHIFT_LEFT_REG_OPCODE)) +#define IS_IT_XXXX_COMMAND(Group, Opcode) ((Opcode<=Group##_MC_OPCODE)&&(Opcode>=Group##_REG_OPCODE)) +#define CheckCaseAndAdjustIP_Macro(size) \ + if (pParserTempData->SourceData32==(UINT32)((CASE_OFFSET*)pParserTempData->pWorkingTableData->IP)->XX_Access.size##.Access.Value){\ + pParserTempData->CommandSpecific.ContinueSwitch = CD_STOP;\ + pParserTempData->pWorkingTableData->IP =(COMMAND_HEADER_POINTER *) RELATIVE_TO_TABLE(((CASE_OFFSET*)pParserTempData->pWorkingTableData->IP)->XX_Access.size##.Access.JumpOffset);\ + }else{\ + pParserTempData->pWorkingTableData->IP+=(sizeof (CASE_##size##ACCESS)\ + +sizeof(((CASE_OFFSET*)pParserTempData->pWorkingTableData->IP)->CaseSignature));\ + } + +#endif +/* pWorkingTableData->pCmd->Header.Attribute.SourceAlignment=alignmentLowerWord;\*/ + +// EOF diff --git a/programs/system/drivers/rhd/AtomBios/includes/ObjectID.h b/programs/system/drivers/rhd/AtomBios/includes/ObjectID.h new file mode 100644 index 000000000..849e74956 --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/ObjectID.h @@ -0,0 +1,518 @@ +/* +* Copyright 2006-2007 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. +*/ +/* based on stg/asic_reg/drivers/inc/asic_reg/ObjectID.h ver 23 */ + +#ifndef _OBJECTID_H +#define _OBJECTID_H + +#if defined(_X86_) +#pragma pack(1) +#endif + +/****************************************************/ +/* Graphics Object Type Definition */ +/****************************************************/ +#define GRAPH_OBJECT_TYPE_NONE 0x0 +#define GRAPH_OBJECT_TYPE_GPU 0x1 +#define GRAPH_OBJECT_TYPE_ENCODER 0x2 +#define GRAPH_OBJECT_TYPE_CONNECTOR 0x3 +#define GRAPH_OBJECT_TYPE_ROUTER 0x4 +/* deleted */ + +/****************************************************/ +/* Encoder Object ID Definition */ +/****************************************************/ +#define ENCODER_OBJECT_ID_NONE 0x00 + +/* Radeon Class Display Hardware */ +#define ENCODER_OBJECT_ID_INTERNAL_LVDS 0x01 +#define ENCODER_OBJECT_ID_INTERNAL_TMDS1 0x02 +#define ENCODER_OBJECT_ID_INTERNAL_TMDS2 0x03 +#define ENCODER_OBJECT_ID_INTERNAL_DAC1 0x04 +#define ENCODER_OBJECT_ID_INTERNAL_DAC2 0x05 /* TV/CV DAC */ +#define ENCODER_OBJECT_ID_INTERNAL_SDVOA 0x06 +#define ENCODER_OBJECT_ID_INTERNAL_SDVOB 0x07 + +/* External Third Party Encoders */ +#define ENCODER_OBJECT_ID_SI170B 0x08 +#define ENCODER_OBJECT_ID_CH7303 0x09 +#define ENCODER_OBJECT_ID_CH7301 0x0A +#define ENCODER_OBJECT_ID_INTERNAL_DVO1 0x0B /* This belongs to Radeon Class Display Hardware */ +#define ENCODER_OBJECT_ID_EXTERNAL_SDVOA 0x0C +#define ENCODER_OBJECT_ID_EXTERNAL_SDVOB 0x0D +#define ENCODER_OBJECT_ID_TITFP513 0x0E +#define ENCODER_OBJECT_ID_INTERNAL_LVTM1 0x0F /* not used for Radeon */ +#define ENCODER_OBJECT_ID_VT1623 0x10 +#define ENCODER_OBJECT_ID_HDMI_SI1930 0x11 +#define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12 +/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */ +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 0x15 +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 0x16 /* Shared with CV/TV and CRT */ +#define ENCODER_OBJECT_ID_SI178 0X17 /* External TMDS (dual link, no HDCP.) */ +#define ENCODER_OBJECT_ID_MVPU_FPGA 0x18 /* MVPU FPGA chip */ +#define ENCODER_OBJECT_ID_INTERNAL_DDI 0x19 +#define ENCODER_OBJECT_ID_VT1625 0x1A +#define ENCODER_OBJECT_ID_HDMI_SI1932 0x1B +#define ENCODER_OBJECT_ID_DP_AN9801 0x1C +#define ENCODER_OBJECT_ID_DP_DP501 0x1D +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY 0x1E +#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA 0x1F +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 0x20 +#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 0x21 + +#define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO 0xFF + +/****************************************************/ +/* Connector Object ID Definition */ +/****************************************************/ +#define CONNECTOR_OBJECT_ID_NONE 0x00 +#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I 0x01 +#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I 0x02 +#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D 0x03 +#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D 0x04 +#define CONNECTOR_OBJECT_ID_VGA 0x05 +#define CONNECTOR_OBJECT_ID_COMPOSITE 0x06 +#define CONNECTOR_OBJECT_ID_SVIDEO 0x07 +#define CONNECTOR_OBJECT_ID_YPbPr 0x08 +#define CONNECTOR_OBJECT_ID_D_CONNECTOR 0x09 +#define CONNECTOR_OBJECT_ID_9PIN_DIN 0x0A /* Supports both CV & TV */ +#define CONNECTOR_OBJECT_ID_SCART 0x0B +#define CONNECTOR_OBJECT_ID_HDMI_TYPE_A 0x0C +#define CONNECTOR_OBJECT_ID_HDMI_TYPE_B 0x0D +#define CONNECTOR_OBJECT_ID_LVDS 0x0E +#define CONNECTOR_OBJECT_ID_7PIN_DIN 0x0F +#define CONNECTOR_OBJECT_ID_PCIE_CONNECTOR 0x10 +#define CONNECTOR_OBJECT_ID_CROSSFIRE 0x11 +#define CONNECTOR_OBJECT_ID_HARDCODE_DVI 0x12 +#define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13 + +/* deleted */ + +/****************************************************/ +/* Router Object ID Definition */ +/****************************************************/ +#define ROUTER_OBJECT_ID_NONE 0x00 +#define ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL 0x01 + +/****************************************************/ +// Graphics Object ENUM ID Definition */ +/****************************************************/ +#define GRAPH_OBJECT_ENUM_ID1 0x01 +#define GRAPH_OBJECT_ENUM_ID2 0x02 +#define GRAPH_OBJECT_ENUM_ID3 0x03 +#define GRAPH_OBJECT_ENUM_ID4 0x04 +#define GRAPH_OBJECT_ENUM_ID5 0x05 +#define GRAPH_OBJECT_ENUM_ID6 0x06 + +/****************************************************/ +/* Graphics Object ID Bit definition */ +/****************************************************/ +#define OBJECT_ID_MASK 0x00FF +#define ENUM_ID_MASK 0x0700 +#define RESERVED1_ID_MASK 0x0800 +#define OBJECT_TYPE_MASK 0x7000 +#define RESERVED2_ID_MASK 0x8000 + +#define OBJECT_ID_SHIFT 0x00 +#define ENUM_ID_SHIFT 0x08 +#define OBJECT_TYPE_SHIFT 0x0C + + +/****************************************************/ +/* Graphics Object family definition */ +/****************************************************/ +#define CONSTRUCTOBJECTFAMILYID(GRAPHICS_OBJECT_TYPE, GRAPHICS_OBJECT_ID) (GRAPHICS_OBJECT_TYPE << OBJECT_TYPE_SHIFT | \ + GRAPHICS_OBJECT_ID << OBJECT_ID_SHIFT) +/****************************************************/ +/* GPU Object ID definition - Shared with BIOS */ +/****************************************************/ +#define GPU_ENUM_ID1 ( GRAPH_OBJECT_TYPE_GPU << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT) + +/****************************************************/ +/* Encoder Object ID definition - Shared with BIOS */ +/****************************************************/ +/* +#define ENCODER_INTERNAL_LVDS_ENUM_ID1 0x2101 +#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 0x2102 +#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 0x2103 +#define ENCODER_INTERNAL_DAC1_ENUM_ID1 0x2104 +#define ENCODER_INTERNAL_DAC2_ENUM_ID1 0x2105 +#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 0x2106 +#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 0x2107 +#define ENCODER_SIL170B_ENUM_ID1 0x2108 +#define ENCODER_CH7303_ENUM_ID1 0x2109 +#define ENCODER_CH7301_ENUM_ID1 0x210A +#define ENCODER_INTERNAL_DVO1_ENUM_ID1 0x210B +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 0x210C +#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 0x210D +#define ENCODER_TITFP513_ENUM_ID1 0x210E +#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 0x210F +#define ENCODER_VT1623_ENUM_ID1 0x2110 +#define ENCODER_HDMI_SI1930_ENUM_ID1 0x2111 +#define ENCODER_HDMI_INTERNAL_ENUM_ID1 0x2112 +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 0x2113 +#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 0x2114 +#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 0x2115 +#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 0x2116 +#define ENCODER_SI178_ENUM_ID1 0x2117 +#define ENCODER_MVPU_FPGA_ENUM_ID1 0x2118 +#define ENCODER_INTERNAL_DDI_ENUM_ID1 0x2119 +#define ENCODER_VT1625_ENUM_ID1 0x211A +#define ENCODER_HDMI_SI1932_ENUM_ID1 0x211B +#define ENCODER_ENCODER_DP_AN9801_ENUM_ID1 0x211C +#define ENCODER_DP_DP501_ENUM_ID1 0x211D +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 0x211E +*/ +#define ENCODER_INTERNAL_LVDS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_LVDS << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_TMDS1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_TMDS2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DAC1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DAC1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DAC2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DAC2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_SDVOB << OBJECT_ID_SHIFT) + +#define ENCODER_SIL170B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_SI170B << OBJECT_ID_SHIFT) + +#define ENCODER_CH7303_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_CH7303 << OBJECT_ID_SHIFT) + +#define ENCODER_CH7301_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_CH7301 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DVO1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DVO1 << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT) + +#define ENCODER_EXTERNAL_SDVOA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT) + + +#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_EXTERNAL_SDVOB << OBJECT_ID_SHIFT) + + +#define ENCODER_TITFP513_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_TITFP513 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_LVTM1 << OBJECT_ID_SHIFT) + +#define ENCODER_VT1623_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_VT1623 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_SI1930_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_SI1930 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_INTERNAL_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_INTERNAL << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT) + + +#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT) + + +#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 << OBJECT_ID_SHIFT) // Shared with CV/TV and CRT + +#define ENCODER_SI178_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_SI178 << OBJECT_ID_SHIFT) + +#define ENCODER_MVPU_FPGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_MVPU_FPGA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_DDI_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_DDI << OBJECT_ID_SHIFT) + +#define ENCODER_VT1625_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_VT1625 << OBJECT_ID_SHIFT) + +#define ENCODER_HDMI_SI1932_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_HDMI_SI1932 << OBJECT_ID_SHIFT) + +#define ENCODER_DP_DP501_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_DP_DP501 << OBJECT_ID_SHIFT) + +#define ENCODER_DP_AN9801_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_DP_AN9801 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_KLDSCP_LVTMA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) + +#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT) + +#define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT) + +/****************************************************/ +/* Connector Object ID definition - Shared with BIOS */ +/****************************************************/ +/* +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 0x3101 +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 0x3102 +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 0x3103 +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 0x3104 +#define CONNECTOR_VGA_ENUM_ID1 0x3105 +#define CONNECTOR_COMPOSITE_ENUM_ID1 0x3106 +#define CONNECTOR_SVIDEO_ENUM_ID1 0x3107 +#define CONNECTOR_YPbPr_ENUM_ID1 0x3108 +#define CONNECTOR_D_CONNECTORE_ENUM_ID1 0x3109 +#define CONNECTOR_9PIN_DIN_ENUM_ID1 0x310A +#define CONNECTOR_SCART_ENUM_ID1 0x310B +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 0x310C +#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 0x310D +#define CONNECTOR_LVDS_ENUM_ID1 0x310E +#define CONNECTOR_7PIN_DIN_ENUM_ID1 0x310F +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 0x3110 +*/ +#define CONNECTOR_LVDS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) + +#define CONNECTOR_VGA_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) + +#define CONNECTOR_VGA_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT) + +#define CONNECTOR_COMPOSITE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_COMPOSITE << OBJECT_ID_SHIFT) + +#define CONNECTOR_SVIDEO_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SVIDEO << OBJECT_ID_SHIFT) + +#define CONNECTOR_YPbPr_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_YPbPr << OBJECT_ID_SHIFT) + +#define CONNECTOR_D_CONNECTOR_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_D_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_9PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_9PIN_DIN << OBJECT_ID_SHIFT) + +#define CONNECTOR_SCART_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_SCART << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT) + +#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT) + +#define CONNECTOR_7PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) + +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT) + +#define CONNECTOR_CROSSFIRE_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT) + +#define CONNECTOR_CROSSFIRE_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT) + + +#define CONNECTOR_HARDCODE_DVI_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT) + +#define CONNECTOR_HARDCODE_DVI_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +#define CONNECTOR_DISPLAYPORT_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ + CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT) + +/****************************************************/ +/* Router Object ID definition - Shared with BIOS */ +/****************************************************/ +#define ROUTER_I2C_EXTENDER_CNTL_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ROUTER << OBJECT_TYPE_SHIFT |\ + GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ + ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL << OBJECT_ID_SHIFT) + +/* deleted */ + +/****************************************************/ +/* Object Cap definition - Shared with BIOS */ +/****************************************************/ +#define GRAPHICS_OBJECT_CAP_I2C 0x00000001L +#define GRAPHICS_OBJECT_CAP_TABLE_ID 0x00000002L + + +#define GRAPHICS_OBJECT_I2CCOMMAND_TABLE_ID 0x01 +#define GRAPHICS_OBJECT_HOTPLUGDETECTIONINTERUPT_TABLE_ID 0x02 +#define GRAPHICS_OBJECT_ENCODER_OUTPUT_PROTECTION_TABLE_ID 0x03 + +#if defined(_X86_) +#pragma pack() +#endif + +#endif /*GRAPHICTYPE */ + + + + diff --git a/programs/system/drivers/rhd/AtomBios/includes/atombios.h b/programs/system/drivers/rhd/AtomBios/includes/atombios.h new file mode 100644 index 000000000..3e3fc58bf --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/atombios.h @@ -0,0 +1,4944 @@ +/* + * Copyright 2006-2007 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. + */ + + +/****************************************************************************/ +/*Portion I: Definitions shared between VBIOS and Driver */ +/****************************************************************************/ + + +#ifndef _ATOMBIOS_H +#define _ATOMBIOS_H + +#define ATOM_VERSION_MAJOR 0x00020000 +#define ATOM_VERSION_MINOR 0x00000002 + +#define ATOM_HEADER_VERSION (ATOM_VERSION_MAJOR | ATOM_VERSION_MINOR) + + +#ifdef _H2INC + #ifndef ULONG + typedef unsigned long ULONG; + #endif + + #ifndef UCHAR + typedef unsigned char UCHAR; + #endif + + #ifndef USHORT + typedef unsigned short USHORT; + #endif +#endif + +#define ATOM_DAC_A 0 +#define ATOM_DAC_B 1 +#define ATOM_EXT_DAC 2 + +#define ATOM_CRTC1 0 +#define ATOM_CRTC2 1 + +#define ATOM_DIGA 0 +#define ATOM_DIGB 1 + +#define ATOM_PPLL1 0 +#define ATOM_PPLL2 1 + +#define ATOM_SCALER1 0 +#define ATOM_SCALER2 1 + +#define ATOM_SCALER_DISABLE 0 +#define ATOM_SCALER_CENTER 1 +#define ATOM_SCALER_EXPANSION 2 +#define ATOM_SCALER_MULTI_EX 3 + +#define ATOM_DISABLE 0 +#define ATOM_ENABLE 1 +#define ATOM_LCD_BLOFF (ATOM_DISABLE+2) +#define ATOM_LCD_BLON (ATOM_ENABLE+2) +#define ATOM_LCD_BL_BRIGHTNESS_CONTROL (ATOM_ENABLE+3) +#define ATOM_LCD_SELFTEST_START (ATOM_DISABLE+5) +#define ATOM_LCD_SELFTEST_STOP (ATOM_ENABLE+5) +#define ATOM_ENCODER_INIT (ATOM_DISABLE+7) + +#define ATOM_BLANKING 1 +#define ATOM_BLANKING_OFF 0 + +#define ATOM_CURSOR1 0 +#define ATOM_CURSOR2 1 + +#define ATOM_ICON1 0 +#define ATOM_ICON2 1 + +#define ATOM_CRT1 0 +#define ATOM_CRT2 1 + +#define ATOM_TV_NTSC 1 +#define ATOM_TV_NTSCJ 2 +#define ATOM_TV_PAL 3 +#define ATOM_TV_PALM 4 +#define ATOM_TV_PALCN 5 +#define ATOM_TV_PALN 6 +#define ATOM_TV_PAL60 7 +#define ATOM_TV_SECAM 8 +#define ATOM_TV_CV 16 + +#define ATOM_DAC1_PS2 1 +#define ATOM_DAC1_CV 2 +#define ATOM_DAC1_NTSC 3 +#define ATOM_DAC1_PAL 4 + +#define ATOM_DAC2_PS2 ATOM_DAC1_PS2 +#define ATOM_DAC2_CV ATOM_DAC1_CV +#define ATOM_DAC2_NTSC ATOM_DAC1_NTSC +#define ATOM_DAC2_PAL ATOM_DAC1_PAL + +#define ATOM_PM_ON 0 +#define ATOM_PM_STANDBY 1 +#define ATOM_PM_SUSPEND 2 +#define ATOM_PM_OFF 3 + +/* Bit0:{=0:single, =1:dual}, + Bit1 {=0:666RGB, =1:888RGB}, + Bit2:3:{Grey level} + Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}*/ + +#define ATOM_PANEL_MISC_DUAL 0x00000001 +#define ATOM_PANEL_MISC_888RGB 0x00000002 +#define ATOM_PANEL_MISC_GREY_LEVEL 0x0000000C +#define ATOM_PANEL_MISC_FPDI 0x00000010 +#define ATOM_PANEL_MISC_GREY_LEVEL_SHIFT 2 +#define ATOM_PANEL_MISC_SPATIAL 0x00000020 +#define ATOM_PANEL_MISC_TEMPORAL 0x00000040 +#define ATOM_PANEL_MISC_API_ENABLED 0x00000080 + + +#define MEMTYPE_DDR1 "DDR1" +#define MEMTYPE_DDR2 "DDR2" +#define MEMTYPE_DDR3 "DDR3" +#define MEMTYPE_DDR4 "DDR4" + +#define ASIC_BUS_TYPE_PCI "PCI" +#define ASIC_BUS_TYPE_AGP "AGP" +#define ASIC_BUS_TYPE_PCIE "PCI_EXPRESS" + +/* Maximum size of that FireGL flag string */ + +#define ATOM_FIREGL_FLAG_STRING "FGL" //Flag used to enable FireGL Support +#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING 3 //sizeof( ATOM_FIREGL_FLAG_STRING ) + +#define ATOM_FAKE_DESKTOP_STRING "DSK" //Flag used to enable mobile ASIC on Desktop +#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING + +#define ATOM_M54T_FLAG_STRING "M54T" //Flag used to enable M54T Support +#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING 4 //sizeof( ATOM_M54T_FLAG_STRING ) + +#define HW_ASSISTED_I2C_STATUS_FAILURE 2 +#define HW_ASSISTED_I2C_STATUS_SUCCESS 1 + +#pragma pack(1) /* BIOS data must use byte aligment */ + +/* Define offset to location of ROM header. */ + +#define OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER 0x00000048L +#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE 0x00000002L + +#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE 0x94 +#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE 20 /* including the terminator 0x0! */ +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER 0x002f +#define OFFSET_TO_GET_ATOMBIOS_STRINGS_START 0x006e + +/* Common header for all ROM Data tables. + Every table pointed _ATOM_MASTER_DATA_TABLE has this common header. + And the pointer actually points to this header. */ + +typedef struct _ATOM_COMMON_TABLE_HEADER +{ + USHORT usStructureSize; + UCHAR ucTableFormatRevision; /*Change it when the Parser is not backward compatible */ + UCHAR ucTableContentRevision; /*Change it only when the table needs to change but the firmware */ + /*Image can't be updated, while Driver needs to carry the new table! */ +}ATOM_COMMON_TABLE_HEADER; + +typedef struct _ATOM_ROM_HEADER +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR uaFirmWareSignature[4]; /*Signature to distinguish between Atombios and non-atombios, + atombios should init it as "ATOM", don't change the position */ + USHORT usBiosRuntimeSegmentAddress; + USHORT usProtectedModeInfoOffset; + USHORT usConfigFilenameOffset; + USHORT usCRC_BlockOffset; + USHORT usBIOS_BootupMessageOffset; + USHORT usInt10Offset; + USHORT usPciBusDevInitCode; + USHORT usIoBaseAddress; + USHORT usSubsystemVendorID; + USHORT usSubsystemID; + USHORT usPCI_InfoOffset; + USHORT usMasterCommandTableOffset; /*Offset for SW to get all command table offsets, Don't change the position */ + USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */ + UCHAR ucExtendedFunctionCode; + UCHAR ucReserved; +}ATOM_ROM_HEADER; + +/*==============================Command Table Portion==================================== */ + +#ifdef UEFI_BUILD + #define UTEMP USHORT + #define USHORT void* +#endif + +/****************************************************************************/ +// Structures used in Command.mtb +/****************************************************************************/ +typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ + USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1 + USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON + USHORT ASIC_RegistersInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT VRAM_BlockVenderDetection; //Atomic Table, used only by Bios + USHORT DIGxEncoderControl; //Only used by Bios + USHORT MemoryControllerInit; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT EnableCRTCMemReq; //Function Table,directly used by various SW components,latest version 2.1 + USHORT MemoryParamAdjust; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock if needed + USHORT DVOEncoderControl; //Function Table,directly used by various SW components,latest version 1.2 + USHORT GPIOPinControl; //Atomic Table, only used by Bios + USHORT SetEngineClock; //Function Table,directly used by various SW components,latest version 1.1 + USHORT SetMemoryClock; //Function Table,directly used by various SW components,latest version 1.1 + USHORT SetPixelClock; //Function Table,directly used by various SW components,latest version 1.2 + USHORT DynamicClockGating; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT ResetMemoryDLL; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT ResetMemoryDevice; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT MemoryPLLInit; + USHORT AdjustDisplayPll; //only used by Bios + USHORT AdjustMemoryController; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT EnableASIC_StaticPwrMgt; //Atomic Table, only used by Bios + USHORT ASIC_StaticPwrMgtStatusChange; //Obsolete , only used by Bios + USHORT DAC_LoadDetection; //Atomic Table, directly used by various SW components,latest version 1.2 + USHORT LVTMAEncoderControl; //Atomic Table,directly used by various SW components,latest version 1.3 + USHORT LCD1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC1EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC2EncoderControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DVOOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT CV1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetConditionalGoldenSetting; //only used by Bios + USHORT TVEncoderControl; //Function Table,directly used by various SW components,latest version 1.1 + USHORT TMDSAEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3 + USHORT LVDSEncoderControl; //Atomic Table, directly used by various SW components,latest version 1.3 + USHORT TV1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableScaler; //Atomic Table, used only by Bios + USHORT BlankCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableCRTC; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetPixelClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableVGA_Render; //Function Table,directly used by various SW components,latest version 1.1 + USHORT EnableVGA_Access; //Obsolete , only used by Bios + USHORT SetCRTC_Timing; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetCRTC_OverScan; //Atomic Table, used by various SW components,latest version 1.1 + USHORT SetCRTC_Replication; //Atomic Table, used only by Bios + USHORT SelectCRTC_Source; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT EnableGraphSurfaces; //Atomic Table, used only by Bios + USHORT UpdateCRTC_DoubleBufferRegisters; + USHORT LUT_AutoFill; //Atomic Table, only used by Bios + USHORT EnableHW_IconCursor; //Atomic Table, only used by Bios + USHORT GetMemoryClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT GetEngineClock; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetCRTC_UsingDTDTiming; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT ExternalEncoderControl; //Atomic Table, directly used by various SW components,latest version 2.1 + USHORT LVTMAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT VRAM_BlockDetectionByStrap; //Atomic Table, used only by Bios + USHORT MemoryCleanUp; //Atomic Table, only used by Bios + USHORT ProcessI2cChannelTransaction; //Function Table,only used by Bios + USHORT WriteOneByteToHWAssistedI2C; //Function Table,indirectly used by various SW components + USHORT ReadHWAssistedI2CStatus; //Atomic Table, indirectly used by various SW components + USHORT SpeedFanControl; //Function Table,indirectly used by various SW components,called from ASIC_Init + USHORT PowerConnectorDetection; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT MC_Synchronization; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT ComputeMemoryEnginePLL; //Atomic Table, indirectly used by various SW components,called from SetMemory/EngineClock + USHORT MemoryRefreshConversion; //Atomic Table, indirectly used by various SW components,called from SetMemory or SetEngineClock + USHORT VRAM_GetCurrentInfoBlock; //Atomic Table, used only by Bios + USHORT DynamicMemorySettings; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT MemoryTraining; //Atomic Table, used only by Bios + USHORT EnableSpreadSpectrumOnPPLL; //Atomic Table, directly used by various SW components,latest version 1.2 + USHORT TMDSAOutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetVoltage; //Function Table,directly and/or indirectly used by various SW components,latest version 1.1 + USHORT DAC1OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT DAC2OutputControl; //Atomic Table, directly used by various SW components,latest version 1.1 + USHORT SetupHWAssistedI2CStatus; //Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" + USHORT ClockSource; //Atomic Table, indirectly used by various SW components,called from ASIC_Init + USHORT MemoryDeviceInit; //Atomic Table, indirectly used by various SW components,called from SetMemoryClock + USHORT EnableYUV; //Atomic Table, indirectly used by various SW components,called from EnableVGARender + USHORT DIG1EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG2EncoderControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG1TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT DIG2TransmitterControl; //Atomic Table,directly used by various SW components,latest version 1.1 + USHORT ProcessAuxChannelTransaction; //Function Table,only used by Bios + USHORT DPEncoderService; //Function Table,only used by Bios +}ATOM_MASTER_LIST_OF_COMMAND_TABLES; + +// For backward compatible +#define ReadEDIDFromHWAssistedI2C ProcessI2cChannelTransaction +#define UNIPHYTransmitterControl DIG1TransmitterControl +#define LVTMATransmitterControl DIG2TransmitterControl +#define SetCRTC_DPM_State GetConditionalGoldenSetting +#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange + +typedef struct _ATOM_MASTER_COMMAND_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables; +}ATOM_MASTER_COMMAND_TABLE; + +/****************************************************************************/ +// Structures used in every command table +/****************************************************************************/ +typedef struct _ATOM_TABLE_ATTRIBUTE +{ + USHORT WS_SizeInBytes:8; //[7:0]=Size of workspace in Bytes (in multiple of a dword), + USHORT PS_SizeInBytes:7; //[14:8]=Size of parameter space in Bytes (multiple of a dword), + USHORT UpdatedByUtility:1; //[15]=Table updated by utility flag +}ATOM_TABLE_ATTRIBUTE; + +/****************************************************************************/ +// Common header for all command tables. +// Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. +// And the pointer actually points to this header. +/****************************************************************************/ +typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER +{ + ATOM_COMMON_TABLE_HEADER CommonHeader; + ATOM_TABLE_ATTRIBUTE TableAttribute; +}ATOM_COMMON_ROM_COMMAND_TABLE_HEADER; + + +/****************************************************************************/ +// Structures used by ComputeMemoryEnginePLLTable +/****************************************************************************/ + +#define COMPUTE_MEMORY_PLL_PARAM 1 +#define COMPUTE_ENGINE_PLL_PARAM 2 + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS +{ + ULONG ulClock; //When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div + UCHAR ucAction; //0:reserved //1:Memory //2:Engine + UCHAR ucReserved; //may expand to return larger Fbdiv later + UCHAR ucFbDiv; //return value + UCHAR ucPostDiv; //return value +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 +{ + ULONG ulClock; //When return, [23:0] return real clock + UCHAR ucAction; //0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register + USHORT usFbDiv; //return Feedback value to be written to register + UCHAR ucPostDiv; //return post div to be written to register +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2; +#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS + + +#define SET_CLOCK_FREQ_MASK 0x00FFFFFF //Clock change tables only take bit [23:0] as the requested clock value +#define USE_NON_BUS_CLOCK_MASK 0x01000000 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) +#define USE_MEMORY_SELF_REFRESH_MASK 0x02000000 //Only applicable to memory clock change, when set, using memory self refresh during clock transition +#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04000000 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change +#define FIRST_TIME_CHANGE_CLOCK 0x08000000 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup +#define SKIP_SW_PROGRAM_PLL 0x10000000 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL +#define USE_SS_ENABLED_PIXEL_CLOCK USE_NON_BUS_CLOCK_MASK + +#define b3USE_NON_BUS_CLOCK_MASK 0x01 //Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) +#define b3USE_MEMORY_SELF_REFRESH 0x02 //Only applicable to memory clock change, when set, using memory self refresh during clock transition +#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE 0x04 //Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change +#define b3FIRST_TIME_CHANGE_CLOCK 0x08 //Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup +#define b3SKIP_SW_PROGRAM_PLL 0x10 //Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL + +typedef struct _ATOM_COMPUTE_CLOCK_FREQ +{ + ULONG ulClockFreq:24; // in unit of 10kHz + ULONG ulComputeClockFlag:8; // =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM +}ATOM_COMPUTE_CLOCK_FREQ; + +typedef struct _ATOM_S_MPLL_FB_DIVIDER +{ + USHORT usFbDivFrac; + USHORT usFbDiv; +}ATOM_S_MPLL_FB_DIVIDER; + +typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 +{ + union + { + ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter + ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter + }; + UCHAR ucRefDiv; //Output Parameter + UCHAR ucPostDiv; //Output Parameter + UCHAR ucCntlFlag; //Output Parameter + UCHAR ucReserved; +}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3; + +// ucCntlFlag +#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN 1 +#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE 2 +#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE 4 + +typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER +{ + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulReserved[2]; +}DYNAMICE_MEMORY_SETTINGS_PARAMETER; + +typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER +{ + ATOM_COMPUTE_CLOCK_FREQ ulClock; + ULONG ulMemoryClock; + ULONG ulReserved; +}DYNAMICE_ENGINE_SETTINGS_PARAMETER; + +/****************************************************************************/ +// Structures used by SetEngineClockTable +/****************************************************************************/ +typedef struct _SET_ENGINE_CLOCK_PARAMETERS +{ + ULONG ulTargetEngineClock; //In 10Khz unit +}SET_ENGINE_CLOCK_PARAMETERS; + +typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION +{ + ULONG ulTargetEngineClock; //In 10Khz unit + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +}SET_ENGINE_CLOCK_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by SetMemoryClockTable +/****************************************************************************/ +typedef struct _SET_MEMORY_CLOCK_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit +}SET_MEMORY_CLOCK_PARAMETERS; + +typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION +{ + ULONG ulTargetMemoryClock; //In 10Khz unit + COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved; +}SET_MEMORY_CLOCK_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by ASIC_Init.ctb +/****************************************************************************/ +typedef struct _ASIC_INIT_PARAMETERS +{ + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit +}ASIC_INIT_PARAMETERS; + +typedef struct _ASIC_INIT_PS_ALLOCATION +{ + ASIC_INIT_PARAMETERS sASICInitClocks; + SET_ENGINE_CLOCK_PS_ALLOCATION sReserved; //Caller doesn't need to init this structure +}ASIC_INIT_PS_ALLOCATION; + +/****************************************************************************/ +// Structure used by DynamicClockGatingTable.ctb +/****************************************************************************/ +typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}DYNAMIC_CLOCK_GATING_PARAMETERS; +#define DYNAMIC_CLOCK_GATING_PS_ALLOCATION DYNAMIC_CLOCK_GATING_PARAMETERS + +/****************************************************************************/ +// Structure used by EnableASIC_StaticPwrMgtTable.ctb +/****************************************************************************/ +typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS; +#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS + +/****************************************************************************/ +// Structures used by DAC_LoadDetectionTable.ctb +/****************************************************************************/ +typedef struct _DAC_LOAD_DETECTION_PARAMETERS +{ + USHORT usDeviceID; //{ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} + UCHAR ucDacType; //{ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC} + UCHAR ucMisc; //Valid only when table revision =1.3 and above +}DAC_LOAD_DETECTION_PARAMETERS; + +// DAC_LOAD_DETECTION_PARAMETERS.ucMisc +#define DAC_LOAD_MISC_YPrPb 0x01 + +typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION +{ + DAC_LOAD_DETECTION_PARAMETERS sDacload; + ULONG Reserved[2];// Don't set this one, allocation for EXT DAC +}DAC_LOAD_DETECTION_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb +/****************************************************************************/ +typedef struct _DAC_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucDacStandard; // See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0) + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder + // 7: ATOM_ENCODER_INIT Initialize DAC +}DAC_ENCODER_CONTROL_PARAMETERS; + +#define DAC_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PARAMETERS + +/****************************************************************************/ +// Structures used by DIG1EncoderControlTable +// DIG2EncoderControlTable +// ExternalEncoderControlTable +/****************************************************************************/ +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucConfig; + // [2] Link Select: + // =0: PHY linkA if bfLane<3 + // =1: PHY linkB if bfLanes<3 + // =0: PHY linkA+B if bfLanes=3 + // [3] Transmitter Sel + // =0: UNIPHY or PCIEPHY + // =1: LVTMA + UCHAR ucAction; // =0: turn off encoder + // =1: turn on encoder + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucReserved[2]; +}DIG_ENCODER_CONTROL_PARAMETERS; +#define DIG_ENCODER_CONTROL_PS_ALLOCATION DIG_ENCODER_CONTROL_PARAMETERS +#define EXTERNAL_ENCODER_CONTROL_PARAMETER DIG_ENCODER_CONTROL_PARAMETERS + +//ucConfig +#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_LINKA_B ATOM_TRANSMITTER_CONFIG_LINKA +#define ATOM_ENCODER_CONFIG_LINKB_A ATOM_ENCODER_CONFIG_LINKB +#define ATOM_ENCODER_CONFIG_TRANSMITTER_SEL_MASK 0x08 +#define ATOM_ENCODER_CONFIG_UNIPHY 0x00 +#define ATOM_ENCODER_CONFIG_LVTMA 0x08 +#define ATOM_ENCODER_CONFIG_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_DIGB 0x80 // VBIOS Internal use, outside SW should set this bit=0 +// ucAction +// ATOM_ENABLE: Enable Encoder +// ATOM_DISABLE: Disable Encoder + +//ucEncoderMode +#define ATOM_ENCODER_MODE_DP 0 +#define ATOM_ENCODER_MODE_LVDS 1 +#define ATOM_ENCODER_MODE_DVI 2 +#define ATOM_ENCODER_MODE_HDMI 3 +#define ATOM_ENCODER_MODE_SDVO 4 +#define ATOM_ENCODER_MODE_TV 13 +#define ATOM_ENCODER_MODE_CV 14 +#define ATOM_ENCODER_MODE_CRT 15 + +typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 +{ + UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz + UCHAR ucReserved:1; + UCHAR ucLinkSel:1; // =0: linkA/C/E =1: linkB/D/F + UCHAR ucTransmitterSel:2; // =0: UniphyAB, =1: UniphyCD =2: UniphyEF + UCHAR ucReserved1:2; +}ATOM_DIG_ENCODER_CONFIG_V2; + + +typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + ATOM_DIG_ENCODER_CONFIG_V2 acConfig; + UCHAR ucAction; + UCHAR ucEncoderMode; + // =0: DP encoder + // =1: LVDS encoder + // =2: DVI encoder + // =3: HDMI encoder + // =4: SDVO encoder + UCHAR ucLaneNum; // how many lanes to enable + UCHAR ucReserved[2]; +}DIG_ENCODER_CONTROL_PARAMETERS_V2; + +//ucConfig +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK 0x01 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ 0x00 +#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ 0x01 +#define ATOM_ENCODER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_ENCODER_CONFIG_V2_LINKA 0x00 +#define ATOM_ENCODER_CONFIG_V2_LINKB 0x04 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER_SEL_MASK 0x18 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER1 0x00 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2 0x08 +#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3 0x10 + +/****************************************************************************/ +// Structures used by UNIPHYTransmitterControlTable +// LVTMATransmitterControlTable +// DVOOutputControlTable +/****************************************************************************/ +typedef struct _ATOM_DP_VS_MODE +{ + UCHAR ucLaneSel; + UCHAR ucLaneSet; +}ATOM_DP_VS_MODE; + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + UCHAR ucConfig; + // [0]=0: 4 lane Link, + // =1: 8 lane Link ( Dual Links TMDS ) + // [1]=0: InCoherent mode + // =1: Coherent Mode + // [2] Link Select: + // =0: PHY linkA if bfLane<3 + // =1: PHY linkB if bfLanes<3 + // =0: PHY linkA+B if bfLanes=3 + // [5:4]PCIE lane Sel + // =0: lane 0~3 or 0~7 + // =1: lane 4~7 + // =2: lane 8~11 or 8~15 + // =3: lane 12~15 + UCHAR ucAction; // =0: turn off encoder + // =1: turn on encoder + UCHAR ucReserved[4]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS; + +#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PARAMETERS + +//ucInitInfo +#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff + +//ucConfig +#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK 0x01 +#define ATOM_TRANSMITTER_CONFIG_COHERENT 0x02 +#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB 0x04 +#define ATOM_TRANSMITTER_CONFIG_LINKA_B 0x00 +#define ATOM_TRANSMITTER_CONFIG_LINKB_A 0x04 + +#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE +#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER 0x00 // only used when ATOM_TRANSMITTER_ACTION_ENABLE +#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER 0x08 // only used when ATOM_TRANSMITTER_ACTION_ENABLE + +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK 0x30 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL 0x00 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PCIE 0x20 +#define ATOM_TRANSMITTER_CONFIG_CLKSRC_XTALIN 0x30 +#define ATOM_TRANSMITTER_CONFIG_LANE_SEL_MASK 0xc0 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_3 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_0_7 0x00 +#define ATOM_TRANSMITTER_CONFIG_LANE_4_7 0x40 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_11 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_8_15 0x80 +#define ATOM_TRANSMITTER_CONFIG_LANE_12_15 0xc0 + +//ucAction +#define ATOM_TRANSMITTER_ACTION_DISABLE 0 +#define ATOM_TRANSMITTER_ACTION_ENABLE 1 +#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF 2 +#define ATOM_TRANSMITTER_ACTION_LCD_BLON 3 +#define ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL 4 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_START 5 +#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_STOP 6 +#define ATOM_TRANSMITTER_ACTION_INIT 7 +#define ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT 8 +#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT 9 +#define ATOM_TRANSMITTER_ACTION_SETUP 10 +#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH 11 + + +// Following are used for DigTransmitterControlTable ver1.2 +typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2 +{ + UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector + UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) + UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E + // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F + UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) + UCHAR fDPConnector:1; //bit4=0: DP connector =1: None DP connector + UCHAR ucReserved:1; + UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) + // =1 Dig Transmitter 2 ( Uniphy CD ) + // =2 Dig Transmitter 3 ( Uniphy EF ) +}ATOM_DIG_TRANSMITTER_CONFIG_V2; + +//ucConfig +//Bit0 +#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR 0x01 + +//Bit1 +#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT 0x02 + +//Bit2 +#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK 0x04 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKA 0x00 +#define ATOM_TRANSMITTER_CONFIG_V2_LINKB 0x04 + +// Bit3 +#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK 0x08 +#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER 0x00 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP +#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER 0x08 // only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP + +// Bit4 +#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR 0x10 + +// Bit7:6 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK 0xC0 +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1 0x00 //AB +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2 0x40 //CD +#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3 0x80 //EF + +typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 +{ + union + { + USHORT usPixelClock; // in 10KHz; for bios convenient + USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h + ATOM_DP_VS_MODE asMode; // DP Voltage swing mode + }; + ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig; + UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX + UCHAR ucReserved[4]; +}DIG_TRANSMITTER_CONTROL_PARAMETERS_V2; + + +/****************************************************************************/ +// Structures used by DAC1OuputControlTable +// DAC2OuputControlTable +// LVTMAOutputControlTable (Before DEC30) +// TMDSAOutputControlTable (Before DEC30) +/****************************************************************************/ +typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +{ + UCHAR ucAction; // Possible input:ATOM_ENABLE||ATOMDISABLE + // When the display is LCD, in addition to above: + // ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START|| + // ATOM_LCD_SELFTEST_STOP + + UCHAR aucPadding[3]; // padding to DWORD aligned +}DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS; + +#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS + + +#define CRT1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CRT2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define CV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define CV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define TV1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define TV1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DFP2_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DFP2_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define LCD1_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define LCD1_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION + +#define DVO_OUTPUT_CONTROL_PARAMETERS DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS +#define DVO_OUTPUT_CONTROL_PS_ALLOCATION DIG_TRANSMITTER_CONTROL_PS_ALLOCATION +#define DVO_OUTPUT_CONTROL_PARAMETERS_V3 DIG_TRANSMITTER_CONTROL_PARAMETERS + +/****************************************************************************/ +// Structures used by BlankCRTCTable +/****************************************************************************/ +typedef struct _BLANK_CRTC_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucBlanking; // ATOM_BLANKING or ATOM_BLANKINGOFF + USHORT usBlackColorRCr; + USHORT usBlackColorGY; + USHORT usBlackColorBCb; +}BLANK_CRTC_PARAMETERS; +#define BLANK_CRTC_PS_ALLOCATION BLANK_CRTC_PARAMETERS + +/****************************************************************************/ +// Structures used by EnableCRTCTable +// EnableCRTCMemReqTable +// UpdateCRTC_DoubleBufferRegistersTable +/****************************************************************************/ +typedef struct _ENABLE_CRTC_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[2]; +}ENABLE_CRTC_PARAMETERS; +#define ENABLE_CRTC_PS_ALLOCATION ENABLE_CRTC_PARAMETERS + +/****************************************************************************/ +// Structures used by SetCRTC_OverScanTable +/****************************************************************************/ +typedef struct _SET_CRTC_OVERSCAN_PARAMETERS +{ + USHORT usOverscanRight; // right + USHORT usOverscanLeft; // left + USHORT usOverscanBottom; // bottom + USHORT usOverscanTop; // top + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding[3]; +}SET_CRTC_OVERSCAN_PARAMETERS; +#define SET_CRTC_OVERSCAN_PS_ALLOCATION SET_CRTC_OVERSCAN_PARAMETERS + +/****************************************************************************/ +// Structures used by SetCRTC_ReplicationTable +/****************************************************************************/ +typedef struct _SET_CRTC_REPLICATION_PARAMETERS +{ + UCHAR ucH_Replication; // horizontal replication + UCHAR ucV_Replication; // vertical replication + UCHAR usCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding; +}SET_CRTC_REPLICATION_PARAMETERS; +#define SET_CRTC_REPLICATION_PS_ALLOCATION SET_CRTC_REPLICATION_PARAMETERS + +/****************************************************************************/ +// Structures used by SelectCRTC_SourceTable +/****************************************************************************/ +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucDevice; // ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|.... + UCHAR ucPadding[2]; +}SELECT_CRTC_SOURCE_PARAMETERS; +#define SELECT_CRTC_SOURCE_PS_ALLOCATION SELECT_CRTC_SOURCE_PARAMETERS + +typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 +{ + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucEncoderID; // DAC1/DAC2/TVOUT/DIG1/DIG2/DVO + UCHAR ucEncodeMode; // Encoding mode, only valid when using DIG1/DIG2/DVO + UCHAR ucPadding; +}SELECT_CRTC_SOURCE_PARAMETERS_V2; + +//ucEncoderID +//#define ASIC_INT_DAC1_ENCODER_ID 0x00 +//#define ASIC_INT_TV_ENCODER_ID 0x02 +//#define ASIC_INT_DIG1_ENCODER_ID 0x03 +//#define ASIC_INT_DAC2_ENCODER_ID 0x04 +//#define ASIC_EXT_TV_ENCODER_ID 0x06 +//#define ASIC_INT_DVO_ENCODER_ID 0x07 +//#define ASIC_INT_DIG2_ENCODER_ID 0x09 +//#define ASIC_EXT_DIG_ENCODER_ID 0x05 + +//ucEncodeMode +//#define ATOM_ENCODER_MODE_DP 0 +//#define ATOM_ENCODER_MODE_LVDS 1 +//#define ATOM_ENCODER_MODE_DVI 2 +//#define ATOM_ENCODER_MODE_HDMI 3 +//#define ATOM_ENCODER_MODE_SDVO 4 +//#define ATOM_ENCODER_MODE_TV 13 +//#define ATOM_ENCODER_MODE_CV 14 +//#define ATOM_ENCODER_MODE_CRT 15 + +/****************************************************************************/ +// Structures used by SetPixelClockTable +// GetPixelClockTable +/****************************************************************************/ +//Major revision=1., Minor revision=1 +typedef struct _PIXEL_CLOCK_PARAMETERS +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER + UCHAR ucCRTC; // Which CRTC uses this Ppll + UCHAR ucPadding; +}PIXEL_CLOCK_PARAMETERS; + +//Major revision=1., Minor revision=2, add ucMiscIfno +//ucMiscInfo: +#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1 +#define MISC_DEVICE_INDEX_MASK 0xF0 +#define MISC_DEVICE_INDEX_SHIFT 4 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucRefDivSrc; // ATOM_PJITTER or ATO_NONPJITTER + UCHAR ucCRTC; // Which CRTC uses this Ppll + UCHAR ucMiscInfo; // Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog +}PIXEL_CLOCK_PARAMETERS_V2; + +//Major revision=1., Minor revision=3, structure/definition change +//ucEncoderMode: +//ATOM_ENCODER_MODE_DP +//ATOM_ENOCDER_MODE_LVDS +//ATOM_ENOCDER_MODE_DVI +//ATOM_ENOCDER_MODE_HDMI +//ATOM_ENOCDER_MODE_SDVO +//ATOM_ENCODER_MODE_TV 13 +//ATOM_ENCODER_MODE_CV 14 +//ATOM_ENCODER_MODE_CRT 15 + +//ucDVOConfig +//#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +//#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +//#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +//#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +//#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +//#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +//#define DVO_ENCODER_CONFIG_24BIT 0x08 + +//ucMiscInfo: also changed, see below +#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL 0x01 +#define PIXEL_CLOCK_MISC_VGA_MODE 0x02 +#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK 0x04 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1 0x00 +#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 0x04 +#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK 0x08 + +typedef struct _PIXEL_CLOCK_PARAMETERS_V3 +{ + USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) + // 0 means disable PPLL. For VGA PPLL,make sure this value is not 0. + USHORT usRefDiv; // Reference divider + USHORT usFbDiv; // feedback divider + UCHAR ucPostDiv; // post divider + UCHAR ucFracFbDiv; // fractional feedback divider + UCHAR ucPpll; // ATOM_PPLL1 or ATOM_PPL2 + UCHAR ucTransmitterId; // graphic encoder id defined in objectId.h + union + { + UCHAR ucEncoderMode; // encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/ + UCHAR ucDVOConfig; // when use DVO, need to know SDR/DDR, 12bit or 24bit + }; + UCHAR ucMiscInfo; // bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel + // bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source +}PIXEL_CLOCK_PARAMETERS_V3; + +#define PIXEL_CLOCK_PARAMETERS_LAST PIXEL_CLOCK_PARAMETERS_V2 +#define GET_PIXEL_CLOCK_PS_ALLOCATION PIXEL_CLOCK_PARAMETERS_LAST + +/****************************************************************************/ +// Structures used by AdjustDisplayPllTable +/****************************************************************************/ +typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS +{ + USHORT usPixelClock; + UCHAR ucTransmitterID; + UCHAR ucEncodeMode; + union + { + UCHAR ucDVOConfig; //if DVO, need passing link rate and output 12bitlow or 24bit + UCHAR ucConfig; //if none DVO, not defined yet + }; + UCHAR ucReserved[3]; +}ADJUST_DISPLAY_PLL_PARAMETERS; + +#define ADJUST_DISPLAY_CONFIG_SS_ENABLE 0x10 + +#define ADJUST_DISPLAY_PLL_PS_ALLOCATION ADJUST_DISPLAY_PLL_PARAMETERS + +/****************************************************************************/ +// Structures used by EnableYUVTable +/****************************************************************************/ +typedef struct _ENABLE_YUV_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) + UCHAR ucCRTC; // Which CRTC needs this YUV or RGB format + UCHAR ucPadding[2]; +}ENABLE_YUV_PARAMETERS; +#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS + +/****************************************************************************/ +// Structures used by GetMemoryClockTable +/****************************************************************************/ +typedef struct _GET_MEMORY_CLOCK_PARAMETERS +{ + ULONG ulReturnMemoryClock; // current memory speed in 10KHz unit +} GET_MEMORY_CLOCK_PARAMETERS; +#define GET_MEMORY_CLOCK_PS_ALLOCATION GET_MEMORY_CLOCK_PARAMETERS + +/****************************************************************************/ +// Structures used by GetEngineClockTable +/****************************************************************************/ +typedef struct _GET_ENGINE_CLOCK_PARAMETERS +{ + ULONG ulReturnEngineClock; // current engine speed in 10KHz unit +} GET_ENGINE_CLOCK_PARAMETERS; +#define GET_ENGINE_CLOCK_PS_ALLOCATION GET_ENGINE_CLOCK_PARAMETERS + +/****************************************************************************/ +// Following Structures and constant may be obsolete +/****************************************************************************/ +//Maxium 8 bytes,the data read in will be placed in the parameter space. +//Read operaion successeful when the paramter space is non-zero, otherwise read operation failed +typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + USHORT usVRAMAddress; //Adress in Frame Buffer where to pace raw EDID + USHORT usStatus; //When use output: lower byte EDID checksum, high byte hardware status + //WHen use input: lower byte as 'byte to read':currently limited to 128byte or 1byte + UCHAR ucSlaveAddr; //Read from which slave + UCHAR ucLineNumber; //Read from which HW assisted line +}READ_EDID_FROM_HW_I2C_DATA_PARAMETERS; +#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION READ_EDID_FROM_HW_I2C_DATA_PARAMETERS + + +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE 0 +#define ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES 1 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK 2 +#define ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK 3 +#define ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK 4 + +typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + USHORT usByteOffset; //Write to which byte + //Upper portion of usByteOffset is Format of data + //1bytePS+offsetPS + //2bytesPS+offsetPS + //blockID+offsetPS + //blockID+offsetID + //blockID+counterID+offsetID + UCHAR ucData; //PS data1 + UCHAR ucStatus; //Status byte 1=success, 2=failure, Also is used as PS data2 + UCHAR ucSlaveAddr; //Write to which slave + UCHAR ucLineNumber; //Write from which HW assisted line +}WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS; + +#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS +{ + USHORT usPrescale; //Ratio between Engine clock and I2C clock + UCHAR ucSlaveAddr; //Write to which slave + UCHAR ucLineNumber; //Write from which HW assisted line +}SET_UP_HW_I2C_DATA_PARAMETERS; + + +/**************************************************************************/ +#define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +/****************************************************************************/ +// Structures used by PowerConnectorDetectionTable +/****************************************************************************/ +typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS +{ + UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected + UCHAR ucPwrBehaviorId; + USHORT usPwrBudget; //how much power currently boot to in unit of watt +}POWER_CONNECTOR_DETECTION_PARAMETERS; + +typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION +{ + UCHAR ucPowerConnectorStatus; //Used for return value 0: detected, 1:not detected + UCHAR ucReserved; + USHORT usPwrBudget; //how much power currently boot to in unit of watt + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}POWER_CONNECTOR_DETECTION_PS_ALLOCATION; + +/****************************LVDS SS Command Table Definitions**********************/ + +/****************************************************************************/ +// Structures used by EnableSpreadSpectrumOnPPLLTable +/****************************************************************************/ +typedef struct _ENABLE_LVDS_SS_PARAMETERS +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStepSize_Delay; //bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY + UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[3]; +}ENABLE_LVDS_SS_PARAMETERS; + +//ucTableFormatRevision=1,ucTableContentRevision=2 +typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2 +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStep; // + UCHAR ucEnable; //ATOM_ENABLE or ATOM_DISABLE + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPadding; +}ENABLE_LVDS_SS_PARAMETERS_V2; + +//This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS. +typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; // Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSpreadSpectrumStep; // + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucSpreadSpectrumDelay; + UCHAR ucSpreadSpectrumRange; + UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2 +}ENABLE_SPREAD_SPECTRUM_ON_PPLL; + +#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/**************************************************************************/ + +typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION +{ + PIXEL_CLOCK_PARAMETERS sPCLKInput; + ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;//Caller doesn't need to init this portion +}SET_PIXEL_CLOCK_PS_ALLOCATION; + +#define ENABLE_VGA_RENDER_PS_ALLOCATION SET_PIXEL_CLOCK_PS_ALLOCATION + +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ +typedef struct _MEMORY_TRAINING_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit +}MEMORY_TRAINING_PARAMETERS; +#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS + + +/****************************LVDS and other encoder command table definitions **********************/ + + +/****************************************************************************/ +// Structures used by LVDSEncoderControlTable (Before DCE30) +// LVTMAEncoderControlTable (Before DCE30) +// TMDSAEncoderControlTable (Before DCE30) +/****************************************************************************/ +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucMisc; // bit0=0: Enable single link + // =1: Enable dual link + // Bit1=0: 666RGB + // =1: 888RGB + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}LVDS_ENCODER_CONTROL_PARAMETERS; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION LVDS_ENCODER_CONTROL_PARAMETERS + +#define TMDS1_ENCODER_CONTROL_PARAMETERS LVDS_ENCODER_CONTROL_PARAMETERS +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS + +#define TMDS2_ENCODER_CONTROL_PARAMETERS TMDS1_ENCODER_CONTROL_PARAMETERS +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS + + +//ucTableFormatRevision=1,ucTableContentRevision=2 +typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucMisc; // see PANEL_ENCODER_MISC_xx defintions below + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder + UCHAR ucTruncate; // bit0=0: Disable truncate + // =1: Enable truncate + // bit4=0: 666RGB + // =1: 888RGB + UCHAR ucSpatial; // bit0=0: Disable spatial dithering + // =1: Enable spatial dithering + // bit4=0: 666RGB + // =1: 888RGB + UCHAR ucTemporal; // bit0=0: Disable temporal dithering + // =1: Enable temporal dithering + // bit4=0: 666RGB + // =1: 888RGB + // bit5=0: Gray level 2 + // =1: Gray level 4 + UCHAR ucFRC; // bit4=0: 25FRC_SEL pattern E + // =1: 25FRC_SEL pattern F + // bit6:5=0: 50FRC_SEL pattern A + // =1: 50FRC_SEL pattern B + // =2: 50FRC_SEL pattern C + // =3: 50FRC_SEL pattern D + // bit7=0: 75FRC_SEL pattern E + // =1: 75FRC_SEL pattern F +}LVDS_ENCODER_CONTROL_PARAMETERS_V2; + +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2 + +#define LVDS_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V2 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3 + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3 LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3 + +/****************************************************************************/ +// Structures used by ### +/****************************************************************************/ +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS +{ + UCHAR ucEnable; // Enable or Disable External TMDS encoder + UCHAR ucMisc; // Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} + UCHAR ucPadding[2]; +}ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS; + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION; + +#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 LVDS_ENCODER_CONTROL_PARAMETERS_V2 + +typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 +{ + ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2; + +typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION +{ + DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by DVOEncoderControlTable +/****************************************************************************/ +//ucTableFormatRevision=1,ucTableContentRevision=3 +//ucDVOConfig: +#define DVO_ENCODER_CONFIG_RATE_SEL 0x01 +#define DVO_ENCODER_CONFIG_DDR_SPEED 0x00 +#define DVO_ENCODER_CONFIG_SDR_SPEED 0x01 +#define DVO_ENCODER_CONFIG_OUTPUT_SEL 0x0c +#define DVO_ENCODER_CONFIG_LOW12BIT 0x00 +#define DVO_ENCODER_CONFIG_UPPER12BIT 0x04 +#define DVO_ENCODER_CONFIG_24BIT 0x08 + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 +{ + USHORT usPixelClock; + UCHAR ucDVOConfig; + UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT + UCHAR ucReseved[4]; +}DVO_ENCODER_CONTROL_PARAMETERS_V3; +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 DVO_ENCODER_CONTROL_PARAMETERS_V3 + +//ucTableFormatRevision=1 +//ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for +// bit1=0: non-coherent mode +// =1: coherent mode + +//========================================================================================== +//Only change is here next time when changing encoder parameter definitions again! +#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST LVDS_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS1_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS1_ENCODER_CONTROL_PARAMETERS_LAST + +#define TMDS2_ENCODER_CONTROL_PARAMETERS_LAST LVDS_ENCODER_CONTROL_PARAMETERS_V3 +#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS2_ENCODER_CONTROL_PARAMETERS_LAST + +#define DVO_ENCODER_CONTROL_PARAMETERS_LAST DVO_ENCODER_CONTROL_PARAMETERS +#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST DVO_ENCODER_CONTROL_PS_ALLOCATION + +//========================================================================================== +#define PANEL_ENCODER_MISC_DUAL 0x01 +#define PANEL_ENCODER_MISC_COHERENT 0x02 +#define PANEL_ENCODER_MISC_TMDS_LINKB 0x04 +#define PANEL_ENCODER_MISC_HDMI_TYPE 0x08 + +#define PANEL_ENCODER_ACTION_DISABLE ATOM_DISABLE +#define PANEL_ENCODER_ACTION_ENABLE ATOM_ENABLE +#define PANEL_ENCODER_ACTION_COHERENTSEQ (ATOM_ENABLE+1) + +#define PANEL_ENCODER_TRUNCATE_EN 0x01 +#define PANEL_ENCODER_TRUNCATE_DEPTH 0x10 +#define PANEL_ENCODER_SPATIAL_DITHER_EN 0x01 +#define PANEL_ENCODER_SPATIAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_DITHER_EN 0x01 +#define PANEL_ENCODER_TEMPORAL_DITHER_DEPTH 0x10 +#define PANEL_ENCODER_TEMPORAL_LEVEL_4 0x20 +#define PANEL_ENCODER_25FRC_MASK 0x10 +#define PANEL_ENCODER_25FRC_E 0x00 +#define PANEL_ENCODER_25FRC_F 0x10 +#define PANEL_ENCODER_50FRC_MASK 0x60 +#define PANEL_ENCODER_50FRC_A 0x00 +#define PANEL_ENCODER_50FRC_B 0x20 +#define PANEL_ENCODER_50FRC_C 0x40 +#define PANEL_ENCODER_50FRC_D 0x60 +#define PANEL_ENCODER_75FRC_MASK 0x80 +#define PANEL_ENCODER_75FRC_E 0x00 +#define PANEL_ENCODER_75FRC_F 0x80 + +/****************************************************************************/ +// Structures used by SetVoltageTable +/****************************************************************************/ +#define SET_VOLTAGE_TYPE_ASIC_VDDC 1 +#define SET_VOLTAGE_TYPE_ASIC_MVDDC 2 +#define SET_VOLTAGE_TYPE_ASIC_MVDDQ 3 +#define SET_VOLTAGE_TYPE_ASIC_VDDCI 4 +#define SET_VOLTAGE_INIT_MODE 5 +#define SET_VOLTAGE_GET_MAX_VOLTAGE 6 //Gets the Max. voltage for the soldered Asic + +#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE 0x1 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_A 0x2 +#define SET_ASIC_VOLTAGE_MODE_SOURCE_B 0x4 + +#define SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE 0x0 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL 0x1 +#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2 + +typedef struct _SET_VOLTAGE_PARAMETERS +{ + UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ + UCHAR ucVoltageMode; // To set all, to set source A or source B or ... + UCHAR ucVoltageIndex; // An index to tell which voltage level + UCHAR ucReserved; +}SET_VOLTAGE_PARAMETERS; + +typedef struct _SET_VOLTAGE_PARAMETERS_V2 +{ + UCHAR ucVoltageType; // To tell which voltage to set up, VDDC/MVDDC/MVDDQ + UCHAR ucVoltageMode; // Not used, maybe use for state machine for differen power mode + USHORT usVoltageLevel; // real voltage level +}SET_VOLTAGE_PARAMETERS_V2; + +typedef struct _SET_VOLTAGE_PS_ALLOCATION +{ + SET_VOLTAGE_PARAMETERS sASICSetVoltage; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; +}SET_VOLTAGE_PS_ALLOCATION; + +/****************************************************************************/ +// Structures used by TVEncoderControlTable +/****************************************************************************/ +typedef struct _TV_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; // in 10KHz; for bios convenient + UCHAR ucTvStandard; // See definition "ATOM_TV_NTSC ..." + UCHAR ucAction; // 0: turn off encoder + // 1: setup and turn on encoder +}TV_ENCODER_CONTROL_PARAMETERS; + +typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION +{ + TV_ENCODER_CONTROL_PARAMETERS sTVEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; // Don't set this one +}TV_ENCODER_CONTROL_PS_ALLOCATION; + +//==============================Data Table Portion==================================== + +#ifdef UEFI_BUILD + #define UTEMP USHORT + #define USHORT void* +#endif + +/****************************************************************************/ +// Structure used in Data.mtb +/****************************************************************************/ +typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES +{ + USHORT UtilityPipeLine; // Offest for the utility to get parser info,Don't change this position! + USHORT MultimediaCapabilityInfo; // Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios + USHORT MultimediaConfigInfo; // Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios + USHORT StandardVESA_Timing; // Only used by Bios + USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4 + USHORT DAC_Info; // Will be obsolete from R600 + USHORT LVDS_Info; // Shared by various SW components,latest version 1.1 + USHORT TMDS_Info; // Will be obsolete from R600 + USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1 + USHORT SupportedDevicesInfo; // Will be obsolete from R600 + USHORT GPIO_I2C_Info; // Shared by various SW components,latest version 1.2 will be used from R600 + USHORT VRAM_UsageByFirmware; // Shared by various SW components,latest version 1.3 will be used from R600 + USHORT GPIO_Pin_LUT; // Shared by various SW components,latest version 1.1 + USHORT VESA_ToInternalModeLUT; // Only used by Bios + USHORT ComponentVideoInfo; // Shared by various SW components,latest version 2.1 will be used from R600 + USHORT PowerPlayInfo; // Shared by various SW components,latest version 2.1,new design from R600 + USHORT CompassionateData; // Will be obsolete from R600 + USHORT SaveRestoreInfo; // Only used by Bios + USHORT PPLL_SS_Info; // Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info + USHORT OemInfo; // Defined and used by external SW, should be obsolete soon + USHORT XTMDS_Info; // Will be obsolete from R600 + USHORT MclkSS_Info; // Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used + USHORT Object_Header; // Shared by various SW components,latest version 1.1 + USHORT IndirectIOAccess; // Only used by Bios,this table position can't change at all!! + USHORT MC_InitParameter; // Only used by command table + USHORT ASIC_VDDC_Info; // Will be obsolete from R600 + USHORT ASIC_InternalSS_Info; // New tabel name from R600, used to be called "ASIC_MVDDC_Info" + USHORT TV_VideoMode; // Only used by command table + USHORT VRAM_Info; // Only used by command table, latest version 1.3 + USHORT MemoryTrainingInfo; // Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 + USHORT IntegratedSystemInfo; // Shared by various SW components + USHORT ASIC_ProfilingInfo; // New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 + USHORT VoltageObjectInfo; // Shared by various SW components, latest version 1.1 + USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1 +}ATOM_MASTER_LIST_OF_DATA_TABLES; + +#ifdef UEFI_BUILD + #define USHORT UTEMP +#endif + +typedef struct _ATOM_MASTER_DATA_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; +}ATOM_MASTER_DATA_TABLE; + +/****************************************************************************/ +// Structure used in MultimediaCapabilityInfoTable +/****************************************************************************/ +typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; // HW info table signature string "$ATI" + UCHAR ucI2C_Type; // I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc) + UCHAR ucTV_OutInfo; // Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7) + UCHAR ucVideoPortInfo; // Provides the video port capabilities + UCHAR ucHostPortInfo; // Provides host port configuration information +}ATOM_MULTIMEDIA_CAPABILITY_INFO; + +/****************************************************************************/ +// Structure used in MultimediaConfigInfoTable +/****************************************************************************/ +typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulSignature; // MM info table signature sting "$MMT" + UCHAR ucTunerInfo; // Type of tuner installed on the adapter (4:0) and video input for tuner (7:5) + UCHAR ucAudioChipInfo; // List the audio chip type (3:0) product type (4) and OEM revision (7:5) + UCHAR ucProductID; // Defines as OEM ID or ATI board ID dependent on product type setting + UCHAR ucMiscInfo1; // Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7) + UCHAR ucMiscInfo2; // I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6) + UCHAR ucMiscInfo3; // Video Decoder Type (3:0) Video In Standard/Crystal (7:4) + UCHAR ucMiscInfo4; // Video Decoder Host Config (2:0) reserved (7:3) + UCHAR ucVideoInput0Info;// Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput1Info;// Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput2Info;// Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput3Info;// Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) + UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) +}ATOM_MULTIMEDIA_CONFIG_INFO; + + +/****************************************************************************/ +// Structures used in FirmwareInfoTable +/****************************************************************************/ + +// usBIOSCapability Defintion: +// Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; +// Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; +// Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; +// Others: Reserved +#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED 0x0001 +#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT 0x0002 +#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT 0x0004 +#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT 0x0008 +#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT 0x0010 +#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU 0x0020 +#define ATOM_BIOS_INFO_WMI_SUPPORT 0x0040 +#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM 0x0080 +#define ATOM_BIOS_INFO_HYPERMEMORY_SUPPORT 0x0100 +#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK 0x1E00 +#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000 +#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE 0x4000 + + +#ifndef _H2INC + +//Please don't add or expand this bitfield structure below, this one will retire soon.! +typedef struct _ATOM_FIRMWARE_CAPABILITY +{ + USHORT FirmwarePosted:1; + USHORT DualCRTC_Support:1; + USHORT ExtendedDesktopSupport:1; + USHORT MemoryClockSS_Support:1; + USHORT EngineClockSS_Support:1; + USHORT GPUControlsBL:1; + USHORT WMI_SUPPORT:1; + USHORT PPMode_Assigned:1; + USHORT HyperMemory_Support:1; + USHORT HyperMemory_Size:4; + USHORT Reserved:3; +}ATOM_FIRMWARE_CAPABILITY; + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS +{ + ATOM_FIRMWARE_CAPABILITY sbfAccess; + USHORT susAccess; +}ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#else + +typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS +{ + USHORT susAccess; +}ATOM_FIRMWARE_CAPABILITY_ACCESS; + +#endif + +typedef struct _ATOM_FIRMWARE_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucPadding[3]; //Don't use them + ULONG aulReservedForBIOS[3]; //Don't use them + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit, the definitions above can't change!!! + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO; + +typedef struct _ATOM_FIRMWARE_INFO_V1_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; //Don't use them + ULONG aulReservedForBIOS[2]; //Don't use them + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_2; + +typedef struct _ATOM_FIRMWARE_INFO_V1_3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + UCHAR ucPadding[2]; //Don't use them + ULONG aulReservedForBIOS; //Don't use them + ULONG ul3DAccelerationEngineClock;//In 10Khz unit + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_3; + +typedef struct _ATOM_FIRMWARE_INFO_V1_4 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulFirmwareRevision; + ULONG ulDefaultEngineClock; //In 10Khz unit + ULONG ulDefaultMemoryClock; //In 10Khz unit + ULONG ulDriverTargetEngineClock; //In 10Khz unit + ULONG ulDriverTargetMemoryClock; //In 10Khz unit + ULONG ulMaxEngineClockPLL_Output; //In 10Khz unit + ULONG ulMaxMemoryClockPLL_Output; //In 10Khz unit + ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit + ULONG ulASICMaxEngineClock; //In 10Khz unit + ULONG ulASICMaxMemoryClock; //In 10Khz unit + UCHAR ucASICMaxTemperature; + UCHAR ucMinAllowedBL_Level; + USHORT usBootUpVDDCVoltage; //In MV unit + USHORT usLcdMinPixelClockPLL_Output; // In MHz unit + USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit + ULONG ul3DAccelerationEngineClock;//In 10Khz unit + ULONG ulMinPixelClockPLL_Output; //In 10Khz unit + USHORT usMinEngineClockPLL_Input; //In 10Khz unit + USHORT usMaxEngineClockPLL_Input; //In 10Khz unit + USHORT usMinEngineClockPLL_Output; //In 10Khz unit + USHORT usMinMemoryClockPLL_Input; //In 10Khz unit + USHORT usMaxMemoryClockPLL_Input; //In 10Khz unit + USHORT usMinMemoryClockPLL_Output; //In 10Khz unit + USHORT usMaxPixelClock; //In 10Khz unit, Max. Pclk + USHORT usMinPixelClockPLL_Input; //In 10Khz unit + USHORT usMaxPixelClockPLL_Input; //In 10Khz unit + USHORT usMinPixelClockPLL_Output; //In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output + ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; + USHORT usReferenceClock; //In 10Khz unit + USHORT usPM_RTS_Location; //RTS PM4 starting location in ROM in 1Kb unit + UCHAR ucPM_RTS_StreamSize; //RTS PM4 packets in Kb unit + UCHAR ucDesign_ID; //Indicate what is the board design + UCHAR ucMemoryModule_ID; //Indicate what is the board design +}ATOM_FIRMWARE_INFO_V1_4; + +#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V1_4 + +/****************************************************************************/ +// Structures used in IntegratedSystemInfoTable +/****************************************************************************/ +#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN 0x2 +#define IGP_CAP_FLAG_AC_CARD 0x4 +#define IGP_CAP_FLAG_SDVO_CARD 0x8 +#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE 0x10 + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulBootUpMemoryClock; //in 10kHz unit + ULONG ulMaxSystemMemoryClock; //in 10kHz unit + ULONG ulMinSystemMemoryClock; //in 10kHz unit + UCHAR ucNumberOfCyclesInPeriodHi; + UCHAR ucLCDTimingSel; //=0:not valid.!=0 sel this timing descriptor from LCD EDID. + USHORT usReserved1; + USHORT usInterNBVoltageLow; //An intermidiate PMW value to set the voltage + USHORT usInterNBVoltageHigh; //Another intermidiate PMW value to set the voltage + ULONG ulReserved[2]; + + USHORT usFSBClock; //In MHz unit + USHORT usCapabilityFlag; //Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable + //Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card + //Bit[4]==1: P/2 mode, ==0: P/1 mode + USHORT usPCIENBCfgReg7; //bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal + USHORT usK8MemoryClock; //in MHz unit + USHORT usK8SyncStartDelay; //in 0.01 us unit + USHORT usK8DataReturnTime; //in 0.01 us unit + UCHAR ucMaxNBVoltage; + UCHAR ucMinNBVoltage; + UCHAR ucMemoryType; //[7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved + UCHAR ucNumberOfCyclesInPeriod; //CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod + UCHAR ucStartingPWM_HighTime; //CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime + UCHAR ucHTLinkWidth; //16 bit vs. 8 bit + UCHAR ucMaxNBVoltageHigh; + UCHAR ucMinNBVoltageHigh; +}ATOM_INTEGRATED_SYSTEM_INFO; + +/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO +ulBootUpMemoryClock: For Intel IGP,it's the UMA system memory clock + For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock +ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 +ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0 + For AMD IGP,for now this can be 0 + +usFSBClock: For Intel IGP,it's FSB Freq + For AMD IGP,it's HT Link Speed + +usK8MemoryClock: For AMD IGP only. For RevF CPU, set it to 200 +usK8SyncStartDelay: For AMD IGP only. Memory access latency in K8, required for watermark calculation +usK8DataReturnTime: For AMD IGP only. Memory access latency in K8, required for watermark calculation + +VC:Voltage Control +ucMaxNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltage: Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + +ucNumberOfCyclesInPeriod: Indicate how many cycles when PWM duty is 100%. low 8 bits of the value. +ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0 + +ucMaxNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. +ucMinNBVoltageHigh: Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all. + + +usInterNBVoltageLow: Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all. +usInterNBVoltageHigh: Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all. +*/ + + +/* +The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST; +Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need. +The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries. + +SW components can access the IGP system infor structure in the same way as before +*/ + + +typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ULONG ulBootUpEngineClock; //in 10kHz unit + ULONG ulReserved1[2]; //must be 0x0 for the reserved + ULONG ulBootUpUMAClock; //in 10kHz unit + ULONG ulBootUpSidePortClock; //in 10kHz unit + ULONG ulMinSidePortClock; //in 10kHz unit + ULONG ulReserved2[6]; //must be 0x0 for the reserved + ULONG ulSystemConfig; //see explanation below + ULONG ulBootUpReqDisplayVector; + ULONG ulOtherDisplayMisc; + ULONG ulDDISlot1Config; + ULONG ulDDISlot2Config; + UCHAR ucMemoryType; //[3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved + UCHAR ucUMAChannelNumber; + UCHAR ucDockingPinBit; + UCHAR ucDockingPinPolarity; + ULONG ulDockingPinCFGInfo; + ULONG ulCPUCapInfo; + USHORT usNumberOfCyclesInPeriod; + USHORT usMaxNBVoltage; + USHORT usMinNBVoltage; + USHORT usBootUpNBVoltage; + ULONG ulHTLinkFreq; //in 10Khz + USHORT usMinHTLinkWidth; + USHORT usMaxHTLinkWidth; + USHORT usUMASyncStartDelay; + USHORT usUMADataReturnTime; + USHORT usLinkStatusZeroTime; + USHORT usReserved; + ULONG ulHighVoltageHTLinkFreq; // in 10Khz + ULONG ulLowVoltageHTLinkFreq; // in 10Khz + USHORT usMaxUpStreamHTLinkWidth; + USHORT usMaxDownStreamHTLinkWidth; + USHORT usMinUpStreamHTLinkWidth; + USHORT usMinDownStreamHTLinkWidth; + ULONG ulReserved3[97]; //must be 0x0 +}ATOM_INTEGRATED_SYSTEM_INFO_V2; + +/* +ulBootUpEngineClock: Boot-up Engine Clock in 10Khz; +ulBootUpUMAClock: Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present +ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock + +ulSystemConfig: +Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode; +Bit[1]=1: system boots up at AMD overdrived state or user customized mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state + =0: system boots up at driver control state. Power state depends on PowerPlay table. +Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used. +Bit[3]=1: Only one power state(Performance) will be supported. + =0: Multiple power states supported from PowerPlay table. +Bit[4]=1: CLMC is supported and enabled on current system. + =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface. +Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement. + =0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied. +Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored. + =0: Voltage settings is determined by powerplay table. +Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue. + =0: Enable CLMC as regular mode, CDLD and CILR will be enabled. + +ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions. + +ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion; + [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSuppportedStd definition; + +ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design). + [3:0] - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [7:4] - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12) + [15:8] - Lane configuration attribute; + [23:16]- Connector type, possible value: + CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D + CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D + CONNECTOR_OBJECT_ID_HDMI_TYPE_A + CONNECTOR_OBJECT_ID_DISPLAYPORT + [31:24]- Reserved + +ulDDISlot2Config: Same as Slot1. +ucMemoryType: SidePort memory type, set it to 0x0 when Sideport memory is not installed. Driver needs this info to change sideport memory clock. Not for display in CCC. +For IGP, Hypermemory is the only memory type showed in CCC. + +ucUMAChannelNumber: how many channels for the UMA; + +ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin +ucDockingPinBit: which bit in this register to read the pin status; +ucDockingPinPolarity:Polarity of the pin when docked; + +ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 + +usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. +usMaxNBVoltage:Voltage regulator dependent PWM value.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all. + +usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode. +usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode. + GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0 + PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1 + GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE + + +ulHTLinkFreq: Bootup HT link Frequency in 10Khz. +usMinHTLinkWidth: Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. +usMaxHTLinkWidth: Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth. + If CDLW enabled, both upstream and downstream width should be the same during bootup. + +usUMASyncStartDelay: Memory access latency, required for watermark calculation +usUMADataReturnTime: Memory access latency, required for watermark calculation +usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us +for Griffin or Greyhound. SBIOS needs to convert to actual time by: + if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us) + if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us) + if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us) + if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us) + +ulHighVoltageHTLinkFreq: HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHTLinkFreq(bootup frequency). +ulLowVoltageHTLinkFreq: HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0. + This must be less than or equal to ulHighVoltageHTLinkFreq. + +usMaxUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMaxHTLinkWidth. Not used for now. +usMaxDownStreamHTLinkWidth: same as above. +usMinUpStreamHTLinkWidth: Asymmetric link width support in the future, to replace usMinHTLinkWidth. Not used for now. +usMinDownStreamHTLinkWidth: same as above. +*/ + + +#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 +#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 +#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE 0x00000004 +#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY 0x00000008 +#define SYSTEM_CONFIG_CLMC_ENABLED 0x00000010 +#define SYSTEM_CONFIG_CDLW_ENABLED 0x00000020 +#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED 0x00000040 +#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED 0x00000080 + +#define IGP_DDI_SLOT_LANE_CONFIG_MASK 0x000000FF + +#define b0IGP_DDI_SLOT_LANE_MAP_MASK 0x0F +#define b0IGP_DDI_SLOT_DOCKING_LANE_MAP_MASK 0xF0 +#define b0IGP_DDI_SLOT_CONFIG_LANE_0_3 0x01 +#define b0IGP_DDI_SLOT_CONFIG_LANE_4_7 0x02 +#define b0IGP_DDI_SLOT_CONFIG_LANE_8_11 0x04 +#define b0IGP_DDI_SLOT_CONFIG_LANE_12_15 0x08 + +#define IGP_DDI_SLOT_ATTRIBUTE_MASK 0x0000FF00 +#define IGP_DDI_SLOT_CONFIG_REVERSED 0x00000100 +#define b1IGP_DDI_SLOT_CONFIG_REVERSED 0x01 + +#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK 0x00FF0000 + +#define ATOM_CRT_INT_ENCODER1_INDEX 0x00000000 +#define ATOM_LCD_INT_ENCODER1_INDEX 0x00000001 +#define ATOM_TV_INT_ENCODER1_INDEX 0x00000002 +#define ATOM_DFP_INT_ENCODER1_INDEX 0x00000003 +#define ATOM_CRT_INT_ENCODER2_INDEX 0x00000004 +#define ATOM_LCD_EXT_ENCODER1_INDEX 0x00000005 +#define ATOM_TV_EXT_ENCODER1_INDEX 0x00000006 +#define ATOM_DFP_EXT_ENCODER1_INDEX 0x00000007 +#define ATOM_CV_INT_ENCODER1_INDEX 0x00000008 +#define ATOM_DFP_INT_ENCODER2_INDEX 0x00000009 +#define ATOM_CRT_EXT_ENCODER1_INDEX 0x0000000A +#define ATOM_CV_EXT_ENCODER1_INDEX 0x0000000B +#define ATOM_DFP_INT_ENCODER3_INDEX 0x0000000C +#define ATOM_DFP_INT_ENCODER4_INDEX 0x0000000D + +// define ASIC internal encoder id ( bit vector ) +#define ASIC_INT_DAC1_ENCODER_ID 0x00 +#define ASIC_INT_TV_ENCODER_ID 0x02 +#define ASIC_INT_DIG1_ENCODER_ID 0x03 +#define ASIC_INT_DAC2_ENCODER_ID 0x04 +#define ASIC_EXT_TV_ENCODER_ID 0x06 +#define ASIC_INT_DVO_ENCODER_ID 0x07 +#define ASIC_INT_DIG2_ENCODER_ID 0x09 +#define ASIC_EXT_DIG_ENCODER_ID 0x05 + +//define Encoder attribute +#define ATOM_ANALOG_ENCODER 0 +#define ATOM_DIGITAL_ENCODER 1 + +#define ATOM_DEVICE_CRT1_INDEX 0x00000000 +#define ATOM_DEVICE_LCD1_INDEX 0x00000001 +#define ATOM_DEVICE_TV1_INDEX 0x00000002 +#define ATOM_DEVICE_DFP1_INDEX 0x00000003 +#define ATOM_DEVICE_CRT2_INDEX 0x00000004 +#define ATOM_DEVICE_LCD2_INDEX 0x00000005 +#define ATOM_DEVICE_TV2_INDEX 0x00000006 +#define ATOM_DEVICE_DFP2_INDEX 0x00000007 +#define ATOM_DEVICE_CV_INDEX 0x00000008 +#define ATOM_DEVICE_DFP3_INDEX 0x00000009 +#define ATOM_DEVICE_DFP4_INDEX 0x0000000A +#define ATOM_DEVICE_DFP5_INDEX 0x0000000B +#define ATOM_DEVICE_RESERVEDC_INDEX 0x0000000C +#define ATOM_DEVICE_RESERVEDD_INDEX 0x0000000D +#define ATOM_DEVICE_RESERVEDE_INDEX 0x0000000E +#define ATOM_DEVICE_RESERVEDF_INDEX 0x0000000F +#define ATOM_MAX_SUPPORTED_DEVICE_INFO (ATOM_DEVICE_DFP3_INDEX+1) +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2 ATOM_MAX_SUPPORTED_DEVICE_INFO +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3 (ATOM_DEVICE_DFP5_INDEX + 1 ) + +#define ATOM_MAX_SUPPORTED_DEVICE (ATOM_DEVICE_RESERVEDF_INDEX+1) + +#define ATOM_DEVICE_CRT1_SUPPORT (0x1L << ATOM_DEVICE_CRT1_INDEX ) +#define ATOM_DEVICE_LCD1_SUPPORT (0x1L << ATOM_DEVICE_LCD1_INDEX ) +#define ATOM_DEVICE_TV1_SUPPORT (0x1L << ATOM_DEVICE_TV1_INDEX ) +#define ATOM_DEVICE_DFP1_SUPPORT (0x1L << ATOM_DEVICE_DFP1_INDEX) +#define ATOM_DEVICE_CRT2_SUPPORT (0x1L << ATOM_DEVICE_CRT2_INDEX ) +#define ATOM_DEVICE_LCD2_SUPPORT (0x1L << ATOM_DEVICE_LCD2_INDEX ) +#define ATOM_DEVICE_TV2_SUPPORT (0x1L << ATOM_DEVICE_TV2_INDEX ) +#define ATOM_DEVICE_DFP2_SUPPORT (0x1L << ATOM_DEVICE_DFP2_INDEX) +#define ATOM_DEVICE_CV_SUPPORT (0x1L << ATOM_DEVICE_CV_INDEX ) +#define ATOM_DEVICE_DFP3_SUPPORT (0x1L << ATOM_DEVICE_DFP3_INDEX ) +#define ATOM_DEVICE_DFP4_SUPPORT (0x1L << ATOM_DEVICE_DFP4_INDEX ) +#define ATOM_DEVICE_DFP5_SUPPORT (0x1L << ATOM_DEVICE_DFP5_INDEX ) + +#define ATOM_DEVICE_CRT_SUPPORT ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT +#define ATOM_DEVICE_DFP_SUPPORT ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | ATOM_DEVICE_DFP5_SUPPORT +#define ATOM_DEVICE_TV_SUPPORT ATOM_DEVICE_TV1_SUPPORT | ATOM_DEVICE_TV2_SUPPORT +#define ATOM_DEVICE_LCD_SUPPORT ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT + +#define ATOM_DEVICE_CONNECTOR_TYPE_MASK 0x000000F0 +#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT 0x00000004 +#define ATOM_DEVICE_CONNECTOR_VGA 0x00000001 +#define ATOM_DEVICE_CONNECTOR_DVI_I 0x00000002 +#define ATOM_DEVICE_CONNECTOR_DVI_D 0x00000003 +#define ATOM_DEVICE_CONNECTOR_DVI_A 0x00000004 +#define ATOM_DEVICE_CONNECTOR_SVIDEO 0x00000005 +#define ATOM_DEVICE_CONNECTOR_COMPOSITE 0x00000006 +#define ATOM_DEVICE_CONNECTOR_LVDS 0x00000007 +#define ATOM_DEVICE_CONNECTOR_DIGI_LINK 0x00000008 +#define ATOM_DEVICE_CONNECTOR_SCART 0x00000009 +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_A 0x0000000A +#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_B 0x0000000B +#define ATOM_DEVICE_CONNECTOR_CASE_1 0x0000000E +#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT 0x0000000F + + +#define ATOM_DEVICE_DAC_INFO_MASK 0x0000000F +#define ATOM_DEVICE_DAC_INFO_SHIFT 0x00000000 +#define ATOM_DEVICE_DAC_INFO_NODAC 0x00000000 +#define ATOM_DEVICE_DAC_INFO_DACA 0x00000001 +#define ATOM_DEVICE_DAC_INFO_DACB 0x00000002 +#define ATOM_DEVICE_DAC_INFO_EXDAC 0x00000003 + +#define ATOM_DEVICE_I2C_ID_NOI2C 0x00000000 + +#define ATOM_DEVICE_I2C_LINEMUX_MASK 0x0000000F +#define ATOM_DEVICE_I2C_LINEMUX_SHIFT 0x00000000 + +#define ATOM_DEVICE_I2C_ID_MASK 0x00000070 +#define ATOM_DEVICE_I2C_ID_SHIFT 0x00000004 +#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE 0x00000001 +#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE 0x00000002 +#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE 0x00000003 //For IGP RS600 +#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL 0x00000004 //For IGP RS690 + +#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK 0x00000080 +#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT 0x00000007 +#define ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C 0x00000000 +#define ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C 0x00000001 + +// usDeviceSupport: +// Bits0 = 0 - no CRT1 support= 1- CRT1 is supported +// Bit 1 = 0 - no LCD1 support= 1- LCD1 is supported +// Bit 2 = 0 - no TV1 support= 1- TV1 is supported +// Bit 3 = 0 - no DFP1 support= 1- DFP1 is supported +// Bit 4 = 0 - no CRT2 support= 1- CRT2 is supported +// Bit 5 = 0 - no LCD2 support= 1- LCD2 is supported +// Bit 6 = 0 - no TV2 support= 1- TV2 is supported +// Bit 7 = 0 - no DFP2 support= 1- DFP2 is supported +// Bit 8 = 0 - no CV support= 1- CV is supported +// Bit 9 = 0 - no DFP3 support= 1- DFP3 is supported +// Byte1 (Supported Device Info) +// Bit 0 = = 0 - no CV support= 1- CV is supported +// +// + +// ucI2C_ConfigID +// [7:0] - I2C LINE Associate ID +// = 0 - no I2C +// [7] - HW_Cap = 1, [6:0]=HW assisted I2C ID(HW line selection) +// = 0, [6:0]=SW assisted I2C ID +// [6-4] - HW_ENGINE_ID = 1, HW engine for NON multimedia use +// = 2, HW engine for Multimedia use +// = 3-7 Reserved for future I2C engines +// [3-0] - I2C_LINE_MUX = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C + +typedef struct _ATOM_I2C_ID_CONFIG +{ + UCHAR bfI2C_LineMux:4; + UCHAR bfHW_EngineID:3; + UCHAR bfHW_Capable:1; +}ATOM_I2C_ID_CONFIG; + +typedef union _ATOM_I2C_ID_CONFIG_ACCESS +{ + ATOM_I2C_ID_CONFIG sbfAccess; + UCHAR ucAccess; +}ATOM_I2C_ID_CONFIG_ACCESS; + +/****************************************************************************/ +// Structure used in GPIO_I2C_InfoTable +/****************************************************************************/ +typedef struct _ATOM_GPIO_I2C_ASSIGMENT +{ + USHORT usClkMaskRegisterIndex; + USHORT usClkEnRegisterIndex; + USHORT usClkY_RegisterIndex; + USHORT usClkA_RegisterIndex; + USHORT usDataMaskRegisterIndex; + USHORT usDataEnRegisterIndex; + USHORT usDataY_RegisterIndex; + USHORT usDataA_RegisterIndex; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; + UCHAR ucClkMaskShift; + UCHAR ucClkEnShift; + UCHAR ucClkY_Shift; + UCHAR ucClkA_Shift; + UCHAR ucDataMaskShift; + UCHAR ucDataEnShift; + UCHAR ucDataY_Shift; + UCHAR ucDataA_Shift; + UCHAR ucReserved1; + UCHAR ucReserved2; +}ATOM_GPIO_I2C_ASSIGMENT; + +typedef struct _ATOM_GPIO_I2C_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE]; +}ATOM_GPIO_I2C_INFO; + +/****************************************************************************/ +// Common Structure used in other structures +/****************************************************************************/ + +#ifndef _H2INC + +//Please don't add or expand this bitfield structure below, this one will retire soon.! +typedef struct _ATOM_MODE_MISC_INFO +{ + USHORT HorizontalCutOff:1; + USHORT HSyncPolarity:1; //0=Active High, 1=Active Low + USHORT VSyncPolarity:1; //0=Active High, 1=Active Low + USHORT VerticalCutOff:1; + USHORT H_ReplicationBy2:1; + USHORT V_ReplicationBy2:1; + USHORT CompositeSync:1; + USHORT Interlace:1; + USHORT DoubleClock:1; + USHORT RGB888:1; + USHORT Reserved:6; +}ATOM_MODE_MISC_INFO; + +typedef union _ATOM_MODE_MISC_INFO_ACCESS +{ + ATOM_MODE_MISC_INFO sbfAccess; + USHORT usAccess; +}ATOM_MODE_MISC_INFO_ACCESS; + +#else + +typedef union _ATOM_MODE_MISC_INFO_ACCESS +{ + USHORT usAccess; +}ATOM_MODE_MISC_INFO_ACCESS; + +#endif + +// usModeMiscInfo- +#define ATOM_H_CUTOFF 0x01 +#define ATOM_HSYNC_POLARITY 0x02 //0=Active High, 1=Active Low +#define ATOM_VSYNC_POLARITY 0x04 //0=Active High, 1=Active Low +#define ATOM_V_CUTOFF 0x08 +#define ATOM_H_REPLICATIONBY2 0x10 +#define ATOM_V_REPLICATIONBY2 0x20 +#define ATOM_COMPOSITESYNC 0x40 +#define ATOM_INTERLACE 0x80 +#define ATOM_DOUBLE_CLOCK_MODE 0x100 +#define ATOM_RGB888_MODE 0x200 + +//usRefreshRate- +#define ATOM_REFRESH_43 43 +#define ATOM_REFRESH_47 47 +#define ATOM_REFRESH_56 56 +#define ATOM_REFRESH_60 60 +#define ATOM_REFRESH_65 65 +#define ATOM_REFRESH_70 70 +#define ATOM_REFRESH_72 72 +#define ATOM_REFRESH_75 75 +#define ATOM_REFRESH_85 85 + +// ATOM_MODE_TIMING data are exactly the same as VESA timing data. +// Translation from EDID to ATOM_MODE_TIMING, use the following formula. +// +// VESA_HTOTAL = VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK +// = EDID_HA + EDID_HBL +// VESA_HDISP = VESA_ACTIVE = EDID_HA +// VESA_HSYNC_START = VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH +// = EDID_HA + EDID_HSO +// VESA_HSYNC_WIDTH = VESA_HSYNC_TIME = EDID_HSPW +// VESA_BORDER = EDID_BORDER + +/****************************************************************************/ +// Structure used in SetCRTC_UsingDTDTimingTable +/****************************************************************************/ +typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS +{ + USHORT usH_Size; + USHORT usH_Blanking_Time; + USHORT usV_Size; + USHORT usV_Blanking_Time; + USHORT usH_SyncOffset; + USHORT usH_SyncWidth; + USHORT usV_SyncOffset; + USHORT usV_SyncWidth; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucH_Border; // From DFP EDID + UCHAR ucV_Border; + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucPadding[3]; +}SET_CRTC_USING_DTD_TIMING_PARAMETERS; + +/****************************************************************************/ +// Structure used in SetCRTC_TimingTable +/****************************************************************************/ +typedef struct _SET_CRTC_TIMING_PARAMETERS +{ + USHORT usH_Total; // horizontal total + USHORT usH_Disp; // horizontal display + USHORT usH_SyncStart; // horozontal Sync start + USHORT usH_SyncWidth; // horizontal Sync width + USHORT usV_Total; // vertical total + USHORT usV_Disp; // vertical display + USHORT usV_SyncStart; // vertical Sync start + USHORT usV_SyncWidth; // vertical Sync width + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucCRTC; // ATOM_CRTC1 or ATOM_CRTC2 + UCHAR ucOverscanRight; // right + UCHAR ucOverscanLeft; // left + UCHAR ucOverscanBottom; // bottom + UCHAR ucOverscanTop; // top + UCHAR ucReserved; +}SET_CRTC_TIMING_PARAMETERS; +#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS + +/****************************************************************************/ +// Structure used in StandardVESA_TimingTable +// AnalogTV_InfoTable +// ComponentVideoInfoTable +/****************************************************************************/ +typedef struct _ATOM_MODE_TIMING +{ + USHORT usCRTC_H_Total; + USHORT usCRTC_H_Disp; + USHORT usCRTC_H_SyncStart; + USHORT usCRTC_H_SyncWidth; + USHORT usCRTC_V_Total; + USHORT usCRTC_V_Disp; + USHORT usCRTC_V_SyncStart; + USHORT usCRTC_V_SyncWidth; + USHORT usPixelClock; //in 10Khz unit + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + USHORT usCRTC_OverscanRight; + USHORT usCRTC_OverscanLeft; + USHORT usCRTC_OverscanBottom; + USHORT usCRTC_OverscanTop; + USHORT usReserve; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +}ATOM_MODE_TIMING; + +typedef struct _ATOM_DTD_FORMAT +{ + USHORT usPixClk; + USHORT usHActive; + USHORT usHBlanking_Time; + USHORT usVActive; + USHORT usVBlanking_Time; + USHORT usHSyncOffset; + USHORT usHSyncWidth; + USHORT usVSyncOffset; + USHORT usVSyncWidth; + USHORT usImageHSize; + USHORT usImageVSize; + UCHAR ucHBorder; + UCHAR ucVBorder; + ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo; + UCHAR ucInternalModeNumber; + UCHAR ucRefreshRate; +}ATOM_DTD_FORMAT; + +/****************************************************************************/ +// Structure used in LVDS_InfoTable +// * Need a document to describe this table +/****************************************************************************/ +#define SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 +#define SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 +#define SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 +#define SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 + +//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. +//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL +#define LCDPANEL_CAP_READ_EDID 0x1 + +//ucTableFormatRevision=1 +//ucTableContentRevision=1 +typedef struct _ATOM_LVDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usModePatchTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} + // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} + // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} + // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; +}ATOM_LVDS_INFO; + +//ucTableFormatRevision=1 +//ucTableContentRevision=2 +typedef struct _ATOM_LVDS_INFO_V12 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT sLCDTiming; + USHORT usExtInfoTableOffset; + USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. + USHORT usOffDelayInMs; + UCHAR ucPowerSequenceDigOntoDEin10Ms; + UCHAR ucPowerSequenceDEtoBLOnin10Ms; + UCHAR ucLVDS_Misc; // Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} + // Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} + // Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} + // Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} + UCHAR ucPanelDefaultRefreshRate; + UCHAR ucPanelIdentification; + UCHAR ucSS_Id; + USHORT usLCDVenderID; + USHORT usLCDProductID; + UCHAR ucLCDPanel_SpecialHandlingCap; + UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable + UCHAR ucReserved[2]; +}ATOM_LVDS_INFO_V12; + +#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 + +typedef struct _ATOM_PATCH_RECORD_MODE +{ + UCHAR ucRecordType; + USHORT usHDisp; + USHORT usVDisp; +}ATOM_PATCH_RECORD_MODE; + +typedef struct _ATOM_LCD_RTS_RECORD +{ + UCHAR ucRecordType; + UCHAR ucRTSValue; +}ATOM_LCD_RTS_RECORD; + +//!! If the record below exits, it shoud always be the first record for easy use in command table!!! +typedef struct _ATOM_LCD_MODE_CONTROL_CAP +{ + UCHAR ucRecordType; + USHORT usLCDCap; +}ATOM_LCD_MODE_CONTROL_CAP; + +#define LCD_MODE_CAP_BL_OFF 1 +#define LCD_MODE_CAP_CRTC_OFF 2 +#define LCD_MODE_CAP_PANEL_OFF 4 + +typedef struct _ATOM_FAKE_EDID_PATCH_RECORD +{ + UCHAR ucRecordType; + UCHAR ucFakeEDIDLength; + UCHAR ucFakeEDIDString[1]; // This actually has ucFakeEdidLength elements. +} ATOM_FAKE_EDID_PATCH_RECORD; + +typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD +{ + UCHAR ucRecordType; + USHORT usHSize; + USHORT usVSize; +}ATOM_PANEL_RESOLUTION_PATCH_RECORD; + +#define LCD_MODE_PATCH_RECORD_MODE_TYPE 1 +#define LCD_RTS_RECORD_TYPE 2 +#define LCD_CAP_RECORD_TYPE 3 +#define LCD_FAKE_EDID_PATCH_RECORD_TYPE 4 +#define LCD_PANEL_RESOLUTION_RECORD_TYPE 5 +#define ATOM_RECORD_END_TYPE 0xFF + +/****************************Spread Spectrum Info Table Definitions **********************/ + +//ucTableFormatRevision=1 +//ucTableContentRevision=2 +typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT +{ + USHORT usSpreadSpectrumPercentage; + UCHAR ucSpreadSpectrumType; //Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD + UCHAR ucSS_Step; + UCHAR ucSS_Delay; + UCHAR ucSS_Id; + UCHAR ucRecommandedRef_Div; + UCHAR ucSS_Range; //it was reserved for V11 +}ATOM_SPREAD_SPECTRUM_ASSIGNMENT; + +#define ATOM_MAX_SS_ENTRY 16 +#define ATOM_DP_SS_ID1 0x0f1 // SS modulation freq=30k +#define ATOM_DP_SS_ID2 0x0f2 // SS modulation freq=33k + + +#define ATOM_SS_DOWN_SPREAD_MODE_MASK 0x00000000 +#define ATOM_SS_DOWN_SPREAD_MODE 0x00000000 +#define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001 +#define ATOM_SS_CENTRE_SPREAD_MODE 0x00000001 +#define ATOM_INTERNAL_SS_MASK 0x00000000 +#define ATOM_EXTERNAL_SS_MASK 0x00000002 +#define EXEC_SS_STEP_SIZE_SHIFT 2 +#define EXEC_SS_DELAY_SHIFT 4 +#define ACTIVEDATA_TO_BLON_DELAY_SHIFT 4 + +typedef struct _ATOM_SPREAD_SPECTRUM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY]; +}ATOM_SPREAD_SPECTRUM_INFO; + +/****************************************************************************/ +// Structure used in AnalogTV_InfoTable (Top level) +/****************************************************************************/ +//ucTVBootUpDefaultStd definiton: + +//ATOM_TV_NTSC 1 +//ATOM_TV_NTSCJ 2 +//ATOM_TV_PAL 3 +//ATOM_TV_PALM 4 +//ATOM_TV_PALCN 5 +//ATOM_TV_PALN 6 +//ATOM_TV_PAL60 7 +//ATOM_TV_SECAM 8 + +//ucTVSuppportedStd definition: +#define NTSC_SUPPORT 0x1 +#define NTSCJ_SUPPORT 0x2 + +#define PAL_SUPPORT 0x4 +#define PALM_SUPPORT 0x8 +#define PALCN_SUPPORT 0x10 +#define PALN_SUPPORT 0x20 +#define PAL60_SUPPORT 0x40 +#define SECAM_SUPPORT 0x80 + +#define MAX_SUPPORTED_TV_TIMING 2 + +typedef struct _ATOM_ANALOG_TV_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTV_SupportedStandard; + UCHAR ucTV_BootUpDefaultStandard; + UCHAR ucExt_TV_ASIC_ID; + UCHAR ucExt_TV_ASIC_SlaveAddr; +/* ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_TV_TIMING]; */ + ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING]; +}ATOM_ANALOG_TV_INFO; + + +/**************************************************************************/ +// VRAM usage and their defintions + +// One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. +// Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. +// All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned! +// To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR +// To Bios: ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX + +#ifndef VESA_MEMORY_IN_64K_BLOCK +#define VESA_MEMORY_IN_64K_BLOCK 0x100 //256*64K=16Mb (Max. VESA memory is 16Mb!) +#endif + +#define ATOM_EDID_RAW_DATASIZE 256 //In Bytes +#define ATOM_HWICON_SURFACE_SIZE 4096 //In Bytes +#define ATOM_HWICON_INFOTABLE_SIZE 32 +#define MAX_DTD_MODE_IN_VRAM 6 +#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT) +#define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) +#define DFP_ENCODER_TYPE_OFFSET 0x80 +#define DP_ENCODER_LANE_NUM_OFFSET 0x84 +#define DP_ENCODER_LINK_RATE_OFFSET 0x88 + +#define ATOM_HWICON1_SURFACE_ADDR 0 +#define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_HWICON_INFOTABLE_ADDR (ATOM_HWICON2_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) +#define ATOM_CRT1_EDID_ADDR (ATOM_HWICON_INFOTABLE_ADDR + ATOM_HWICON_INFOTABLE_SIZE) +#define ATOM_CRT1_DTD_MODE_TBL_ADDR (ATOM_CRT1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT1_STD_MODE_TBL_ADDR (ATOM_CRT1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD1_EDID_ADDR (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD1_DTD_MODE_TBL_ADDR (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD1_STD_MODE_TBL_ADDR (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV1_DTD_MODE_TBL_ADDR (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP1_EDID_ADDR (ATOM_TV1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP1_DTD_MODE_TBL_ADDR (ATOM_DFP1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP1_STD_MODE_TBL_ADDR (ATOM_DFP1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CRT2_EDID_ADDR (ATOM_DFP1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CRT2_DTD_MODE_TBL_ADDR (ATOM_CRT2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CRT2_STD_MODE_TBL_ADDR (ATOM_CRT2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_LCD2_EDID_ADDR (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_LCD2_DTD_MODE_TBL_ADDR (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_LCD2_STD_MODE_TBL_ADDR (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_TV2_EDID_ADDR (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_TV2_DTD_MODE_TBL_ADDR (ATOM_TV2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_TV2_STD_MODE_TBL_ADDR (ATOM_TV2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP2_EDID_ADDR (ATOM_TV2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP2_DTD_MODE_TBL_ADDR (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP2_STD_MODE_TBL_ADDR (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_CV_EDID_ADDR (ATOM_DFP2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_CV_DTD_MODE_TBL_ADDR (ATOM_CV_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_CV_STD_MODE_TBL_ADDR (ATOM_CV_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP3_EDID_ADDR (ATOM_CV_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP3_DTD_MODE_TBL_ADDR (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP3_STD_MODE_TBL_ADDR (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP4_EDID_ADDR (ATOM_DFP3_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP4_DTD_MODE_TBL_ADDR (ATOM_DFP4_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP4_STD_MODE_TBL_ADDR (ATOM_DFP4_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DFP5_EDID_ADDR (ATOM_DFP4_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) +#define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) +#define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) + +#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256) +#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512 + +//The size below is in Kb! +#define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC) + +#define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L +#define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 +#define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 +#define ATOM_VRAM_BLOCK_NEEDS_RESERVATION 0x0 + +/***********************************************************************************/ +// Structure used in VRAM_UsageByFirmwareTable +// Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm +// at running time. +// note2: From RV770, the memory is more than 32bit addressable, so we will change +// ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains +// exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware +// (in offset to start of memory address) is KB aligned instead of byte aligend. +/***********************************************************************************/ +#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO 1 + +typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO +{ + ULONG ulStartAddrUsedByFirmware; + USHORT usFirmwareUseInKb; + USHORT usReserved; +}ATOM_FIRMWARE_VRAM_RESERVE_INFO; + +typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_FIRMWARE_VRAM_RESERVE_INFO asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO]; +}ATOM_VRAM_USAGE_BY_FIRMWARE; + +/****************************************************************************/ +// Structure used in GPIO_Pin_LUTTable +/****************************************************************************/ +typedef struct _ATOM_GPIO_PIN_ASSIGNMENT +{ + USHORT usGpioPin_AIndex; + UCHAR ucGpioPinBitShift; + UCHAR ucGPIO_ID; +}ATOM_GPIO_PIN_ASSIGNMENT; + +typedef struct _ATOM_GPIO_PIN_LUT +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1]; +}ATOM_GPIO_PIN_LUT; + +/****************************************************************************/ +// Structure used in ComponentVideoInfoTable +/****************************************************************************/ +#define GPIO_PIN_ACTIVE_HIGH 0x1 + +#define MAX_SUPPORTED_CV_STANDARDS 5 + +// definitions for ATOM_D_INFO.ucSettings +#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK 0x1F // [4:0] +#define ATOM_GPIO_SETTINGS_RESERVED_MASK 0x60 // [6:5] = must be zeroed out +#define ATOM_GPIO_SETTINGS_ACTIVE_MASK 0x80 // [7] + +typedef struct _ATOM_GPIO_INFO +{ + USHORT usAOffset; + UCHAR ucSettings; + UCHAR ucReserved; +}ATOM_GPIO_INFO; + +// definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector) +#define ATOM_CV_RESTRICT_FORMAT_SELECTION 0x2 + +// definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i +#define ATOM_GPIO_DEFAULT_MODE_EN 0x80 //[7]; +#define ATOM_GPIO_SETTING_PERMODE_MASK 0x7F //[6:0] + +// definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode +//Line 3 out put 5V. +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A 0x01 //represent gpio 3 state for 16:9 +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B 0x02 //represent gpio 4 state for 16:9 +#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT 0x0 + +//Line 3 out put 2.2V +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04 //represent gpio 3 state for 4:3 Letter box +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08 //represent gpio 4 state for 4:3 Letter box +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2 + +//Line 3 out put 0V +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A 0x10 //represent gpio 3 state for 4:3 +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B 0x20 //represent gpio 4 state for 4:3 +#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT 0x4 + +#define ATOM_CV_LINE3_ASPECTRATIO_MASK 0x3F // bit [5:0] + +#define ATOM_CV_LINE3_ASPECTRATIO_EXIST 0x80 //bit 7 + +//GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks. +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A 3 //bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. +#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B 4 //bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. + + +typedef struct _ATOM_COMPONENT_VIDEO_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMask_PinRegisterIndex; + USHORT usEN_PinRegisterIndex; + USHORT usY_PinRegisterIndex; + USHORT usA_PinRegisterIndex; + UCHAR ucBitShift; + UCHAR ucPinActiveState; //ucPinActiveState: Bit0=1 active high, =0 active low + ATOM_DTD_FORMAT sReserved; // must be zeroed out + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucLetterBoxMode; + UCHAR ucReserved[3]; + UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +}ATOM_COMPONENT_VIDEO_INFO; + +//ucTableFormatRevision=2 +//ucTableContentRevision=1 +typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucMiscInfo; + UCHAR uc480i; + UCHAR uc480p; + UCHAR uc720p; + UCHAR uc1080i; + UCHAR ucReserved; + UCHAR ucLetterBoxMode; + UCHAR ucNumOfWbGpioBlocks; //For Component video D-Connector support. If zere, NTSC type connector + ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS]; + ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS]; +}ATOM_COMPONENT_VIDEO_INFO_V21; + +#define ATOM_COMPONENT_VIDEO_INFO_LAST ATOM_COMPONENT_VIDEO_INFO_V21 + +/****************************************************************************/ +// Structure used in object_InfoTable +/****************************************************************************/ +typedef struct _ATOM_OBJECT_HEADER +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + USHORT usConnectorObjectTableOffset; + USHORT usRouterObjectTableOffset; + USHORT usEncoderObjectTableOffset; + USHORT usProtectionObjectTableOffset; //only available when Protection block is independent. + USHORT usDisplayPathTableOffset; +}ATOM_OBJECT_HEADER; + + +typedef struct _ATOM_DISPLAY_OBJECT_PATH +{ + USHORT usDeviceTag; //supported device + USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH + USHORT usConnObjectId; //Connector Object ID + USHORT usGPUObjectId; //GPU ID + USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. +}ATOM_DISPLAY_OBJECT_PATH; + +typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE +{ + UCHAR ucNumOfDispPath; + UCHAR ucVersion; + UCHAR ucPadding[2]; + ATOM_DISPLAY_OBJECT_PATH asDispPath[1]; +}ATOM_DISPLAY_OBJECT_PATH_TABLE; + + +typedef struct _ATOM_OBJECT //each object has this structure +{ + USHORT usObjectID; + USHORT usSrcDstTableOffset; + USHORT usRecordOffset; //this pointing to a bunch of records defined below + USHORT usReserved; +}ATOM_OBJECT; + +typedef struct _ATOM_OBJECT_TABLE //Above 4 object table offset pointing to a bunch of objects all have this structure +{ + UCHAR ucNumberOfObjects; + UCHAR ucPadding[3]; + ATOM_OBJECT asObjects[1]; +}ATOM_OBJECT_TABLE; + +typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT //usSrcDstTableOffset pointing to this structure +{ + UCHAR ucNumberOfSrc; + USHORT usSrcObjectID[1]; + UCHAR ucNumberOfDst; + USHORT usDstObjectID[1]; +}ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT; + + +//Related definitions, all records are differnt but they have a commond header +typedef struct _ATOM_COMMON_RECORD_HEADER +{ + UCHAR ucRecordType; //An emun to indicate the record type + UCHAR ucRecordSize; //The size of the whole record in byte +}ATOM_COMMON_RECORD_HEADER; + + +#define ATOM_I2C_RECORD_TYPE 1 +#define ATOM_HPD_INT_RECORD_TYPE 2 +#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE 3 +#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE 4 +#define ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE 5 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE 6 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE 7 +#define ATOM_JTAG_RECORD_TYPE 8 //Obsolete, switch to use GPIO_CNTL_RECORD_TYPE +#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE 9 +#define ATOM_ENCODER_DVO_CF_RECORD_TYPE 10 +#define ATOM_CONNECTOR_CF_RECORD_TYPE 11 +#define ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE 12 +#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE 13 +#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE 14 +#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE 15 + +//Must be updated when new record type is added,equal to that record definition! +#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_CF_RECORD_TYPE + +typedef struct _ATOM_I2C_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_I2C_ID_CONFIG sucI2cId; + UCHAR ucI2CAddr; //The slave address, it's 0 when the record is attached to connector for DDC +}ATOM_I2C_RECORD; + +typedef struct _ATOM_HPD_INT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucHPDIntGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info + UCHAR ucPluggged_PinState; +}ATOM_HPD_INT_RECORD; + + +typedef struct _ATOM_OUTPUT_PROTECTION_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucProtectionFlag; + UCHAR ucReserved; +}ATOM_OUTPUT_PROTECTION_RECORD; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG +{ + ULONG ulACPIDeviceEnum; //Reserved for now + USHORT usDeviceID; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT" + USHORT usPadding; +}ATOM_CONNECTOR_DEVICE_TAG; + +typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucNumberOfDevice; + UCHAR ucReserved; + ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1]; //This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation +}ATOM_CONNECTOR_DEVICE_TAG_RECORD; + + +typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucConfigGPIOID; + UCHAR ucConfigGPIOState; //Set to 1 when it's active high to enable external flow in + UCHAR ucFlowinGPIPID; + UCHAR ucExtInGPIPID; +}ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD; + +typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucCTL1GPIO_ID; + UCHAR ucCTL1GPIOState; //Set to 1 when it's active high + UCHAR ucCTL2GPIO_ID; + UCHAR ucCTL2GPIOState; //Set to 1 when it's active high + UCHAR ucCTL3GPIO_ID; + UCHAR ucCTL3GPIOState; //Set to 1 when it's active high + UCHAR ucCTLFPGA_IN_ID; + UCHAR ucPadding[3]; +}ATOM_ENCODER_FPGA_CONTROL_RECORD; + +typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucGPIOID; //Corresponding block in GPIO_PIN_INFO table gives the pin info + UCHAR ucTVActiveState; //Indicating when the pin==0 or 1 when TV is connected +}ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD; + +typedef struct _ATOM_JTAG_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucTMSGPIO_ID; + UCHAR ucTMSGPIOState; //Set to 1 when it's active high + UCHAR ucTCKGPIO_ID; + UCHAR ucTCKGPIOState; //Set to 1 when it's active high + UCHAR ucTDOGPIO_ID; + UCHAR ucTDOGPIOState; //Set to 1 when it's active high + UCHAR ucTDIGPIO_ID; + UCHAR ucTDIGPIOState; //Set to 1 when it's active high + UCHAR ucPadding[2]; +}ATOM_JTAG_RECORD; + + +//The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually +typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR +{ + UCHAR ucGPIOID; // GPIO_ID, find the corresponding ID in GPIO_LUT table + UCHAR ucGPIO_PinState; // Pin state showing how to set-up the pin +}ATOM_GPIO_PIN_CONTROL_PAIR; + +typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucFlags; // Future expnadibility + UCHAR ucNumberOfPins; // Number of GPIO pins used to control the object + ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1]; // the real gpio pin pair determined by number of pins ucNumberOfPins +}ATOM_OBJECT_GPIO_CNTL_RECORD; + +//Definitions for GPIO pin state +#define GPIO_PIN_TYPE_INPUT 0x00 +#define GPIO_PIN_TYPE_OUTPUT 0x10 +#define GPIO_PIN_TYPE_HW_CONTROL 0x20 + +//For GPIO_PIN_TYPE_OUTPUT the following is defined +#define GPIO_PIN_OUTPUT_STATE_MASK 0x01 +#define GPIO_PIN_OUTPUT_STATE_SHIFT 0 +#define GPIO_PIN_STATE_ACTIVE_LOW 0x0 +#define GPIO_PIN_STATE_ACTIVE_HIGH 0x1 + +typedef struct _ATOM_ENCODER_DVO_CF_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ULONG ulStrengthControl; // DVOA strength control for CF + UCHAR ucPadding[2]; +}ATOM_ENCODER_DVO_CF_RECORD; + +// value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1 +#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2 + +typedef struct _ATOM_CONNECTOR_CF_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + USHORT usMaxPixClk; + UCHAR ucFlowCntlGpioId; + UCHAR ucSwapCntlGpioId; + UCHAR ucConnectedDvoBundle; + UCHAR ucPadding; +}ATOM_CONNECTOR_CF_RECORD; + +typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + ATOM_DTD_FORMAT asTiming; +}ATOM_CONNECTOR_HARDCODE_DTD_RECORD; + +typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; //ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE + UCHAR ucSubConnectorType; //CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A + UCHAR ucReserved; +}ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD; + + +typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; //decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; //for alligment purpose +}ATOM_ROUTER_DDC_PATH_SELECT_RECORD; + +typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD +{ + ATOM_COMMON_RECORD_HEADER sheader; + UCHAR ucMuxType; + UCHAR ucMuxControlPin; + UCHAR ucMuxState[2]; //for alligment purpose +}ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD; + +// define ucMuxType +#define ATOM_ROUTER_MUX_PIN_STATE_MASK 0x0f +#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT 0x01 + +/****************************************************************************/ +// ASIC voltage data table +/****************************************************************************/ +typedef struct _ATOM_VOLTAGE_INFO_HEADER +{ + USHORT usVDDCBaseLevel; //In number of 50mv unit + USHORT usReserved; //For possible extension table offset + UCHAR ucNumOfVoltageEntries; + UCHAR ucBytesPerVoltageEntry; + UCHAR ucVoltageStep; //Indicating in how many mv increament is one step, 0.5mv unit + UCHAR ucDefaultVoltageEntry; + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; +}ATOM_VOLTAGE_INFO_HEADER; + +typedef struct _ATOM_VOLTAGE_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_INFO_HEADER viHeader; + UCHAR ucVoltageEntries[64]; //64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry +}ATOM_VOLTAGE_INFO; + + +typedef struct _ATOM_VOLTAGE_FORMULA +{ + USHORT usVoltageBaseLevel; // In number of 1mv unit + USHORT usVoltageStep; // Indicating in how many mv increament is one step, 1mv unit + UCHAR ucNumOfVoltageEntries; // Number of Voltage Entry, which indicate max Voltage + UCHAR ucFlag; // bit0=0 :step is 1mv =1 0.5mv + UCHAR ucBaseVID; // if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep + UCHAR ucReserved; + UCHAR ucVIDAdjustEntries[32]; // 32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries +}ATOM_VOLTAGE_FORMULA; + +typedef struct _ATOM_VOLTAGE_CONTROL +{ + UCHAR ucVoltageControlId; //Indicate it is controlled by I2C or GPIO or HW state machine + UCHAR ucVoltageControlI2cLine; + UCHAR ucVoltageControlAddress; + UCHAR ucVoltageControlOffset; + USHORT usGpioPin_AIndex; //GPIO_PAD register index + UCHAR ucGpioPinBitShift[9]; //at most 8 pin support 255 VIDs, termintate with 0xff + UCHAR ucReserved; +}ATOM_VOLTAGE_CONTROL; + +// Define ucVoltageControlId +#define VOLTAGE_CONTROLLED_BY_HW 0x00 +#define VOLTAGE_CONTROLLED_BY_I2C_MASK 0x7F +#define VOLTAGE_CONTROLLED_BY_GPIO 0x80 +#define VOLTAGE_CONTROL_ID_LM64 0x01 //I2C control, used for R5xx Core Voltage +#define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI +#define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage +#define VOLTAGE_CONTROL_ID_DS4402 0x04 + +typedef struct _ATOM_VOLTAGE_OBJECT +{ + UCHAR ucVoltageType; //Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI + UCHAR ucSize; //Size of Object + ATOM_VOLTAGE_CONTROL asControl; //describ how to control + ATOM_VOLTAGE_FORMULA asFormula; //Indicate How to convert real Voltage to VID +}ATOM_VOLTAGE_OBJECT; + +typedef struct _ATOM_VOLTAGE_OBJECT_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VOLTAGE_OBJECT asVoltageObj[3]; //Info for Voltage control +}ATOM_VOLTAGE_OBJECT_INFO; + +typedef struct _ATOM_LEAKID_VOLTAGE +{ + UCHAR ucLeakageId; + UCHAR ucReserved; + USHORT usVoltage; +}ATOM_LEAKID_VOLTAGE; + +typedef struct _ATOM_ASIC_PROFILE_VOLTAGE +{ + UCHAR ucProfileId; + UCHAR ucReserved; + USHORT usSize; + USHORT usEfuseSpareStartAddr; + USHORT usFuseIndex[8]; //from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id, + ATOM_LEAKID_VOLTAGE asLeakVol[2]; //Leakid and relatd voltage +}ATOM_ASIC_PROFILE_VOLTAGE; + +//ucProfileId +#define ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE 1 +#define ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE 2 + +typedef struct _ATOM_ASIC_PROFILING_INFO +{ + ATOM_COMMON_TABLE_HEADER asHeader; + ATOM_ASIC_PROFILE_VOLTAGE asVoltage; +}ATOM_ASIC_PROFILING_INFO; + +typedef struct _ATOM_POWER_SOURCE_OBJECT +{ + UCHAR ucPwrSrcId; // Power source + UCHAR ucPwrSensorType; // GPIO, I2C or none + UCHAR ucPwrSensId; // if GPIO detect, it is GPIO id, if I2C detect, it is I2C id + UCHAR ucPwrSensSlaveAddr; // Slave address if I2C detect + UCHAR ucPwrSensRegIndex; // I2C register Index if I2C detect + UCHAR ucPwrSensRegBitMask; // detect which bit is used if I2C detect + UCHAR ucPwrSensActiveState; // high active or low active + UCHAR ucReserve[3]; // reserve + USHORT usSensPwr; // in unit of watt +}ATOM_POWER_SOURCE_OBJECT; + +typedef struct _ATOM_POWER_SOURCE_INFO +{ + ATOM_COMMON_TABLE_HEADER asHeader; + UCHAR asPwrbehave[16]; + ATOM_POWER_SOURCE_OBJECT asPwrObj[1]; +}ATOM_POWER_SOURCE_INFO; + + +//Define ucPwrSrcId +#define POWERSOURCE_PCIE_ID1 0x00 +#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01 +#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02 +#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04 +#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08 + +//define ucPwrSensorId +#define POWER_SENSOR_ALWAYS 0x00 +#define POWER_SENSOR_GPIO 0x01 +#define POWER_SENSOR_I2C 0x02 + +/**************************************************************************/ +// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design +//Memory SS Info Table +//Define Memory Clock SS chip ID +#define ICS91719 1 +#define ICS91720 2 + +//Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol +typedef struct _ATOM_I2C_DATA_RECORD +{ + UCHAR ucNunberOfBytes; //Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop" + UCHAR ucI2CData[1]; //I2C data in bytes, should be less than 16 bytes usually +}ATOM_I2C_DATA_RECORD; + + +//Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information +typedef struct _ATOM_I2C_DEVICE_SETUP_INFO +{ + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //I2C line and HW/SW assisted cap. + UCHAR ucSSChipID; //SS chip being used + UCHAR ucSSChipSlaveAddr; //Slave Address to set up this SS chip + UCHAR ucNumOfI2CDataRecords; //number of data block + ATOM_I2C_DATA_RECORD asI2CData[1]; +}ATOM_I2C_DEVICE_SETUP_INFO; + +//========================================================================================== +typedef struct _ATOM_ASIC_MVDD_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1]; +}ATOM_ASIC_MVDD_INFO; + +//========================================================================================== +#define ATOM_MCLK_SS_INFO ATOM_ASIC_MVDD_INFO + +//========================================================================================== +/**************************************************************************/ + +typedef struct _ATOM_ASIC_SS_ASSIGNMENT +{ + ULONG ulTargetClockRange; //Clock Out frequence (VCO ), in unit of 10Khz + USHORT usSpreadSpectrumPercentage; //in unit of 0.01% + USHORT usSpreadRateInKhz; //in unit of kHz, modulation freq + UCHAR ucClockIndication; //Indicate which clock source needs SS + UCHAR ucSpreadSpectrumMode; //Bit1=0 Down Spread,=1 Center Spread. + UCHAR ucReserved[2]; +}ATOM_ASIC_SS_ASSIGNMENT; + +//Define ucSpreadSpectrumType +#define ASIC_INTERNAL_MEMORY_SS 1 +#define ASIC_INTERNAL_ENGINE_SS 2 +#define ASIC_INTERNAL_UVD_SS 3 + +typedef struct _ATOM_ASIC_INTERNAL_SS_INFO{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4]; +}ATOM_ASIC_INTERNAL_SS_INFO; + +//==============================Scratch Pad Definition Portion=============================== +#define ATOM_DEVICE_CONNECT_INFO_DEF 0 +#define ATOM_ROM_LOCATION_DEF 1 +#define ATOM_TV_STANDARD_DEF 2 +#define ATOM_ACTIVE_INFO_DEF 3 +#define ATOM_LCD_INFO_DEF 4 +#define ATOM_DOS_REQ_INFO_DEF 5 +#define ATOM_ACC_CHANGE_INFO_DEF 6 +#define ATOM_DOS_MODE_INFO_DEF 7 +#define ATOM_I2C_CHANNEL_STATUS_DEF 8 +#define ATOM_I2C_CHANNEL_STATUS1_DEF 9 + + +// BIOS_0_SCRATCH Definition +#define ATOM_S0_CRT1_MONO 0x00000001L +#define ATOM_S0_CRT1_COLOR 0x00000002L +#define ATOM_S0_CRT1_MASK (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR) + +#define ATOM_S0_TV1_COMPOSITE_A 0x00000004L +#define ATOM_S0_TV1_SVIDEO_A 0x00000008L +#define ATOM_S0_TV1_MASK_A (ATOM_S0_TV1_COMPOSITE_A+ATOM_S0_TV1_SVIDEO_A) + +#define ATOM_S0_CV_A 0x00000010L +#define ATOM_S0_CV_DIN_A 0x00000020L +#define ATOM_S0_CV_MASK_A (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A) + + +#define ATOM_S0_CRT2_MONO 0x00000100L +#define ATOM_S0_CRT2_COLOR 0x00000200L +#define ATOM_S0_CRT2_MASK (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR) + +#define ATOM_S0_TV1_COMPOSITE 0x00000400L +#define ATOM_S0_TV1_SVIDEO 0x00000800L +#define ATOM_S0_TV1_SCART 0x00004000L +#define ATOM_S0_TV1_MASK (ATOM_S0_TV1_COMPOSITE+ATOM_S0_TV1_SVIDEO+ATOM_S0_TV1_SCART) + +#define ATOM_S0_CV 0x00001000L +#define ATOM_S0_CV_DIN 0x00002000L +#define ATOM_S0_CV_MASK (ATOM_S0_CV+ATOM_S0_CV_DIN) + +#define ATOM_S0_DFP1 0x00010000L +#define ATOM_S0_DFP2 0x00020000L +#define ATOM_S0_LCD1 0x00040000L +#define ATOM_S0_LCD2 0x00080000L +#define ATOM_S0_TV2 0x00100000L +#define ATOM_S0_DFP3 0x00200000L +#define ATOM_S0_DFP4 0x00400000L +#define ATOM_S0_DFP5 0x00800000L + +#define ATOM_S0_DFP_MASK ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5 + +#define ATOM_S0_FAD_REGISTER_BUG 0x02000000L // If set, indicates we are running a PCIE asic with + // the FAD/HDP reg access bug. Bit is read by DAL + +#define ATOM_S0_THERMAL_STATE_MASK 0x1C000000L +#define ATOM_S0_THERMAL_STATE_SHIFT 26 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L +#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29 + +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2 +#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 + +//Byte aligned defintion for BIOS usage +#define ATOM_S0_CRT1_MONOb0 0x01 +#define ATOM_S0_CRT1_COLORb0 0x02 +#define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0) + +#define ATOM_S0_TV1_COMPOSITEb0 0x04 +#define ATOM_S0_TV1_SVIDEOb0 0x08 +#define ATOM_S0_TV1_MASKb0 (ATOM_S0_TV1_COMPOSITEb0+ATOM_S0_TV1_SVIDEOb0) + +#define ATOM_S0_CVb0 0x10 +#define ATOM_S0_CV_DINb0 0x20 +#define ATOM_S0_CV_MASKb0 (ATOM_S0_CVb0+ATOM_S0_CV_DINb0) + +#define ATOM_S0_CRT2_MONOb1 0x01 +#define ATOM_S0_CRT2_COLORb1 0x02 +#define ATOM_S0_CRT2_MASKb1 (ATOM_S0_CRT2_MONOb1+ATOM_S0_CRT2_COLORb1) + +#define ATOM_S0_TV1_COMPOSITEb1 0x04 +#define ATOM_S0_TV1_SVIDEOb1 0x08 +#define ATOM_S0_TV1_SCARTb1 0x40 +#define ATOM_S0_TV1_MASKb1 (ATOM_S0_TV1_COMPOSITEb1+ATOM_S0_TV1_SVIDEOb1+ATOM_S0_TV1_SCARTb1) + +#define ATOM_S0_CVb1 0x10 +#define ATOM_S0_CV_DINb1 0x20 +#define ATOM_S0_CV_MASKb1 (ATOM_S0_CVb1+ATOM_S0_CV_DINb1) + +#define ATOM_S0_DFP1b2 0x01 +#define ATOM_S0_DFP2b2 0x02 +#define ATOM_S0_LCD1b2 0x04 +#define ATOM_S0_LCD2b2 0x08 +#define ATOM_S0_TV2b2 0x10 +#define ATOM_S0_DFP3b2 0x20 +#define ATOM_S0_DFP4b2 0x40 +#define ATOM_S0_DFP5b2 0x80 + +#define ATOM_S0_THERMAL_STATE_MASKb3 0x1C +#define ATOM_S0_THERMAL_STATE_SHIFTb3 2 + +#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0 +#define ATOM_S0_LCD1_SHIFT 18 + +// BIOS_1_SCRATCH Definition +#define ATOM_S1_ROM_LOCATION_MASK 0x0000FFFFL +#define ATOM_S1_PCI_BUS_DEV_MASK 0xFFFF0000L + +// BIOS_2_SCRATCH Definition +#define ATOM_S2_TV1_STANDARD_MASK 0x0000000FL +#define ATOM_S2_CURRENT_BL_LEVEL_MASK 0x0000FF00L +#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT 8 + +#define ATOM_S2_CRT1_DPMS_STATE 0x00010000L +#define ATOM_S2_LCD1_DPMS_STATE 0x00020000L +#define ATOM_S2_TV1_DPMS_STATE 0x00040000L +#define ATOM_S2_DFP1_DPMS_STATE 0x00080000L +#define ATOM_S2_CRT2_DPMS_STATE 0x00100000L +#define ATOM_S2_LCD2_DPMS_STATE 0x00200000L +#define ATOM_S2_TV2_DPMS_STATE 0x00400000L +#define ATOM_S2_DFP2_DPMS_STATE 0x00800000L +#define ATOM_S2_CV_DPMS_STATE 0x01000000L +#define ATOM_S2_DFP3_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP4_DPMS_STATE 0x04000000L +#define ATOM_S2_DFP5_DPMS_STATE 0x08000000L + +#define ATOM_S2_DFP_DPM_STATE ATOM_S2_DFP1_DPMS_STATE | ATOM_S2_DFP2_DPMS_STATE | ATOM_S2_DFP3_DPMS_STATE | ATOM_S2_DFP4_DPMS_STATE | ATOM_S2_DFP5_DPMS_STATE + +#define ATOM_S2_DEVICE_DPMS_STATE (ATOM_S2_CRT1_DPMS_STATE+ATOM_S2_LCD1_DPMS_STATE+ATOM_S2_TV1_DPMS_STATE+\ + ATOM_S2_DFP_DPMS_STATE+ATOM_S2_CRT2_DPMS_STATE+ATOM_S2_LCD2_DPMS_STATE+\ + ATOM_S2_TV2_DPMS_STATE+ATOM_S2_CV_DPMS_STATE + +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK 0x0C000000L +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26 +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE 0x10000000L + +#define ATOM_S2_VRI_BRIGHT_ENABLE 0x20000000L + +#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE 0x0 +#define ATOM_S2_DISPLAY_ROTATION_90_DEGREE 0x1 +#define ATOM_S2_DISPLAY_ROTATION_180_DEGREE 0x2 +#define ATOM_S2_DISPLAY_ROTATION_270_DEGREE 0x3 +#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30 +#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L + + +//Byte aligned defintion for BIOS usage +#define ATOM_S2_TV1_STANDARD_MASKb0 0x0F +#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF +#define ATOM_S2_CRT1_DPMS_STATEb2 0x01 +#define ATOM_S2_LCD1_DPMS_STATEb2 0x02 +#define ATOM_S2_TV1_DPMS_STATEb2 0x04 +#define ATOM_S2_DFP1_DPMS_STATEb2 0x08 +#define ATOM_S2_CRT2_DPMS_STATEb2 0x10 +#define ATOM_S2_LCD2_DPMS_STATEb2 0x20 +#define ATOM_S2_TV2_DPMS_STATEb2 0x40 +#define ATOM_S2_DFP2_DPMS_STATEb2 0x80 +#define ATOM_S2_CV_DPMS_STATEb3 0x01 +#define ATOM_S2_DFP3_DPMS_STATEb3 0x02 +#define ATOM_S2_DFP4_DPMS_STATEb3 0x04 +#define ATOM_S2_DFP5_DPMS_STATEb3 0x08 + +#define ATOM_S2_DEVICE_DPMS_MASKw1 0x3FF +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3 0x0C +#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGEb3 0x10 +#define ATOM_S2_VRI_BRIGHT_ENABLEb3 0x20 +#define ATOM_S2_ROTATION_STATE_MASKb3 0xC0 + + +// BIOS_3_SCRATCH Definition +#define ATOM_S3_CRT1_ACTIVE 0x00000001L +#define ATOM_S3_LCD1_ACTIVE 0x00000002L +#define ATOM_S3_TV1_ACTIVE 0x00000004L +#define ATOM_S3_DFP1_ACTIVE 0x00000008L +#define ATOM_S3_CRT2_ACTIVE 0x00000010L +#define ATOM_S3_LCD2_ACTIVE 0x00000020L +#define ATOM_S3_TV2_ACTIVE 0x00000040L +#define ATOM_S3_DFP2_ACTIVE 0x00000080L +#define ATOM_S3_CV_ACTIVE 0x00000100L +#define ATOM_S3_DFP3_ACTIVE 0x00000200L +#define ATOM_S3_DFP4_ACTIVE 0x00000400L +#define ATOM_S3_DFP5_ACTIVE 0x00000800L + +#define ATOM_S3_DEVICE_ACTIVE_MASK 0x00000FFFL + +#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE 0x00001000L +#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L + +#define ATOM_S3_CRT1_CRTC_ACTIVE 0x00010000L +#define ATOM_S3_LCD1_CRTC_ACTIVE 0x00020000L +#define ATOM_S3_TV1_CRTC_ACTIVE 0x00040000L +#define ATOM_S3_DFP1_CRTC_ACTIVE 0x00080000L +#define ATOM_S3_CRT2_CRTC_ACTIVE 0x00100000L +#define ATOM_S3_LCD2_CRTC_ACTIVE 0x00200000L +#define ATOM_S3_TV2_CRTC_ACTIVE 0x00400000L +#define ATOM_S3_DFP2_CRTC_ACTIVE 0x00800000L +#define ATOM_S3_CV_CRTC_ACTIVE 0x01000000L +#define ATOM_S3_DFP3_CRTC_ACTIVE 0x02000000L +#define ATOM_S3_DFP4_CRTC_ACTIVE 0x04000000L +#define ATOM_S3_DFP5_CRTC_ACTIVE 0x08000000L + +#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L +#define ATOM_S3_ASIC_GUI_ENGINE_HUNG 0x20000000L +#define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L +#define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L + +//Byte aligned defintion for BIOS usage +#define ATOM_S3_CRT1_ACTIVEb0 0x01 +#define ATOM_S3_LCD1_ACTIVEb0 0x02 +#define ATOM_S3_TV1_ACTIVEb0 0x04 +#define ATOM_S3_DFP1_ACTIVEb0 0x08 +#define ATOM_S3_CRT2_ACTIVEb0 0x10 +#define ATOM_S3_LCD2_ACTIVEb0 0x20 +#define ATOM_S3_TV2_ACTIVEb0 0x40 +#define ATOM_S3_DFP2_ACTIVEb0 0x80 +#define ATOM_S3_CV_ACTIVEb1 0x01 +#define ATOM_S3_DFP3_ACTIVEb1 0x02 +#define ATOM_S3_DFP4_ACTIVEb1 0x04 +#define ATOM_S3_DFP5_ACTIVEb1 0x08 + +#define ATOM_S3_ACTIVE_CRTC1w0 0xFFF + +#define ATOM_S3_CRT1_CRTC_ACTIVEb2 0x01 +#define ATOM_S3_LCD1_CRTC_ACTIVEb2 0x02 +#define ATOM_S3_TV1_CRTC_ACTIVEb2 0x04 +#define ATOM_S3_DFP1_CRTC_ACTIVEb2 0x08 +#define ATOM_S3_CRT2_CRTC_ACTIVEb2 0x10 +#define ATOM_S3_LCD2_CRTC_ACTIVEb2 0x20 +#define ATOM_S3_TV2_CRTC_ACTIVEb2 0x40 +#define ATOM_S3_DFP2_CRTC_ACTIVEb2 0x80 +#define ATOM_S3_CV_CRTC_ACTIVEb3 0x01 +#define ATOM_S3_DFP3_CRTC_ACTIVEb3 0x02 +#define ATOM_S3_DFP4_CRTC_ACTIVEb3 0x04 +#define ATOM_S3_DFP5_CRTC_ACTIVEb3 0x08 + +#define ATOM_S3_ACTIVE_CRTC2w1 0xFFF + +#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20 +#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40 +#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3 0x80 + +// BIOS_4_SCRATCH Definition +#define ATOM_S4_LCD1_PANEL_ID_MASK 0x000000FFL +#define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L +#define ATOM_S4_LCD1_REFRESH_SHIFT 8 + +//Byte aligned defintion for BIOS usage +#define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF +#define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0 +#define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0 + +// BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! +#define ATOM_S5_DOS_REQ_CRT1b0 0x01 +#define ATOM_S5_DOS_REQ_LCD1b0 0x02 +#define ATOM_S5_DOS_REQ_TV1b0 0x04 +#define ATOM_S5_DOS_REQ_DFP1b0 0x08 +#define ATOM_S5_DOS_REQ_CRT2b0 0x10 +#define ATOM_S5_DOS_REQ_LCD2b0 0x20 +#define ATOM_S5_DOS_REQ_TV2b0 0x40 +#define ATOM_S5_DOS_REQ_DFP2b0 0x80 +#define ATOM_S5_DOS_REQ_CVb1 0x01 +#define ATOM_S5_DOS_REQ_DFP3b1 0x02 +#define ATOM_S5_DOS_REQ_DFP4b1 0x04 +#define ATOM_S5_DOS_REQ_DFP5b1 0x08 + +#define ATOM_S5_DOS_REQ_DEVICEw0 0x03FF + +#define ATOM_S5_DOS_REQ_CRT1 0x0001 +#define ATOM_S5_DOS_REQ_LCD1 0x0002 +#define ATOM_S5_DOS_REQ_TV1 0x0004 +#define ATOM_S5_DOS_REQ_DFP1 0x0008 +#define ATOM_S5_DOS_REQ_CRT2 0x0010 +#define ATOM_S5_DOS_REQ_LCD2 0x0020 +#define ATOM_S5_DOS_REQ_TV2 0x0040 +#define ATOM_S5_DOS_REQ_DFP2 0x0080 +#define ATOM_S5_DOS_REQ_CV 0x0100 +#define ATOM_S5_DOS_REQ_DFP3 0x0200 +#define ATOM_S5_DOS_REQ_DFP4 0x0400 +#define ATOM_S5_DOS_REQ_DFP5 0x0800 + +#define ATOM_S5_DOS_FORCE_CRT1b2 ATOM_S5_DOS_REQ_CRT1b0 +#define ATOM_S5_DOS_FORCE_TV1b2 ATOM_S5_DOS_REQ_TV1b0 +#define ATOM_S5_DOS_FORCE_CRT2b2 ATOM_S5_DOS_REQ_CRT2b0 +#define ATOM_S5_DOS_FORCE_CVb3 ATOM_S5_DOS_REQ_CVb1 +#define ATOM_S5_DOS_FORCE_DEVICEw1 (ATOM_S5_DOS_FORCE_CRT1b2+ATOM_S5_DOS_FORCE_TV1b2+ATOM_S5_DOS_FORCE_CRT2b2+\ + (ATOM_S5_DOS_FORCE_CVb3<<8)) + +// BIOS_6_SCRATCH Definition +#define ATOM_S6_DEVICE_CHANGE 0x00000001L +#define ATOM_S6_SCALER_CHANGE 0x00000002L +#define ATOM_S6_LID_CHANGE 0x00000004L +#define ATOM_S6_DOCKING_CHANGE 0x00000008L +#define ATOM_S6_ACC_MODE 0x00000010L +#define ATOM_S6_EXT_DESKTOP_MODE 0x00000020L +#define ATOM_S6_LID_STATE 0x00000040L +#define ATOM_S6_DOCK_STATE 0x00000080L +#define ATOM_S6_CRITICAL_STATE 0x00000100L +#define ATOM_S6_HW_I2C_BUSY_STATE 0x00000200L +#define ATOM_S6_THERMAL_STATE_CHANGE 0x00000400L +#define ATOM_S6_INTERRUPT_SET_BY_BIOS 0x00000800L +#define ATOM_S6_REQ_LCD_EXPANSION_FULL 0x00001000L //Normal expansion Request bit for LCD +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO 0x00002000L //Aspect ratio expansion Request bit for LCD + +#define ATOM_S6_DISPLAY_STATE_CHANGE 0x00004000L //This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion +#define ATOM_S6_I2C_STATE_CHANGE 0x00008000L //This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion + +#define ATOM_S6_ACC_REQ_CRT1 0x00010000L +#define ATOM_S6_ACC_REQ_LCD1 0x00020000L +#define ATOM_S6_ACC_REQ_TV1 0x00040000L +#define ATOM_S6_ACC_REQ_DFP1 0x00080000L +#define ATOM_S6_ACC_REQ_CRT2 0x00100000L +#define ATOM_S6_ACC_REQ_LCD2 0x00200000L +#define ATOM_S6_ACC_REQ_TV2 0x00400000L +#define ATOM_S6_ACC_REQ_DFP2 0x00800000L +#define ATOM_S6_ACC_REQ_CV 0x01000000L +#define ATOM_S6_ACC_REQ_DFP3 0x02000000L +#define ATOM_S6_ACC_REQ_DFP4 0x04000000L +#define ATOM_S6_ACC_REQ_DFP5 0x08000000L + +#define ATOM_S6_ACC_REQ_MASK 0x0FFF0000L +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE 0x10000000L +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH 0x20000000L +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L + +//Byte aligned defintion for BIOS usage +#define ATOM_S6_DEVICE_CHANGEb0 0x01 +#define ATOM_S6_SCALER_CHANGEb0 0x02 +#define ATOM_S6_LID_CHANGEb0 0x04 +#define ATOM_S6_DOCKING_CHANGEb0 0x08 +#define ATOM_S6_ACC_MODEb0 0x10 +#define ATOM_S6_EXT_DESKTOP_MODEb0 0x20 +#define ATOM_S6_LID_STATEb0 0x40 +#define ATOM_S6_DOCK_STATEb0 0x80 +#define ATOM_S6_CRITICAL_STATEb1 0x01 +#define ATOM_S6_HW_I2C_BUSY_STATEb1 0x02 +#define ATOM_S6_THERMAL_STATE_CHANGEb1 0x04 +#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08 +#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1 0x10 +#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20 + +#define ATOM_S6_ACC_REQ_CRT1b2 0x01 +#define ATOM_S6_ACC_REQ_LCD1b2 0x02 +#define ATOM_S6_ACC_REQ_TV1b2 0x04 +#define ATOM_S6_ACC_REQ_DFP1b2 0x08 +#define ATOM_S6_ACC_REQ_CRT2b2 0x10 +#define ATOM_S6_ACC_REQ_LCD2b2 0x20 +#define ATOM_S6_ACC_REQ_TV2b2 0x40 +#define ATOM_S6_ACC_REQ_DFP2b2 0x80 +#define ATOM_S6_ACC_REQ_CVb3 0x01 +#define ATOM_S6_ACC_REQ_DFP3b3 0x02 +#define ATOM_S6_ACC_REQ_DFP4b3 0x04 +#define ATOM_S6_ACC_REQ_DFP5b3 0x08 + +#define ATOM_S6_ACC_REQ_DEVICEw1 ATOM_S5_DOS_REQ_DEVICEw0 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCHb3 0x20 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGEb3 0x40 +#define ATOM_S6_CONFIG_DISPLAY_CHANGEb3 0x80 + +#define ATOM_S6_DEVICE_CHANGE_SHIFT 0 +#define ATOM_S6_SCALER_CHANGE_SHIFT 1 +#define ATOM_S6_LID_CHANGE_SHIFT 2 +#define ATOM_S6_DOCKING_CHANGE_SHIFT 3 +#define ATOM_S6_ACC_MODE_SHIFT 4 +#define ATOM_S6_EXT_DESKTOP_MODE_SHIFT 5 +#define ATOM_S6_LID_STATE_SHIFT 6 +#define ATOM_S6_DOCK_STATE_SHIFT 7 +#define ATOM_S6_CRITICAL_STATE_SHIFT 8 +#define ATOM_S6_HW_I2C_BUSY_STATE_SHIFT 9 +#define ATOM_S6_THERMAL_STATE_CHANGE_SHIFT 10 +#define ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT 11 +#define ATOM_S6_REQ_SCALER_SHIFT 12 +#define ATOM_S6_REQ_SCALER_ARATIO_SHIFT 13 +#define ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT 14 +#define ATOM_S6_I2C_STATE_CHANGE_SHIFT 15 +#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT 28 +#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH_SHIFT 29 +#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT 30 +#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT 31 + +// BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!! +#define ATOM_S7_DOS_MODE_TYPEb0 0x03 +#define ATOM_S7_DOS_MODE_VGAb0 0x00 +#define ATOM_S7_DOS_MODE_VESAb0 0x01 +#define ATOM_S7_DOS_MODE_EXTb0 0x02 +#define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0 0x0C +#define ATOM_S7_DOS_MODE_PIXEL_FORMATb0 0xF0 +#define ATOM_S7_DOS_8BIT_DAC_ENb1 0x01 +#define ATOM_S7_DOS_MODE_NUMBERw1 0x0FFFF + +#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT 8 + +// BIOS_8_SCRATCH Definition +#define ATOM_S8_I2C_CHANNEL_BUSY_MASK 0x00000FFFF +#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK 0x0FFFF0000 + +#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT 0 +#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT 16 + +// BIOS_9_SCRATCH Definition +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK +#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK 0x0000FFFF +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK +#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK 0xFFFF0000 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT +#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0 +#endif +#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT +#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT 16 +#endif + + +#define ATOM_FLAG_SET 0x20 +#define ATOM_FLAG_CLEAR 0 +#define CLEAR_ATOM_S6_ACC_MODE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR) +#define SET_ATOM_S6_DEVICE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SCALER_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_LID_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_LID_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_DOCK_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_DOCK_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_THERMAL_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET) +#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET) + +#define SET_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_CRITICAL_STATE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR) + +#define SET_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S6_REQ_SCALER ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR ) + +#define SET_ATOM_S6_I2C_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DISPLAY_STATE_CHANGE ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET ) + +#define SET_ATOM_S6_DEVICE_RECONFIG ((ATOM_ACC_CHANGE_INFO_DEF << 8 )|ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET) +#define CLEAR_ATOM_S0_LCD1 ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 )| ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR ) +#define SET_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET ) +#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN ((ATOM_DOS_MODE_INFO_DEF << 8 )|ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR ) + +/****************************************************************************/ +//Portion II: Definitinos only used in Driver +/****************************************************************************/ + +// Macros used by driver + +#define GetIndexIntoMasterTable(MasterOrData, FieldName) (((char*)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES*)0)->FieldName)-(char*)0)/sizeof(USHORT)) + +#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F) +#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F) + +#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION +#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION + +/****************************************************************************/ +//Portion III: Definitinos only used in VBIOS +/****************************************************************************/ +#define ATOM_DAC_SRC 0x80 +#define ATOM_SRC_DAC1 0 +#define ATOM_SRC_DAC2 0x80 + + +#ifdef UEFI_BUILD + #define USHORT UTEMP +#endif + +typedef struct _MEMORY_PLLINIT_PARAMETERS +{ + ULONG ulTargetMemoryClock; //In 10Khz unit + UCHAR ucAction; //not define yet + UCHAR ucFbDiv_Hi; //Fbdiv Hi byte + UCHAR ucFbDiv; //FB value + UCHAR ucPostDiv; //Post div +}MEMORY_PLLINIT_PARAMETERS; + +#define MEMORY_PLLINIT_PS_ALLOCATION MEMORY_PLLINIT_PARAMETERS + + +#define GPIO_PIN_WRITE 0x01 +#define GPIO_PIN_READ 0x00 + +typedef struct _GPIO_PIN_CONTROL_PARAMETERS +{ + UCHAR ucGPIO_ID; //return value, read from GPIO pins + UCHAR ucGPIOBitShift; //define which bit in uGPIOBitVal need to be update + UCHAR ucGPIOBitVal; //Set/Reset corresponding bit defined in ucGPIOBitMask + UCHAR ucAction; //=GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write +}GPIO_PIN_CONTROL_PARAMETERS; + +typedef struct _ENABLE_SCALER_PARAMETERS +{ + UCHAR ucScaler; // ATOM_SCALER1, ATOM_SCALER2 + UCHAR ucEnable; // ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION + UCHAR ucTVStandard; // + UCHAR ucPadding[1]; +}ENABLE_SCALER_PARAMETERS; +#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS + +//ucEnable: +#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION 0 +#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION 1 +#define SCALER_ENABLE_2TAP_ALPHA_MODE 2 +#define SCALER_ENABLE_MULTITAP_MODE 3 + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS +{ + ULONG usHWIconHorzVertPosn; // Hardware Icon Vertical position + UCHAR ucHWIconVertOffset; // Hardware Icon Vertical offset + UCHAR ucHWIconHorzOffset; // Hardware Icon Horizontal offset + UCHAR ucSelection; // ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE +}ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS; + +typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION +{ + ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon; + ENABLE_CRTC_PARAMETERS sReserved; +}ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucPadding[3]; +}ENABLE_GRAPH_SURFACE_PARAMETERS; + +typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2 +{ + USHORT usHight; // Image Hight + USHORT usWidth; // Image Width + UCHAR ucSurface; // Surface 1 or 2 + UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE + UCHAR ucPadding[2]; +}ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2; + +typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION +{ + ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface; + ENABLE_YUV_PS_ALLOCATION sReserved; // Don't set this one +}ENABLE_GRAPH_SURFACE_PS_ALLOCATION; + +typedef struct _MEMORY_CLEAN_UP_PARAMETERS +{ + USHORT usMemoryStart; //in 8Kb boundry, offset from memory base address + USHORT usMemorySize; //8Kb blocks aligned +}MEMORY_CLEAN_UP_PARAMETERS; +#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS + +typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS +{ + USHORT usX_Size; //When use as input parameter, usX_Size indicates which CRTC + USHORT usY_Size; +}GET_DISPLAY_SURFACE_SIZE_PARAMETERS; + +typedef struct _INDIRECT_IO_ACCESS +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR IOAccessSequence[256]; +} INDIRECT_IO_ACCESS; + +#define INDIRECT_READ 0x00 +#define INDIRECT_WRITE 0x80 + +#define INDIRECT_IO_MM 0 +#define INDIRECT_IO_PLL 1 +#define INDIRECT_IO_MC 2 +#define INDIRECT_IO_PCIE 3 +#define INDIRECT_IO_PCIEP 4 +#define INDIRECT_IO_NBMISC 5 + +#define INDIRECT_IO_PLL_READ INDIRECT_IO_PLL | INDIRECT_READ +#define INDIRECT_IO_PLL_WRITE INDIRECT_IO_PLL | INDIRECT_WRITE +#define INDIRECT_IO_MC_READ INDIRECT_IO_MC | INDIRECT_READ +#define INDIRECT_IO_MC_WRITE INDIRECT_IO_MC | INDIRECT_WRITE +#define INDIRECT_IO_PCIE_READ INDIRECT_IO_PCIE | INDIRECT_READ +#define INDIRECT_IO_PCIE_WRITE INDIRECT_IO_PCIE | INDIRECT_WRITE +#define INDIRECT_IO_PCIEP_READ INDIRECT_IO_PCIEP | INDIRECT_READ +#define INDIRECT_IO_PCIEP_WRITE INDIRECT_IO_PCIEP | INDIRECT_WRITE +#define INDIRECT_IO_NBMISC_READ INDIRECT_IO_NBMISC | INDIRECT_READ +#define INDIRECT_IO_NBMISC_WRITE INDIRECT_IO_NBMISC | INDIRECT_WRITE + +typedef struct _ATOM_OEM_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +}ATOM_OEM_INFO; + +typedef struct _ATOM_TV_MODE +{ + UCHAR ucVMode_Num; //Video mode number + UCHAR ucTV_Mode_Num; //Internal TV mode number +}ATOM_TV_MODE; + +typedef struct _ATOM_BIOS_INT_TVSTD_MODE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usTV_Mode_LUT_Offset; // Pointer to standard to internal number conversion table + USHORT usTV_FIFO_Offset; // Pointer to FIFO entry table + USHORT usNTSC_Tbl_Offset; // Pointer to SDTV_Mode_NTSC table + USHORT usPAL_Tbl_Offset; // Pointer to SDTV_Mode_PAL table + USHORT usCV_Tbl_Offset; // Pointer to SDTV_Mode_PAL table +}ATOM_BIOS_INT_TVSTD_MODE; + + +typedef struct _ATOM_TV_MODE_SCALER_PTR +{ + USHORT ucFilter0_Offset; //Pointer to filter format 0 coefficients + USHORT usFilter1_Offset; //Pointer to filter format 0 coefficients + UCHAR ucTV_Mode_Num; +}ATOM_TV_MODE_SCALER_PTR; + +typedef struct _ATOM_STANDARD_VESA_TIMING +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_DTD_FORMAT aModeTimings[16]; // 16 is not the real array number, just for initial allocation +}ATOM_STANDARD_VESA_TIMING; + + +typedef struct _ATOM_STD_FORMAT +{ + USHORT usSTD_HDisp; + USHORT usSTD_VDisp; + USHORT usSTD_RefreshRate; + USHORT usReserved; +}ATOM_STD_FORMAT; + +typedef struct _ATOM_VESA_TO_EXTENDED_MODE +{ + USHORT usVESA_ModeNumber; + USHORT usExtendedModeNumber; +}ATOM_VESA_TO_EXTENDED_MODE; + +typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT +{ + ATOM_COMMON_TABLE_HEADER sHeader; + ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76]; +}ATOM_VESA_TO_INTENAL_MODE_LUT; + +/*************** ATOM Memory Related Data Structure ***********************/ +typedef struct _ATOM_MEMORY_VENDOR_BLOCK{ + UCHAR ucMemoryType; + UCHAR ucMemoryVendor; + UCHAR ucAdjMCId; + UCHAR ucDynClkId; + ULONG ulDllResetClkRange; +}ATOM_MEMORY_VENDOR_BLOCK; + + +typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG{ + ULONG ulMemClockRange:24; + ULONG ucMemBlkId:8; +}ATOM_MEMORY_SETTING_ID_CONFIG; + +typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS +{ + ATOM_MEMORY_SETTING_ID_CONFIG slAccess; + ULONG ulAccess; +}ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS; + + +typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK{ + ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID; + ULONG aulMemData[1]; +}ATOM_MEMORY_SETTING_DATA_BLOCK; + + +typedef struct _ATOM_INIT_REG_INDEX_FORMAT{ + USHORT usRegIndex; // MC register index + UCHAR ucPreRegDataLength; // offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf +}ATOM_INIT_REG_INDEX_FORMAT; + + +typedef struct _ATOM_INIT_REG_BLOCK{ + USHORT usRegIndexTblSize; //size of asRegIndexBuf + USHORT usRegDataBlkSize; //size of ATOM_MEMORY_SETTING_DATA_BLOCK + ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1]; + ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1]; +}ATOM_INIT_REG_BLOCK; + +#define END_OF_REG_INDEX_BLOCK 0x0ffff +#define END_OF_REG_DATA_BLOCK 0x00000000 +#define ATOM_INIT_REG_MASK_FLAG 0x80 +#define CLOCK_RANGE_HIGHEST 0x00ffffff + +#define VALUE_DWORD SIZEOF ULONG +#define VALUE_SAME_AS_ABOVE 0 +#define VALUE_MASK_DWORD 0x84 + +#define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1) +#define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1) +#define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1) + + +typedef struct _ATOM_MC_INIT_PARAM_TABLE +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usAdjustARB_SEQDataOffset; + USHORT usMCInitMemTypeTblOffset; + USHORT usMCInitCommonTblOffset; + USHORT usMCInitPowerDownTblOffset; + ULONG ulARB_SEQDataBuf[32]; + ATOM_INIT_REG_BLOCK asMCInitMemType; + ATOM_INIT_REG_BLOCK asMCInitCommon; +}ATOM_MC_INIT_PARAM_TABLE; + + +#define _4Mx16 0x2 +#define _4Mx32 0x3 +#define _8Mx16 0x12 +#define _8Mx32 0x13 +#define _16Mx16 0x22 +#define _16Mx32 0x23 +#define _32Mx16 0x32 +#define _32Mx32 0x33 +#define _64Mx8 0x41 +#define _64Mx16 0x42 + +#define SAMSUNG 0x1 +#define INFINEON 0x2 +#define ELPIDA 0x3 +#define ETRON 0x4 +#define NANYA 0x5 +#define HYNIX 0x6 +#define MOSEL 0x7 +#define WINBOND 0x8 +#define ESMT 0x9 +#define MICRON 0xF + +#define QIMONDA INFINEON +#define PROMOS MOSEL + +/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// + +#define UCODE_ROM_START_ADDRESS 0x1c000 +#define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode + +//uCode block header for reference + +typedef struct _MCuCodeHeader +{ + ULONG ulSignature; + UCHAR ucRevision; + UCHAR ucChecksum; + UCHAR ucReserved1; + UCHAR ucReserved2; + USHORT usParametersLength; + USHORT usUCodeLength; + USHORT usReserved1; + USHORT usReserved2; +} MCuCodeHeader; + +////////////////////////////////////////////////////////////////////////////////// + +#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16 + +#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF +typedef struct _ATOM_VRAM_MODULE_V1 +{ + ULONG ulReserved; + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender + UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucChannelNum; // Number of channel; + UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 + UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; + UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; + UCHAR ucReserved[2]; +}ATOM_VRAM_MODULE_V1; + + +typedef struct _ATOM_VRAM_MODULE_V2 +{ + ULONG ulReserved; + ULONG ulFlags; // To enable/disable functionalities based on memory type + ULONG ulEngineClock; // Override of default engine clock for particular memory type + ULONG ulMemoryClock; // Override of default memory clock for particular memory type + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRSValue; + USHORT usMRSValue; + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed + UCHAR ucMemoryDeviceCfg; // [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucChannelNum; // Number of channel; + UCHAR ucChannelConfig; // [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 + UCHAR ucDefaultMVDDQ_ID; // Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; + UCHAR ucDefaultMVDDC_ID; // Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; + UCHAR ucRefreshRateFactor; + UCHAR ucReserved[3]; +}ATOM_VRAM_MODULE_V2; + + +typedef struct _ATOM_MEMORY_TIMING_FORMAT +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + union{ + USHORT usMRS; // mode register + USHORT usDDR3_MR0; + }; + union{ + USHORT usEMRS; // extended mode register + USHORT usDDR3_MR1; + }; + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + union + { + struct { + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon + UCHAR ucReserved; + }; + USHORT usDDR3_MR2; + }; +}ATOM_MEMORY_TIMING_FORMAT; + + +typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1 +{ + ULONG ulClkRange; // memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing + USHORT usMRS; // mode register + USHORT usEMRS; // extended mode register + UCHAR ucCL; // CAS latency + UCHAR ucWL; // WRITE Latency + UCHAR uctRAS; // tRAS + UCHAR uctRC; // tRC + UCHAR uctRFC; // tRFC + UCHAR uctRCDR; // tRCDR + UCHAR uctRCDW; // tRCDW + UCHAR uctRP; // tRP + UCHAR uctRRD; // tRRD + UCHAR uctWR; // tWR + UCHAR uctWTR; // tWTR + UCHAR uctPDIX; // tPDIX + UCHAR uctFAW; // tFAW + UCHAR uctAOND; // tAOND + UCHAR ucflag; // flag to control memory timing calculation. bit0= control EMRS2 Infineon +////////////////////////////////////GDDR parameters/////////////////////////////////// + UCHAR uctCCDL; // + UCHAR uctCRCRL; // + UCHAR uctCRCWL; // + UCHAR uctCKE; // + UCHAR uctCKRSE; // + UCHAR uctCKRSX; // + UCHAR uctFAW32; // + UCHAR ucReserved1; // + UCHAR ucReserved2; // + UCHAR ucTerminator; +}ATOM_MEMORY_TIMING_FORMAT_V1; + + +typedef struct _ATOM_MEMORY_FORMAT +{ + ULONG ulDllDisClock; // memory DLL will be disable when target memory clock is below this clock + union{ + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_Reserved; // Not used for DDR3 memory + }; + union{ + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_MR3; // Used for DDR3 memory + }; + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; + UCHAR ucMemoryVenderID; // Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed + UCHAR ucRow; // Number of Row,in power of 2; + UCHAR ucColumn; // Number of Column,in power of 2; + UCHAR ucBank; // Nunber of Bank; + UCHAR ucRank; // Number of Rank, in power of 2 + UCHAR ucBurstSize; // burst size, 0= burst size=4 1= burst size=8 + UCHAR ucDllDisBit; // position of DLL Enable/Disable bit in EMRS ( Extended Mode Register ) + UCHAR ucRefreshRateFactor; // memory refresh rate in unit of ms + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucPreamble; //[7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemAttrib; // Memory Device Addribute, like RDBI/WDBI etc + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5]; //Memory Timing block sort from lower clock to higher clock +}ATOM_MEMORY_FORMAT; + + +typedef struct _ATOM_VRAM_MODULE_V3 +{ + ULONG ulChannelMapCfg; // board dependent paramenter:Channel combination + USHORT usSize; // size of ATOM_VRAM_MODULE_V3 + USHORT usDefaultMVDDQ; // board dependent parameter:Default Memory Core Voltage + USHORT usDefaultMVDDC; // board dependent parameter:Default Memory IO Voltage + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucChannelNum; // board dependent parameter:Number of channel; + UCHAR ucChannelSize; // board dependent parameter:32bit or 64bit + UCHAR ucVREFI; // board dependnt parameter: EXT or INT +160mv to -140mv + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucFlag; // To enable/disable functionalities based on memory type + ATOM_MEMORY_FORMAT asMemory; // describ all of video memory parameters from memory spec +}ATOM_VRAM_MODULE_V3; + + +//ATOM_VRAM_MODULE_V3.ucNPL_RT +#define NPL_RT_MASK 0x0f +#define BATTERY_ODT_MASK 0xc0 + +#define ATOM_VRAM_MODULE ATOM_VRAM_MODULE_V3 + +typedef struct _ATOM_VRAM_MODULE_V4 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + union{ + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_Reserved; + }; + union{ + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + USHORT usDDR3_MR3; // Used for DDR3 memory + }; + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucReserved2[2]; + ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V4; + +#define VRAM_MODULE_V4_MISC_RANK_MASK 0x3 +#define VRAM_MODULE_V4_MISC_DUAL_RANK 0x1 +#define VRAM_MODULE_V4_MISC_BL_MASK 0x4 +#define VRAM_MODULE_V4_MISC_BL8 0x4 +#define VRAM_MODULE_V4_MISC_DUAL_CS 0x10 + +typedef struct _ATOM_VRAM_MODULE_V5 +{ + ULONG ulChannelMapCfg; // board dependent parameter: Channel combination + USHORT usModuleSize; // size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE + USHORT usPrivateReserved; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) + USHORT usReserved; + UCHAR ucExtMemoryID; // An external indicator (by hardcode, callback or pin) to tell what is the current memory module + UCHAR ucMemoryType; // [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; + UCHAR ucChannelNum; // Number of channels present in this module config + UCHAR ucChannelWidth; // 0 - 32 bits; 1 - 64 bits + UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 + UCHAR ucFlag; // To enable/disable functionalities based on memory type + UCHAR ucMisc; // bit0: 0 - single rank; 1 - dual rank; bit2: 0 - burstlength 4, 1 - burstlength 8 + UCHAR ucVREFI; // board dependent parameter + UCHAR ucNPL_RT; // board dependent parameter:NPL round trip delay, used for calculate memory timing parameters + UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble + UCHAR ucMemorySize; // BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! + // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros + UCHAR ucReserved[3]; + +//compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level + USHORT usEMRS2Value; // EMRS2 Value is used for GDDR2 and GDDR4 memory type + USHORT usEMRS3Value; // EMRS3 Value is used for GDDR2 and GDDR4 memory type + UCHAR ucMemoryVenderID; // Predefined, If not predefined, vendor detection table gets executed + UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) + UCHAR ucFIFODepth; // FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth + UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth + ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock +}ATOM_VRAM_MODULE_V5; + +typedef struct _ATOM_VRAM_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; +}ATOM_VRAM_INFO_V2; + +typedef struct _ATOM_VRAM_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usRerseved; + UCHAR aVID_PinsShift[9]; // 8 bit strap maximum+terminator + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; + ATOM_INIT_REG_BLOCK asMemPatch; // for allocation + // ATOM_INIT_REG_BLOCK aMemAdjust; +}ATOM_VRAM_INFO_V3; + +#define ATOM_VRAM_INFO_LAST ATOM_VRAM_INFO_V3 + +typedef struct _ATOM_VRAM_INFO_V4 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting + USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting + USHORT usRerseved; + UCHAR ucMemDQ7_0ByteRemap; // DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3 + ULONG ulMemDQ7_0BitRemap; // each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21] + UCHAR ucReservde[4]; + UCHAR ucNumOfVRAMModule; + ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; + ATOM_INIT_REG_BLOCK asMemPatch; // for allocation + // ATOM_INIT_REG_BLOCK aMemAdjust; +}ATOM_VRAM_INFO_V4; + +typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR aVID_PinsShift[9]; //8 bit strap maximum+terminator +}ATOM_VRAM_GPIO_DETECTION_INFO; + + +typedef struct _ATOM_MEMORY_TRAINING_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucTrainingLoop; + UCHAR ucReserved[3]; + ATOM_INIT_REG_BLOCK asMemTrainingSetting; +}ATOM_MEMORY_TRAINING_INFO; + + +typedef struct SW_I2C_CNTL_DATA_PARAMETERS +{ + UCHAR ucControl; + UCHAR ucData; + UCHAR ucSatus; + UCHAR ucTemp; +} SW_I2C_CNTL_DATA_PARAMETERS; + +#define SW_I2C_CNTL_DATA_PS_ALLOCATION SW_I2C_CNTL_DATA_PARAMETERS + +typedef struct _SW_I2C_IO_DATA_PARAMETERS +{ + USHORT GPIO_Info; + UCHAR ucAct; + UCHAR ucData; + } SW_I2C_IO_DATA_PARAMETERS; + +#define SW_I2C_IO_DATA_PS_ALLOCATION SW_I2C_IO_DATA_PARAMETERS + +/****************************SW I2C CNTL DEFINITIONS**********************/ +#define SW_I2C_IO_RESET 0 +#define SW_I2C_IO_GET 1 +#define SW_I2C_IO_DRIVE 2 +#define SW_I2C_IO_SET 3 +#define SW_I2C_IO_START 4 + +#define SW_I2C_IO_CLOCK 0 +#define SW_I2C_IO_DATA 0x80 + +#define SW_I2C_IO_ZERO 0 +#define SW_I2C_IO_ONE 0x100 + +#define SW_I2C_CNTL_READ 0 +#define SW_I2C_CNTL_WRITE 1 +#define SW_I2C_CNTL_START 2 +#define SW_I2C_CNTL_STOP 3 +#define SW_I2C_CNTL_OPEN 4 +#define SW_I2C_CNTL_CLOSE 5 +#define SW_I2C_CNTL_WRITE1BIT 6 + +//==============================VESA definition Portion=============================== +#define VESA_OEM_PRODUCT_REV '01.00' +#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT 0xBB //refer to VBE spec p.32, no TTY support +#define VESA_MODE_WIN_ATTRIBUTE 7 +#define VESA_WIN_SIZE 64 + +typedef struct _PTR_32_BIT_STRUCTURE +{ + USHORT Offset16; + USHORT Segment16; +} PTR_32_BIT_STRUCTURE; + +typedef union _PTR_32_BIT_UNION +{ + PTR_32_BIT_STRUCTURE SegmentOffset; + ULONG Ptr32_Bit; +} PTR_32_BIT_UNION; + +typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE +{ + UCHAR VbeSignature[4]; + USHORT VbeVersion; + PTR_32_BIT_UNION OemStringPtr; + UCHAR Capabilities[4]; + PTR_32_BIT_UNION VideoModePtr; + USHORT TotalMemory; +} VBE_1_2_INFO_BLOCK_UPDATABLE; + + +typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE +{ + VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock; + USHORT OemSoftRev; + PTR_32_BIT_UNION OemVendorNamePtr; + PTR_32_BIT_UNION OemProductNamePtr; + PTR_32_BIT_UNION OemProductRevPtr; +} VBE_2_0_INFO_BLOCK_UPDATABLE; + +typedef union _VBE_VERSION_UNION +{ + VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock; + VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock; +} VBE_VERSION_UNION; + +typedef struct _VBE_INFO_BLOCK +{ + VBE_VERSION_UNION UpdatableVBE_Info; + UCHAR Reserved[222]; + UCHAR OemData[256]; +} VBE_INFO_BLOCK; + +typedef struct _VBE_FP_INFO +{ + USHORT HSize; + USHORT VSize; + USHORT FPType; + UCHAR RedBPP; + UCHAR GreenBPP; + UCHAR BlueBPP; + UCHAR ReservedBPP; + ULONG RsvdOffScrnMemSize; + ULONG RsvdOffScrnMEmPtr; + UCHAR Reserved[14]; +} VBE_FP_INFO; + +typedef struct _VESA_MODE_INFO_BLOCK +{ +// Mandatory information for all VBE revisions + USHORT ModeAttributes; // dw ? ; mode attributes + UCHAR WinAAttributes; // db ? ; window A attributes + UCHAR WinBAttributes; // db ? ; window B attributes + USHORT WinGranularity; // dw ? ; window granularity + USHORT WinSize; // dw ? ; window size + USHORT WinASegment; // dw ? ; window A start segment + USHORT WinBSegment; // dw ? ; window B start segment + ULONG WinFuncPtr; // dd ? ; real mode pointer to window function + USHORT BytesPerScanLine;// dw ? ; bytes per scan line + +//; Mandatory information for VBE 1.2 and above + USHORT XResolution; // dw ? ; horizontal resolution in pixels or characters + USHORT YResolution; // dw ? ; vertical resolution in pixels or characters + UCHAR XCharSize; // db ? ; character cell width in pixels + UCHAR YCharSize; // db ? ; character cell height in pixels + UCHAR NumberOfPlanes; // db ? ; number of memory planes + UCHAR BitsPerPixel; // db ? ; bits per pixel + UCHAR NumberOfBanks; // db ? ; number of banks + UCHAR MemoryModel; // db ? ; memory model type + UCHAR BankSize; // db ? ; bank size in KB + UCHAR NumberOfImagePages;// db ? ; number of images + UCHAR ReservedForPageFunction;//db 1 ; reserved for page function + +//; Direct Color fields(required for direct/6 and YUV/7 memory models) + UCHAR RedMaskSize; // db ? ; size of direct color red mask in bits + UCHAR RedFieldPosition; // db ? ; bit position of lsb of red mask + UCHAR GreenMaskSize; // db ? ; size of direct color green mask in bits + UCHAR GreenFieldPosition; // db ? ; bit position of lsb of green mask + UCHAR BlueMaskSize; // db ? ; size of direct color blue mask in bits + UCHAR BlueFieldPosition; // db ? ; bit position of lsb of blue mask + UCHAR RsvdMaskSize; // db ? ; size of direct color reserved mask in bits + UCHAR RsvdFieldPosition; // db ? ; bit position of lsb of reserved mask + UCHAR DirectColorModeInfo;// db ? ; direct color mode attributes + +//; Mandatory information for VBE 2.0 and above + ULONG PhysBasePtr; // dd ? ; physical address for flat memory frame buffer + ULONG Reserved_1; // dd 0 ; reserved - always set to 0 + USHORT Reserved_2; // dw 0 ; reserved - always set to 0 + +//; Mandatory information for VBE 3.0 and above + USHORT LinBytesPerScanLine; // dw ? ; bytes per scan line for linear modes + UCHAR BnkNumberOfImagePages;// db ? ; number of images for banked modes + UCHAR LinNumberOfImagPages; // db ? ; number of images for linear modes + UCHAR LinRedMaskSize; // db ? ; size of direct color red mask(linear modes) + UCHAR LinRedFieldPosition; // db ? ; bit position of lsb of red mask(linear modes) + UCHAR LinGreenMaskSize; // db ? ; size of direct color green mask(linear modes) + UCHAR LinGreenFieldPosition;// db ? ; bit position of lsb of green mask(linear modes) + UCHAR LinBlueMaskSize; // db ? ; size of direct color blue mask(linear modes) + UCHAR LinBlueFieldPosition; // db ? ; bit position of lsb of blue mask(linear modes) + UCHAR LinRsvdMaskSize; // db ? ; size of direct color reserved mask(linear modes) + UCHAR LinRsvdFieldPosition; // db ? ; bit position of lsb of reserved mask(linear modes) + ULONG MaxPixelClock; // dd ? ; maximum pixel clock(in Hz) for graphics mode + UCHAR Reserved; // db 190 dup (0) +} VESA_MODE_INFO_BLOCK; + +// BIOS function CALLS +#define ATOM_BIOS_EXTENDED_FUNCTION_CODE 0xA0 // ATI Extended Function code +#define ATOM_BIOS_FUNCTION_COP_MODE 0x00 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY1 0x04 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY2 0x05 +#define ATOM_BIOS_FUNCTION_SHORT_QUERY3 0x06 +#define ATOM_BIOS_FUNCTION_GET_DDC 0x0B +#define ATOM_BIOS_FUNCTION_ASIC_DSTATE 0x0E +#define ATOM_BIOS_FUNCTION_DEBUG_PLAY 0x0F +#define ATOM_BIOS_FUNCTION_STV_STD 0x16 +#define ATOM_BIOS_FUNCTION_DEVICE_DET 0x17 +#define ATOM_BIOS_FUNCTION_DEVICE_SWITCH 0x18 + +#define ATOM_BIOS_FUNCTION_PANEL_CONTROL 0x82 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET 0x83 +#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH 0x84 +#define ATOM_BIOS_FUNCTION_HW_ICON 0x8A +#define ATOM_BIOS_FUNCTION_SET_CMOS 0x8B +#define SUB_FUNCTION_UPDATE_DISPLAY_INFO 0x8000 // Sub function 80 +#define SUB_FUNCTION_UPDATE_EXPANSION_INFO 0x8100 // Sub function 80 + +#define ATOM_BIOS_FUNCTION_DISPLAY_INFO 0x8D +#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF 0x8E +#define ATOM_BIOS_FUNCTION_VIDEO_STATE 0x8F +#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE 0x0300 // Sub function 03 +#define ATOM_SUB_FUNCTION_GET_LIDSTATE 0x0700 // Sub function 7 +#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE 0x1400 // Notify caller the current thermal state +#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 // Notify caller the current critical state +#define ATOM_SUB_FUNCTION_SET_LIDSTATE 0x8500 // Sub function 85 +#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900// Sub function 89 +#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT 0x9400 // Notify caller that ADC is supported + + +#define ATOM_BIOS_FUNCTION_VESA_DPMS 0x4F10 // Set DPMS +#define ATOM_SUB_FUNCTION_SET_DPMS 0x0001 // BL: Sub function 01 +#define ATOM_SUB_FUNCTION_GET_DPMS 0x0002 // BL: Sub function 02 +#define ATOM_PARAMETER_VESA_DPMS_ON 0x0000 // BH Parameter for DPMS ON. +#define ATOM_PARAMETER_VESA_DPMS_STANDBY 0x0100 // BH Parameter for DPMS STANDBY +#define ATOM_PARAMETER_VESA_DPMS_SUSPEND 0x0200 // BH Parameter for DPMS SUSPEND +#define ATOM_PARAMETER_VESA_DPMS_OFF 0x0400 // BH Parameter for DPMS OFF +#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON 0x0800 // BH Parameter for DPMS REDUCE ON (NOT SUPPORTED) + +#define ATOM_BIOS_RETURN_CODE_MASK 0x0000FF00L +#define ATOM_BIOS_REG_HIGH_MASK 0x0000FF00L +#define ATOM_BIOS_REG_LOW_MASK 0x000000FFL + +// structure used for VBIOS only + +//DispOutInfoTable +typedef struct _ASIC_TRANSMITTER_INFO +{ + USHORT usTransmitterObjId; + USHORT usSupportDevice; + UCHAR ucTransmitterCmdTblId; + UCHAR ucConfig; + UCHAR ucEncoderID; //available 1st encoder ( default ) + UCHAR ucOptionEncoderID; //available 2nd encoder ( optional ) + UCHAR uc2ndEncoderID; + UCHAR ucReserved; +}ASIC_TRANSMITTER_INFO; + +typedef struct _ASIC_ENCODER_INFO +{ + UCHAR ucEncoderID; + UCHAR ucEncoderConfig; + USHORT usEncoderCmdTblId; +}ASIC_ENCODER_INFO; + +typedef struct _ATOM_DISP_OUT_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT ptrTransmitterInfo; + USHORT ptrEncoderInfo; + ASIC_TRANSMITTER_INFO asTransmitterInfo[1]; + ASIC_ENCODER_INFO asEncoderInfo[1]; +}ATOM_DISP_OUT_INFO; + +// DispDevicePriorityInfo +typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT asDevicePriority[16]; +}ATOM_DISPLAY_DEVICE_PRIORITY_INFO; + +//ProcessAuxChannelTransactionTable +typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS +{ + USHORT lpAuxRequest; + USHORT lpDataOut; + UCHAR ucChannelID; + union + { + UCHAR ucReplyStatus; + UCHAR ucDelay; + }; + UCHAR ucDataOutLen; + UCHAR ucReserved; +}PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS + +//GetSinkType + +typedef struct _DP_ENCODER_SERVICE_PARAMETERS +{ + USHORT ucLinkClock; + union + { + UCHAR ucConfig; // for DP training command + UCHAR ucI2cId; // use for GET_SINK_TYPE command + }; + UCHAR ucAction; + UCHAR ucStatus; + UCHAR ucLaneNum; + UCHAR ucReserved[2]; +}DP_ENCODER_SERVICE_PARAMETERS; + +// ucAction +#define ATOM_DP_ACTION_GET_SINK_TYPE 0x01 +#define ATOM_DP_ACTION_TRAINING_START 0x02 +#define ATOM_DP_ACTION_TRAINING_COMPLETE 0x03 +#define ATOM_DP_ACTION_TRAINING_PATTERN_SEL 0x04 +#define ATOM_DP_ACTION_SET_VSWING_PREEMP 0x05 +#define ATOM_DP_ACTION_GET_VSWING_PREEMP 0x06 +#define ATOM_DP_ACTION_BLANKING 0x07 + +// ucConfig +#define ATOM_DP_CONFIG_ENCODER_SEL_MASK 0x03 +#define ATOM_DP_CONFIG_DIG1_ENCODER 0x00 +#define ATOM_DP_CONFIG_DIG2_ENCODER 0x01 +#define ATOM_DP_CONFIG_EXTERNAL_ENCODER 0x02 +#define ATOM_DP_CONFIG_LINK_SEL_MASK 0x04 +#define ATOM_DP_CONFIG_LINK_A 0x00 +#define ATOM_DP_CONFIG_LINK_B 0x04 + +#define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS + +// DP_TRAINING_TABLE +#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR +#define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 ) +#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 16 ) +#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 24 ) +#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 32) +#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 40) +#define DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 48) +#define DP_I2C_AUX_DDC_WRITE_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 60) +#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 64) +#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 72) +#define DP_I2C_AUX_DDC_READ_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 76) +#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 80) + + +typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS +{ + UCHAR ucI2CSpeed; + union + { + UCHAR ucRegIndex; + UCHAR ucStatus; + }; + USHORT lpI2CDataOut; + UCHAR ucFlag; + UCHAR ucTransBytes; + UCHAR ucSlaveAddr; + UCHAR ucLineNumber; +}PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS; + +#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS + +//ucFlag +#define HW_I2C_WRITE 1 +#define HW_I2C_READ 0 + + +/****************************************************************************/ +//Portion VI: Definitinos being oboselete +/****************************************************************************/ + +//========================================================================================== +//Remove the definitions below when driver is ready! +typedef struct _ATOM_DAC_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; // in 10kHz unit + USHORT usReserved; +}ATOM_DAC_INFO; + + +typedef struct _COMPASSIONATE_DATA +{ + ATOM_COMMON_TABLE_HEADER sHeader; + + //============================== DAC1 portion + UCHAR ucDAC1_BG_Adjustment; + UCHAR ucDAC1_DAC_Adjustment; + USHORT usDAC1_FORCE_Data; + //============================== DAC2 portion + UCHAR ucDAC2_CRT2_BG_Adjustment; + UCHAR ucDAC2_CRT2_DAC_Adjustment; + USHORT usDAC2_CRT2_FORCE_Data; + USHORT usDAC2_CRT2_MUX_RegisterIndex; + UCHAR ucDAC2_CRT2_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_NTSC_BG_Adjustment; + UCHAR ucDAC2_NTSC_DAC_Adjustment; + USHORT usDAC2_TV1_FORCE_Data; + USHORT usDAC2_TV1_MUX_RegisterIndex; + UCHAR ucDAC2_TV1_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_CV_BG_Adjustment; + UCHAR ucDAC2_CV_DAC_Adjustment; + USHORT usDAC2_CV_FORCE_Data; + USHORT usDAC2_CV_MUX_RegisterIndex; + UCHAR ucDAC2_CV_MUX_RegisterInfo; //Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low + UCHAR ucDAC2_PAL_BG_Adjustment; + UCHAR ucDAC2_PAL_DAC_Adjustment; + USHORT usDAC2_TV2_FORCE_Data; +}COMPASSIONATE_DATA; + +/****************************Supported Device Info Table Definitions**********************/ +// ucConnectInfo: +// [7:4] - connector type +// = 1 - VGA connector +// = 2 - DVI-I +// = 3 - DVI-D +// = 4 - DVI-A +// = 5 - SVIDEO +// = 6 - COMPOSITE +// = 7 - LVDS +// = 8 - DIGITAL LINK +// = 9 - SCART +// = 0xA - HDMI_type A +// = 0xB - HDMI_type B +// = 0xE - Special case1 (DVI+DIN) +// Others=TBD +// [3:0] - DAC Associated +// = 0 - no DAC +// = 1 - DACA +// = 2 - DACB +// = 3 - External DAC +// Others=TBD +// + +typedef struct _ATOM_CONNECTOR_INFO +{ + UCHAR bfAssociatedDAC:4; + UCHAR bfConnectorType:4; +}ATOM_CONNECTOR_INFO; + +typedef union _ATOM_CONNECTOR_INFO_ACCESS +{ + ATOM_CONNECTOR_INFO sbfAccess; + UCHAR ucAccess; +}ATOM_CONNECTOR_INFO_ACCESS; + +typedef struct _ATOM_CONNECTOR_INFO_I2C +{ + ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; +}ATOM_CONNECTOR_INFO_I2C; + + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO]; +}ATOM_SUPPORTED_DEVICES_INFO; + +#define NO_INT_SRC_MAPPED 0xFF + +typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP +{ + UCHAR ucIntSrcBitmap; +}ATOM_CONNECTOR_INC_SRC_BITMAP; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2]; +}ATOM_SUPPORTED_DEVICES_INFO_2; + +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE]; +}ATOM_SUPPORTED_DEVICES_INFO_2d1; + +#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1 + + + +typedef struct _ATOM_MISC_CONTROL_INFO +{ + USHORT usFrequency; + UCHAR ucPLL_ChargePump; // PLL charge-pump gain control + UCHAR ucPLL_DutyCycle; // PLL duty cycle control + UCHAR ucPLL_VCO_Gain; // PLL VCO gain control + UCHAR ucPLL_VoltageSwing; // PLL driver voltage swing control +}ATOM_MISC_CONTROL_INFO; + + +#define ATOM_MAX_MISC_INFO 4 + +typedef struct _ATOM_TMDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usMaxFrequency; // in 10Khz + ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO]; +}ATOM_TMDS_INFO; + + +typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE +{ + UCHAR ucTVStandard; //Same as TV standards defined above, + UCHAR ucPadding[1]; +}ATOM_ENCODER_ANALOG_ATTRIBUTE; + +typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE +{ + UCHAR ucAttribute; //Same as other digital encoder attributes defined above + UCHAR ucPadding[1]; +}ATOM_ENCODER_DIGITAL_ATTRIBUTE; + +typedef union _ATOM_ENCODER_ATTRIBUTE +{ + ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib; + ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib; +}ATOM_ENCODER_ATTRIBUTE; + + +typedef struct _DVO_ENCODER_CONTROL_PARAMETERS +{ + USHORT usPixelClock; + USHORT usEncoderID; + UCHAR ucDeviceType; //Use ATOM_DEVICE_xxx1_Index to indicate device type only. + UCHAR ucAction; //ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT + ATOM_ENCODER_ATTRIBUTE usDevAttr; +}DVO_ENCODER_CONTROL_PARAMETERS; + +typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION +{ + DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder; + WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved; //Caller doesn't need to init this portion +}DVO_ENCODER_CONTROL_PS_ALLOCATION; + + +#define ATOM_XTMDS_ASIC_SI164_ID 1 +#define ATOM_XTMDS_ASIC_SI178_ID 2 +#define ATOM_XTMDS_ASIC_TFP513_ID 3 +#define ATOM_XTMDS_SUPPORTED_SINGLELINK 0x00000001 +#define ATOM_XTMDS_SUPPORTED_DUALLINK 0x00000002 +#define ATOM_XTMDS_MVPU_FPGA 0x00000004 + + +typedef struct _ATOM_XTMDS_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usSingleLinkMaxFrequency; + ATOM_I2C_ID_CONFIG_ACCESS sucI2cId; //Point the ID on which I2C is used to control external chip + UCHAR ucXtransimitterID; + UCHAR ucSupportedLink; // Bit field, bit0=1, single link supported;bit1=1,dual link supported + UCHAR ucSequnceAlterID; // Even with the same external TMDS asic, it's possible that the program seqence alters + // due to design. This ID is used to alert driver that the sequence is not "standard"! + UCHAR ucMasterAddress; // Address to control Master xTMDS Chip + UCHAR ucSlaveAddress; // Address to control Slave xTMDS Chip +}ATOM_XTMDS_INFO; + +typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS +{ + UCHAR ucEnable; // ATOM_ENABLE=On or ATOM_DISABLE=Off + UCHAR ucDevice; // ATOM_DEVICE_DFP1_INDEX.... + UCHAR ucPadding[2]; +}DFP_DPMS_STATUS_CHANGE_PARAMETERS; + +/****************************Legacy Power Play Table Definitions **********************/ + +//Definitions for ulPowerPlayMiscInfo +#define ATOM_PM_MISCINFO_SPLIT_CLOCK 0x00000000L +#define ATOM_PM_MISCINFO_USING_MCLK_SRC 0x00000001L +#define ATOM_PM_MISCINFO_USING_SCLK_SRC 0x00000002L + +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT 0x00000004L +#define ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH 0x00000008L + +#define ATOM_PM_MISCINFO_LOAD_PERFORMANCE_EN 0x00000010L + +#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN 0x00000020L +#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN 0x00000040L +#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE 0x00000080L //When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program + +#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN 0x00000100L +#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN 0x00000200L +#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN 0x00000400L +#define ATOM_PM_MISCINFO_LOAD_BALANCE_EN 0x00000800L +#define ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE 0x00001000L +#define ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE 0x00002000L +#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE 0x00004000L + +#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE 0x00008000L +#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE 0x00010000L +#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE 0x00020000L +#define ATOM_PM_MISCINFO_POWER_SAVING_MODE 0x00040000L +#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE 0x00080000L + +#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK 0x00300000L //0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved +#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT 20 + +#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE 0x00400000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2 0x00800000L +#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4 0x01000000L +#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN 0x02000000L //When set, Dynamic +#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN 0x04000000L //When set, Dynamic +#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN 0x08000000L //When set, This mode is for acceleated 3D mode + +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK 0x70000000L //1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks) +#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT 28 +#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS 0x80000000L + +#define ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE 0x00000001L +#define ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT 0x00000002L +#define ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN 0x00000004L +#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO 0x00000008L +#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE 0x00000010L +#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN 0x00000020L +#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE 0x00000040L //If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption. + //If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback +#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC 0x00000080L +#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN 0x00000100L +#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE 0x00000200L + +//ucTableFormatRevision=1 +//ucTableContentRevision=1 +typedef struct _ATOM_POWERMODE_INFO +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulReserved1; // must set to 0 + ULONG ulReserved2; // must set to 0 + USHORT usEngineClock; + USHORT usMemoryClock; + UCHAR ucVoltageDropIndex; // index to GPIO table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes +}ATOM_POWERMODE_INFO; + +//ucTableFormatRevision=2 +//ucTableContentRevision=1 +typedef struct _ATOM_POWERMODE_INFO_V2 +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; // index to GPIO table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes +}ATOM_POWERMODE_INFO_V2; + +//ucTableFormatRevision=2 +//ucTableContentRevision=2 +typedef struct _ATOM_POWERMODE_INFO_V3 +{ + ULONG ulMiscInfo; //The power level should be arranged in ascending order + ULONG ulMiscInfo2; + ULONG ulEngineClock; + ULONG ulMemoryClock; + UCHAR ucVoltageDropIndex; // index to Core (VDDC) votage table + UCHAR ucSelectedPanel_RefreshRate;// panel refresh rate + UCHAR ucMinTemperature; + UCHAR ucMaxTemperature; + UCHAR ucNumPciELanes; // number of PCIE lanes + UCHAR ucVDDCI_VoltageDropIndex; // index to VDDCI votage table +}ATOM_POWERMODE_INFO_V3; + + +#define ATOM_MAX_NUMBEROF_POWER_BLOCK 8 + +#define ATOM_PP_OVERDRIVE_INTBITMAP_AUXWIN 0x01 +#define ATOM_PP_OVERDRIVE_INTBITMAP_OVERDRIVE 0x02 + +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM63 0x01 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1032 0x02 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1030 0x03 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649 0x04 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64 0x05 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375 0x06 +#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512 0x07 // Andigilog + + +typedef struct _ATOM_POWERPLAY_INFO +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO; + +typedef struct _ATOM_POWERPLAY_INFO_V2 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO_V2; + +typedef struct _ATOM_POWERPLAY_INFO_V3 +{ + ATOM_COMMON_TABLE_HEADER sHeader; + UCHAR ucOverdriveThermalController; + UCHAR ucOverdriveI2cLine; + UCHAR ucOverdriveIntBitmap; + UCHAR ucOverdriveControllerAddress; + UCHAR ucSizeOfPowerModeEntry; + UCHAR ucNumOfPowerModeEntries; + ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK]; +}ATOM_POWERPLAY_INFO_V3; + + + +/**************************************************************************/ + + +// Following definitions are for compatiblity issue in different SW components. +#define ATOM_MASTER_DATA_TABLE_REVISION 0x01 +#define Object_Info Object_Header +#define AdjustARB_SEQ MC_InitParameter +#define VRAM_GPIO_DetectionInfo VoltageObjectInfo +#define ASIC_VDDCI_Info ASIC_ProfilingInfo +#define ASIC_MVDDQ_Info MemoryTrainingInfo +#define SS_Info PPLL_SS_Info +#define ASIC_MVDDC_Info ASIC_InternalSS_Info +#define DispDevicePriorityInfo SaveRestoreInfo +#define DispOutInfo TV_VideoMode + + +#define ATOM_ENCODER_OBJECT_TABLE ATOM_OBJECT_TABLE +#define ATOM_CONNECTOR_OBJECT_TABLE ATOM_OBJECT_TABLE + +//New device naming, remove them when both DAL/VBIOS is ready +#define DFP2I_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS + +#define DFP1X_OUTPUT_CONTROL_PARAMETERS CRT1_OUTPUT_CONTROL_PARAMETERS +#define DFP1X_OUTPUT_CONTROL_PS_ALLOCATION DFP1X_OUTPUT_CONTROL_PARAMETERS + +#define DFP1I_OUTPUT_CONTROL_PARAMETERS DFP1_OUTPUT_CONTROL_PARAMETERS +#define DFP1I_OUTPUT_CONTROL_PS_ALLOCATION DFP1_OUTPUT_CONTROL_PS_ALLOCATION + +#define ATOM_DEVICE_DFP1I_SUPPORT ATOM_DEVICE_DFP1_SUPPORT +#define ATOM_DEVICE_DFP1X_SUPPORT ATOM_DEVICE_DFP2_SUPPORT + +#define ATOM_DEVICE_DFP1I_INDEX ATOM_DEVICE_DFP1_INDEX +#define ATOM_DEVICE_DFP1X_INDEX ATOM_DEVICE_DFP2_INDEX + +#define ATOM_DEVICE_DFP2I_INDEX 0x00000009 +#define ATOM_DEVICE_DFP2I_SUPPORT (0x1L << ATOM_DEVICE_DFP2I_INDEX) + +#define ATOM_S0_DFP1I ATOM_S0_DFP1 +#define ATOM_S0_DFP1X ATOM_S0_DFP2 + +#define ATOM_S0_DFP2I 0x00200000L +#define ATOM_S0_DFP2Ib2 0x20 + +#define ATOM_S2_DFP1I_DPMS_STATE ATOM_S2_DFP1_DPMS_STATE +#define ATOM_S2_DFP1X_DPMS_STATE ATOM_S2_DFP2_DPMS_STATE + +#define ATOM_S2_DFP2I_DPMS_STATE 0x02000000L +#define ATOM_S2_DFP2I_DPMS_STATEb3 0x02 + +#define ATOM_S3_DFP2I_ACTIVEb1 0x02 + +#define ATOM_S3_DFP1I_ACTIVE ATOM_S3_DFP1_ACTIVE +#define ATOM_S3_DFP1X_ACTIVE ATOM_S3_DFP2_ACTIVE + +#define ATOM_S3_DFP2I_ACTIVE 0x00000200L + +#define ATOM_S3_DFP1I_CRTC_ACTIVE ATOM_S3_DFP1_CRTC_ACTIVE +#define ATOM_S3_DFP1X_CRTC_ACTIVE ATOM_S3_DFP2_CRTC_ACTIVE +#define ATOM_S3_DFP2I_CRTC_ACTIVE 0x02000000L + +#define ATOM_S3_DFP2I_CRTC_ACTIVEb3 0x02 +#define ATOM_S5_DOS_REQ_DFP2Ib1 0x02 + +#define ATOM_S5_DOS_REQ_DFP2I 0x0200 +#define ATOM_S6_ACC_REQ_DFP1I ATOM_S6_ACC_REQ_DFP1 +#define ATOM_S6_ACC_REQ_DFP1X ATOM_S6_ACC_REQ_DFP2 + +#define ATOM_S6_ACC_REQ_DFP2Ib3 0x02 +#define ATOM_S6_ACC_REQ_DFP2I 0x02000000L + +#define TMDS1XEncoderControl DVOEncoderControl +#define DFP1XOutputControl DVOOutputControl + +#define ExternalDFPOutputControl DFP1XOutputControl +#define EnableExternalTMDS_Encoder TMDS1XEncoderControl + +#define DFP1IOutputControl TMDSAOutputControl +#define DFP2IOutputControl LVTMAOutputControl + +#define DAC1_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define DAC2_ENCODER_CONTROL_PARAMETERS DAC_ENCODER_CONTROL_PARAMETERS +#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION + +#define ucDac1Standard ucDacStandard +#define ucDac2Standard ucDacStandard + +#define TMDS1EncoderControl TMDSAEncoderControl +#define TMDS2EncoderControl LVTMAEncoderControl + +#define DFP1OutputControl TMDSAOutputControl +#define DFP2OutputControl LVTMAOutputControl +#define CRT1OutputControl DAC1OutputControl +#define CRT2OutputControl DAC2OutputControl + +//These two lines will be removed for sure in a few days, will follow up with Michael V. +#define EnableLVDS_SS EnableSpreadSpectrumOnPPLL +#define ENABLE_LVDS_SS_PARAMETERS_V3 ENABLE_SPREAD_SPECTRUM_ON_PPLL + +/*********************************************************************************/ + +#pragma pack() // BIOS data must use byte aligment + +#endif /* _ATOMBIOS_H */ diff --git a/programs/system/drivers/rhd/AtomBios/includes/regsdef.h b/programs/system/drivers/rhd/AtomBios/includes/regsdef.h new file mode 100644 index 000000000..e557ac048 --- /dev/null +++ b/programs/system/drivers/rhd/AtomBios/includes/regsdef.h @@ -0,0 +1,25 @@ +/* + * Copyright 2006-2007 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. + */ + +//This is a dummy file used by driver-parser during compilation. +//Without this file, compatibility will be broken among ASICs and BIOs vs. driver +//James H. Apr. 22/03 diff --git a/programs/system/drivers/rhd/Xmd.h b/programs/system/drivers/rhd/Xmd.h new file mode 100644 index 000000000..8c70de94a --- /dev/null +++ b/programs/system/drivers/rhd/Xmd.h @@ -0,0 +1,203 @@ +/* $XFree86: xc/include/Xmd.h,v 3.18tsi Exp $ */ +/*********************************************************** + +Copyright 1987, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#ifndef XMD_H +#define XMD_H 1 +/* $Xorg: Xmd.h,v 1.4 2001/02/09 02:03:22 xorgcvs Exp $ */ +/* + * Xmd.h: MACHINE DEPENDENT DECLARATIONS. + */ + +/* + * Special per-machine configuration flags. + */ +#ifdef CRAY +#define WORD64 /* 64-bit architecture */ +#endif +#if defined (_LP64) || \ + defined(__alpha) || defined(__alpha__) || \ + defined(__ia64__) || defined(ia64) || \ + defined(__sparc64__) || \ + defined(__s390x__) || \ + (defined(__hppa__) && defined(__LP64__)) || \ + defined(__amd64__) || defined(amd64) || \ + defined(__powerpc64__) || \ + (defined(sgi) && (_MIPS_SZLONG == 64)) +#define LONG64 /* 32/64-bit architecture */ +#endif + +/* + * Stuff to handle large architecture machines; the constants were generated + * on a 32-bit machine and must coorespond to the protocol. + */ +#ifdef WORD64 +#define MUSTCOPY +#endif /* WORD64 */ + + +/* + * Definition of macro used to set constants for size of network structures; + * machines with preprocessors that can't handle all of the sz_ symbols + * can define this macro to be sizeof(x) if and only if their compiler doesn't + * pad out structures (esp. the xTextElt structure which contains only two + * one-byte fields). Network structures should always define sz_symbols. + * + * The sz_ prefix is used instead of something more descriptive so that the + * symbols are no more than 32 characters long (which causes problems for some + * compilers and preprocessors). + * + * The extra indirection in the __STDC__ case is to get macro arguments to + * expand correctly before the concatenation, rather than afterward. + */ +#if ((defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus)) && !defined(UNIXCPP)) || defined(ANSICPP) +#define _SIZEOF(x) sz_##x +#define SIZEOF(x) _SIZEOF(x) +#else +#define SIZEOF(x) sz_/**/x +#endif /* if ANSI C compiler else not */ + +/* + * Bitfield suffixes for the protocol structure elements, if you + * need them. Note that bitfields are not guarranteed to be signed + * (or even unsigned) according to ANSI C. + */ +#ifdef WORD64 +typedef long INT64; +typedef unsigned long CARD64; +#define B32 :32 +#define B16 :16 +#ifdef UNSIGNEDBITFIELDS +typedef unsigned int INT32; +typedef unsigned int INT16; +#else +#ifdef __STDC__ +typedef signed int INT32; +typedef signed int INT16; +#else +typedef int INT32; +typedef int INT16; +#endif +#endif +#else +#define B32 +#define B16 +#ifdef LONG64 +typedef long INT64; +typedef int INT32; +#else +typedef long INT32; +#endif +typedef short INT16; +#endif + +#if defined(__STDC__) || defined(sgi) || defined(AIXV3) +typedef signed char INT8; +#else +typedef char INT8; +#endif + +#ifdef LONG64 +typedef unsigned long CARD64; +typedef unsigned int CARD32; +#else +typedef unsigned long CARD32; +#endif +typedef unsigned short CARD16; +typedef unsigned char CARD8; + +typedef CARD32 BITS32; +typedef CARD16 BITS16; + +#ifndef I_NEED_OS2_H +typedef CARD8 BYTE; +typedef CARD8 BOOL; +#else +#define BYTE CARD8 +#define BOOL CARD8 +#endif + +/* + * definitions for sign-extending bitfields on 64-bit architectures + */ +#if defined(WORD64) && defined(UNSIGNEDBITFIELDS) +#define cvtINT8toInt(val) (((val) & 0x00000080) ? ((val) | 0xffffffffffffff00) : (val)) +#define cvtINT16toInt(val) (((val) & 0x00008000) ? ((val) | 0xffffffffffff0000) : (val)) +#define cvtINT32toInt(val) (((val) & 0x80000000) ? ((val) | 0xffffffff00000000) : (val)) +#define cvtINT8toShort(val) cvtINT8toInt(val) +#define cvtINT16toShort(val) cvtINT16toInt(val) +#define cvtINT32toShort(val) cvtINT32toInt(val) +#define cvtINT8toLong(val) cvtINT8toInt(val) +#define cvtINT16toLong(val) cvtINT16toInt(val) +#define cvtINT32toLong(val) cvtINT32toInt(val) +#else +#define cvtINT8toInt(val) (val) +#define cvtINT16toInt(val) (val) +#define cvtINT32toInt(val) (val) +#define cvtINT8toShort(val) (val) +#define cvtINT16toShort(val) (val) +#define cvtINT32toShort(val) (val) +#define cvtINT8toLong(val) (val) +#define cvtINT16toLong(val) (val) +#define cvtINT32toLong(val) (val) +#endif /* WORD64 and UNSIGNEDBITFIELDS */ + + + +#ifdef MUSTCOPY +/* + * This macro must not cast or else pointers will get aligned and be wrong + */ +#define NEXTPTR(p,t) (((char *) p) + SIZEOF(t)) +#else /* else not MUSTCOPY, this is used for 32-bit machines */ +/* + * this version should leave result of type (t *), but that should only be + * used when not in MUSTCOPY + */ +#define NEXTPTR(p,t) (((t *)(p)) + 1) +#endif /* MUSTCOPY - used machines whose C structs don't line up with proto */ + +#endif /* XMD_H */ diff --git a/programs/system/drivers/rhd/common.h b/programs/system/drivers/rhd/common.h new file mode 100644 index 000000000..f251cf8e5 --- /dev/null +++ b/programs/system/drivers/rhd/common.h @@ -0,0 +1,246 @@ + +//#define ATOM_BIOS 1 +//#define ATOM_BIOS_PARSER 1 + +#define OS_BASE 0x80000000 + +#include "xmd.h" + +#define NULL (void*)(0) + +#define FALSE 0 +#define TRUE 1 + +typedef void *pointer; + +typedef unsigned int Bool; + +typedef unsigned char u8_t; +typedef unsigned short u16_t; +typedef unsigned int u32_t; + +typedef unsigned int memType; +typedef unsigned int size_t; + +#define MAX_HSYNC 8 +#define MAX_VREFRESH 8 +#define INTERLACE_REFRESH_WEIGHT 1.5 +#define SYNC_TOLERANCE 0.01 /* 1 percent */ +#define CLOCK_TOLERANCE 2000 /* Clock matching tolerance (2MHz) */ + +typedef struct { float hi, lo; } range; + + +#define STDCALL __attribute__ ((stdcall)) __attribute__ ((dllimport)) +#define IMPORT __attribute__ ((dllimport)) + + +CARD32 STDCALL AllocKernelSpace(unsigned size)__asm__("AllocKernelSpace"); +void* STDCALL KernelAlloc(unsigned size)__asm__("KernelAlloc"); +int KernelFree(void *); + +CARD32 STDCALL MapIoMem(CARD32 Base,CARD32 size,CARD32 flags)__asm__("MapIoMem"); + +u8_t STDCALL PciRead8 (u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead8"); +u16_t STDCALL PciRead16(u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead16"); +u32_t STDCALL PciRead32(u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead32"); + +#define pciReadLong(tag, reg) \ + PciRead32(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg)) + +u32_t STDCALL PciWrite8 (u32_t bus, u32_t devfn, u32_t reg,u8_t val) __asm__("PciWrite8"); +u32_t STDCALL PciWrite16(u32_t bus, u32_t devfn, u32_t reg,u16_t val)__asm__("PciWrite16"); +u32_t STDCALL PciWrite32(u32_t bus, u32_t devfn, u32_t reg,u32_t val)__asm__("PciWrite32"); + +#define pciWriteLong(tag, reg, val) \ + PciWrite32(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg),(val)) + +void usleep(u32_t delay); + +/////////////////////////////////////////////////////////////////////////////// + +void *malloc(size_t); +void *calloc( size_t num, size_t size ); +void *realloc(void*, size_t); +void free(void*); + + +#define xalloc malloc +#define xnfalloc malloc + +#define xcalloc calloc +#define xnfcalloc calloc + +#define xrealloc realloc + +#define xfree free + +/////////////////////////////////////////////////////////////////////////////// + +void* memset(void *s, int c, size_t n); +void* memcpy(void * dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); + +size_t strlen(const char *str); +char* strcpy(char *to, const char *from); +char* strcat(char *s, const char *append); +char* strdup(const char *s); +char* strchr(const char *s, int c); +int strcmp(const char *s1, const char *s2); + +#define xstrdup strdup + +/////////////////////////////////////////////////////////////////////////////// + +int snprintf(char *s, size_t n, const char *format, ...); +int printf(const char* format, ...); +int dbg_open(char *path); +int dbgprintf(const char* format, ...); + +/////////////////////////////////////////////////////////////////////////////// + +/* These are possible return values for xf86CheckMode() and ValidMode() */ +typedef enum { + MODE_OK = 0, /* Mode OK */ + MODE_HSYNC, /* hsync out of range */ + MODE_VSYNC, /* vsync out of range */ + MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_BAD_WIDTH, /* requires an unsupported linepitch */ + MODE_NOMODE, /* no mode with a maching name */ + MODE_NO_INTERLACE, /* interlaced mode not supported */ + MODE_NO_DBLESCAN, /* doublescan mode not supported */ + MODE_NO_VSCAN, /* multiscan mode not supported */ + MODE_MEM, /* insufficient video memory */ + MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ + MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ + MODE_MEM_VIRT, /* insufficient video memory given virtual size */ + MODE_NOCLOCK, /* no fixed clock available */ + MODE_CLOCK_HIGH, /* clock required is too high */ + MODE_CLOCK_LOW, /* clock required is too low */ + MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ + MODE_BAD_HVALUE, /* horizontal timing was out of range */ + MODE_BAD_VVALUE, /* vertical timing was out of range */ + MODE_BAD_VSCAN, /* VScan value out of range */ + MODE_HSYNC_NARROW, /* horizontal sync too narrow */ + MODE_HSYNC_WIDE, /* horizontal sync too wide */ + MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ + MODE_HBLANK_WIDE, /* horizontal blanking too wide */ + MODE_VSYNC_NARROW, /* vertical sync too narrow */ + MODE_VSYNC_WIDE, /* vertical sync too wide */ + MODE_VBLANK_NARROW, /* vertical blanking too narrow */ + MODE_VBLANK_WIDE, /* vertical blanking too wide */ + MODE_PANEL, /* exceeds panel dimensions */ + MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ + MODE_ONE_WIDTH, /* only one width is supported */ + MODE_ONE_HEIGHT, /* only one height is supported */ + MODE_ONE_SIZE, /* only one resolution is supported */ + MODE_BAD = -2, /* unspecified reason */ + MODE_ERROR = -1 /* error condition */ +} ModeStatus; + +typedef enum { + V_PHSYNC = 0x0001, + V_NHSYNC = 0x0002, + V_PVSYNC = 0x0004, + V_NVSYNC = 0x0008, + V_INTERLACE = 0x0010, + V_DBLSCAN = 0x0020, + V_CSYNC = 0x0040, + V_PCSYNC = 0x0080, + V_NCSYNC = 0x0100, + V_HSKEW = 0x0200, /* hskew provided */ + V_BCAST = 0x0400, + V_PIXMUX = 0x1000, + V_DBLCLK = 0x2000, + V_CLKDIV2 = 0x4000 +} ModeFlags; + +# define M_T_DEFAULT 0x10 /* (VESA) default modes */ +# define M_T_USERDEF 0x20 /* One of the modes from the config file */ + + +/* Video mode */ +typedef struct _DisplayModeRec { + struct _DisplayModeRec * prev; + struct _DisplayModeRec * next; + char * name; /* identifier for the mode */ + ModeStatus status; + int type; + + /* These are the values that the user sees/provides */ + int Clock; /* pixel clock freq */ + int HDisplay; /* horizontal timing */ + int HSyncStart; + int HSyncEnd; + int HTotal; + int HSkew; + int VDisplay; /* vertical timing */ + int VSyncStart; + int VSyncEnd; + int VTotal; + int VScan; + int Flags; + + /* These are the values the hardware uses */ + int ClockIndex; + int SynthClock; /* Actual clock freq to + * be programmed */ + int CrtcHDisplay; + int CrtcHBlankStart; + int CrtcHSyncStart; + int CrtcHSyncEnd; + int CrtcHBlankEnd; + int CrtcHTotal; + int CrtcHSkew; + int CrtcVDisplay; + int CrtcVBlankStart; + int CrtcVSyncStart; + int CrtcVSyncEnd; + int CrtcVBlankEnd; + int CrtcVTotal; + Bool CrtcHAdjusted; + Bool CrtcVAdjusted; + int PrivSize; + CARD32* Private; + int PrivFlags; + + float HSync, VRefresh; +} DisplayModeRec, *DisplayModePtr; + +typedef struct +{ + unsigned short red, green, blue; +} LOCO; + + +static void __attribute__ ((always_inline)) +__clear (void * dst, unsigned len) +{ u32_t tmp; + asm __volatile__ + ( + "xor eax, eax \n\t" + "cld \n\t" + "rep stosb" + :"=c"(tmp),"=D"(tmp) + :"c"(len),"D"(dst) + :"memory","eax","cc" + ); +}; + +static int __attribute__ ((always_inline)) +abs (int i) +{ + return i < 0 ? -i : i; +}; + +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 + + + +#define max(x,y) (((y)>(x))?(y):(x)) +#define min(x,y) (((y)<(x))?(y):(x)) + diff --git a/programs/system/drivers/rhd/dbg.c b/programs/system/drivers/rhd/dbg.c new file mode 100644 index 000000000..c93157da7 --- /dev/null +++ b/programs/system/drivers/rhd/dbg.c @@ -0,0 +1,486 @@ + +#include "common.h" + +#pragma pack(push, 1) +typedef struct +{ + char sec; + char min; + char hour; + char rsv; +}detime_t; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct +{ + char day; + char month; + short year; +}dedate_t; +#pragma pack(pop) + + +#pragma pack(push, 1) +typedef struct +{ unsigned attr; + unsigned flags; + union + { + detime_t ctime; + unsigned cr_time; + }; + union + { + dedate_t cdate; + unsigned cr_date; + }; + union + { + detime_t atime; + unsigned acc_time; + }; + union + { + dedate_t adate; + unsigned acc_date; + }; + union + { + detime_t mtime; + unsigned mod_time; + }; + union + { + dedate_t mdate; + unsigned mod_date; + }; + unsigned size; + unsigned size_high; +} FILEINFO; +#pragma pack(pop) + +typedef struct +{ + char *path; + int offset; +} dbgfile_t; + +static dbgfile_t dbgfile; + +static void _SysMsgBoardStr(char *text) +{ + asm __volatile__ + ( + "call [DWORD PTR __imp__SysMsgBoardStr]" + : + :"S" (text) + ); +}; + +int get_fileinfo(const char *path,FILEINFO *info) +{ + int retval; + + asm __volatile__ + ( + "push 0 \n\t" + "push 0 \n\t" + "mov [esp+1], eax \n\t" + "push ebx \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push 5 \n\t" + "mov ebx, esp \n\t" + "mov eax, 70 \n\t" + "int 0x40 \n\t" + "add esp, 28 \n\t" + :"=eax" (retval) + :"a" (path), "b" (info) + ); + return retval; +}; + +int create_file(const char *path) +{ + int retval; + asm __volatile__( + "push 0 \n\t" + "push 0 \n\t" + "mov [esp+1], eax \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push 2 \n\t" + "mov ebx, esp \n\t" + "mov eax, 70 \n\t" + "int 0x40 \n\t" + "add esp, 28" + :"=eax" (retval) + :"a" (path) + ); + return retval; +}; + +int set_file_size(const char *path, unsigned size) +{ + int retval; + asm __volatile__( + "push 0 \n\t" + "push 0 \n\t" + "mov [esp+1], eax \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push 0 \n\t" + "push ebx \n\t" + "push 4 \n\t" + "mov ebx, esp \n\t" + "mov eax, 70 \n\t" + "int 0x40 \n\t" + "add esp, 28" + :"=eax" (retval) + :"a" (path), "b" (size) + ); + return retval; +}; + +int write_file(const char *path,const void *buff, + unsigned offset,unsigned count,unsigned *writes) +{ + int retval; + asm __volatile__ + ("push ebx \n\t" + "push 0 \n\t" + "push 0 \n\t" + "mov [esp+1], eax \n\t" + "push ebx \n\t" + "push edx \n\t" + "push 0 \n\t" + "push ecx \n\t" + "push 3 \n\t" + "mov ebx, esp \n\t" + "mov eax, 70 \n\t" + "int 0x40 \n\t" + "test esi, esi \n\t" + "jz 1f \n\t" + "mov [esi], ebx \n\t" +"1:" + "add esp, 28 \n\t" + "pop ebx" + :"=eax" (retval) + :"a"(path),"b"(buff),"c"(offset),"d"(count),"S"(writes) + ); + return retval; +}; + +char * _putc(char *s, int c) +{ + int i=0; + + switch(c) + { + case '\n': + *s++ = '\r'; + *s++ = '\n'; + + case '\r': + break; + + case '\t': + do + { + *s++ = ' '; + } + while (i % 8 != 0); + break; + default: + *s++ = c; + } + return s; +} + +char *print_string(char *buff, char* s) +{ + int i=0; + char c; + + while (c=*s++) + { + switch(c) + { + case '\r': + break; + + case '\n': + *buff++ = '\r'; + *buff++ = '\n'; + i=0; + + case '\t': + do + { + *buff++ = ' '; + i++; + } + while (i % 8 != 0); + break; + + default: + *buff++ = c; + i++; + }; + } + return buff; +} + +char *print_dec(char *buff,int val) +{ + char dbuff[16]; + int i = 14; + + dbuff[15] = '\0'; + do + { + dbuff[i] = (val % 10) + '0'; + val = val / 10; + i--; + } while(val); + + return print_string(buff, &dbuff[i+1]); +} + +const char hexchars[] = "0123456789ABCDEF"; + +char *print_hex(char *buff, u32_t val) +{ + int i; + for (i=sizeof(u32_t)*8-4; i >= 0; i -= 4) + buff = _putc(buff,hexchars[((u32_t)val >> i) & 0xF]); + return buff; +} + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +typedef __builtin_va_list __gnuc_va_list; +typedef __gnuc_va_list va_list; + +#define arg(x) va_arg (ap, u32_t) + +char txtbuf[128]; + +int printf(const char* format, ...) +{ + u32_t ret = 1; + u32_t i = 0; + char *sbuf = txtbuf; + + va_list ap; + + va_start (ap, format); + + if (format == 0) + return 0; + + while (*format) + { + switch (*(format)) + { + case '%': +next_fmt: + switch (*(++format)) + { + case 'l': case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + goto next_fmt; + + case 'c': + sbuf = _putc (sbuf,arg (i)); + break; + case 'd': + sbuf = print_dec (sbuf,arg (i)); + break; + case 'p': + case 'x': + sbuf = print_hex (sbuf,(u32_t) arg (i)); + break; + case 's': + sbuf = print_string (sbuf,(char*) arg (i)); + break; + default: + sbuf = print_string (sbuf,"?"); + break; + } + i++; + break; + + default: + sbuf = _putc (sbuf,*format); + break; + } + format++; + } + + va_end (ap); + *sbuf=0; + _SysMsgBoardStr(txtbuf); + return ret; +} + +int dbg_open(char *path) +{ + FILEINFO info; + + dbgfile.offset = 0; + + if(get_fileinfo(path,&info)) + { + if(!create_file(path)) + { + dbgfile.path = path; + return TRUE; + } + else + return FALSE; + }; + set_file_size(path, 0); + dbgfile.path = path; + dbgfile.offset = 0; + return TRUE; +}; + +int vsnprintf(char *s, size_t n, const char *format, va_list arg); + +int dbgprintf(const char* format, ...) +{ + unsigned writes; + + int len=0; +// char *sbuf = txtbuf; + + va_list ap; + + va_start(ap, format); + if (format) + len = vsnprintf(txtbuf, 128, format, ap); + va_end(ap); + + _SysMsgBoardStr(txtbuf); + + if(dbgfile.path) + { + write_file(dbgfile.path,txtbuf,dbgfile.offset,len,&writes); + dbgfile.offset+=writes; + }; + return len; +} + +int snprintf(char *s, size_t n, const char *format, ...) +{ + va_list ap; + int retval; + + va_start(ap, format); + retval = vsnprintf(s, n, format, ap); + va_end(ap); + + return retval; +} +/* +int snprintf(char *buf,int count, const char* format, ...) +{ + int len; + + // u32 ret = 1; + u32 i = 0; + char *sbuf = buf; + + va_list ap; + + va_start (ap, format); + + if (format == 0) + return 0; + + while (*format) + { + switch (*(format)) + { + case '%': +next_fmt: + switch (*(++format)) + { + case 'l': case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + goto next_fmt; + + case 'c': + sbuf = _putc (sbuf,arg (i)); + break; + case 'd': + sbuf = print_dec (sbuf,arg (i)); + break; + case 'p': + case 'x': + sbuf = print_hex (sbuf,(u32) arg (i)); + break; + case 's': + sbuf = print_string (sbuf,(char*) arg (i)); + break; + default: + sbuf = print_string (sbuf,"?"); + break; + } + i++; + break; + + default: + sbuf = _putc (sbuf,*format); + break; + } + format++; + } + + va_end (ap); + *sbuf=0; + len = sbuf-txtbuf; + + return len; +} +*/ + +char * +RhdAppendString(char *s1, const char *s2) +{ + + if (!s2) + return s1; + else + if (!s1) + return strdup(s2); + else + { + int len = strlen(s1) + strlen(s2) + 1; + char *result = (char *)malloc(len); + + if (!result) return s1; + + strcpy(result,s1); + strcat(result,s2); + free(s1); + return result; + } + + return 0; +} + + diff --git a/programs/system/drivers/rhd/edid.h b/programs/system/drivers/rhd/edid.h new file mode 100644 index 000000000..b1b4ba722 --- /dev/null +++ b/programs/system/drivers/rhd/edid.h @@ -0,0 +1,464 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/ddc/edid.h,v 1.6 2000/04/17 16:29:55 eich Exp $ */ + +/* edid.h: defines to parse an EDID block + * + * This file contains all information to interpret a standard EDIC block + * transmitted by a display device via DDC (Display Data Channel). So far + * there is no information to deal with optional EDID blocks. + * DDC is a Trademark of VESA (Video Electronics Standard Association). + * + * Copyright 1998 by Egbert Eich + */ + +#ifndef _EDID_H_ +#define _EDID_H_ + +#include "vdif.h" + +/* read complete EDID record */ +#define EDID1_LEN 128 +#define BITS_PER_BYTE 9 +#define NUM BITS_PER_BYTE*EDID1_LEN +#define HEADER 6 + +#define STD_TIMINGS 8 +#define DET_TIMINGS 4 + +#ifdef _PARSE_EDID_ + +/* header: 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 */ +#define HEADER_SECTION 0 +#define HEADER_LENGTH 8 + +/* vendor section */ +#define VENDOR_SECTION (HEADER_SECTION + HEADER_LENGTH) +#define V_MANUFACTURER 0 +#define V_PROD_ID (V_MANUFACTURER + 2) +#define V_SERIAL (V_PROD_ID + 2) +#define V_WEEK (V_SERIAL + 4) +#define V_YEAR (V_WEEK + 1) +#define VENDOR_LENGTH (V_YEAR + 1) + +/* EDID version */ +#define VERSION_SECTION (VENDOR_SECTION + VENDOR_LENGTH) +#define V_VERSION 0 +#define V_REVISION (V_VERSION + 1) +#define VERSION_LENGTH (V_REVISION + 1) + +/* display information */ +#define DISPLAY_SECTION (VERSION_SECTION + VERSION_LENGTH) +#define D_INPUT 0 +#define D_HSIZE (D_INPUT + 1) +#define D_VSIZE (D_HSIZE + 1) +#define D_GAMMA (D_VSIZE + 1) +#define FEAT_S (D_GAMMA + 1) +#define D_RG_LOW (FEAT_S + 1) +#define D_BW_LOW (D_RG_LOW + 1) +#define D_REDX (D_BW_LOW + 1) +#define D_REDY (D_REDX + 1) +#define D_GREENX (D_REDY + 1) +#define D_GREENY (D_GREENX + 1) +#define D_BLUEX (D_GREENY + 1) +#define D_BLUEY (D_BLUEX + 1) +#define D_WHITEX (D_BLUEY + 1) +#define D_WHITEY (D_WHITEX + 1) +#define DISPLAY_LENGTH (D_WHITEY + 1) + +/* supported VESA and other standard timings */ +#define ESTABLISHED_TIMING_SECTION (DISPLAY_SECTION + DISPLAY_LENGTH) +#define E_T1 0 +#define E_T2 (E_T1 + 1) +#define E_TMANU (E_T2 + 1) +#define E_TIMING_LENGTH (E_TMANU + 1) + +/* non predefined standard timings supported by display */ +#define STD_TIMING_SECTION (ESTABLISHED_TIMING_SECTION + E_TIMING_LENGTH) +#define STD_TIMING_INFO_LEN 2 +#define STD_TIMING_INFO_NUM STD_TIMINGS +#define STD_TIMING_LENGTH (STD_TIMING_INFO_LEN * STD_TIMING_INFO_NUM) + +/* detailed timing info of non standard timings */ +#define DET_TIMING_SECTION (STD_TIMING_SECTION + STD_TIMING_LENGTH) +#define DET_TIMING_INFO_LEN 18 +#define MONITOR_DESC_LEN DET_TIMING_INFO_LEN +#define DET_TIMING_INFO_NUM DET_TIMINGS +#define DET_TIMING_LENGTH (DET_TIMING_INFO_LEN * DET_TIMING_INFO_NUM) + +/* number of EDID sections to follow */ +#define NO_EDID (DET_TIMING_SECTION + DET_TIMING_LENGTH) +/* one byte checksum */ +#define CHECKSUM (NO_EDID + 1) + +#if (CHECKSUM != (EDID1_LEN - 1)) +# error "EDID1 length != 128!" +#endif + + +#define SECTION(x,y) (Uchar *)(x + y) +#define GET_ARRAY(y) ((Uchar *)(c + y)) +#define GET(y) *(Uchar *)(c + y) + +/* extract information from vendor section */ +#define _PROD_ID(x) x[0] + (x[1] << 8); +#define PROD_ID _PROD_ID(GET_ARRAY(V_PROD_ID)) +#define _SERIAL_NO(x) x[0] + (x[1] << 8) + (x[2] << 16) + (x[3] << 24) +#define SERIAL_NO _SERIAL_NO(GET_ARRAY(V_SERIAL)) +#define _YEAR(x) (x & 0xFF) + 1990 +#define YEAR _YEAR(GET(V_YEAR)) +#define WEEK GET(V_WEEK) & 0xFF +#define _L1(x) ((x[0] & 0x7C) >> 2) + '@' +#define _L2(x) ((x[0] & 0x03) << 3) + ((x[1] & 0xE0) >> 5) + '@' +#define _L3(x) (x[1] & 0x1F) + '@'; +#define L1 _L1(GET_ARRAY(V_MANUFACTURER)) +#define L2 _L2(GET_ARRAY(V_MANUFACTURER)) +#define L3 _L3(GET_ARRAY(V_MANUFACTURER)) + +/* extract information from version section */ +#define VERSION GET(V_VERSION) +#define REVISION GET(V_REVISION) + +/* extract information from display section */ +#define _INPUT_TYPE(x) ((x & 0x80) >> 7) +#define INPUT_TYPE _INPUT_TYPE(GET(D_INPUT)) +#define _INPUT_VOLTAGE(x) ((x & 0x60) >> 5) +#define INPUT_VOLTAGE _INPUT_VOLTAGE(GET(D_INPUT)) +#define _SETUP(x) ((x & 0x10) >> 4) +#define SETUP _SETUP(GET(D_INPUT)) +#define _SYNC(x) (x & 0x0F) +#define SYNC _SYNC(GET(D_INPUT)) +#define _DFP(x) (x & 0x01) +#define DFP _DFP(GET(D_INPUT)) +#define _GAMMA(x) (x == 0xff ? 1.0 : ((x + 100.0)/100.0)) +#define GAMMA _GAMMA(GET(D_GAMMA)) +#define HSIZE_MAX GET(D_HSIZE) +#define VSIZE_MAX GET(D_VSIZE) +#define _DPMS(x) ((x & 0xE0) >> 5) +#define DPMS _DPMS(GET(FEAT_S)) +#define _DISPLAY_TYPE(x) ((x & 0x18) >> 3) +#define DISPLAY_TYPE _DISPLAY_TYPE(GET(FEAT_S)) +#define _MSC(x) (x & 0x7) +#define MSC _MSC(GET(FEAT_S)) + + +/* color characteristics */ +#define CC_L(x,y) ((x & (0x03 << y)) >> y) +#define CC_H(x) (x << 2) +#define I_CC(x,y,z) CC_H(y) | CC_L(x,z) +#define F_CC(x) ((x)/1024.0) +#define REDX F_CC(I_CC((GET(D_RG_LOW)),(GET(D_REDX)),6)) +#define REDY F_CC(I_CC((GET(D_RG_LOW)),(GET(D_REDY)),4)) +#define GREENX F_CC(I_CC((GET(D_RG_LOW)),(GET(D_GREENX)),2)) +#define GREENY F_CC(I_CC((GET(D_RG_LOW)),(GET(D_GREENY)),0)) +#define BLUEX F_CC(I_CC((GET(D_BW_LOW)),(GET(D_BLUEX)),6)) +#define BLUEY F_CC(I_CC((GET(D_BW_LOW)),(GET(D_BLUEY)),4)) +#define WHITEX F_CC(I_CC((GET(D_BW_LOW)),(GET(D_WHITEX)),2)) +#define WHITEY F_CC(I_CC((GET(D_BW_LOW)),(GET(D_WHITEY)),0)) + +/* extract information from standard timing section */ +#define T1 GET(E_T1) +#define T2 GET(E_T2) +#define T_MANU GET(E_TMANU) + +/* extract information from estabished timing section */ +#define _VALID_TIMING(x) !(((x[0] == 0x01) && (x[1] == 0x01)) \ + || ((x[0] == 0x00) && (x[1] == 0x00)) \ + || ((x[0] == 0x20) && (x[1] == 0x20)) ) + +#define VALID_TIMING _VALID_TIMING(c) +#define _HSIZE1(x) ((x[0] + 31) * 8) +#define HSIZE1 _HSIZE1(c) +#define RATIO(x) ((x[1] & 0xC0) >> 6) +#define RATIO1_1 0 +/* EDID Ver. 1.3 redefined this */ +#define RATIO16_10 RATIO1_1 +#define RATIO4_3 1 +#define RATIO5_4 2 +#define RATIO16_9 3 +#define _VSIZE1(x,y,r) switch(RATIO(x)){ \ + case RATIO1_1: y = ((v->version > 1 || v->revision > 2) \ + ? (_HSIZE1(x) * 10) / 16 : _HSIZE1(x)); break; \ + case RATIO4_3: y = _HSIZE1(x) * 3 / 4; break; \ + case RATIO5_4: y = _HSIZE1(x) * 4 / 5; break; \ + case RATIO16_9: y = _HSIZE1(x) * 9 / 16; break; \ + } +#define VSIZE1(x) _VSIZE1(c,x,v) +#define _REFRESH_R(x) (x[1] & 0x3F) + 60 +#define REFRESH_R _REFRESH_R(c) +#define _ID_LOW(x) x[0] +#define ID_LOW _ID_LOW(c) +#define _ID_HIGH(x) (x[1] << 8) +#define ID_HIGH _ID_HIGH(c) +#define STD_TIMING_ID (ID_LOW | ID_HIGH) +#define _NEXT_STD_TIMING(x) (x = (x + STD_TIMING_INFO_LEN)) +#define NEXT_STD_TIMING _NEXT_STD_TIMING(c) + + +/* EDID Ver. >= 1.2 */ +#define _IS_MONITOR_DESC(x) (x[0] == 0 && x[1] == 0 && x[2] == 0 && x[4] == 0) +#define IS_MONITOR_DESC _IS_MONITOR_DESC(c) +#define _PIXEL_CLOCK(x) (x[0] + (x[1] << 8)) * 10000 +#define PIXEL_CLOCK _PIXEL_CLOCK(c) +#define _H_ACTIVE(x) (x[2] + ((x[4] & 0xF0) << 4)) +#define H_ACTIVE _H_ACTIVE(c) +#define _H_BLANK(x) (x[3] + ((x[4] & 0x0F) << 8)) +#define H_BLANK _H_BLANK(c) +#define _V_ACTIVE(x) (x[5] + ((x[7] & 0xF0) << 4)) +#define V_ACTIVE _V_ACTIVE(c) +#define _V_BLANK(x) (x[6] + ((x[7] & 0x0F) << 8)) +#define V_BLANK _V_BLANK(c) +#define _H_SYNC_OFF(x) (x[8] + ((x[11] & 0xC0) << 2)) +#define H_SYNC_OFF _H_SYNC_OFF(c) +#define _H_SYNC_WIDTH(x) (x[9] + ((x[11] & 0x30) << 4)) +#define H_SYNC_WIDTH _H_SYNC_WIDTH(c) +#define _V_SYNC_OFF(x) ((x[10] >> 4) + ((x[11] & 0x0C) << 2)) +#define V_SYNC_OFF _V_SYNC_OFF(c) +#define _V_SYNC_WIDTH(x) ((x[10] & 0x0F) + ((x[11] & 0x03) << 4)) +#define V_SYNC_WIDTH _V_SYNC_WIDTH(c) +#define _H_SIZE(x) (x[12] + ((x[14] & 0xF0) << 4)) +#define H_SIZE _H_SIZE(c) +#define _V_SIZE(x) (x[13] + ((x[14] & 0x0F) << 8)) +#define V_SIZE _V_SIZE(c) +#define _H_BORDER(x) (x[15]) +#define H_BORDER _H_BORDER(c) +#define _V_BORDER(x) (x[16]) +#define V_BORDER _V_BORDER(c) +#define _INTERLACED(x) ((x[17] & 0x80) >> 7) +#define INTERLACED _INTERLACED(c) +#define _STEREO(x) ((x[17] & 0x60) >> 5) +#define STEREO _STEREO(c) +#define _STEREO1(x) (x[17] & 0x1) +#define STEREO1 _STEREO(c) +#define _SYNC_T(x) ((x[17] & 0x18) >> 4) +#define SYNC_T _SYNC_T(c) +#define _MISC(x) ((x[17] & 0x06) >> 2) +#define MISC _MISC(c) + +#define _MONITOR_DESC_TYPE(x) x[3] +#define MONITOR_DESC_TYPE _MONITOR_DESC_TYPE(c) +#define SERIAL_NUMBER 0xFF +#define ASCII_STR 0xFE +#define MONITOR_RANGES 0xFD +#define _MIN_V(x) x[5] +#define MIN_V _MIN_V(c) +#define _MAX_V(x) x[6] +#define MAX_V _MAX_V(c) +#define _MIN_H(x) x[7] +#define MIN_H _MIN_H(c) +#define _MAX_H(x) x[8] +#define MAX_H _MAX_H(c) +#define _MAX_CLOCK(x) x[9] +#define MAX_CLOCK _MAX_CLOCK(c) +#define _HAVE_2ND_GTF(x) (x[10] == 0x02) +#define HAVE_2ND_GTF _HAVE_2ND_GTF(c) +#define _F_2ND_GTF(x) (x[12] * 2) +#define F_2ND_GTF _F_2ND_GTF(c) +#define _C_2ND_GTF(x) (x[13] / 2) +#define C_2ND_GTF _C_2ND_GTF(c) +#define _M_2ND_GTF(x) (x[14] + (x[15] << 8)) +#define M_2ND_GTF _M_2ND_GTF(c) +#define _K_2ND_GTF(x) (x[16]) +#define K_2ND_GTF _K_2ND_GTF(c) +#define _J_2ND_GTF(x) (x[17] / 2) +#define J_2ND_GTF _J_2ND_GTF(c) +#define MONITOR_NAME 0xFC +#define ADD_COLOR_POINT 0xFB +#define WHITEX F_CC(I_CC((GET(D_BW_LOW)),(GET(D_WHITEX)),2)) +#define WHITEY F_CC(I_CC((GET(D_BW_LOW)),(GET(D_WHITEY)),0)) +#define _WHITEX_ADD(x,y) F_CC(I_CC(((*(x + y))),(*(x + y + 1)),2)) +#define _WHITEY_ADD(x,y) F_CC(I_CC(((*(x + y))),(*(x + y + 2)),0)) +#define _WHITE_INDEX1(x) x[5] +#define WHITE_INDEX1 _WHITE_INDEX1(c) +#define _WHITE_INDEX2(x) x[10] +#define WHITE_INDEX2 _WHITE_INDEX2(c) +#define WHITEX1 _WHITEX_ADD(c,6) +#define WHITEY1 _WHITEY_ADD(c,6) +#define WHITEX2 _WHITEX_ADD(c,12) +#define WHITEY2 _WHITEY_ADD(c,12) +#define _WHITE_GAMMA1(x) _GAMMA(x[9]) +#define WHITE_GAMMA1 _WHITE_GAMMA1(c) +#define _WHITE_GAMMA2(x) _GAMMA(x[14]) +#define WHITE_GAMMA2 _WHITE_GAMMA2(c) +#define ADD_STD_TIMINGS 0xFA +#define ADD_DUMMY 0x10 + +#define _NEXT_DT_MD_SECTION(x) (x = (x + DET_TIMING_INFO_LEN)) +#define NEXT_DT_MD_SECTION _NEXT_DT_MD_SECTION(c) + +#endif /* _PARSE_EDID_ */ + +/* input type */ +#define DIGITAL(x) x + +/* DFP */ +#define DFP1(x) x + +/* input voltage level */ +#define V070 0 /* 0.700V/0.300V */ +#define V071 1 /* 0.714V/0.286V */ +#define V100 2 /* 1.000V/0.400V */ +#define V007 3 /* 0.700V/0.000V */ + +/* Signal level setup */ +#define SIG_SETUP(x) (x) + +/* sync characteristics */ +#define SEP_SYNC(x) (x & 0x08) +#define COMP_SYNC(x) (x & 0x04) +#define SYNC_O_GREEN(x) (x & 0x02) +#define SYNC_SERR(x) (x & 0x01) + +/* DPMS features */ +#define DPMS_STANDBY(x) (x & 0x04) +#define DPMS_SUSPEND(x) (x & 0x02) +#define DPMS_OFF(x) (x & 0x01) + +/* display type */ +#define DISP_MONO 0 +#define DISP_RGB 1 +#define DISP_MULTCOLOR 2 + +/* Msc stuff EDID Ver > 1.1 */ +#define STD_COLOR_SPACE(x) (x & 0x4) +#define PREFERRED_TIMING_MODE(x) (x & 0x2) +#define GFT_SUPPORTED(x) (x & 0x1) + +/* detailed timing misc */ +#define IS_INTERLACED(x) (x) +#define IS_STEREO(x) (x) +#define IS_RIGHT_STEREO(x) (x & 0x01) +#define IS_LEFT_STEREO(x) (x & 0x02) +#define IS_4WAY_STEREO(x) (x & 0x03) +#define IS_RIGHT_ON_SYNC(x) IS_RIGHT_STEREO(x) +#define IS_LEFT_ON_SYNC(x) IS_LEFT_STEREO(x) + + +typedef unsigned int Uint; +typedef unsigned char Uchar; + +struct vendor { + char name[4]; + int prod_id; + Uint serial; + int week; + int year; +}; + +struct edid_version { + int version; + int revision; +}; + +struct disp_features { + unsigned int input_type:1; + unsigned int input_voltage:2; + unsigned int input_setup:1; + unsigned int input_sync:5; + unsigned int input_dfp:1; + int hsize; + int vsize; + float gamma; + unsigned int dpms:3; + unsigned int display_type:2; + unsigned int msc:3; + float redx; + float redy; + float greenx; + float greeny; + float bluex; + float bluey; + float whitex; + float whitey; +}; + +struct established_timings { + Uchar t1; + Uchar t2; + Uchar t_manu; +}; + +struct std_timings { + int hsize; + int vsize; + int refresh; + CARD16 id; +}; + +struct detailed_timings { + int clock; + int h_active; + int h_blanking; + int v_active; + int v_blanking; + int h_sync_off; + int h_sync_width; + int v_sync_off; + int v_sync_width; + int h_size; + int v_size; + int h_border; + int v_border; + unsigned int interlaced:1; + unsigned int stereo:2; + unsigned int sync:2; + unsigned int misc:2; + unsigned int stereo_1:1; +}; + +#define DT 0 +#define DS_SERIAL 0xFF +#define DS_ASCII_STR 0xFE +#define DS_NAME 0xFC +#define DS_RANGES 0xFD +#define DS_WHITE_P 0xFB +#define DS_STD_TIMINGS 0xFA +#define DS_DUMMY 0x10 + +struct monitor_ranges { + int min_v; + int max_v; + int min_h; + int max_h; + int max_clock; + int gtf_2nd_f; + int gtf_2nd_c; + int gtf_2nd_m; + int gtf_2nd_k; + int gtf_2nd_j; +}; + +struct whitePoints{ + int index; + float white_x; + float white_y; + float white_gamma; +}; + +struct detailed_monitor_section { + int type; + union { + struct detailed_timings d_timings; + Uchar serial[13]; + Uchar ascii_data[13]; + Uchar name[13]; + struct monitor_ranges ranges; + struct std_timings std_t[5]; + struct whitePoints wp[2]; + } section; +}; + +typedef struct { + RHDPtr rhdPtr; + struct vendor vendor; + struct edid_version ver; + struct disp_features features; + struct established_timings timings1; + struct std_timings timings2[8]; + struct detailed_monitor_section det_mon[4]; + xf86vdifPtr vdif; + int no_sections; + Uchar *rawData; +} xf86Monitor, *xf86MonPtr; + +extern xf86MonPtr ConfiguredMonitor; + +#endif /* _EDID_H_ */ diff --git a/programs/system/drivers/rhd/loc_incl.h b/programs/system/drivers/rhd/loc_incl.h new file mode 100644 index 000000000..188d40bdd --- /dev/null +++ b/programs/system/drivers/rhd/loc_incl.h @@ -0,0 +1,40 @@ +/* + * loc_incl.h - local include file for stdio library + */ +/* $Header$ */ + +//#include + +#define io_testflag(p,x) ((p)->_flags & (x)) + +#include + +#ifdef _ANSI +int _doprnt(const char *format, va_list ap, FILE *stream); +int _doscan(FILE * stream, const char *format, va_list ap); +char *_i_compute(unsigned long val, int base, char *s, int nrdigits); +char *_f_print(va_list *ap, int flags, char *s, char c, int precision); +void __cleanup(void); + +FILE *popen(const char *command, const char *type); +FILE *fdopen(int fd, const char *mode); + +#ifndef NOFLOAT +char *_ecvt(long double value, int ndigit, int *decpt, int *sign); +char *_fcvt(long double value, int ndigit, int *decpt, int *sign); +#endif /* NOFLOAT */ +#endif + +#define FL_LJUST 0x0001 /* left-justify field */ +#define FL_SIGN 0x0002 /* sign in signed conversions */ +#define FL_SPACE 0x0004 /* space in signed conversions */ +#define FL_ALT 0x0008 /* alternate form */ +#define FL_ZEROFILL 0x0010 /* fill with zero's */ +#define FL_SHORT 0x0020 /* optional h */ +#define FL_LONG 0x0040 /* optional l */ +#define FL_LONGDOUBLE 0x0080 /* optional L */ +#define FL_WIDTHSPEC 0x0100 /* field width is specified */ +#define FL_PRECSPEC 0x0200 /* precision is specified */ +#define FL_SIGNEDCONV 0x0400 /* may contain a sign */ +#define FL_NOASSIGN 0x0800 /* do not assign (in scanf) */ +#define FL_NOMORE 0x1000 /* all flags collected */ diff --git a/programs/system/drivers/rhd/makefile b/programs/system/drivers/rhd/makefile new file mode 100644 index 000000000..69f2c0f40 --- /dev/null +++ b/programs/system/drivers/rhd/makefile @@ -0,0 +1,116 @@ + +CC = gcc +FASM = e:/fasm/fasm.exe +CFLAGS = -c -Os -fomit-frame-pointer -fno-builtin-printf +LDCORE = -shared -s --file-alignment 32 --output-def core.def --out-implib core.lib +LDRHD = -shared -T ld.x -s --file-alignment 32 + +CORE_SRC:= core.asm + +HFILES:= common.h \ + rhd.h \ + rhd_card.h \ + rhd_connector.h \ + rhd_output.h \ + rhd_mc.h \ + rhd_hdmi.h \ + pci.h + +RHD_SRC:= rhd.c \ + rhd_id.c \ + rhd_mem.c \ + rhd_vga.c \ + rhd_mc.c \ + rhd_crtc.c \ + rhd_dac.c \ + rhd_pll.c \ + rhd_lut.c \ + rhd_atombios.c \ + rhd_atomout.c \ + rhd_biosscratch.c \ + rhd_atomcrtc.c \ + rhd_atompll.c \ + rhd_i2c.c \ + rhd_edid.c \ + rhd_connector.c \ + rhd_ddia.c \ + rhd_dig.c \ + rhd_monitor.c \ + rhd_modes.c \ + rhd_output.c \ + rhd_lvtma.c \ + rhd_tmds.c \ + rhd_hdmi.c \ + xf86i2c.c \ + string.c \ + malloc.c \ + vsprintf.c \ + memset.asm \ + s_ceilf.asm \ + dbg.c \ + pci.c + +DBG_DEFINES = -DDBG_NONE + +ATOM_BIOS_PARSER_SRCS = rhd_atomwrapper.c \ + AtomBios/CD_Operations.c \ + AtomBios/Decoder.c \ + AtomBios/hwserv_drv.c + +ATOM_BIOS_PARSER_OBJS = rhd_atomwrapper.obj \ + AtomBios/CD_Operations.obj \ + AtomBios/Decoder.obj \ + AtomBios/hwserv_drv.obj + +ATOM_BIOS_INCLUDES = -I ./AtomBios/includes +ATOM_BIOS_DEFINES = -DATOM_BIOS=1 +ATOM_BIOS_PARSER_INCLUDES = -I./AtomBios +ATOM_BIOS_PARSER_DEFINES = -DDRIVER_PARSER \ + -DDISABLE_EASF \ + -DENABLE_ALL_SERVICE_FUNCTIONS \ + -DATOM_BIOS_PARSER=1 + +DEFINES = $(INCLUDES) $(ATOM_BIOS_INCLUDES) \ + $(ATOM_BIOS_PARSER_INCLUDES) $(ATOM_BIOS_DEFINES)\ + $(ATOM_BIOS_PARSER_DEFINES) $(DBG_DEFINES) + +CORE_OBJS = $(patsubst %.s, %.obj, $(patsubst %.asm, %.obj,\ + $(patsubst %.c, %.obj, $(CORE_SRC)))) + +RHD_OBJS = $(patsubst %.s, %.obj, $(patsubst %.asm, %.obj,\ + $(patsubst %.c, %.obj, $(RHD_SRC)))) + + +RHD = rhd.exe +CORE = core.dll + +all: $(CORE) $(RHD) + + +$(RHD): $(RHD_OBJS) $(ATOM_BIOS_PARSER_OBJS) Makefile + wmake -f rhd.mk + +$(CORE): $(CORE_OBJS) Makefile + ld $(LDCORE) -o $@ $(CORE_OBJS) + +rhd_crtc.obj : rhd_crtc.c + $(CC) $(CFLAGS) $(DEFINES) -o $@ -c $< + +malloc.obj : malloc.c + $(CC) $(CFLAGS) $(DEFINES) -o $@ -c $< + +rhd_monitor.obj : rhd_monitor.c + $(CC) $(CFLAGS) $(DEFINES) -o $@ -c $< + +xf86i2c.obj : xf86i2c.c + $(CC) $(CFLAGS) $(DEFINES) -o $@ -c $< + +string.obj : string.c + $(CC) $(CFLAGS) $(DEFINES) -o $@ -c $< + +%.obj : %.c $(HFILES) + $(CC) $(CFLAGS) -masm=intel $(DEFINES) -o $@ -c $< + +%.obj: %.asm + as -o $@ $< + diff --git a/programs/system/drivers/rhd/malloc.c b/programs/system/drivers/rhd/malloc.c new file mode 100644 index 000000000..2c2f4793a --- /dev/null +++ b/programs/system/drivers/rhd/malloc.c @@ -0,0 +1,3966 @@ +/* + This is a version (aka dlmalloc) of malloc/free/realloc written by + Doug Lea and released to the public domain, as explained at + http://creativecommons.org/licenses/publicdomain. Send questions, + comments, complaints, performance data, etc to dl@cs.oswego.edu + +* Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://gee.cs.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Quickstart + + This library is all in one file to simplify the most common usage: + ftp it, compile it (-O3), and link it into another program. All of + the compile-time options default to reasonable values for use on + most platforms. You might later want to step through various + compile-time and dynamic tuning options. + + For convenience, an include file for code using this malloc is at: + ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.3.h + You don't really need this .h file unless you call functions not + defined in your system include files. The .h file contains only the + excerpts from this file needed for using this malloc on ANSI C/C++ + systems, so long as you haven't changed compile-time options about + naming and tuning parameters. If you do, then you can create your + own malloc.h that does include all settings by cutting at the point + indicated below. Note that you may already by default be using a C + library containing a malloc that is based on some version of this + malloc (for example in linux). You might still want to use the one + in this file to customize settings or to avoid overheads associated + with library versions. + +* Vital statistics: + + Supported pointer/size_t representation: 4 or 8 bytes + size_t MUST be an unsigned type of the same width as + pointers. (If you are using an ancient system that declares + size_t as a signed type, or need it to be a different width + than pointers, you can use a previous release of this malloc + (e.g. 2.7.2) supporting these.) + + Alignment: 8 bytes (default) + This suffices for nearly all current machines and C compilers. + However, you can define MALLOC_ALIGNMENT to be wider than this + if necessary (up to 128bytes), at the expense of using more space. + + Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) + 8 or 16 bytes (if 8byte sizes) + Each malloced chunk has a hidden word of overhead holding size + and status information, and additional cross-check word + if FOOTERS is defined. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) + 8-byte ptrs: 32 bytes (including overhead) + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + The maximum overhead wastage (i.e., number of extra bytes + allocated than were requested in malloc) is less than or equal + to the minimum size, except for requests >= mmap_threshold that + are serviced via mmap(), where the worst case wastage is about + 32 bytes plus the remainder from a system page (the minimal + mmap unit); typically 4096 or 8192 bytes. + + Security: static-safe; optionally more or less + The "security" of malloc refers to the ability of malicious + code to accentuate the effects of errors (for example, freeing + space that is not currently malloc'ed or overwriting past the + ends of chunks) in code that calls malloc. This malloc + guarantees not to modify any memory locations below the base of + heap, i.e., static variables, even in the presence of usage + errors. The routines additionally detect most improper frees + and reallocs. All this holds as long as the static bookkeeping + for malloc itself is not corrupted by some other means. This + is only one aspect of security -- these checks do not, and + cannot, detect all possible programming errors. + + If FOOTERS is defined nonzero, then each allocated chunk + carries an additional check word to verify that it was malloced + from its space. These check words are the same within each + execution of a program using malloc, but differ across + executions, so externally crafted fake chunks cannot be + freed. This improves security by rejecting frees/reallocs that + could corrupt heap memory, in addition to the checks preventing + writes to statics that are always on. This may further improve + security at the expense of time and space overhead. (Note that + FOOTERS may also be worth using with MSPACES.) + + By default detected errors cause the program to abort (calling + "abort()"). You can override this to instead proceed past + errors by defining PROCEED_ON_ERROR. In this case, a bad free + has no effect, and a malloc that encounters a bad address + caused by user overwrites will ignore the bad address by + dropping pointers and indices to all known memory. This may + be appropriate for programs that should continue if at all + possible in the face of programming errors, although they may + run out of memory because dropped memory is never reclaimed. + + If you don't like either of these options, you can define + CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything + else. And if if you are sure that your program using malloc has + no errors or vulnerabilities, you can define INSECURE to 1, + which might (or might not) provide a small performance improvement. + + Thread-safety: NOT thread-safe unless USE_LOCKS defined + When USE_LOCKS is defined, each public call to malloc, free, + etc is surrounded with either a pthread mutex or a win32 + spinlock (depending on WIN32). This is not especially fast, and + can be a major bottleneck. It is designed only to provide + minimal protection in concurrent environments, and to provide a + basis for extensions. If you are using malloc in a concurrent + program, consider instead using ptmalloc, which is derived from + a version of this malloc. (See http://www.malloc.de). + + System requirements: Any combination of MORECORE and/or MMAP/MUNMAP + This malloc can use unix sbrk or any emulation (invoked using + the CALL_MORECORE macro) and/or mmap/munmap or any emulation + (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system + memory. On most unix systems, it tends to work best if both + MORECORE and MMAP are enabled. On Win32, it uses emulations + based on VirtualAlloc. It also uses common C library functions + like memset. + + Compliance: I believe it is compliant with the Single Unix Specification + (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably + others as well. + +* Overview of algorithms + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and + tunable. Consistent balance across these factors results in a good + general-purpose allocator for malloc-intensive programs. + + In most ways, this malloc is a best-fit allocator. Generally, it + chooses the best-fitting existing chunk for a request, with ties + broken in approximately least-recently-used order. (This strategy + normally maintains low fragmentation.) However, for requests less + than 256bytes, it deviates from best-fit when there is not an + exactly fitting available chunk by preferring to use space adjacent + to that used for the previous small request, as well as by breaking + ties in approximately most-recently-used order. (These enhance + locality of series of small allocations.) And for very large requests + (>= 256Kb by default), it relies on system memory mapping + facilities, if supported. (This helps avoid carrying around and + possibly fragmenting memory used only for large chunks.) + + All operations (except malloc_stats and mallinfo) have execution + times that are bounded by a constant factor of the number of bits in + a size_t, not counting any clearing in calloc or copying in realloc, + or actions surrounding MORECORE and MMAP that have times + proportional to the number of non-contiguous regions returned by + system allocation routines, which is often just 1. + + The implementation is not very modular and seriously overuses + macros. Perhaps someday all C compilers will do as good a job + inlining modular code as can now be done by brute-force expansion, + but now, enough of them seem not to. + + Some compilers issue a lot of warnings about code that is + dead/unreachable only on some platforms, and also about intentional + uses of negation on unsigned types. All known cases of each can be + ignored. + + For a longer but out of date high-level description, see + http://gee.cs.oswego.edu/dl/html/malloc.html + +* MSPACES + If MSPACES is defined, then in addition to malloc, free, etc., + this file also defines mspace_malloc, mspace_free, etc. These + are versions of malloc routines that take an "mspace" argument + obtained using create_mspace, to control all internal bookkeeping. + If ONLY_MSPACES is defined, only these versions are compiled. + So if you would like to use this allocator for only some allocations, + and your system malloc for others, you can compile with + ONLY_MSPACES and then do something like... + static mspace mymspace = create_mspace(0,0); // for example + #define mymalloc(bytes) mspace_malloc(mymspace, bytes) + + (Note: If you only need one instance of an mspace, you can instead + use "USE_DL_PREFIX" to relabel the global malloc.) + + You can similarly create thread-local allocators by storing + mspaces as thread-locals. For example: + static __thread mspace tlms = 0; + void* tlmalloc(size_t bytes) { + if (tlms == 0) tlms = create_mspace(0, 0); + return mspace_malloc(tlms, bytes); + } + void tlfree(void* mem) { mspace_free(tlms, mem); } + + Unless FOOTERS is defined, each mspace is completely independent. + You cannot allocate from one and free to another (although + conformance is only weakly checked, so usage errors are not always + caught). If FOOTERS is defined, then each chunk carries around a tag + indicating its originating mspace, and frees are directed to their + originating spaces. + + ------------------------- Compile-time options --------------------------- + +Be careful in setting #define values for numerical constants of type +size_t. On some systems, literal values are not automatically extended +to size_t precision unless they are explicitly casted. + +WIN32 default: defined if _WIN32 defined + Defining WIN32 sets up defaults for MS environment and compilers. + Otherwise defaults are for unix. + +MALLOC_ALIGNMENT default: (size_t)8 + Controls the minimum alignment for malloc'ed chunks. It must be a + power of two and at least 8, even on machines for which smaller + alignments would suffice. It may be defined as larger than this + though. Note however that code and data structures are optimized for + the case of 8-byte alignment. + +MSPACES default: 0 (false) + If true, compile in support for independent allocation spaces. + This is only supported if HAVE_MMAP is true. + +ONLY_MSPACES default: 0 (false) + If true, only compile in mspace versions, not regular versions. + +USE_LOCKS default: 0 (false) + Causes each call to each public routine to be surrounded with + pthread or WIN32 mutex lock/unlock. (If set true, this can be + overridden on a per-mspace basis for mspace versions.) + +FOOTERS default: 0 + If true, provide extra checking and dispatching by placing + information in the footers of allocated chunks. This adds + space and time overhead. + +INSECURE default: 0 + If true, omit checks for usage errors and heap space overwrites. + +USE_DL_PREFIX default: NOT defined + Causes compiler to prefix all public routines with the string 'dl'. + This can be useful when you only want to use this malloc in one part + of a program, using your regular system malloc elsewhere. + +ABORT default: defined as abort() + Defines how to abort on failed checks. On most systems, a failed + check cannot die with an "assert" or even print an informative + message, because the underlying print routines in turn call malloc, + which will fail again. Generally, the best policy is to simply call + abort(). It's not very useful to do more than this because many + errors due to overwriting will show up as address faults (null, odd + addresses etc) rather than malloc-triggered checks, so will also + abort. Also, most compilers know that abort() does not return, so + can better optimize code conditionally calling it. + +PROCEED_ON_ERROR default: defined as 0 (false) + Controls whether detected bad addresses cause them to bypassed + rather than aborting. If set, detected bad arguments to free and + realloc are ignored. And all bookkeeping information is zeroed out + upon a detected overwrite of freed heap space, thus losing the + ability to ever return it from malloc again, but enabling the + application to proceed. If PROCEED_ON_ERROR is defined, the + static variable malloc_corruption_error_count is compiled in + and can be examined to see if errors have occurred. This option + generates slower code than the default abort policy. + +DEBUG default: NOT defined + The DEBUG setting is mainly intended for people trying to modify + this code or diagnose problems when porting to new platforms. + However, it may also be able to better isolate user errors than just + using runtime checks. The assertions in the check routines spell + out in more detail the assumptions and invariants underlying the + algorithms. The checking is fairly extensive, and will slow down + execution noticeably. Calling malloc_stats or mallinfo with DEBUG + set will attempt to check every non-mmapped allocated and free chunk + in the course of computing the summaries. + +ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) + Debugging assertion failures can be nearly impossible if your + version of the assert macro causes malloc to be called, which will + lead to a cascade of further failures, blowing the runtime stack. + ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), + which will usually make debugging easier. + +MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 + The action to take before "return 0" when malloc fails to be able to + return memory because there is none available. + +HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES + True if this system supports sbrk or an emulation of it. + +MORECORE default: sbrk + The name of the sbrk-style system routine to call to obtain more + memory. See below for guidance on writing custom MORECORE + functions. The type of the argument to sbrk/MORECORE varies across + systems. It cannot be size_t, because it supports negative + arguments, so it is normally the signed type of the same width as + size_t (sometimes declared as "intptr_t"). It doesn't much matter + though. Internally, we only call it with arguments less than half + the max value of a size_t, which should work across all reasonable + possibilities, although sometimes generating compiler warnings. See + near the end of this file for guidelines for creating a custom + version of MORECORE. + +MORECORE_CONTIGUOUS default: 1 (true) + If true, take advantage of fact that consecutive calls to MORECORE + with positive arguments always return contiguous increasing + addresses. This is true of unix sbrk. It does not hurt too much to + set it true anyway, since malloc copes with non-contiguities. + Setting it false when definitely non-contiguous saves time + and possibly wasted space it would take to discover this though. + +MORECORE_CANNOT_TRIM default: NOT defined + True if MORECORE cannot release space back to the system when given + negative arguments. This is generally necessary only if you are + using a hand-crafted MORECORE function that cannot handle negative + arguments. + +HAVE_MMAP default: 1 (true) + True if this system supports mmap or an emulation of it. If so, and + HAVE_MORECORE is not true, MMAP is used for all system + allocation. If set and HAVE_MORECORE is true as well, MMAP is + primarily used to directly allocate very large blocks. It is also + used as a backup strategy in cases where MORECORE fails to provide + space from system. Note: A single call to MUNMAP is assumed to be + able to unmap memory that may have be allocated using multiple calls + to MMAP, so long as they are adjacent. + +HAVE_MREMAP default: 1 on linux, else 0 + If true realloc() uses mremap() to re-allocate large blocks and + extend or shrink allocation spaces. + +MMAP_CLEARS default: 1 on unix + True if mmap clears memory so calloc doesn't need to. This is true + for standard unix mmap using /dev/zero. + +USE_BUILTIN_FFS default: 0 (i.e., not used) + Causes malloc to use the builtin ffs() function to compute indices. + Some compilers may recognize and intrinsify ffs to be faster than the + supplied C version. Also, the case of x86 using gcc is special-cased + to an asm instruction, so is already as fast as it can be, and so + this setting has no effect. (On most x86s, the asm version is only + slightly faster than the C version.) + +malloc_getpagesize default: derive from system includes, or 4096. + The system page size. To the extent possible, this malloc manages + memory from the system in page-size units. This may be (and + usually is) a function rather than a constant. This is ignored + if WIN32, where page size is determined using getSystemInfo during + initialization. + +USE_DEV_RANDOM default: 0 (i.e., not used) + Causes malloc to use /dev/random to initialize secure magic seed for + stamping footers. Otherwise, the current time is used. + +NO_MALLINFO default: 0 + If defined, don't compile "mallinfo". This can be a simple way + of dealing with mismatches between system declarations and + those in this file. + +MALLINFO_FIELD_TYPE default: size_t + The type of the fields in the mallinfo struct. This was originally + defined as "int" in SVID etc, but is more usefully defined as + size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set + +REALLOC_ZERO_BYTES_FREES default: not defined + This should be set if a call to realloc with zero bytes should + be the same as a call to free. Some people think it should. Otherwise, + since this malloc returns a unique pointer for malloc(0), so does + realloc(p, 0). + +LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H +LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H +LACKS_STDLIB_H default: NOT defined unless on WIN32 + Define these if your system does not have these header files. + You might need to manually insert some of the declarations they provide. + +DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, + system_info.dwAllocationGranularity in WIN32, + otherwise 64K. + Also settable using mallopt(M_GRANULARITY, x) + The unit for allocating and deallocating memory from the system. On + most systems with contiguous MORECORE, there is no reason to + make this more than a page. However, systems with MMAP tend to + either require or encourage larger granularities. You can increase + this value to prevent system allocation functions to be called so + often, especially if they are slow. The value must be at least one + page and must be a power of two. Setting to 0 causes initialization + to either page size or win32 region size. (Note: In previous + versions of malloc, the equivalent of this option was called + "TOP_PAD") + +DEFAULT_TRIM_THRESHOLD default: 2MB + Also settable using mallopt(M_TRIM_THRESHOLD, x) + The maximum amount of unused top-most memory to keep before + releasing via malloc_trim in free(). Automatic trimming is mainly + useful in long-lived programs using contiguous MORECORE. Because + trimming via sbrk can be slow on some systems, and can sometimes be + wasteful (in cases where programs immediately afterward allocate + more large chunks) the value should be high enough so that your + overall system performance would improve by releasing this much + memory. As a rough guide, you might set to a value close to the + average size of a process (program) running on your system. + Releasing this much memory would allow such a process to run in + memory. Generally, it is worth tuning trim thresholds when a + program undergoes phases where several large chunks are allocated + and released in ways that can reuse each other's storage, perhaps + mixed with phases where there are no such chunks at all. The trim + value must be greater than page size to have any useful effect. To + disable trimming completely, you can set to MAX_SIZE_T. Note that the trick + some people use of mallocing a huge space and then freeing it at + program startup, in an attempt to reserve system memory, doesn't + have the intended effect under automatic trimming, since that memory + will immediately be returned to the system. + +DEFAULT_MMAP_THRESHOLD default: 256K + Also settable using mallopt(M_MMAP_THRESHOLD, x) + The request size threshold for using MMAP to directly service a + request. Requests of at least this size that cannot be allocated + using already-existing space will be serviced via mmap. (If enough + normal freed space already exists it is used instead.) Using mmap + segregates relatively large chunks of memory so that they can be + individually obtained and released from the host system. A request + serviced through mmap is never reused by any other request (at least + not directly; the system may just so happen to remap successive + requests to the same locations). Segregating space in this way has + the benefits that: Mmapped space can always be individually released + back to the system, which helps keep the system level memory demands + of a long-lived program low. Also, mapped memory doesn't become + `locked' between other chunks, as can happen with normally allocated + chunks, which means that even trimming via malloc_trim would not + release them. However, it has the disadvantage that the space + cannot be reclaimed, consolidated, and then used to service later + requests, as happens with normal chunks. The advantages of mmap + nearly always outweigh disadvantages for "large" chunks, but the + value of "large" may vary across systems. The default is an + empirically derived value that works well in most systems. You can + disable mmap by setting to MAX_SIZE_T. + +*/ + +#define STDCALL __attribute__ ((stdcall)) __attribute__ ((dllimport)) +void* STDCALL KernelAlloc(unsigned size)__asm__("KernelAlloc"); +int KernelFree(void*); + +#define MALLOC_ALIGNMENT ((size_t)8U) +#define DEFAULT_MMAP_THRESHOLD ((size_t)32U * (size_t)1024U) +#define NO_MALLINFO 1 +#define HAVE_MMAP 1 +#define MORECORE_CANNOT_TRIM +#define FOOTERS 0 +#define ABORT + +#ifndef WIN32 +#ifdef _WIN32 +#define WIN32 1 +#endif /* _WIN32 */ +#endif /* WIN32 */ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define HAVE_MMAP 1 +#define HAVE_MORECORE 0 +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H +#define LACKS_SYS_MMAN_H +#define LACKS_STRING_H +#define LACKS_STRINGS_H +#define LACKS_SYS_TYPES_H +#define LACKS_ERRNO_H +#define MALLOC_FAILURE_ACTION +#define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */ +#endif /* WIN32 */ + +#if defined(DARWIN) || defined(_DARWIN) +/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ +#ifndef HAVE_MORECORE +#define HAVE_MORECORE 0 +#define HAVE_MMAP 1 +#endif /* HAVE_MORECORE */ +#endif /* DARWIN */ + +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef ONLY_MSPACES +#define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ +#ifndef MSPACES +#if ONLY_MSPACES +#define MSPACES 1 +#else /* ONLY_MSPACES */ +#define MSPACES 0 +#endif /* ONLY_MSPACES */ +#endif /* MSPACES */ +#ifndef MALLOC_ALIGNMENT +#define MALLOC_ALIGNMENT ((size_t)8U) +#endif /* MALLOC_ALIGNMENT */ +#ifndef FOOTERS +#define FOOTERS 0 +#endif /* FOOTERS */ +#ifndef ABORT +#define ABORT abort() +#endif /* ABORT */ +#ifndef ABORT_ON_ASSERT_FAILURE +#define ABORT_ON_ASSERT_FAILURE 1 +#endif /* ABORT_ON_ASSERT_FAILURE */ +#ifndef PROCEED_ON_ERROR +#define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ +#ifndef USE_LOCKS +#define USE_LOCKS 0 +#endif /* USE_LOCKS */ +#ifndef INSECURE +#define INSECURE 0 +#endif /* INSECURE */ +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ +#ifndef MMAP_CLEARS +#define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ +#ifndef HAVE_MREMAP +#ifdef linux +#define HAVE_MREMAP 1 +#else /* linux */ +#define HAVE_MREMAP 0 +#endif /* linux */ +#endif /* HAVE_MREMAP */ +#ifndef MALLOC_FAILURE_ACTION +#define MALLOC_FAILURE_ACTION errno = ENOMEM; +#endif /* MALLOC_FAILURE_ACTION */ +#ifndef HAVE_MORECORE +#if ONLY_MSPACES +#define HAVE_MORECORE 0 +#else /* ONLY_MSPACES */ +#define HAVE_MORECORE 1 +#endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ +#if !HAVE_MORECORE +#define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ +#ifndef MORECORE +#define MORECORE sbrk +#endif /* MORECORE */ +#ifndef MORECORE_CONTIGUOUS +#define MORECORE_CONTIGUOUS 1 +#endif /* MORECORE_CONTIGUOUS */ +#endif /* HAVE_MORECORE */ +#ifndef DEFAULT_GRANULARITY +#if MORECORE_CONTIGUOUS +#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ +#else /* MORECORE_CONTIGUOUS */ +#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) +#endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ +#ifndef DEFAULT_TRIM_THRESHOLD +#ifndef MORECORE_CANNOT_TRIM +#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) +#else /* MORECORE_CANNOT_TRIM */ +#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T +#endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ +#ifndef DEFAULT_MMAP_THRESHOLD +#if HAVE_MMAP +#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) +#else /* HAVE_MMAP */ +#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T +#endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ +#ifndef USE_BUILTIN_FFS +#define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ +#ifndef USE_DEV_RANDOM +#define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ +#ifndef NO_MALLINFO +#define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE +#define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ + + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +/* ------------------------ Mallinfo declarations ------------------------ */ + +#if !NO_MALLINFO +#endif /* NO_MALLINFO */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if !ONLY_MSPACES + +/* ------------------- Declarations of public routines ------------------- */ + +#ifndef USE_DL_PREFIX +#define dlcalloc calloc +#define dlfree free +#define dlmalloc malloc +#define dlmemalign memalign +#define dlrealloc realloc +#define dlvalloc valloc +#define dlpvalloc pvalloc +#define dlmallinfo mallinfo +#define dlmallopt mallopt +#define dlmalloc_trim malloc_trim +#define dlmalloc_stats malloc_stats +#define dlmalloc_usable_size malloc_usable_size +#define dlmalloc_footprint malloc_footprint +#define dlmalloc_max_footprint malloc_max_footprint +#define dlindependent_calloc independent_calloc +#define dlindependent_comalloc independent_comalloc +#endif /* USE_DL_PREFIX */ + + +/* + malloc(size_t n) + Returns a pointer to a newly allocated chunk of at least n bytes, or + null if no space is available, in which case errno is set to ENOMEM + on ANSI C systems. + + If n is zero, malloc returns a minimum-sized chunk. (The minimum + size is 16 bytes on most 32bit systems, and 32 bytes on 64bit + systems.) Note that size_t is an unsigned type, so calls with + arguments that would be negative if signed are interpreted as + requests for huge amounts of space, which will often fail. The + maximum supported value of n differs across systems, but is in all + cases less than the maximum representable value of a size_t. +*/ +void* dlmalloc(size_t); + +/* + free(void* p) + Releases the chunk of memory pointed to by p, that had been previously + allocated using malloc or a related routine such as realloc. + It has no effect if p is null. If p was not malloced or already + freed, free(p) will by default cause the current program to abort. +*/ +void dlfree(void*); + +/* + calloc(size_t n_elements, size_t element_size); + Returns a pointer to n_elements * element_size bytes, with all locations + set to zero. +*/ +void* dlcalloc(size_t, size_t); + +/* + realloc(void* p, size_t n) + Returns a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. + + The returned pointer may or may not be the same as p. The algorithm + prefers extending p in most cases when possible, otherwise it + employs the equivalent of a malloc-copy-free sequence. + + If p is null, realloc is equivalent to malloc. + + If space is not available, realloc returns null, errno is set (if on + ANSI) and p is NOT freed. + + if n is for fewer bytes than already held by p, the newly unused + space is lopped off and freed if possible. realloc with a size + argument of zero (re)allocates a minimum-sized chunk. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is not supported. +*/ + +void* dlrealloc(void*, size_t); + +/* + memalign(size_t alignment, size_t n); + Returns a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument. + + The alignment argument should be a power of two. If the argument is + not a power of two, the nearest greater power is used. + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. +*/ +void* dlmemalign(size_t, size_t); + +/* + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system. If the pagesize is unknown, 4096 is used. +*/ +void* dlvalloc(size_t); + +/* + mallopt(int parameter_number, int parameter_value) + Sets tunable parameters The format is to provide a + (parameter-number, parameter-value) pair. mallopt then sets the + corresponding parameter to the argument value if it can (i.e., so + long as the value is meaningful), and returns 1 if successful else + 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, + normally defined in malloc.h. None of these are use in this malloc, + so setting them has no effect. But this malloc also supports other + options in mallopt. See below for details. Briefly, supported + parameters are as follows (listed defaults are for "typical" + configurations). + + Symbol param # default allowed param values + M_TRIM_THRESHOLD -1 2*1024*1024 any (MAX_SIZE_T disables) + M_GRANULARITY -2 page size any power of 2 >= page size + M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) +*/ +int dlmallopt(int, int); + +/* + malloc_footprint(); + Returns the number of bytes obtained from the system. The total + number of bytes allocated by malloc, realloc etc., is less than this + value. Unlike mallinfo, this function returns only a precomputed + result, so can be called frequently to monitor memory consumption. + Even if locks are otherwise defined, this function does not use them, + so results might not be up to date. +*/ +size_t dlmalloc_footprint(void); + +/* + malloc_max_footprint(); + Returns the maximum number of bytes obtained from the system. This + value will be greater than current footprint if deallocated space + has been reclaimed by the system. The peak number of bytes allocated + by malloc, realloc etc., is less than this value. Unlike mallinfo, + this function returns only a precomputed result, so can be called + frequently to monitor memory consumption. Even if locks are + otherwise defined, this function does not use them, so results might + not be up to date. +*/ +size_t dlmalloc_max_footprint(void); + +#if !NO_MALLINFO +#endif /* NO_MALLINFO */ + +/* + independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); + + independent_calloc is similar to calloc, but instead of returning a + single cleared space, it returns an array of pointers to n_elements + independent elements that can hold contents of size elem_size, each + of which starts out cleared, and can be independently freed, + realloc'ed etc. The elements are guaranteed to be adjacently + allocated (this is not guaranteed to occur with multiple callocs or + mallocs), which may also improve cache locality in some + applications. + + The "chunks" argument is optional (i.e., may be null, which is + probably the most typical usage). If it is null, the returned array + is itself dynamically allocated and should also be freed when it is + no longer needed. Otherwise, the chunks array must be of at least + n_elements in length. It is filled in with the pointers to the + chunks. + + In either case, independent_calloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and "chunks" + is null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use regular calloc and assign pointers into this + space to represent elements. (In this case though, you cannot + independently free elements.) + + independent_calloc simplifies and speeds up implementations of many + kinds of pools. It may also be useful when constructing large data + structures that initially have a fixed number of fixed-sized nodes, + but the number is not known at compile time, and some of the nodes + may later need to be freed. For example: + + struct Node { int item; struct Node* next; }; + + struct Node* build_list() { + struct Node** pool; + int n = read_number_of_nodes_needed(); + if (n <= 0) return 0; + pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); + if (pool == 0) die(); + // organize into a linked list... + struct Node* first = pool[0]; + for (i = 0; i < n-1; ++i) + pool[i]->next = pool[i+1]; + free(pool); // Can now free the array (or not, if it is needed later) + return first; + } +*/ +void** dlindependent_calloc(size_t, size_t, void**); + +/* + independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); + + independent_comalloc allocates, all at once, a set of n_elements + chunks with sizes indicated in the "sizes" array. It returns + an array of pointers to these elements, each of which can be + independently freed, realloc'ed etc. The elements are guaranteed to + be adjacently allocated (this is not guaranteed to occur with + multiple callocs or mallocs), which may also improve cache locality + in some applications. + + The "chunks" argument is optional (i.e., may be null). If it is null + the returned array is itself dynamically allocated and should also + be freed when it is no longer needed. Otherwise, the chunks array + must be of at least n_elements in length. It is filled in with the + pointers to the chunks. + + In either case, independent_comalloc returns this pointer array, or + null if the allocation failed. If n_elements is zero and chunks is + null, it returns a chunk representing an array with zero elements + (which should be freed if not wanted). + + Each element must be individually freed when it is no longer + needed. If you'd like to instead be able to free all at once, you + should instead use a single regular malloc, and assign pointers at + particular offsets in the aggregate space. (In this case though, you + cannot independently free elements.) + + independent_comallac differs from independent_calloc in that each + element may have a different size, and also that it does not + automatically clear elements. + + independent_comalloc can be used to speed up allocation in cases + where several structs or objects must always be allocated at the + same time. For example: + + struct Head { ... } + struct Foot { ... } + + void send_message(char* msg) { + int msglen = strlen(msg); + size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; + void* chunks[3]; + if (independent_comalloc(3, sizes, chunks) == 0) + die(); + struct Head* head = (struct Head*)(chunks[0]); + char* body = (char*)(chunks[1]); + struct Foot* foot = (struct Foot*)(chunks[2]); + // ... + } + + In general though, independent_comalloc is worth using only for + larger values of n_elements. For small values, you probably won't + detect enough difference from series of malloc calls to bother. + + Overuse of independent_comalloc can increase overall memory usage, + since it cannot reuse existing noncontiguous small chunks that + might be available for some of the elements. +*/ +void** dlindependent_comalloc(size_t, size_t*, void**); + + +/* + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + */ +void* dlpvalloc(size_t); + +/* + malloc_trim(size_t pad); + + If possible, gives memory back to the system (via negative arguments + to sbrk) if there is unused memory at the `high' end of the malloc + pool or in unused MMAP segments. You can call this after freeing + large blocks of memory to potentially reduce the system-level memory + requirements of a program. However, it cannot guarantee to reduce + memory. Under some allocation patterns, some large free blocks of + memory will be locked between two used chunks, so they cannot be + given back to the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, only + the minimum amount of memory to maintain internal data structures + will be left. Non-zero arguments can be supplied to maintain enough + trailing space to service future expected allocations without having + to re-obtain memory from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. +*/ +int dlmalloc_trim(size_t); + +/* + malloc_usable_size(void* p); + + Returns the number of bytes you can actually use in + an allocated chunk, which may be more than you requested (although + often not) due to alignment and minimum size constraints. + You can use this many bytes without worrying about + overwriting other allocated objects. This is not a particularly great + programming practice. malloc_usable_size can be more useful in + debugging and assertions, for example: + + p = malloc(n); + assert(malloc_usable_size(p) >= 256); +*/ +size_t dlmalloc_usable_size(void*); + +/* + malloc_stats(); + Prints on stderr the amount of space obtained from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), and the current + number of bytes allocated via malloc (or realloc, etc) but not yet + freed. Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead. Because it includes + alignment wastage as being in use, this figure may be greater than + zero even when no user-level chunks are allocated. + + The reported current and maximum system memory can be inaccurate if + a program makes other calls to system memory allocation functions + (normally sbrk) outside of malloc. + + malloc_stats prints only the most commonly interesting statistics. + More information can be obtained by calling mallinfo. +*/ +void dlmalloc_stats(void); + +#endif /* ONLY_MSPACES */ + +#if MSPACES +#endif /* MSPACES */ + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif /* __cplusplus */ + +/* + ======================================================================== + To make a fully customizable malloc.h header file, cut everything + above this line, put into file malloc.h, edit to suit, and #include it + on the next line, as well as in programs that use this malloc. + ======================================================================== +*/ + +/* #include "malloc.h" */ + +/*------------------------------ internal #includes ---------------------- */ + +#ifdef WIN32 +#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ +#endif /* WIN32 */ + +#include /* for printing in malloc_stats */ + +#ifndef LACKS_ERRNO_H +#include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ +#if FOOTERS +#include /* for magic initialization */ +#endif /* FOOTERS */ +#ifndef LACKS_STDLIB_H +#include /* for abort() */ +#endif /* LACKS_STDLIB_H */ +#ifdef DEBUG +#if ABORT_ON_ASSERT_FAILURE +#define assert(x) if(!(x)) ABORT +#else /* ABORT_ON_ASSERT_FAILURE */ +#include +#endif /* ABORT_ON_ASSERT_FAILURE */ +#else /* DEBUG */ +#define assert(x) +#endif /* DEBUG */ +#ifndef LACKS_STRING_H +#include /* for memset etc */ +#endif /* LACKS_STRING_H */ +#if USE_BUILTIN_FFS +#ifndef LACKS_STRINGS_H +#include /* for ffs */ +#endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ +#if HAVE_MMAP +#ifndef LACKS_SYS_MMAN_H +#include /* for mmap */ +#endif /* LACKS_SYS_MMAN_H */ +#ifndef LACKS_FCNTL_H +#include +#endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ +#if HAVE_MORECORE +#endif /* HAVE_MMAP */ + +#ifndef WIN32 +#endif + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some plaftorms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define align_offset(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ + +#if !HAVE_MMAP +#else /* HAVE_MMAP */ +#define IS_MMAPPED_BIT (SIZE_T_ONE) +#define USE_MMAP_BIT (SIZE_T_ONE) + +#ifndef WIN32 + +#else /* WIN32 */ + +/* Win32 MMAP via VirtualAlloc */ +static void* win32mmap(size_t size) { + void* ptr = KernelAlloc(size); + return (ptr != 0)? ptr: MFAIL; +} + +/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ +static void* win32direct_mmap(size_t size) { + void* ptr = KernelAlloc(size); + return (ptr != 0)? ptr: MFAIL; +} + +/* This function supports releasing coalesed segments */ +static int win32munmap(void* ptr, size_t size) { + KernelFree(ptr); + return 0; +} + +#define CALL_MMAP(s) win32mmap(s) +#define CALL_MUNMAP(a, s) win32munmap((a), (s)) +#define DIRECT_MMAP(s) win32direct_mmap(s) +#endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MMAP && HAVE_MREMAP +#else /* HAVE_MMAP && HAVE_MREMAP */ +#define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +#if HAVE_MORECORE +#else /* HAVE_MORECORE */ +#define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +/* --------------------------- Lock preliminaries ------------------------ */ + +#if USE_LOCKS +#else /* USE_LOCKS */ +#define USE_LOCK_BIT (0U) +#define INITIAL_LOCK(l) +#endif /* USE_LOCKS */ + +#if USE_LOCKS && HAVE_MORECORE +#define ACQUIRE_MORECORE_LOCK() ACQUIRE_LOCK(&morecore_mutex); +#define RELEASE_MORECORE_LOCK() RELEASE_LOCK(&morecore_mutex); +#else /* USE_LOCKS && HAVE_MORECORE */ +#define ACQUIRE_MORECORE_LOCK() +#define RELEASE_MORECORE_LOCK() +#endif /* USE_LOCKS && HAVE_MORECORE */ + +#if USE_LOCKS +#define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex); +#define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex); +#else /* USE_LOCKS */ +#define ACQUIRE_MAGIC_INIT_LOCK() +#define RELEASE_MAGIC_INIT_LOCK() +#endif /* USE_LOCKS */ + + +/* ----------------------- Chunk representations ------------------------ */ + +/* + (The following includes lightly edited explanations by Colin Plumb.) + + The malloc_chunk declaration below is misleading (but accurate and + necessary). It declares a "view" into memory allowing access to + necessary fields at known offsets from a given base. + + Chunks of memory are maintained using a `boundary tag' method as + originally described by Knuth. (See the paper by Paul Wilson + ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such + techniques.) Sizes of free chunks are stored both in the front of + each chunk and at the end. This makes consolidating fragmented + chunks into bigger chunks fast. The head fields also hold bits + representing whether chunks are free or in use. + + Here are some pictures to make it clearer. They are "exploded" to + show that the state of a chunk can be thought of as extending from + the high 31 bits of the head field of its header through the + prev_foot and PINUSE_BIT bit of the following chunk header. + + A chunk that's in use looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk (if P = 1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 1| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +- -+ + | | + +- -+ + | : + +- size - sizeof(size_t) available payload bytes -+ + : | + chunk-> +- -+ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| + | Size of next chunk (may or may not be in use) | +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + And if it's free, it looks like this: + + chunk-> +- -+ + | User payload (must be in use, or we would have merged!) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| + | Size of this chunk 0| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Next pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Prev pointer | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- size - sizeof(struct chunk) unused bytes -+ + : | + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| + | Size of next chunk (must be in use, or we would have merged)| +-+ + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | : + +- User payload -+ + : | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0| + +-+ + Note that since we always merge adjacent free chunks, the chunks + adjacent to a free chunk must be in use. + + Given a pointer to a chunk (which can be derived trivially from the + payload pointer) we can, in O(1) time, find out whether the adjacent + chunks are free, and if so, unlink them from the lists that they + are on and merge them with the current chunk. + + Chunks always begin on even word boundaries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus at least double-word aligned. + + The P (PINUSE_BIT) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + The very first chunk allocated always has this bit set, preventing + access to non-existent (or non-owned) memory. If pinuse is set for + any given chunk, then you CANNOT determine the size of the + previous chunk, and might even get a memory addressing fault when + trying to do so. + + The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of + the chunk size redundantly records whether the current chunk is + inuse. This redundancy enables usage checks within free and realloc, + and reduces indirection when freeing and consolidating chunks. + + Each freshly allocated chunk must have both cinuse and pinuse set. + That is, each allocated chunk borders either a previously allocated + and still in-use chunk, or the base of its memory arena. This is + ensured by making all allocations from the the `lowest' part of any + found chunk. Further, no free chunk physically borders another one, + so each free chunk is known to be preceded and followed by either + inuse chunks or the ends of memory. + + Note that the `foot' of the current chunk is actually represented + as the prev_foot of the NEXT chunk. This makes it easier to + deal with alignments etc but can be very confusing when trying + to extend or adapt this code. + + The exceptions to all this are + + 1. The special chunk `top' is the top-most available chunk (i.e., + the one bordering the end of available memory). It is treated + specially. Top is never included in any bin, is used only if + no other chunk is available, and is released back to the + system if it is very large (see M_TRIM_THRESHOLD). In effect, + the top chunk is treated as larger (and thus less well + fitting) than any other available chunk. The top chunk + doesn't update its trailing size field since there is no next + contiguous chunk that would have to index off it. However, + space is still allocated for it (TOP_FOOT_SIZE) to enable + separation or merging when space is extended. + + 3. Chunks allocated via mmap, which have the lowest-order bit + (IS_MMAPPED_BIT) set in their prev_foot fields, and do not set + PINUSE_BIT in their head fields. Because they are allocated + one-by-one, each must carry its own prev_foot field, which is + also used to hold the offset this chunk has within its mmapped + region, which is needed to preserve alignment. Each mmapped + chunk is trailed by the first two fields of a fake next-chunk + for sake of usage checks. + +*/ + +struct malloc_chunk { + size_t prev_foot; /* Size of previous chunk (if free). */ + size_t head; /* Size and inuse bits. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + +/* ------------------- Chunks sizes and alignments ----------------------- */ + +#define MCHUNK_SIZE (sizeof(mchunk)) + +#if FOOTERS +#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +#else /* FOOTERS */ +#define CHUNK_OVERHEAD (SIZE_T_SIZE) +#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE\ + ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define pad_request(req) \ + (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define request2size(req) \ + (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) + + +/* ------------------ Operations on head and foot fields ----------------- */ + +/* + The head field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use. If the chunk was obtained with mmap, the prev_foot field has + IS_MMAPPED_BIT set, otherwise holding the offset of the base of the + mmapped region to the base of the chunk. +*/ + +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from head words */ +#define cinuse(p) ((p)->head & CINUSE_BIT) +#define pinuse(p) ((p)->head & PINUSE_BIT) +#define chunksize(p) ((p)->head & ~(INUSE_BITS)) + +#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) +#define clear_cinuse(p) ((p)->head &= ~CINUSE_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) +#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~INUSE_BITS))) +#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) + +/* extract next chunk's pinuse bit */ +#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) + +/* Get/set size at footer */ +#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) + +/* Set size, pinuse bit, and foot */ +#define set_size_and_pinuse_of_free_chunk(p, s)\ + ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) + +/* Set size, pinuse bit, foot, and clear next pinuse */ +#define set_free_with_pinuse(p, s, n)\ + (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) + +#define is_mmapped(p)\ + (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT)) + +/* Get the internal overhead associated with chunk p */ +#define overhead_for(p)\ + (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS +#define calloc_must_clear(p) (!is_mmapped(p)) +#else /* MMAP_CLEARS */ +#define calloc_must_clear(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ + +/* + When chunks are not in use, they are treated as nodes of either + lists or trees. + + "Small" chunks are stored in circular doubly-linked lists, and look + like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Larger chunks are kept in a form of bitwise digital trees (aka + tries) keyed on chunksizes. Because malloc_tree_chunks are only for + free chunks greater than 256 bytes, their size doesn't impose any + constraints on user chunk sizes. Each node looks like: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk of same size | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to left child (child[0]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to right child (child[1]) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Pointer to parent | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | bin index of this chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Each tree holding treenodes is a tree of unique chunk sizes. Chunks + of the same size are arranged in a circularly-linked list, with only + the oldest chunk (the next to be used, in our FIFO ordering) + actually in the tree. (Tree members are distinguished by a non-null + parent pointer.) If a chunk with the same size an an existing node + is inserted, it is linked off the existing node using pointers that + work in the same way as fd/bk pointers of small chunks. + + Each tree contains a power of 2 sized range of chunk sizes (the + smallest is 0x100 <= x < 0x180), which is is divided in half at each + tree level, with the chunks in the smaller half of the range (0x100 + <= x < 0x140 for the top nose) in the left subtree and the larger + half (0x140 <= x < 0x180) in the right subtree. This is, of course, + done by inspecting individual bits. + + Using these rules, each node's left subtree contains all smaller + sizes than its right subtree. However, the node at the root of each + subtree has no particular ordering relationship to either. (The + dividing line between the subtree sizes is based on trie relation.) + If we remove the last chunk of a given size from the interior of the + tree, we need to replace it with a leaf node. The tree ordering + rules permit a node to be replaced by any leaf below it. + + The smallest chunk in a tree (a common operation in a best-fit + allocator) can be found by walking a path to the leftmost leaf in + the tree. Unlike a usual binary tree, where we follow left child + pointers until we reach a null, here we follow the right child + pointer any time the left one is null, until we reach a leaf with + both child pointers null. The smallest chunk in the tree will be + somewhere along that path. + + The worst case number of steps to add, find, or remove a node is + bounded by the number of bits differentiating chunks within + bins. Under current bin calculations, this ranges from 6 up to 21 + (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case + is of course much better. +*/ + +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t prev_foot; + size_t head; + struct malloc_tree_chunk* fd; + struct malloc_tree_chunk* bk; + + struct malloc_tree_chunk* child[2]; + struct malloc_tree_chunk* parent; + bindex_t index; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) + +/* ----------------------------- Segments -------------------------------- */ + +/* + Each malloc space may include non-contiguous segments, held in a + list headed by an embedded malloc_segment record representing the + top-most space. Segments also include flags holding properties of + the space. Large chunks that are directly allocated by mmap are not + included in this list. They are instead independently created and + destroyed without otherwise keeping track of them. + + Segment management mainly comes into play for spaces allocated by + MMAP. Any call to MMAP might or might not return memory that is + adjacent to an existing segment. MORECORE normally contiguously + extends the current space, so this space is almost always adjacent, + which is simpler and faster to deal with. (This is why MORECORE is + used preferentially to MMAP when both are available -- see + sys_alloc.) When allocating using MMAP, we don't use any of the + hinting mechanisms (inconsistently) supported in various + implementations of unix mmap, or distinguish reserving from + committing memory. Instead, we just ask for space, and exploit + contiguity when we get it. It is probably possible to do + better than this on some systems, but no general scheme seems + to be significantly better. + + Management entails a simpler variant of the consolidation scheme + used for chunks to reduce fragmentation -- new adjacent memory is + normally prepended or appended to an existing segment. However, + there are limitations compared to chunk consolidation that mostly + reflect the fact that segment processing is relatively infrequent + (occurring only when getting memory from system) and that we + don't expect to have huge numbers of segments: + + * Segments are not indexed, so traversal requires linear scans. (It + would be possible to index these, but is not worth the extra + overhead and complexity for most programs on most platforms.) + * New segments are only appended to old ones when holding top-most + memory; if they cannot be prepended to others, they are held in + different segments. + + Except for the top-most segment of an mstate, each segment record + is kept at the tail of its segment. Segments are added by pushing + segment records onto the list headed by &mstate.seg for the + containing mstate. + + Segment flags control allocation/merge/deallocation policies: + * If EXTERN_BIT set, then we did not allocate this segment, + and so should not try to deallocate or merge with others. + (This currently holds only for the initial segment passed + into create_mspace_with_base.) + * If IS_MMAPPED_BIT set, the segment may be merged with + other surrounding mmapped segments and trimmed/de-allocated + using munmap. + * If neither bit is set, then the segment was obtained using + MORECORE so can be merged with surrounding MORECORE'd segments + and deallocated/trimmed using MORECORE with negative arguments. +*/ + +struct malloc_segment { + char* base; /* base address */ + size_t size; /* allocated size */ + struct malloc_segment* next; /* ptr to next segment */ + flag_t sflags; /* mmap and extern flag */ +}; + +#define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) +#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/* ---------------------------- malloc_state ----------------------------- */ + +/* + A malloc_state holds all of the bookkeeping for a space. + The main fields are: + + Top + The topmost chunk of the currently active segment. Its size is + cached in topsize. The actual size of topmost space is + topsize+TOP_FOOT_SIZE, which includes space reserved for adding + fenceposts and segment records if necessary when getting more + space from the system. The size at which to autotrim top is + cached from mparams in trim_check, except that it is disabled if + an autotrim fails. + + Designated victim (dv) + This is the preferred chunk for servicing small requests that + don't have exact fits. It is normally the chunk split off most + recently to service another small request. Its size is cached in + dvsize. The link fields of this chunk are not maintained since it + is not kept in a bin. + + SmallBins + An array of bin headers for free chunks. These bins hold chunks + with sizes less than MIN_LARGE_SIZE bytes. Each bin contains + chunks of all the same size, spaced 8 bytes apart. To simplify + use in double-linked lists, each bin header acts as a malloc_chunk + pointing to the real first node, if it exists (else pointing to + itself). This avoids special-casing for headers. But to avoid + waste, we allocate only the fd/bk pointers of bins, and then use + repositioning tricks to treat these as the fields of a chunk. + + TreeBins + Treebins are pointers to the roots of trees holding a range of + sizes. There are 2 equally spaced treebins for each power of two + from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything + larger. + + Bin maps + There is one bit map for small bins ("smallmap") and one for + treebins ("treemap). Each bin sets its bit when non-empty, and + clears the bit when empty. Bit operations are then used to avoid + bin-by-bin searching -- nearly all "search" is done without ever + looking at bins that won't be selected. The bit maps + conservatively use 32 bits per map word, even if on 64bit system. + For a good description of some of the bit-based techniques used + here, see Henry S. Warren Jr's book "Hacker's Delight" (and + supplement at http://hackersdelight.org/). Many of these are + intended to reduce the branchiness of paths through malloc etc, as + well as to reduce the number of memory locations read or written. + + Segments + A list of segments headed by an embedded malloc_segment record + representing the initial space. + + Address check support + The least_addr field is the least address ever obtained from + MORECORE or MMAP. Attempted frees and reallocs of any address less + than this are trapped (unless INSECURE is defined). + + Magic tag + A cross-check field that should always hold same value as mparams.magic. + + Flags + Bits recording whether to use MMAP, locks, or contiguous MORECORE + + Statistics + Each space keeps track of current and maximum system memory + obtained via MORECORE or MMAP. + + Locking + If USE_LOCKS is defined, the "mutex" lock is acquired and released + around every public call using this mspace. +*/ + +/* Bin types, widths and sizes */ +#define NSMALLBINS (32U) +#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +struct malloc_state { + binmap_t smallmap; + binmap_t treemap; + size_t dvsize; + size_t topsize; + char* least_addr; + mchunkptr dv; + mchunkptr top; + size_t trim_check; + size_t magic; + mchunkptr smallbins[(NSMALLBINS+1)*2]; + tbinptr treebins[NTREEBINS]; + size_t footprint; + size_t max_footprint; + flag_t mflags; +#if USE_LOCKS + MLOCK_T mutex; /* locate lock among fields that rarely change */ +#endif /* USE_LOCKS */ + msegment seg; +}; + +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. +*/ + +struct malloc_params { + size_t magic; + size_t page_size; + size_t granularity; + size_t mmap_threshold; + size_t trim_threshold; + flag_t default_mflags; +}; + +static struct malloc_params mparams; + +/* The global malloc_state used for all non-"mspace" calls */ +static struct malloc_state _gm_; +#define gm (&_gm_) +#define is_global(M) ((M) == &_gm_) +#define is_initialized(M) ((M)->top != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on mflags */ + +#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) +#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) +#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) + +#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) +#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) +#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) + +#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) +#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) + +#define set_lock(M,L)\ + ((M)->mflags = (L)?\ + ((M)->mflags | USE_LOCK_BIT) :\ + ((M)->mflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define page_align(S)\ + (((S) + (mparams.page_size)) & ~(mparams.page_size - SIZE_T_ONE)) + +/* granularity-align a size */ +#define granularity_align(S)\ + (((S) + (mparams.granularity)) & ~(mparams.granularity - SIZE_T_ONE)) + +#define is_page_aligned(S)\ + (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) +#define is_granularity_aligned(S)\ + (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define segment_holds(S, A)\ + ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) + +/* Return segment holding given address */ +static msegmentptr segment_holding(mstate m, char* addr) { + msegmentptr sp = &m->seg; + for (;;) { + if (addr >= sp->base && addr < sp->base + sp->size) + return sp; + if ((sp = sp->next) == 0) + return 0; + } +} + +/* Return true if segment contains a segment link */ +static int has_segment_link(mstate m, msegmentptr ss) { + msegmentptr sp = &m->seg; + for (;;) { + if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) + return 1; + if ((sp = sp->next) == 0) + return 0; + } +} + +#ifndef MORECORE_CANNOT_TRIM +#define should_trim(M,s) ((s) > (M)->trim_check) +#else /* MORECORE_CANNOT_TRIM */ +#define should_trim(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE\ + (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + + +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS + +/* Ensure locks are initialized */ +#define GLOBALLY_INITIALIZE() (mparams.page_size == 0 && init_mparams()) + +#define PREACTION(M) ((GLOBALLY_INITIALIZE() || use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) +#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } +#else /* USE_LOCKS */ + +#ifndef PREACTION +#define PREACTION(M) (0) +#endif /* PREACTION */ + +#ifndef POSTACTION +#define POSTACTION(M) +#endif /* POSTACTION */ + +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + +/* A count of the number of corruption errors causing resets */ +int malloc_corruption_error_count; + +/* default corruption action */ +static void reset_on_error(mstate m); + +#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) +#define USAGE_ERROR_ACTION(m, p) + +#else /* PROCEED_ON_ERROR */ + +#ifndef CORRUPTION_ERROR_ACTION +#define CORRUPTION_ERROR_ACTION(m) ABORT +#endif /* CORRUPTION_ERROR_ACTION */ + +#ifndef USAGE_ERROR_ACTION +#define USAGE_ERROR_ACTION(m,p) ABORT +#endif /* USAGE_ERROR_ACTION */ + +#endif /* PROCEED_ON_ERROR */ + +/* -------------------------- Debugging setup ---------------------------- */ + +#if ! DEBUG + +#define check_free_chunk(M,P) +#define check_inuse_chunk(M,P) +#define check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) +#define check_malloc_state(M) +#define check_top_chunk(M,P) + +#else /* DEBUG */ +#define check_free_chunk(M,P) do_check_free_chunk(M,P) +#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) +#define check_top_chunk(M,P) do_check_top_chunk(M,P) +#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) +#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) +#define check_malloc_state(M) do_check_malloc_state(M) + +static void do_check_any_chunk(mstate m, mchunkptr p); +static void do_check_top_chunk(mstate m, mchunkptr p); +static void do_check_mmapped_chunk(mstate m, mchunkptr p); +static void do_check_inuse_chunk(mstate m, mchunkptr p); +static void do_check_free_chunk(mstate m, mchunkptr p); +static void do_check_malloced_chunk(mstate m, void* mem, size_t s); +static void do_check_tree(mstate m, tchunkptr t); +static void do_check_treebin(mstate m, bindex_t i); +static void do_check_smallbin(mstate m, bindex_t i); +static void do_check_malloc_state(mstate m); +static int bin_find(mstate m, mchunkptr x); +static size_t traverse_and_check(mstate m); +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define small_index(s) ((s) >> SMALLBIN_SHIFT) +#define small_index2size(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) +#define treebin_at(M,i) (&((M)->treebins[i])) + +/* assign tree index for size S to variable I */ +#if defined(__GNUC__) && defined(i386) +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int K;\ + __asm__("bsrl %1,%0\n\t" : "=r" (K) : "rm" (X));\ + I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ + }\ +} +#else /* GNUC */ +#define compute_tree_index(S, I)\ +{\ + size_t X = S >> TREEBIN_SHIFT;\ + if (X == 0)\ + I = 0;\ + else if (X > 0xFFFF)\ + I = NTREEBINS-1;\ + else {\ + unsigned int Y = (unsigned int)X;\ + unsigned int N = ((Y - 0x100) >> 16) & 8;\ + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ + N += K;\ + N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ + K = 14 - N + ((Y <<= K) >> 15);\ + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ + }\ +} +#endif /* GNUC */ + +/* Bit representing maximum resolved size in a treebin at i */ +#define bit_for_tree_index(i) \ + (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define leftshift_for_tree_index(i) \ + ((i == NTREEBINS-1)? 0 : \ + ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define minsize_for_tree_index(i) \ + ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ + (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ + +/* bit corresponding to given index */ +#define idx2bit(i) ((binmap_t)(1) << (i)) + +/* Mark/Clear bits with given index */ +#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) +#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) +#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) + +#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) +#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) +#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) + +/* index corresponding to given bit */ + +#if defined(__GNUC__) && defined(i386) +#define compute_bit2idx(X, I)\ +{\ + unsigned int J;\ + __asm__("bsfl %1,%0\n\t" : "=r" (J) : "rm" (X));\ + I = (bindex_t)J;\ +} + +#else /* GNUC */ +#if USE_BUILTIN_FFS +#define compute_bit2idx(X, I) I = ffs(X)-1 + +#else /* USE_BUILTIN_FFS */ +#define compute_bit2idx(X, I)\ +{\ + unsigned int Y = X - 1;\ + unsigned int K = Y >> (16-4) & 16;\ + unsigned int N = K; Y >>= K;\ + N += K = Y >> (8-3) & 8; Y >>= K;\ + N += K = Y >> (4-2) & 4; Y >>= K;\ + N += K = Y >> (2-1) & 2; Y >>= K;\ + N += K = Y >> (1-0) & 1; Y >>= K;\ + I = (bindex_t)(N + Y);\ +} +#endif /* USE_BUILTIN_FFS */ +#endif /* GNUC */ + +/* isolate the least set bit of a bitmap */ +#define least_bit(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define left_bits(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define same_or_left_bits(x) ((x) | -(x)) + + +/* ----------------------- Runtime Check Support ------------------------- */ + +/* + For security, the main invariant is that malloc/free/etc never + writes to a static address other than malloc_state, unless static + malloc_state itself has been corrupted, which cannot occur via + malloc (because of these checks). In essence this means that we + believe all pointers, sizes, maps etc held in malloc_state, but + check all of those linked or offsetted from other embedded data + structures. These checks are interspersed with main code in a way + that tends to minimize their run-time cost. + + When FOOTERS is defined, in addition to range checking, we also + verify footer fields of inuse chunks, which can be used guarantee + that the mstate controlling malloc/free is intact. This is a + streamlined version of the approach described by William Robertson + et al in "Run-time Detection of Heap-based Overflows" LISA'03 + http://www.usenix.org/events/lisa03/tech/robertson.html The footer + of an inuse chunk holds the xor of its mstate and a random seed, + that is checked upon calls to free() and realloc(). This is + (probablistically) unguessable from outside the program, but can be + computed by any code successfully malloc'ing any chunk, so does not + itself provide protection against code that has already broken + security through some other means. Unlike Robertson et al, we + always dynamically check addresses of all offset chunks (previous, + next, etc). This turns out to be cheaper than relying on hashes. +*/ + +#if !INSECURE +/* Check if address a is at least as high as any from MORECORE or MMAP */ +#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) +/* Check if address of next chunk n is higher than base chunk p */ +#define ok_next(p, n) ((char*)(p) < (char*)(n)) +/* Check if p has its cinuse bit on */ +#define ok_cinuse(p) cinuse(p) +/* Check if p has its pinuse bit on */ +#define ok_pinuse(p) pinuse(p) + +#else /* !INSECURE */ +#define ok_address(M, a) (1) +#define ok_next(b, n) (1) +#define ok_cinuse(p) (1) +#define ok_pinuse(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) +/* Check if (alleged) mstate m has expected magic field */ +#define ok_magic(M) ((M)->magic == mparams.magic) +#else /* (FOOTERS && !INSECURE) */ +#define ok_magic(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE +#if defined(__GNUC__) && __GNUC__ >= 3 +#define RTCHECK(e) __builtin_expect(e, 1) +#else /* GNUC */ +#define RTCHECK(e) (e) +#endif /* GNUC */ +#else /* !INSECURE */ +#define RTCHECK(e) (1) +#endif /* !INSECURE */ + +/* macros to set up inuse chunks with or without footers */ + +#if !FOOTERS + +#define mark_inuse_foot(M,p,s) + +/* Set cinuse bit and pinuse bit of next chunk */ +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) + +/* Set size, cinuse and pinuse bit of this chunk */ +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) + +#else /* FOOTERS */ + +/* Set foot of inuse chunk to be xor of mstate and seed */ +#define mark_inuse_foot(M,p,s)\ + (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) + +#define get_mstate_for(p)\ + ((mstate)(((mchunkptr)((char*)(p) +\ + (chunksize(p))))->prev_foot ^ mparams.magic)) + +#define set_inuse(M,p,s)\ + ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ + mark_inuse_foot(M,p,s)) + +#define set_inuse_and_pinuse(M,p,s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ + mark_inuse_foot(M,p,s)) + +#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ + ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ + mark_inuse_foot(M, p, s)) + +#endif /* !FOOTERS */ + +/* ---------------------------- setting mparams -------------------------- */ + +/* Initialize mparams */ +static int init_mparams(void) { + if (mparams.page_size == 0) { + size_t s; + + mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; + mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; +#if MORECORE_CONTIGUOUS + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; +#else /* MORECORE_CONTIGUOUS */ + mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; +#endif /* MORECORE_CONTIGUOUS */ + +#if (FOOTERS && !INSECURE) + { +#if USE_DEV_RANDOM + int fd; + unsigned char buf[sizeof(size_t)]; + /* Try to use /dev/urandom, else fall back on using time */ + if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && + read(fd, buf, sizeof(buf)) == sizeof(buf)) { + s = *((size_t *) buf); + close(fd); + } + else +#endif /* USE_DEV_RANDOM */ + s = (size_t)(time(0) ^ (size_t)0x55555555U); + + s |= (size_t)8U; /* ensure nonzero */ + s &= ~(size_t)7U; /* improve chances of fault for bad values */ + + } +#else /* (FOOTERS && !INSECURE) */ + s = (size_t)0x58585858U; +#endif /* (FOOTERS && !INSECURE) */ + ACQUIRE_MAGIC_INIT_LOCK(); + if (mparams.magic == 0) { + mparams.magic = s; + /* Set up lock for main malloc area */ + INITIAL_LOCK(&gm->mutex); + gm->mflags = mparams.default_mflags; + } + RELEASE_MAGIC_INIT_LOCK(); + +#ifndef WIN32 + mparams.page_size = malloc_getpagesize; + mparams.granularity = ((DEFAULT_GRANULARITY != 0)? + DEFAULT_GRANULARITY : mparams.page_size); +#else /* WIN32 */ + { + mparams.page_size = 4096; + mparams.granularity = 16384; + } +#endif /* WIN32 */ + + /* Sanity-check configuration: + size_t must be unsigned and as wide as pointer type. + ints must be at least 4 bytes. + alignment must be at least 8. + Alignment, min chunk size, and page size must all be powers of 2. + */ + if ((sizeof(size_t) != sizeof(char*)) || + (MAX_SIZE_T < MIN_CHUNK_SIZE) || + (sizeof(int) < 4) || + (MALLOC_ALIGNMENT < (size_t)8U) || + ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || + ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || + ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) || + ((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0)) + ABORT; + } + return 0; +} + +/* support for mallopt */ +static int change_mparam(int param_number, int value) { + size_t val = (size_t)value; + init_mparams(); + switch(param_number) { + case M_TRIM_THRESHOLD: + mparams.trim_threshold = val; + return 1; + case M_GRANULARITY: + if (val >= mparams.page_size && ((val & (val-1)) == 0)) { + mparams.granularity = val; + return 1; + } + else + return 0; + case M_MMAP_THRESHOLD: + mparams.mmap_threshold = val; + return 1; + default: + return 0; + } +} + +#if DEBUG +#endif /* DEBUG */ + +/* ----------------------------- statistics ------------------------------ */ + +#if !NO_MALLINFO +#endif /* !NO_MALLINFO */ + +/* ----------------------- Operations on smallbins ----------------------- */ + +/* + Various forms of linking and unlinking are defined as macros. Even + the ones for trees, which are very long but have very short typical + paths. This is ugly but reduces reliance on inlining support of + compilers. +*/ + +/* Link a free chunk into a smallbin */ +#define insert_small_chunk(M, P, S) {\ + bindex_t I = small_index(S);\ + mchunkptr B = smallbin_at(M, I);\ + mchunkptr F = B;\ + assert(S >= MIN_CHUNK_SIZE);\ + if (!smallmap_is_marked(M, I))\ + mark_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, B->fd)))\ + F = B->fd;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + B->fd = P;\ + F->bk = P;\ + P->fd = F;\ + P->bk = B;\ +} + +/* Unlink a chunk from a smallbin */ +#define unlink_small_chunk(M, P, S) {\ + mchunkptr F = P->fd;\ + mchunkptr B = P->bk;\ + bindex_t I = small_index(S);\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (F == B)\ + clear_smallmap(M, I);\ + else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\ + (B == smallbin_at(M,I) || ok_address(M, B)))) {\ + F->bk = B;\ + B->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Unlink the first chunk from a smallbin */ +#define unlink_first_small_chunk(M, B, P, I) {\ + mchunkptr F = P->fd;\ + assert(P != B);\ + assert(P != F);\ + assert(chunksize(P) == small_index2size(I));\ + if (B == F)\ + clear_smallmap(M, I);\ + else if (RTCHECK(ok_address(M, F))) {\ + B->fd = F;\ + F->bk = B;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ +} + +/* Replace dv node, binning the old one */ +/* Used only when dvsize known to be small */ +#define replace_dv(M, P, S) {\ + size_t DVS = M->dvsize;\ + if (DVS != 0) {\ + mchunkptr DV = M->dv;\ + assert(is_small(DVS));\ + insert_small_chunk(M, DV, DVS);\ + }\ + M->dvsize = S;\ + M->dv = P;\ +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +#define insert_large_chunk(M, X, S) {\ + tbinptr* H;\ + bindex_t I;\ + compute_tree_index(S, I);\ + H = treebin_at(M, I);\ + X->index = I;\ + X->child[0] = X->child[1] = 0;\ + if (!treemap_is_marked(M, I)) {\ + mark_treemap(M, I);\ + *H = X;\ + X->parent = (tchunkptr)H;\ + X->fd = X->bk = X;\ + }\ + else {\ + tchunkptr T = *H;\ + size_t K = S << leftshift_for_tree_index(I);\ + for (;;) {\ + if (chunksize(T) != S) {\ + tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ + K <<= 1;\ + if (*C != 0)\ + T = *C;\ + else if (RTCHECK(ok_address(M, C))) {\ + *C = X;\ + X->parent = T;\ + X->fd = X->bk = X;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + else {\ + tchunkptr F = T->fd;\ + if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ + T->fd = F->bk = X;\ + X->fd = F;\ + X->bk = T;\ + X->parent = 0;\ + break;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + break;\ + }\ + }\ + }\ + }\ +} + +/* + Unlink steps: + + 1. If x is a chained node, unlink it from its same-sized fd/bk links + and choose its bk node as its replacement. + 2. If x was the last node of its size, but not a leaf node, it must + be replaced with a leaf node (not merely one with an open left or + right), to make sure that lefts and rights of descendents + correspond properly to bit masks. We use the rightmost descendent + of x. We could use any other leaf, but this is easy to locate and + tends to counteract removal of leftmosts elsewhere, and so keeps + paths shorter than minimally guaranteed. This doesn't loop much + because on average a node in a tree is near the bottom. + 3. If x is the base of a chain (i.e., has parent links) relink + x's parent and children to x's replacement (or null if none). +*/ + +#define unlink_large_chunk(M, X) {\ + tchunkptr XP = X->parent;\ + tchunkptr R;\ + if (X->bk != X) {\ + tchunkptr F = X->fd;\ + R = X->bk;\ + if (RTCHECK(ok_address(M, F))) {\ + F->bk = R;\ + R->fd = F;\ + }\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else {\ + tchunkptr* RP;\ + if (((R = *(RP = &(X->child[1]))) != 0) ||\ + ((R = *(RP = &(X->child[0]))) != 0)) {\ + tchunkptr* CP;\ + while ((*(CP = &(R->child[1])) != 0) ||\ + (*(CP = &(R->child[0])) != 0)) {\ + R = *(RP = CP);\ + }\ + if (RTCHECK(ok_address(M, RP)))\ + *RP = 0;\ + else {\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + }\ + if (XP != 0) {\ + tbinptr* H = treebin_at(M, X->index);\ + if (X == *H) {\ + if ((*H = R) == 0) \ + clear_treemap(M, X->index);\ + }\ + else if (RTCHECK(ok_address(M, XP))) {\ + if (XP->child[0] == X) \ + XP->child[0] = R;\ + else \ + XP->child[1] = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + if (R != 0) {\ + if (RTCHECK(ok_address(M, R))) {\ + tchunkptr C0, C1;\ + R->parent = XP;\ + if ((C0 = X->child[0]) != 0) {\ + if (RTCHECK(ok_address(M, C0))) {\ + R->child[0] = C0;\ + C0->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + if ((C1 = X->child[1]) != 0) {\ + if (RTCHECK(ok_address(M, C1))) {\ + R->child[1] = C1;\ + C1->parent = R;\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ + else\ + CORRUPTION_ERROR_ACTION(M);\ + }\ + }\ +} + +/* Relays to large vs small bin operations */ + +#define insert_chunk(M, P, S)\ + if (is_small(S)) insert_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } + +#define unlink_chunk(M, P, S)\ + if (is_small(S)) unlink_small_chunk(M, P, S)\ + else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } + + +/* Relays to internal calls to malloc/free from realloc, memalign etc */ + +#if ONLY_MSPACES +#define internal_malloc(m, b) mspace_malloc(m, b) +#define internal_free(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ +#if MSPACES +#define internal_malloc(m, b)\ + (m == gm)? dlmalloc(b) : mspace_malloc(m, b) +#define internal_free(m, mem)\ + if (m == gm) dlfree(mem); else mspace_free(m,mem); +#else /* MSPACES */ +#define internal_malloc(m, b) dlmalloc(b) +#define internal_free(m, mem) dlfree(mem) +#endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + +/* ----------------------- Direct-mmapping chunks ----------------------- */ + +/* + Directly mmapped chunks are set up with an offset to the start of + the mmapped region stored in the prev_foot field of the chunk. This + allows reconstruction of the required argument to MUNMAP when freed, + and also allows adjustment of the returned chunk to meet alignment + requirements (especially in memalign). There is also enough space + allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain + the PINUSE bit so frees can be checked. +*/ + +/* Malloc using mmap */ +static void* mmap_alloc(mstate m, size_t nb) { + size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + if (mmsize > nb) { /* Check for wrap around 0 */ + char* mm = (char*)(DIRECT_MMAP(mmsize)); + if (mm != CMFAIL) { + size_t offset = align_offset(chunk2mem(mm)); + size_t psize = mmsize - offset - MMAP_FOOT_PAD; + mchunkptr p = (mchunkptr)(mm + offset); + p->prev_foot = offset | IS_MMAPPED_BIT; + (p)->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, p, psize); + chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; + + if (mm < m->least_addr) + m->least_addr = mm; + if ((m->footprint += mmsize) > m->max_footprint) + m->max_footprint = m->footprint; + assert(is_aligned(chunk2mem(p))); + check_mmapped_chunk(m, p); + return chunk2mem(p); + } + } + return 0; +} + +/* Realloc using mmap */ +static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { + size_t oldsize = chunksize(oldp); + if (is_small(nb)) /* Can't shrink mmap regions below small size */ + return 0; + /* Keep old chunk if big enough but not too big */ + if (oldsize >= nb + SIZE_T_SIZE && + (oldsize - nb) <= (mparams.granularity << 1)) + return oldp; + else { + size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT; + size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; + size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES + + CHUNK_ALIGN_MASK); + char* cp = (char*)CALL_MREMAP((char*)oldp - offset, + oldmmsize, newmmsize, 1); + if (cp != CMFAIL) { + mchunkptr newp = (mchunkptr)(cp + offset); + size_t psize = newmmsize - offset - MMAP_FOOT_PAD; + newp->head = (psize|CINUSE_BIT); + mark_inuse_foot(m, newp, psize); + chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; + chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; + + if (cp < m->least_addr) + m->least_addr = cp; + if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) + m->max_footprint = m->footprint; + check_mmapped_chunk(m, newp); + return newp; + } + } + return 0; +} + +/* -------------------------- mspace management -------------------------- */ + +/* Initialize top chunk and its size */ +static void init_top(mstate m, mchunkptr p, size_t psize) { + /* Ensure alignment */ + size_t offset = align_offset(chunk2mem(p)); + p = (mchunkptr)((char*)p + offset); + psize -= offset; + + m->top = p; + m->topsize = psize; + p->head = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; + m->trim_check = mparams.trim_threshold; /* reset on each update */ +} + +/* Initialize bins for a new mstate that is otherwise zeroed out */ +static void init_bins(mstate m) { + /* Establish circular links for smallbins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = smallbin_at(m,i); + bin->fd = bin->bk = bin; + } +} + +#if PROCEED_ON_ERROR + +/* default corruption action */ +static void reset_on_error(mstate m) { + int i; + ++malloc_corruption_error_count; + /* Reinitialize fields to forget about all memory */ + m->smallbins = m->treebins = 0; + m->dvsize = m->topsize = 0; + m->seg.base = 0; + m->seg.size = 0; + m->seg.next = 0; + m->top = m->dv = 0; + for (i = 0; i < NTREEBINS; ++i) + *treebin_at(m, i) = 0; + init_bins(m); +} +#endif /* PROCEED_ON_ERROR */ + +/* Allocate chunk and prepend remainder with chunk in successor base. */ +static void* prepend_alloc(mstate m, char* newbase, char* oldbase, + size_t nb) { + mchunkptr p = align_as_chunk(newbase); + mchunkptr oldfirst = align_as_chunk(oldbase); + size_t psize = (char*)oldfirst - (char*)p; + mchunkptr q = chunk_plus_offset(p, nb); + size_t qsize = psize - nb; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + + assert((char*)oldfirst > (char*)q); + assert(pinuse(oldfirst)); + assert(qsize >= MIN_CHUNK_SIZE); + + /* consolidate remainder with first chunk of old base */ + if (oldfirst == m->top) { + size_t tsize = m->topsize += qsize; + m->top = q; + q->head = tsize | PINUSE_BIT; + check_top_chunk(m, q); + } + else if (oldfirst == m->dv) { + size_t dsize = m->dvsize += qsize; + m->dv = q; + set_size_and_pinuse_of_free_chunk(q, dsize); + } + else { + if (!cinuse(oldfirst)) { + size_t nsize = chunksize(oldfirst); + unlink_chunk(m, oldfirst, nsize); + oldfirst = chunk_plus_offset(oldfirst, nsize); + qsize += nsize; + } + set_free_with_pinuse(q, qsize, oldfirst); + insert_chunk(m, q, qsize); + check_free_chunk(m, q); + } + + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); +} + + +/* Add a segment to hold a new noncontiguous region */ +static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { + /* Determine locations and sizes of segment, fenceposts, old top */ + char* old_top = (char*)m->top; + msegmentptr oldsp = segment_holding(m, old_top); + char* old_end = oldsp->base + oldsp->size; + size_t ssize = pad_request(sizeof(struct malloc_segment)); + char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); + size_t offset = align_offset(chunk2mem(rawsp)); + char* asp = rawsp + offset; + char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; + mchunkptr sp = (mchunkptr)csp; + msegmentptr ss = (msegmentptr)(chunk2mem(sp)); + mchunkptr tnext = chunk_plus_offset(sp, ssize); + mchunkptr p = tnext; + int nfences = 0; + + /* reset top to new space */ + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + + /* Set up segment record */ + assert(is_aligned(ss)); + set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); + *ss = m->seg; /* Push current record */ + m->seg.base = tbase; + m->seg.size = tsize; + m->seg.sflags = mmapped; + m->seg.next = ss; + + /* Insert trailing fenceposts */ + for (;;) { + mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); + p->head = FENCEPOST_HEAD; + ++nfences; + if ((char*)(&(nextp->head)) < old_end) + p = nextp; + else + break; + } + assert(nfences >= 2); + + /* Insert the rest of old top into a bin as an ordinary free chunk */ + if (csp != old_top) { + mchunkptr q = (mchunkptr)old_top; + size_t psize = csp - old_top; + mchunkptr tn = chunk_plus_offset(q, psize); + set_free_with_pinuse(q, psize, tn); + insert_chunk(m, q, psize); + } + + check_top_chunk(m, m->top); +} + +/* -------------------------- System allocation -------------------------- */ + +/* Get memory from system using MORECORE or MMAP */ +static void* sys_alloc(mstate m, size_t nb) { + char* tbase = CMFAIL; + size_t tsize = 0; + flag_t mmap_flag = 0; + + init_mparams(); + + /* Directly map large chunks */ + if (use_mmap(m) && nb >= mparams.mmap_threshold) { + void* mem = mmap_alloc(m, nb); + if (mem != 0) + return mem; + } + + /* + Try getting memory in any of three ways (in most-preferred to + least-preferred order): + 1. A call to MORECORE that can normally contiguously extend memory. + (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or + or main space is mmapped or a previous contiguous call failed) + 2. A call to MMAP new space (disabled if not HAVE_MMAP). + Note that under the default settings, if MORECORE is unable to + fulfill a request, and HAVE_MMAP is true, then mmap is + used as a noncontiguous system allocator. This is a useful backup + strategy for systems with holes in address spaces -- in this case + sbrk cannot contiguously expand the heap, but mmap may be able to + find space. + 3. A call to MORECORE that cannot usually contiguously extend memory. + (disabled if not HAVE_MORECORE) + */ + + if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { + char* br = CMFAIL; + msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); + size_t asize = 0; + ACQUIRE_MORECORE_LOCK(); + + if (ss == 0) { /* First time through or recovery */ + char* base = (char*)CALL_MORECORE(0); + if (base != CMFAIL) { + asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); + /* Adjust to end on a page boundary */ + if (!is_page_aligned(base)) + asize += (page_align((size_t)base) - (size_t)base); + /* Can't call MORECORE if size is negative when treated as signed */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == base) { + tbase = base; + tsize = asize; + } + } + } + else { + /* Subtract out existing available top space from MORECORE request. */ + asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE); + /* Use mem here only if it did continuously extend old space */ + if (asize < HALF_MAX_SIZE_T && + (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { + tbase = br; + tsize = asize; + } + } + + if (tbase == CMFAIL) { /* Cope with partial failure */ + if (br != CMFAIL) { /* Try to use/extend the space we did get */ + if (asize < HALF_MAX_SIZE_T && + asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) { + size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize); + if (esize < HALF_MAX_SIZE_T) { + char* end = (char*)CALL_MORECORE(esize); + if (end != CMFAIL) + asize += esize; + else { /* Can't use; try to release */ + CALL_MORECORE(-asize); + br = CMFAIL; + } + } + } + } + if (br != CMFAIL) { /* Use the space we did get */ + tbase = br; + tsize = asize; + } + else + disable_contiguous(m); /* Don't try contiguous path in the future */ + } + + RELEASE_MORECORE_LOCK(); + } + + if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ + size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; + size_t rsize = granularity_align(req); + if (rsize > nb) { /* Fail if wraps around zero */ + char* mp = (char*)(CALL_MMAP(rsize)); + if (mp != CMFAIL) { + tbase = mp; + tsize = rsize; + mmap_flag = IS_MMAPPED_BIT; + } + } + } + + if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ + size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); + if (asize < HALF_MAX_SIZE_T) { + char* br = CMFAIL; + char* end = CMFAIL; + ACQUIRE_MORECORE_LOCK(); + br = (char*)(CALL_MORECORE(asize)); + end = (char*)(CALL_MORECORE(0)); + RELEASE_MORECORE_LOCK(); + if (br != CMFAIL && end != CMFAIL && br < end) { + size_t ssize = end - br; + if (ssize > nb + TOP_FOOT_SIZE) { + tbase = br; + tsize = ssize; + } + } + } + } + + if (tbase != CMFAIL) { + + if ((m->footprint += tsize) > m->max_footprint) + m->max_footprint = m->footprint; + + if (!is_initialized(m)) { /* first-time initialization */ + m->seg.base = m->least_addr = tbase; + m->seg.size = tsize; + m->seg.sflags = mmap_flag; + m->magic = mparams.magic; + init_bins(m); + if (is_global(m)) + init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); + else { + /* Offset top by embedded malloc_state */ + mchunkptr mn = next_chunk(mem2chunk(m)); + init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); + } + } + + else { + /* Try to merge with an existing segment */ + msegmentptr sp = &m->seg; + while (sp != 0 && tbase != sp->base + sp->size) + sp = sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag && + segment_holds(sp, m->top)) { /* append */ + sp->size += tsize; + init_top(m, m->top, m->topsize + tsize); + } + else { + if (tbase < m->least_addr) + m->least_addr = tbase; + sp = &m->seg; + while (sp != 0 && sp->base != tbase + tsize) + sp = sp->next; + if (sp != 0 && + !is_extern_segment(sp) && + (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) { + char* oldbase = sp->base; + sp->base = tbase; + sp->size += tsize; + return prepend_alloc(m, tbase, oldbase, nb); + } + else + add_segment(m, tbase, tsize, mmap_flag); + } + } + + if (nb < m->topsize) { /* Allocate from new or extended top space */ + size_t rsize = m->topsize -= nb; + mchunkptr p = m->top; + mchunkptr r = m->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(m, p, nb); + check_top_chunk(m, m->top); + check_malloced_chunk(m, chunk2mem(p), nb); + return chunk2mem(p); + } + } + + MALLOC_FAILURE_ACTION; + return 0; +} + +/* ----------------------- system deallocation -------------------------- */ + +/* Unmap and unlink any mmapped segments that don't contain used chunks */ +static size_t release_unused_segments(mstate m) { + size_t released = 0; + msegmentptr pred = &m->seg; + msegmentptr sp = pred->next; + while (sp != 0) { + char* base = sp->base; + size_t size = sp->size; + msegmentptr next = sp->next; + if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { + mchunkptr p = align_as_chunk(base); + size_t psize = chunksize(p); + /* Can unmap if first chunk holds entire segment and not pinned */ + if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { + tchunkptr tp = (tchunkptr)p; + assert(segment_holds(sp, (char*)sp)); + if (p == m->dv) { + m->dv = 0; + m->dvsize = 0; + } + else { + unlink_large_chunk(m, tp); + } + if (CALL_MUNMAP(base, size) == 0) { + released += size; + m->footprint -= size; + /* unlink obsoleted record */ + sp = pred; + sp->next = next; + } + else { /* back out if cannot unmap */ + insert_large_chunk(m, tp, psize); + } + } + } + pred = sp; + sp = next; + } + return released; +} + +static int sys_trim(mstate m, size_t pad) { + size_t released = 0; + if (pad < MAX_REQUEST && is_initialized(m)) { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->topsize > pad) { + /* Shrink top space in granularity-size units, keeping at least one */ + size_t unit = mparams.granularity; + size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - + SIZE_T_ONE) * unit; + msegmentptr sp = segment_holding(m, (char*)m->top); + + if (!is_extern_segment(sp)) { + if (is_mmapped_segment(sp)) { + if (HAVE_MMAP && + sp->size >= extra && + !has_segment_link(m, sp)) { /* can't shrink if pinned */ + size_t newsize = sp->size - extra; + /* Prefer mremap, fall back to munmap */ + if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || + (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { + released = extra; + } + } + } + else if (HAVE_MORECORE) { + if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ + extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; + ACQUIRE_MORECORE_LOCK(); + { + /* Make sure end of memory is where we last set it. */ + char* old_br = (char*)(CALL_MORECORE(0)); + if (old_br == sp->base + sp->size) { + char* rel_br = (char*)(CALL_MORECORE(-extra)); + char* new_br = (char*)(CALL_MORECORE(0)); + if (rel_br != CMFAIL && new_br < old_br) + released = old_br - new_br; + } + } + RELEASE_MORECORE_LOCK(); + } + } + + if (released != 0) { + sp->size -= released; + m->footprint -= released; + init_top(m, m->top, m->topsize - released); + check_top_chunk(m, m->top); + } + } + + /* Unmap any unused mmapped segments */ + if (HAVE_MMAP) + released += release_unused_segments(m); + + /* On failure, disable autotrim to avoid repeated failed future calls */ + if (released == 0) + m->trim_check = MAX_SIZE_T; + } + + return (released != 0)? 1 : 0; +} + +/* ---------------------------- malloc support --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +static void* tmalloc_large(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + compute_tree_index(nb, idx); + + if ((t = *treebin_at(m, idx)) != 0) { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << leftshift_for_tree_index(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) { + tchunkptr rt; + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->child[1]; + t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + + if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ + binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; + if (leftbits != 0) { + bindex_t i; + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + t = *treebin_at(m, i); + } + } + + while (t != 0) { /* find smallest of tree or subtree */ + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = leftmost_child(t); + } + + /* If dv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { + if (RTCHECK(ok_address(m, v))) { /* split */ + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + insert_chunk(m, r, rsize); + } + return chunk2mem(v); + } + } + CORRUPTION_ERROR_ACTION(m); + } + return 0; +} + +/* allocate a small request from the best fitting chunk in a treebin */ +static void* tmalloc_small(mstate m, size_t nb) { + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = least_bit(m->treemap); + compute_bit2idx(leastbit, i); + + v = t = *treebin_at(m, i); + rsize = chunksize(t) - nb; + + while ((t = leftmost_child(t)) != 0) { + size_t trem = chunksize(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + } + + if (RTCHECK(ok_address(m, v))) { + mchunkptr r = chunk_plus_offset(v, nb); + assert(chunksize(v) == rsize + nb); + if (RTCHECK(ok_next(v, r))) { + unlink_large_chunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(m, v, (rsize + nb)); + else { + set_size_and_pinuse_of_inuse_chunk(m, v, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(m, r, rsize); + } + return chunk2mem(v); + } + } + + CORRUPTION_ERROR_ACTION(m); + return 0; +} + +/* --------------------------- realloc support --------------------------- */ + +static void* internal_realloc(mstate m, void* oldmem, size_t bytes) { + if (bytes >= MAX_REQUEST) { + MALLOC_FAILURE_ACTION; + return 0; + } + if (!PREACTION(m)) { + mchunkptr oldp = mem2chunk(oldmem); + size_t oldsize = chunksize(oldp); + mchunkptr next = chunk_plus_offset(oldp, oldsize); + mchunkptr newp = 0; + void* extra = 0; + + /* Try to either shrink or extend into top. Else malloc-copy-free */ + + if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && + ok_next(oldp, next) && ok_pinuse(next))) { + size_t nb = request2size(bytes); + if (is_mmapped(oldp)) + newp = mmap_resize(m, oldp, nb); + else if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + newp = oldp; + if (rsize >= MIN_CHUNK_SIZE) { + mchunkptr remainder = chunk_plus_offset(newp, nb); + set_inuse(m, newp, nb); + set_inuse(m, remainder, rsize); + extra = chunk2mem(remainder); + } + } + else if (next == m->top && oldsize + m->topsize > nb) { + /* Expand into top */ + size_t newsize = oldsize + m->topsize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = chunk_plus_offset(oldp, nb); + set_inuse(m, oldp, nb); + newtop->head = newtopsize |PINUSE_BIT; + m->top = newtop; + m->topsize = newtopsize; + newp = oldp; + } + } + else { + USAGE_ERROR_ACTION(m, oldmem); + POSTACTION(m); + return 0; + } + + POSTACTION(m); + + if (newp != 0) { + if (extra != 0) { + internal_free(m, extra); + } + check_inuse_chunk(m, newp); + return chunk2mem(newp); + } + else { + void* newmem = internal_malloc(m, bytes); + if (newmem != 0) { + size_t oc = oldsize - overhead_for(oldp); + memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); + internal_free(m, oldmem); + } + return newmem; + } + } + return 0; +} + +/* --------------------------- memalign support -------------------------- */ + +static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { + if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */ + return internal_malloc(m, bytes); + if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ + alignment = MIN_CHUNK_SIZE; + if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ + size_t a = MALLOC_ALIGNMENT << 1; + while (a < alignment) a <<= 1; + alignment = a; + } + + if (bytes >= MAX_REQUEST - alignment) { + if (m != 0) { /* Test isn't needed but avoids compiler warning */ + MALLOC_FAILURE_ACTION; + } + } + else { + size_t nb = request2size(bytes); + size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; + char* mem = (char*)internal_malloc(m, req); + if (mem != 0) { + void* leader = 0; + void* trailer = 0; + mchunkptr p = mem2chunk(mem); + + if (PREACTION(m)) return 0; + if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */ + /* + Find an aligned spot inside chunk. Since we need to give + back leading space in a chunk of at least MIN_CHUNK_SIZE, if + the first calculation places us at a spot with less than + MIN_CHUNK_SIZE leader, we can move to the next aligned spot. + We've allocated enough total room so that this is always + possible. + */ + char* br = (char*)mem2chunk((size_t)(((size_t)(mem + + alignment - + SIZE_T_ONE)) & + -alignment)); + char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? + br : br+alignment; + mchunkptr newp = (mchunkptr)pos; + size_t leadsize = pos - (char*)(p); + size_t newsize = chunksize(p) - leadsize; + + if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ + newp->prev_foot = p->prev_foot + leadsize; + newp->head = (newsize|CINUSE_BIT); + } + else { /* Otherwise, give back leader, use the rest */ + set_inuse(m, newp, newsize); + set_inuse(m, p, leadsize); + leader = chunk2mem(p); + } + p = newp; + } + + /* Give back spare room at the end */ + if (!is_mmapped(p)) { + size_t size = chunksize(p); + if (size > nb + MIN_CHUNK_SIZE) { + size_t remainder_size = size - nb; + mchunkptr remainder = chunk_plus_offset(p, nb); + set_inuse(m, p, nb); + set_inuse(m, remainder, remainder_size); + trailer = chunk2mem(remainder); + } + } + + assert (chunksize(p) >= nb); + assert((((size_t)(chunk2mem(p))) % alignment) == 0); + check_inuse_chunk(m, p); + POSTACTION(m); + if (leader != 0) { + internal_free(m, leader); + } + if (trailer != 0) { + internal_free(m, trailer); + } + return chunk2mem(p); + } + } + return 0; +} + +/* ------------------------ comalloc/coalloc support --------------------- */ + +static void** ialloc(mstate m, + size_t n_elements, + size_t* sizes, + int opts, + void* chunks[]) { + /* + This provides common support for independent_X routines, handling + all of the combinations that can result. + + The opts arg has: + bit 0 set if all elements are same size (using sizes[0]) + bit 1 set if elements should be zeroed + */ + + size_t element_size; /* chunksize of each element, if all same */ + size_t contents_size; /* total size of elements */ + size_t array_size; /* request size of pointer array */ + void* mem; /* malloced aggregate space */ + mchunkptr p; /* corresponding chunk */ + size_t remainder_size; /* remaining bytes while splitting */ + void** marray; /* either "chunks" or malloced ptr array */ + mchunkptr array_chunk; /* chunk for malloced ptr array */ + flag_t was_enabled; /* to disable mmap */ + size_t size; + size_t i; + + /* compute array length, if needed */ + if (chunks != 0) { + if (n_elements == 0) + return chunks; /* nothing to do */ + marray = chunks; + array_size = 0; + } + else { + /* if empty req, must still return chunk representing empty array */ + if (n_elements == 0) + return (void**)internal_malloc(m, 0); + marray = 0; + array_size = request2size(n_elements * (sizeof(void*))); + } + + /* compute total element size */ + if (opts & 0x1) { /* all-same-size */ + element_size = request2size(*sizes); + contents_size = n_elements * element_size; + } + else { /* add up all the sizes */ + element_size = 0; + contents_size = 0; + for (i = 0; i != n_elements; ++i) + contents_size += request2size(sizes[i]); + } + + size = contents_size + array_size; + + /* + Allocate the aggregate chunk. First disable direct-mmapping so + malloc won't use it, since we would not be able to later + free/realloc space internal to a segregated mmap region. + */ + was_enabled = use_mmap(m); + disable_mmap(m); + mem = internal_malloc(m, size - CHUNK_OVERHEAD); + if (was_enabled) + enable_mmap(m); + if (mem == 0) + return 0; + + if (PREACTION(m)) return 0; + p = mem2chunk(mem); + remainder_size = chunksize(p); + + assert(!is_mmapped(p)); + + if (opts & 0x2) { /* optionally clear the elements */ + memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); + } + + /* If not provided, allocate the pointer array as final part of chunk */ + if (marray == 0) { + size_t array_chunk_size; + array_chunk = chunk_plus_offset(p, contents_size); + array_chunk_size = remainder_size - contents_size; + marray = (void**) (chunk2mem(array_chunk)); + set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); + remainder_size = contents_size; + } + + /* split out elements */ + for (i = 0; ; ++i) { + marray[i] = chunk2mem(p); + if (i != n_elements-1) { + if (element_size != 0) + size = element_size; + else + size = request2size(sizes[i]); + remainder_size -= size; + set_size_and_pinuse_of_inuse_chunk(m, p, size); + p = chunk_plus_offset(p, size); + } + else { /* the final element absorbs any overallocation slop */ + set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); + break; + } + } + +#if DEBUG + if (marray != chunks) { + /* final element must have exactly exhausted chunk */ + if (element_size != 0) { + assert(remainder_size == element_size); + } + else { + assert(remainder_size == request2size(sizes[i])); + } + check_inuse_chunk(m, mem2chunk(marray)); + } + for (i = 0; i != n_elements; ++i) + check_inuse_chunk(m, mem2chunk(marray[i])); + +#endif /* DEBUG */ + + POSTACTION(m); + return marray; +} + + +/* -------------------------- public routines ---------------------------- */ + +#if !ONLY_MSPACES + +void* dlmalloc(size_t bytes) { + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the dv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in dv. + 4. If it is big enough, use the top chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than dv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the dv chunk. + 3. If it is big enough, use the top chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it + + The ugly goto's here ensure that postaction occurs along all paths. + */ + + if (!PREACTION(gm)) { + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); + idx = small_index(nb); + smallbits = gm->smallmap >> idx; + + if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = smallbin_at(gm, idx); + p = b->fd; + assert(chunksize(p) == small_index2size(idx)); + unlink_first_small_chunk(gm, b, p, idx); + set_inuse_and_pinuse(gm, p, small_index2size(idx)); + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb > gm->dvsize) { + if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); + binmap_t leastbit = least_bit(leftbits); + compute_bit2idx(leastbit, i); + b = smallbin_at(gm, i); + p = b->fd; + assert(chunksize(p) == small_index2size(i)); + unlink_first_small_chunk(gm, b, p, i); + rsize = small_index2size(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + set_inuse_and_pinuse(gm, p, small_index2size(i)); + else { + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + r = chunk_plus_offset(p, nb); + set_size_and_pinuse_of_free_chunk(r, rsize); + replace_dv(gm, r, rsize); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else { + nb = pad_request(bytes); + if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + } + + if (nb <= gm->dvsize) { + size_t rsize = gm->dvsize - nb; + mchunkptr p = gm->dv; + if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ + mchunkptr r = gm->dv = chunk_plus_offset(p, nb); + gm->dvsize = rsize; + set_size_and_pinuse_of_free_chunk(r, rsize); + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + } + else { /* exhaust dv */ + size_t dvs = gm->dvsize; + gm->dvsize = 0; + gm->dv = 0; + set_inuse_and_pinuse(gm, p, dvs); + } + mem = chunk2mem(p); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + else if (nb < gm->topsize) { /* Split top */ + size_t rsize = gm->topsize -= nb; + mchunkptr p = gm->top; + mchunkptr r = gm->top = chunk_plus_offset(p, nb); + r->head = rsize | PINUSE_BIT; + set_size_and_pinuse_of_inuse_chunk(gm, p, nb); + mem = chunk2mem(p); + check_top_chunk(gm, gm->top); + check_malloced_chunk(gm, mem, nb); + goto postaction; + } + + mem = sys_alloc(gm, nb); + + postaction: + POSTACTION(gm); + return mem; + } + + return 0; +} + +void dlfree(void* mem) { + /* + Consolidate freed chunks with preceeding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for top, dv, mmapped chunks, and usage errors. + */ + + if (mem != 0) { + mchunkptr p = mem2chunk(mem); +#if FOOTERS + mstate fm = get_mstate_for(p); + if (!ok_magic(fm)) { + USAGE_ERROR_ACTION(fm, p); + return; + } +#else /* FOOTERS */ +#define fm gm +#endif /* FOOTERS */ + if (!PREACTION(fm)) { + check_inuse_chunk(fm, p); + if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { + size_t psize = chunksize(p); + mchunkptr next = chunk_plus_offset(p, psize); + if (!pinuse(p)) { + size_t prevsize = p->prev_foot; + if ((prevsize & IS_MMAPPED_BIT) != 0) { + prevsize &= ~IS_MMAPPED_BIT; + psize += prevsize + MMAP_FOOT_PAD; + if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) + fm->footprint -= psize; + goto postaction; + } + else { + mchunkptr prev = chunk_minus_offset(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ + if (p != fm->dv) { + unlink_chunk(fm, p, prevsize); + } + else if ((next->head & INUSE_BITS) == INUSE_BITS) { + fm->dvsize = psize; + set_free_with_pinuse(p, psize, next); + goto postaction; + } + } + else + goto erroraction; + } + } + + if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { + if (!cinuse(next)) { /* consolidate forward */ + if (next == fm->top) { + size_t tsize = fm->topsize += psize; + fm->top = p; + p->head = tsize | PINUSE_BIT; + if (p == fm->dv) { + fm->dv = 0; + fm->dvsize = 0; + } + if (should_trim(fm, tsize)) + sys_trim(fm, 0); + goto postaction; + } + else if (next == fm->dv) { + size_t dsize = fm->dvsize += psize; + fm->dv = p; + set_size_and_pinuse_of_free_chunk(p, dsize); + goto postaction; + } + else { + size_t nsize = chunksize(next); + psize += nsize; + unlink_chunk(fm, next, nsize); + set_size_and_pinuse_of_free_chunk(p, psize); + if (p == fm->dv) { + fm->dvsize = psize; + goto postaction; + } + } + } + else + set_free_with_pinuse(p, psize, next); + insert_chunk(fm, p, psize); + check_free_chunk(fm, p); + goto postaction; + } + } + erroraction: + USAGE_ERROR_ACTION(fm, p); + postaction: + POSTACTION(fm); + } + } +#if !FOOTERS +#undef fm +#endif /* FOOTERS */ +} + +void* dlcalloc(size_t n_elements, size_t elem_size) { + void* mem; + size_t req = 0; + if (n_elements != 0) { + req = n_elements * elem_size; + if (((n_elements | elem_size) & ~(size_t)0xffff) && + (req / n_elements != elem_size)) + req = MAX_SIZE_T; /* force downstream failure on overflow */ + } + mem = dlmalloc(req); + if (mem != 0) + memset(mem, 0, req); + return mem; +} + +void* dlrealloc(void* oldmem, size_t bytes) { + if (oldmem == 0) + return dlmalloc(bytes); +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { + dlfree(oldmem); + return 0; + } +#endif /* REALLOC_ZERO_BYTES_FREES */ + else { +#if ! FOOTERS + mstate m = gm; +#else /* FOOTERS */ + mstate m = get_mstate_for(mem2chunk(oldmem)); + if (!ok_magic(m)) { + USAGE_ERROR_ACTION(m, oldmem); + return 0; + } +#endif /* FOOTERS */ + return internal_realloc(m, oldmem, bytes); + } +} + +void* dlmemalign(size_t alignment, size_t bytes) { + return internal_memalign(gm, alignment, bytes); +} + +void** dlindependent_calloc(size_t n_elements, size_t elem_size, + void* chunks[]) { + size_t sz = elem_size; /* serves as 1-element array */ + return ialloc(gm, n_elements, &sz, 3, chunks); +} + +void** dlindependent_comalloc(size_t n_elements, size_t sizes[], + void* chunks[]) { + return ialloc(gm, n_elements, sizes, 0, chunks); +} + +void* dlvalloc(size_t bytes) { + size_t pagesz; + init_mparams(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, bytes); +} + +void* dlpvalloc(size_t bytes) { + size_t pagesz; + init_mparams(); + pagesz = mparams.page_size; + return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); +} + +int dlmalloc_trim(size_t pad) { + int result = 0; + if (!PREACTION(gm)) { + result = sys_trim(gm, pad); + POSTACTION(gm); + } + return result; +} + +size_t dlmalloc_footprint(void) { + return gm->footprint; +} + +size_t dlmalloc_max_footprint(void) { + return gm->max_footprint; +} + +#if !NO_MALLINFO +struct mallinfo dlmallinfo(void) { + return internal_mallinfo(gm); +} +#endif /* NO_MALLINFO */ + +//void dlmalloc_stats() { +// internal_malloc_stats(gm); +//} + +size_t dlmalloc_usable_size(void* mem) { + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (cinuse(p)) + return chunksize(p) - overhead_for(p); + } + return 0; +} + +int dlmallopt(int param_number, int value) { + return change_mparam(param_number, value); +} + +#endif /* !ONLY_MSPACES */ + +/* ----------------------------- user mspaces ---------------------------- */ + +#if MSPACES +#endif /* MSPACES */ + +/* -------------------- Alternative MORECORE functions ------------------- */ + +/* + Guidelines for creating a custom version of MORECORE: + + * For best performance, MORECORE should allocate in multiples of pagesize. + * MORECORE may allocate more memory than requested. (Or even less, + but this will usually result in a malloc failure.) + * MORECORE must not allocate memory when given argument zero, but + instead return one past the end address of memory from previous + nonzero call. + * For best performance, consecutive calls to MORECORE with positive + arguments should return increasing addresses, indicating that + space has been contiguously extended. + * Even though consecutive calls to MORECORE need not return contiguous + addresses, it must be OK for malloc'ed chunks to span multiple + regions in those cases where they do happen to be contiguous. + * MORECORE need not handle negative arguments -- it may instead + just return MFAIL when given negative arguments. + Negative arguments are always multiples of pagesize. MORECORE + must not misinterpret negative args as large positive unsigned + args. You can suppress all such calls from even occurring by defining + MORECORE_CANNOT_TRIM, + + As an example alternative MORECORE, here is a custom allocator + kindly contributed for pre-OSX macOS. It uses virtually but not + necessarily physically contiguous non-paged memory (locked in, + present and won't get swapped out). You can use it by uncommenting + this section, adding some #includes, and setting up the appropriate + defines above: + + #define MORECORE osMoreCore + + There is also a shutdown routine that should somehow be called for + cleanup upon program exit. + + #define MAX_POOL_ENTRIES 100 + #define MINIMUM_MORECORE_SIZE (64 * 1024U) + static int next_os_pool; + void *our_os_pools[MAX_POOL_ENTRIES]; + + void *osMoreCore(int size) + { + void *ptr = 0; + static void *sbrk_top = 0; + + if (size > 0) + { + if (size < MINIMUM_MORECORE_SIZE) + size = MINIMUM_MORECORE_SIZE; + if (CurrentExecutionLevel() == kTaskLevel) + ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); + if (ptr == 0) + { + return (void *) MFAIL; + } + // save ptrs so they can be freed during cleanup + our_os_pools[next_os_pool] = ptr; + next_os_pool++; + ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); + sbrk_top = (char *) ptr + size; + return ptr; + } + else if (size < 0) + { + // we don't currently support shrink behavior + return (void *) MFAIL; + } + else + { + return sbrk_top; + } + } + + // cleanup any allocated memory pools + // called as last thing before shutting down driver + + void osCleanupMem(void) + { + void **ptr; + + for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) + if (*ptr) + { + PoolDeallocate(*ptr); + *ptr = 0; + } + } + +*/ + + +/* ----------------------------------------------------------------------- +History: + V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) + * Add max_footprint functions + * Ensure all appropriate literals are size_t + * Fix conditional compilation problem for some #define settings + * Avoid concatenating segments with the one provided + in create_mspace_with_base + * Rename some variables to avoid compiler shadowing warnings + * Use explicit lock initialization. + * Better handling of sbrk interference. + * Simplify and fix segment insertion, trimming and mspace_destroy + * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x + * Thanks especially to Dennis Flanagan for help on these. + + V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) + * Fix memalign brace error. + + V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) + * Fix improper #endif nesting in C++ + * Add explicit casts needed for C++ + + V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) + * Use trees for large bins + * Support mspaces + * Use segments to unify sbrk-based and mmap-based system allocation, + removing need for emulation on most platforms without sbrk. + * Default safety checks + * Optional footer checks. Thanks to William Robertson for the idea. + * Internal code refactoring + * Incorporate suggestions and platform-specific changes. + Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, + Aaron Bachmann, Emery Berger, and others. + * Speed up non-fastbin processing enough to remove fastbins. + * Remove useless cfree() to avoid conflicts with other apps. + * Remove internal memcpy, memset. Compilers handle builtins better. + * Remove some options that no one ever used and rename others. + + V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) + * Fix malloc_state bitmap array misdeclaration + + V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) + * Allow tuning of FIRST_SORTED_BIN_SIZE + * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. + * Better detection and support for non-contiguousness of MORECORE. + Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger + * Bypass most of malloc if no frees. Thanks To Emery Berger. + * Fix freeing of old top non-contiguous chunk im sysmalloc. + * Raised default trim and map thresholds to 256K. + * Fix mmap-related #defines. Thanks to Lubos Lunak. + * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. + * Branch-free bin calculation + * Default trim and mmap thresholds now 256K. + + V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) + * Introduce independent_comalloc and independent_calloc. + Thanks to Michael Pachos for motivation and help. + * Make optional .h file available + * Allow > 2GB requests on 32bit systems. + * new WIN32 sbrk, mmap, munmap, lock code from . + Thanks also to Andreas Mueller , + and Anonymous. + * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for + helping test this.) + * memalign: check alignment arg + * realloc: don't try to shift chunks backwards, since this + leads to more fragmentation in some programs and doesn't + seem to help in any others. + * Collect all cases in malloc requiring system memory into sysmalloc + * Use mmap as backup to sbrk + * Place all internal state in malloc_state + * Introduce fastbins (although similar to 2.5.1) + * Many minor tunings and cosmetic improvements + * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK + * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS + Thanks to Tony E. Bennett and others. + * Include errno.h to support default failure action. + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/programs/system/drivers/rhd/memset.asm b/programs/system/drivers/rhd/memset.asm new file mode 100644 index 000000000..bb445235a --- /dev/null +++ b/programs/system/drivers/rhd/memset.asm @@ -0,0 +1,52 @@ +/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ +##include +# .file "memset.s" + .text + .global _memset + .align 4 +_memset: + pushl %ebp + movl %esp,%ebp + pushl %edi + movl 8(%ebp),%edi + movl 12(%ebp),%eax + movl 16(%ebp),%ecx + cld + + # We will handle memsets of <= 15 bytes one byte at a time. + # This avoids some extra overhead for small memsets, and + # knowing we are setting > 15 bytes eliminates some annoying + # checks in the "long move" case. + cmpl $15,%ecx + jle L3 + + # Otherwise, tile the byte value out into %eax. + # 0x41 -> 0x41414141, etc. + movb %al,%ah + movl %eax,%edx + sall $16,%eax + movw %dx,%ax + jmp L2 + + # Handle any cruft necessary to get %edi long-aligned. +L1: stosb + decl %ecx +L2: testl $3,%edi + jnz L1 + + # Now slam out all of the longs. + movl %ecx,%edx + shrl $2,%ecx + rep + stosl + + # Finally, handle any trailing cruft. We know the high three bytes + # of %ecx must be zero, so just put the "slop count" in the low byte. + movb %dl,%cl + andb $3,%cl +L3: rep + stosb + popl %edi + movl 8(%ebp),%eax + leave + ret diff --git a/programs/system/drivers/rhd/pci.c b/programs/system/drivers/rhd/pci.c new file mode 100644 index 000000000..8fb529db4 --- /dev/null +++ b/programs/system/drivers/rhd/pci.c @@ -0,0 +1,159 @@ + +#include "common.h" +#include "pci.h" + + +int +pciGetBaseSize(int bus, int devfn, int index, Bool destructive, Bool *min) +{ + int offset; + CARD32 addr1; + CARD32 addr2; + CARD32 mask1; + CARD32 mask2; + int bits = 0; + + /* + * silently ignore bogus index values. Valid values are 0-6. 0-5 are + * the 6 base address registers, and 6 is the ROM base address register. + */ + if (index < 0 || index > 6) + return 0; + + if (min) + *min = destructive; + + /* Get the PCI offset */ + if (index == 6) + offset = PCI_MAP_ROM_REG; + else + offset = PCI_MAP_REG_START + (index << 2); + + addr1 = PciRead32(bus, devfn, offset); + /* + * Check if this is the second part of a 64 bit address. + * XXX need to check how endianness affects 64 bit addresses. + */ + if (index > 0 && index < 6) { + addr2 = PciRead32(bus, devfn, offset - 4); + if (PCI_MAP_IS_MEM(addr2) && PCI_MAP_IS64BITMEM(addr2)) + return 0; + } + + if (destructive) { + PciWrite32(bus, devfn, offset, 0xffffffff); + mask1 = PciRead32(bus, devfn, offset); + PciWrite32(bus, devfn, offset, addr1); + } else { + mask1 = addr1; + } + + /* Check if this is the first part of a 64 bit address. */ + if (index < 5 && PCI_MAP_IS_MEM(mask1) && PCI_MAP_IS64BITMEM(mask1)) + { + if (PCIGETMEMORY(mask1) == 0) + { + addr2 = PciRead32(bus, devfn, offset + 4); + if (destructive) + { + PciWrite32(bus, devfn, offset + 4, 0xffffffff); + mask2 = PciRead32(bus, devfn, offset + 4); + PciWrite32(bus, devfn, offset + 4, addr2); + } + else + { + mask2 = addr2; + } + if (mask2 == 0) + return 0; + bits = 32; + while ((mask2 & 1) == 0) + { + bits++; + mask2 >>= 1; + } + if (bits > 32) + return bits; + } + } + if (index < 6) + if (PCI_MAP_IS_MEM(mask1)) + mask1 = PCIGETMEMORY(mask1); + else + mask1 = PCIGETIO(mask1); + else + mask1 = PCIGETROM(mask1); + if (mask1 == 0) + return 0; + bits = 0; + while ((mask1 & 1) == 0) { + bits++; + mask1 >>= 1; + } + /* I/O maps can be no larger than 8 bits */ + + if ((index < 6) && PCI_MAP_IS_IO(addr1) && bits > 8) + bits = 8; + /* ROM maps can be no larger than 24 bits */ + if (index == 6 && bits > 24) + bits = 24; + return bits; +} + +/* + int chipRev; + int subsysVendor; + int subsysCard; + int bus; + int devfn; +// int func; + int class; + int subclass; + int interface; + memType memBase[6]; + memType ioBase[6]; + int size[6]; + unsigned char type[6]; + memType biosBase; + int biosSize; +*/ + +int pciGetInfo(pciVideoPtr pci) +{ + CARD32 reg0,reg2C; + int i; + + reg0 = PciRead32(pci->bus,pci->devfn, 0); + reg2C = PciRead32(pci->bus,pci->devfn, 0x2C); + + pci->vendor = reg0 & 0xFFFF; + pci->devtype = reg0 >> 16; + + pci->subsysVendor = reg2C & 0xFFFF; + pci->subsysCard = reg2C >> 16; + + for (i = 0; i < 6; i++) + { + CARD32 base; + + base = PciRead32(pci->bus,pci->devfn, PCI_MAP_REG_START + (i << 2)); + if(base) + { + if (base & PCI_MAP_IO) + { + pci->ioBase[i] = (memType)PCIGETIO(base); + pci->type[i] = base & PCI_MAP_IO_ATTR_MASK; + } + else + { + pci->type[i] = base & PCI_MAP_MEMORY_ATTR_MASK; + pci->memBase[i] = (memType)PCIGETMEMORY(base); + } + } + + pci->size[i] = + pciGetBaseSize(pci->bus,pci->devfn, i, TRUE, &pci->validSize); + } + +} + diff --git a/programs/system/drivers/rhd/pci.h b/programs/system/drivers/rhd/pci.h new file mode 100644 index 000000000..df45a4124 --- /dev/null +++ b/programs/system/drivers/rhd/pci.h @@ -0,0 +1,70 @@ + +typedef unsigned long PCITAG; + +typedef struct { + int vendor; + int devtype; + int devRev; + int subsysVendor; + int subsysCard; + int bus; + int devfn; +// int func; + int class; + int subclass; + int interface; + memType memBase[6]; + memType ioBase[6]; + int size[6]; + unsigned char type[6]; + memType biosBase; + int biosSize; +// pointer thisCard; + Bool validSize; +// Bool validate; +// CARD32 listed_class; +} pciVideoRec, *pciVideoPtr; + + +#define PCI_MAP_REG_START 0x10 +#define PCI_MAP_REG_END 0x28 +#define PCI_MAP_ROM_REG 0x30 + +#define PCI_MAP_MEMORY 0x00000000 +#define PCI_MAP_IO 0x00000001 + +#define PCI_MAP_MEMORY_TYPE 0x00000007 +#define PCI_MAP_IO_TYPE 0x00000003 + +#define PCI_MAP_MEMORY_TYPE_32BIT 0x00000000 +#define PCI_MAP_MEMORY_TYPE_32BIT_1M 0x00000002 +#define PCI_MAP_MEMORY_TYPE_64BIT 0x00000004 +#define PCI_MAP_MEMORY_TYPE_MASK 0x00000006 +#define PCI_MAP_MEMORY_CACHABLE 0x00000008 +#define PCI_MAP_MEMORY_ATTR_MASK 0x0000000e +#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0 + +#define PCI_MAP_IO_ATTR_MASK 0x00000003 + +#define PCI_MAP_IS_IO(b) ((b) & PCI_MAP_IO) +#define PCI_MAP_IS_MEM(b) (!PCI_MAP_IS_IO(b)) + +#define PCI_MAP_IS64BITMEM(b) \ + (((b) & PCI_MAP_MEMORY_TYPE_MASK) == PCI_MAP_MEMORY_TYPE_64BIT) + +#define PCIGETMEMORY(b) ((b) & PCI_MAP_MEMORY_ADDRESS_MASK) +#define PCIGETMEMORY64HIGH(b) (*((CARD32*)&b + 1)) +#define PCIGETMEMORY64(b) \ + (PCIGETMEMORY(b) | ((CARD64)PCIGETMEMORY64HIGH(b) << 32)) + +#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc + +#define PCIGETIO(b) ((b) & PCI_MAP_IO_ADDRESS_MASK) + +#define PCI_MAP_ROM_DECODE_ENABLE 0x00000001 +#define PCI_MAP_ROM_ADDRESS_MASK 0xfffff800 + +#define PCIGETROM(b) ((b) & PCI_MAP_ROM_ADDRESS_MASK) + +int pciGetBaseSize(int bus, int devfn, int index, Bool destructive, Bool *min); +int pciGetInfo(pciVideoPtr pci); diff --git a/programs/system/drivers/rhd/proc32.inc b/programs/system/drivers/rhd/proc32.inc new file mode 100644 index 000000000..f623e7273 --- /dev/null +++ b/programs/system/drivers/rhd/proc32.inc @@ -0,0 +1,269 @@ + + +; Macroinstructions for defining and calling procedures + +macro stdcall proc,[arg] ; directly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call proc } + +macro invoke proc,[arg] ; indirectly call STDCALL procedure + { common + if ~ arg eq + reverse + pushd arg + common + end if + call [proc] } + +macro ccall proc,[arg] ; directly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call proc + if size@ccall + add esp,size@ccall + end if } + +macro cinvoke proc,[arg] ; indirectly call CDECL procedure + { common + size@ccall = 0 + if ~ arg eq + reverse + pushd arg + size@ccall = size@ccall+4 + common + end if + call [proc] + if size@ccall + add esp,size@ccall + end if } + +macro proc [args] ; define procedure + { common + match name params, args> + \{ define@proc name, \{ prologue name,flag,parmbytes,localbytes,reglist \} + macro locals + \{ virtual at ebp-localbytes+current + macro label . \\{ deflocal@proc .,:, \\} + struc db [val] \\{ \common deflocal@proc .,db,val \\} + struc dw [val] \\{ \common deflocal@proc .,dw,val \\} + struc dp [val] \\{ \common deflocal@proc .,dp,val \\} + struc dd [val] \\{ \common deflocal@proc .,dd,val \\} + struc dt [val] \\{ \common deflocal@proc .,dt,val \\} + struc dq [val] \\{ \common deflocal@proc .,dq,val \\} + struc rb cnt \\{ deflocal@proc .,rb cnt, \\} + struc rw cnt \\{ deflocal@proc .,rw cnt, \\} + struc rp cnt \\{ deflocal@proc .,rp cnt, \\} + struc rd cnt \\{ deflocal@proc .,rd cnt, \\} + struc rt cnt \\{ deflocal@proc .,rt cnt, \\} + struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} + macro endl + \{ purge label + restruc db,dw,dp,dd,dt,dq + restruc rb,rw,rp,rd,rt,rq + restruc byte,word,dword,pword,tword,qword + current = $-(ebp-localbytes) + end virtual \} + macro ret operand + \{ match any, operand \\{ retn operand \\} + match , operand \\{ match epilogue:reglist, epilogue@proc: + \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} + macro finish@proc \{ localbytes = (((current-1) shr 2)+1) shl 2 + end if \} } + +macro defargs@proc [arg] + { common + if ~ arg eq + forward + local ..arg,current@arg + match argname:type, arg + \{ current@arg equ argname + label ..arg type + argname equ ..arg + if dqword eq type + dd ?,?,?,? + else if tbyte eq type + dd ?,?,? + else if qword eq type | pword eq type + dd ?,? + else + dd ? + end if \} + match =current@arg,current@arg + \{ current@arg equ arg + arg equ ..arg + ..arg dd ? \} + common + args@proc equ current@arg + forward + restore current@arg + common + end if } + +macro deflocal@proc name,def,[val] + { common + match vars, all@vars \{ all@vars equ all@vars, \} + all@vars equ all@vars name + forward + local ..var,..tmp + ..var def val + match =?, val \{ ..tmp equ \} + match any =dup (=?), val \{ ..tmp equ \} + match tmp : value, ..tmp : val + \{ tmp: end virtual + initlocal@proc ..var,def value + virtual at tmp\} + common + match first rest, ..var, \{ name equ first \} } + +macro initlocal@proc name,def + { virtual at name + def + size@initlocal = $ - name + end virtual + position@initlocal = 0 + while size@initlocal > position@initlocal + virtual at name + def + if size@initlocal - position@initlocal < 2 + current@initlocal = 1 + load byte@initlocal byte from name+position@initlocal + else if size@initlocal - position@initlocal < 4 + current@initlocal = 2 + load word@initlocal word from name+position@initlocal + else + current@initlocal = 4 + load dword@initlocal dword from name+position@initlocal + end if + end virtual + if current@initlocal = 1 + mov byte [name+position@initlocal],byte@initlocal + else if current@initlocal = 2 + mov word [name+position@initlocal],word@initlocal + else + mov dword [name+position@initlocal],dword@initlocal + end if + position@initlocal = position@initlocal + current@initlocal + end while } + +macro endp + { purge ret,locals,endl + finish@proc + purge finish@proc + restore regs@proc + match all,args@proc \{ restore all \} + restore args@proc + match all,all@vars \{ restore all \} } + +macro local [var] + { common + locals + forward done@local equ + match varname[count]:vartype, var + \{ match =BYTE, vartype \\{ varname rb count + restore done@local \\} + match =WORD, vartype \\{ varname rw count + restore done@local \\} + match =DWORD, vartype \\{ varname rd count + restore done@local \\} + match =PWORD, vartype \\{ varname rp count + restore done@local \\} + match =QWORD, vartype \\{ varname rq count + restore done@local \\} + match =TBYTE, vartype \\{ varname rt count + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + rq count+count + restore done@local \\} + match , done@local \\{ virtual + varname vartype + end virtual + rb count*sizeof.\#vartype + restore done@local \\} \} + match :varname:vartype, done@local:var + \{ match =BYTE, vartype \\{ varname db ? + restore done@local \\} + match =WORD, vartype \\{ varname dw ? + restore done@local \\} + match =DWORD, vartype \\{ varname dd ? + restore done@local \\} + match =PWORD, vartype \\{ varname dp ? + restore done@local \\} + match =QWORD, vartype \\{ varname dq ? + restore done@local \\} + match =TBYTE, vartype \\{ varname dt ? + restore done@local \\} + match =DQWORD, vartype \\{ label varname dqword + dq ?,? + restore done@local \\} + match , done@local \\{ varname vartype + restore done@local \\} \} + match ,done@local + \{ var + restore done@local \} + common + endl } diff --git a/programs/system/drivers/rhd/r5xx_accel.h b/programs/system/drivers/rhd/r5xx_accel.h new file mode 100644 index 000000000..b0c03326f --- /dev/null +++ b/programs/system/drivers/rhd/r5xx_accel.h @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Luc Verhaegen + * Copyright 2008 Matthias Hopf + * Copyright 2008 Egbert Eich + * Copyright 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. + */ + +/* + * Functionality shared by both R5xx XAA and EXA code. + */ + +#ifndef _RHD_ACCEL_H +#define _RHD_ACCEL_H 1 + + +#endif /* _RHD_ACCEL_H */ diff --git a/programs/system/drivers/rhd/radeon_reg.h b/programs/system/drivers/rhd/radeon_reg.h new file mode 100644 index 000000000..7d9bad399 --- /dev/null +++ b/programs/system/drivers/rhd/radeon_reg.h @@ -0,0 +1,4985 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * 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 on 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 (including the + * next paragraph) 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 + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS 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. + */ + +/* + * Authors: + * Kevin E. Martin + * Rickard E. Faith + * Alan Hourihane + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * !!!! FIXME !!!! + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +/* !!!! FIXME !!!! NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h + * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT + * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! */ + +#ifndef _RADEON_REG_H_ +#define _RADEON_REG_H_ + +#define ATI_DATATYPE_VQ 0 +#define ATI_DATATYPE_CI4 1 +#define ATI_DATATYPE_CI8 2 +#define ATI_DATATYPE_ARGB1555 3 +#define ATI_DATATYPE_RGB565 4 +#define ATI_DATATYPE_RGB888 5 +#define ATI_DATATYPE_ARGB8888 6 +#define ATI_DATATYPE_RGB332 7 +#define ATI_DATATYPE_Y8 8 +#define ATI_DATATYPE_RGB8 9 +#define ATI_DATATYPE_CI16 10 +#define ATI_DATATYPE_VYUY_422 11 +#define ATI_DATATYPE_YVYU_422 12 +#define ATI_DATATYPE_AYUV_444 14 +#define ATI_DATATYPE_ARGB4444 15 + + /* Registers for 2D/Video/Overlay */ +#define RADEON_ADAPTER_ID 0x0f2c /* PCI */ +#define RADEON_AGP_BASE 0x0170 +#define RADEON_AGP_CNTL 0x0174 +# define RADEON_AGP_APER_SIZE_256MB (0x00 << 0) +# define RADEON_AGP_APER_SIZE_128MB (0x20 << 0) +# define RADEON_AGP_APER_SIZE_64MB (0x30 << 0) +# define RADEON_AGP_APER_SIZE_32MB (0x38 << 0) +# define RADEON_AGP_APER_SIZE_16MB (0x3c << 0) +# define RADEON_AGP_APER_SIZE_8MB (0x3e << 0) +# define RADEON_AGP_APER_SIZE_4MB (0x3f << 0) +# define RADEON_AGP_APER_SIZE_MASK (0x3f << 0) +#define RADEON_STATUS_PCI_CONFIG 0x06 +# define RADEON_CAP_LIST 0x100000 +#define RADEON_CAPABILITIES_PTR_PCI_CONFIG 0x34 /* offset in PCI config*/ +# define RADEON_CAP_PTR_MASK 0xfc /* mask off reserved bits of CAP_PTR */ +# define RADEON_CAP_ID_NULL 0x00 /* End of capability list */ +# define RADEON_CAP_ID_AGP 0x02 /* AGP capability ID */ +# define RADEON_CAP_ID_EXP 0x10 /* PCI Express */ +#define RADEON_AGP_COMMAND 0x0f60 /* PCI */ +#define RADEON_AGP_COMMAND_PCI_CONFIG 0x0060 /* offset in PCI config*/ +# define RADEON_AGP_ENABLE (1<<8) +#define RADEON_AGP_PLL_CNTL 0x000b /* PLL */ +#define RADEON_AGP_STATUS 0x0f5c /* PCI */ +# define RADEON_AGP_1X_MODE 0x01 +# define RADEON_AGP_2X_MODE 0x02 +# define RADEON_AGP_4X_MODE 0x04 +# define RADEON_AGP_FW_MODE 0x10 +# define RADEON_AGP_MODE_MASK 0x17 +# define RADEON_AGPv3_MODE 0x08 +# define RADEON_AGPv3_4X_MODE 0x01 +# define RADEON_AGPv3_8X_MODE 0x02 +#define RADEON_ATTRDR 0x03c1 /* VGA */ +#define RADEON_ATTRDW 0x03c0 /* VGA */ +#define RADEON_ATTRX 0x03c0 /* VGA */ +#define RADEON_AUX_SC_CNTL 0x1660 +# define RADEON_AUX1_SC_EN (1 << 0) +# define RADEON_AUX1_SC_MODE_OR (0 << 1) +# define RADEON_AUX1_SC_MODE_NAND (1 << 1) +# define RADEON_AUX2_SC_EN (1 << 2) +# define RADEON_AUX2_SC_MODE_OR (0 << 3) +# define RADEON_AUX2_SC_MODE_NAND (1 << 3) +# define RADEON_AUX3_SC_EN (1 << 4) +# define RADEON_AUX3_SC_MODE_OR (0 << 5) +# define RADEON_AUX3_SC_MODE_NAND (1 << 5) +#define RADEON_AUX1_SC_BOTTOM 0x1670 +#define RADEON_AUX1_SC_LEFT 0x1664 +#define RADEON_AUX1_SC_RIGHT 0x1668 +#define RADEON_AUX1_SC_TOP 0x166c +#define RADEON_AUX2_SC_BOTTOM 0x1680 +#define RADEON_AUX2_SC_LEFT 0x1674 +#define RADEON_AUX2_SC_RIGHT 0x1678 +#define RADEON_AUX2_SC_TOP 0x167c +#define RADEON_AUX3_SC_BOTTOM 0x1690 +#define RADEON_AUX3_SC_LEFT 0x1684 +#define RADEON_AUX3_SC_RIGHT 0x1688 +#define RADEON_AUX3_SC_TOP 0x168c +#define RADEON_AUX_WINDOW_HORZ_CNTL 0x02d8 +#define RADEON_AUX_WINDOW_VERT_CNTL 0x02dc + +#define RADEON_BASE_CODE 0x0f0b +#define RADEON_BIOS_0_SCRATCH 0x0010 +# define RADEON_FP_PANEL_SCALABLE (1 << 16) +# define RADEON_FP_PANEL_SCALE_EN (1 << 17) +# define RADEON_FP_CHIP_SCALE_EN (1 << 18) +# define RADEON_DRIVER_BRIGHTNESS_EN (1 << 26) +# define RADEON_DISPLAY_ROT_MASK (3 << 28) +# define RADEON_DISPLAY_ROT_00 (0 << 28) +# define RADEON_DISPLAY_ROT_90 (1 << 28) +# define RADEON_DISPLAY_ROT_180 (2 << 28) +# define RADEON_DISPLAY_ROT_270 (3 << 28) +#define RADEON_BIOS_1_SCRATCH 0x0014 +#define RADEON_BIOS_2_SCRATCH 0x0018 +#define RADEON_BIOS_3_SCRATCH 0x001c +#define RADEON_BIOS_4_SCRATCH 0x0020 +# define RADEON_CRT1_ATTACHED_MASK (3 << 0) +# define RADEON_CRT1_ATTACHED_MONO (1 << 0) +# define RADEON_CRT1_ATTACHED_COLOR (2 << 0) +# define RADEON_LCD1_ATTACHED (1 << 2) +# define RADEON_DFP1_ATTACHED (1 << 3) +# define RADEON_TV1_ATTACHED_MASK (3 << 4) +# define RADEON_TV1_ATTACHED_COMP (1 << 4) +# define RADEON_TV1_ATTACHED_SVIDEO (2 << 4) +# define RADEON_CRT2_ATTACHED_MASK (3 << 8) +# define RADEON_CRT2_ATTACHED_MONO (1 << 8) +# define RADEON_CRT2_ATTACHED_COLOR (2 << 8) +# define RADEON_DFP2_ATTACHED (1 << 11) +#define RADEON_BIOS_5_SCRATCH 0x0024 +# define RADEON_LCD1_ON (1 << 0) +# define RADEON_CRT1_ON (1 << 1) +# define RADEON_TV1_ON (1 << 2) +# define RADEON_DFP1_ON (1 << 3) +# define RADEON_CRT2_ON (1 << 5) +# define RADEON_CV1_ON (1 << 6) +# define RADEON_DFP2_ON (1 << 7) +# define RADEON_LCD1_CRTC_MASK (1 << 8) +# define RADEON_LCD1_CRTC_SHIFT 8 +# define RADEON_CRT1_CRTC_MASK (1 << 9) +# define RADEON_CRT1_CRTC_SHIFT 9 +# define RADEON_TV1_CRTC_MASK (1 << 10) +# define RADEON_TV1_CRTC_SHIFT 10 +# define RADEON_DFP1_CRTC_MASK (1 << 11) +# define RADEON_DFP1_CRTC_SHIFT 11 +# define RADEON_CRT2_CRTC_MASK (1 << 12) +# define RADEON_CRT2_CRTC_SHIFT 12 +# define RADEON_CV1_CRTC_MASK (1 << 13) +# define RADEON_CV1_CRTC_SHIFT 13 +# define RADEON_DFP2_CRTC_MASK (1 << 14) +# define RADEON_DFP2_CRTC_SHIFT 14 +#define RADEON_BIOS_6_SCRATCH 0x0028 +# define RADEON_ACC_MODE_CHANGE (1 << 2) +# define RADEON_EXT_DESKTOP_MODE (1 << 3) +# define RADEON_LCD_DPMS_ON (1 << 20) +# define RADEON_CRT_DPMS_ON (1 << 21) +# define RADEON_TV_DPMS_ON (1 << 22) +# define RADEON_DFP_DPMS_ON (1 << 23) +# define RADEON_DPMS_MASK (3 << 24) +# define RADEON_DPMS_ON (0 << 24) +# define RADEON_DPMS_STANDBY (1 << 24) +# define RADEON_DPMS_SUSPEND (2 << 24) +# define RADEON_DPMS_OFF (3 << 24) +# define RADEON_SCREEN_BLANKING (1 << 26) +# define RADEON_DRIVER_CRITICAL (1 << 27) +# define RADEON_DISPLAY_SWITCHING_DIS (1 << 30) +#define RADEON_BIOS_7_SCRATCH 0x002c +# define RADEON_SYS_HOTKEY (1 << 10) +# define RADEON_DRV_LOADED (1 << 12) +#define RADEON_BIOS_ROM 0x0f30 /* PCI */ +#define RADEON_BIST 0x0f0f /* PCI */ +#define RADEON_BRUSH_DATA0 0x1480 +#define RADEON_BRUSH_DATA1 0x1484 +#define RADEON_BRUSH_DATA10 0x14a8 +#define RADEON_BRUSH_DATA11 0x14ac +#define RADEON_BRUSH_DATA12 0x14b0 +#define RADEON_BRUSH_DATA13 0x14b4 +#define RADEON_BRUSH_DATA14 0x14b8 +#define RADEON_BRUSH_DATA15 0x14bc +#define RADEON_BRUSH_DATA16 0x14c0 +#define RADEON_BRUSH_DATA17 0x14c4 +#define RADEON_BRUSH_DATA18 0x14c8 +#define RADEON_BRUSH_DATA19 0x14cc +#define RADEON_BRUSH_DATA2 0x1488 +#define RADEON_BRUSH_DATA20 0x14d0 +#define RADEON_BRUSH_DATA21 0x14d4 +#define RADEON_BRUSH_DATA22 0x14d8 +#define RADEON_BRUSH_DATA23 0x14dc +#define RADEON_BRUSH_DATA24 0x14e0 +#define RADEON_BRUSH_DATA25 0x14e4 +#define RADEON_BRUSH_DATA26 0x14e8 +#define RADEON_BRUSH_DATA27 0x14ec +#define RADEON_BRUSH_DATA28 0x14f0 +#define RADEON_BRUSH_DATA29 0x14f4 +#define RADEON_BRUSH_DATA3 0x148c +#define RADEON_BRUSH_DATA30 0x14f8 +#define RADEON_BRUSH_DATA31 0x14fc +#define RADEON_BRUSH_DATA32 0x1500 +#define RADEON_BRUSH_DATA33 0x1504 +#define RADEON_BRUSH_DATA34 0x1508 +#define RADEON_BRUSH_DATA35 0x150c +#define RADEON_BRUSH_DATA36 0x1510 +#define RADEON_BRUSH_DATA37 0x1514 +#define RADEON_BRUSH_DATA38 0x1518 +#define RADEON_BRUSH_DATA39 0x151c +#define RADEON_BRUSH_DATA4 0x1490 +#define RADEON_BRUSH_DATA40 0x1520 +#define RADEON_BRUSH_DATA41 0x1524 +#define RADEON_BRUSH_DATA42 0x1528 +#define RADEON_BRUSH_DATA43 0x152c +#define RADEON_BRUSH_DATA44 0x1530 +#define RADEON_BRUSH_DATA45 0x1534 +#define RADEON_BRUSH_DATA46 0x1538 +#define RADEON_BRUSH_DATA47 0x153c +#define RADEON_BRUSH_DATA48 0x1540 +#define RADEON_BRUSH_DATA49 0x1544 +#define RADEON_BRUSH_DATA5 0x1494 +#define RADEON_BRUSH_DATA50 0x1548 +#define RADEON_BRUSH_DATA51 0x154c +#define RADEON_BRUSH_DATA52 0x1550 +#define RADEON_BRUSH_DATA53 0x1554 +#define RADEON_BRUSH_DATA54 0x1558 +#define RADEON_BRUSH_DATA55 0x155c +#define RADEON_BRUSH_DATA56 0x1560 +#define RADEON_BRUSH_DATA57 0x1564 +#define RADEON_BRUSH_DATA58 0x1568 +#define RADEON_BRUSH_DATA59 0x156c +#define RADEON_BRUSH_DATA6 0x1498 +#define RADEON_BRUSH_DATA60 0x1570 +#define RADEON_BRUSH_DATA61 0x1574 +#define RADEON_BRUSH_DATA62 0x1578 +#define RADEON_BRUSH_DATA63 0x157c +#define RADEON_BRUSH_DATA7 0x149c +#define RADEON_BRUSH_DATA8 0x14a0 +#define RADEON_BRUSH_DATA9 0x14a4 +#define RADEON_BRUSH_SCALE 0x1470 +#define RADEON_BRUSH_Y_X 0x1474 +#define RADEON_BUS_CNTL 0x0030 +# define RADEON_BUS_MASTER_DIS (1 << 6) +# define RADEON_BUS_RD_DISCARD_EN (1 << 24) +# define RADEON_BUS_RD_ABORT_EN (1 << 25) +# define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define RADEON_BUS_WRT_BURST (1 << 29) +# define RADEON_BUS_READ_BURST (1 << 30) +#define RADEON_BUS_CNTL1 0x0034 +# define RADEON_BUS_WAIT_ON_LOCK_EN (1 << 4) + +#define RADEON_CACHE_CNTL 0x1724 +#define RADEON_CACHE_LINE 0x0f0c /* PCI */ +#define RADEON_CAPABILITIES_ID 0x0f50 /* PCI */ +#define RADEON_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define RADEON_CLK_PIN_CNTL 0x0001 /* PLL */ +# define RADEON_SCLK_DYN_START_CNTL (1 << 15) +#define RADEON_CLOCK_CNTL_DATA 0x000c +#define RADEON_CLOCK_CNTL_INDEX 0x0008 +# define RADEON_PLL_WR_EN (1 << 7) +# define RADEON_PLL_DIV_SEL (3 << 8) +# define RADEON_PLL2_DIV_SEL_MASK ~(3 << 8) +#define RADEON_CLK_PWRMGT_CNTL 0x0014 +# define RADEON_ENGIN_DYNCLK_MODE (1 << 12) +# define RADEON_ACTIVE_HILO_LAT_MASK (3 << 13) +# define RADEON_ACTIVE_HILO_LAT_SHIFT 13 +# define RADEON_DISP_DYN_STOP_LAT_MASK (1 << 12) +# define RADEON_MC_BUSY (1 << 16) +# define RADEON_DLL_READY (1 << 19) +# define RADEON_CG_NO1_DEBUG_0 (1 << 24) +# define RADEON_CG_NO1_DEBUG_MASK (0x1f << 24) +# define RADEON_DYN_STOP_MODE_MASK (7 << 21) +# define RADEON_TVPLL_PWRMGT_OFF (1 << 30) +# define RADEON_TVCLK_TURNOFF (1 << 31) +#define RADEON_PLL_PWRMGT_CNTL 0x0015 +# define RADEON_TCL_BYPASS_DISABLE (1 << 20) +#define RADEON_CLR_CMP_CLR_3D 0x1a24 +#define RADEON_CLR_CMP_CLR_DST 0x15c8 +#define RADEON_CLR_CMP_CLR_SRC 0x15c4 +#define RADEON_CLR_CMP_CNTL 0x15c0 +# define RADEON_SRC_CMP_EQ_COLOR (4 << 0) +# define RADEON_SRC_CMP_NEQ_COLOR (5 << 0) +# define RADEON_CLR_CMP_SRC_SOURCE (1 << 24) +#define RADEON_CLR_CMP_MASK 0x15cc +# define RADEON_CLR_CMP_MSK 0xffffffff +#define RADEON_CLR_CMP_MASK_3D 0x1A28 +#define RADEON_COMMAND 0x0f04 /* PCI */ +#define RADEON_COMPOSITE_SHADOW_ID 0x1a0c +#define RADEON_CONFIG_APER_0_BASE 0x0100 +#define RADEON_CONFIG_APER_1_BASE 0x0104 +#define RADEON_CONFIG_APER_SIZE 0x0108 +#define RADEON_CONFIG_BONDS 0x00e8 +#define RADEON_CONFIG_CNTL 0x00e0 +# define RADEON_CFG_ATI_REV_A11 (0 << 16) +# define RADEON_CFG_ATI_REV_A12 (1 << 16) +# define RADEON_CFG_ATI_REV_A13 (2 << 16) +# define RADEON_CFG_ATI_REV_ID_MASK (0xf << 16) +#define RADEON_CONFIG_MEMSIZE 0x00f8 +#define RADEON_CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define RADEON_CONFIG_REG_1_BASE 0x010c +#define RADEON_CONFIG_REG_APER_SIZE 0x0110 +#define RADEON_CONFIG_XSTRAP 0x00e4 +#define RADEON_CONSTANT_COLOR_C 0x1d34 +# define RADEON_CONSTANT_COLOR_MASK 0x00ffffff +# define RADEON_CONSTANT_COLOR_ONE 0x00ffffff +# define RADEON_CONSTANT_COLOR_ZERO 0x00000000 +#define RADEON_CRC_CMDFIFO_ADDR 0x0740 +#define RADEON_CRC_CMDFIFO_DOUT 0x0744 +#define RADEON_GRPH_BUFFER_CNTL 0x02f0 +# define RADEON_GRPH_START_REQ_MASK (0x7f) +# define RADEON_GRPH_START_REQ_SHIFT 0 +# define RADEON_GRPH_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH_STOP_REQ_SHIFT 8 +# define RADEON_GRPH_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH_BUFFER_SIZE (1<<29) +# define RADEON_GRPH_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH_STOP_CNTL (1<<31) +#define RADEON_GRPH2_BUFFER_CNTL 0x03f0 +# define RADEON_GRPH2_START_REQ_MASK (0x7f) +# define RADEON_GRPH2_START_REQ_SHIFT 0 +# define RADEON_GRPH2_STOP_REQ_MASK (0x7f<<8) +# define RADEON_GRPH2_STOP_REQ_SHIFT 8 +# define RADEON_GRPH2_CRITICAL_POINT_MASK (0x7f<<16) +# define RADEON_GRPH2_CRITICAL_POINT_SHIFT 16 +# define RADEON_GRPH2_CRITICAL_CNTL (1<<28) +# define RADEON_GRPH2_BUFFER_SIZE (1<<29) +# define RADEON_GRPH2_CRITICAL_AT_SOF (1<<30) +# define RADEON_GRPH2_STOP_CNTL (1<<31) +#define RADEON_CRTC_CRNT_FRAME 0x0214 +#define RADEON_CRTC_EXT_CNTL 0x0054 +# define RADEON_CRTC_VGA_XOVERSCAN (1 << 0) +# define RADEON_VGA_ATI_LINEAR (1 << 3) +# define RADEON_XCRT_CNT_EN (1 << 6) +# define RADEON_CRTC_HSYNC_DIS (1 << 8) +# define RADEON_CRTC_VSYNC_DIS (1 << 9) +# define RADEON_CRTC_DISPLAY_DIS (1 << 10) +# define RADEON_CRTC_SYNC_TRISTAT (1 << 11) +# define RADEON_CRTC_CRT_ON (1 << 15) +#define RADEON_CRTC_EXT_CNTL_DPMS_BYTE 0x0055 +# define RADEON_CRTC_HSYNC_DIS_BYTE (1 << 0) +# define RADEON_CRTC_VSYNC_DIS_BYTE (1 << 1) +# define RADEON_CRTC_DISPLAY_DIS_BYTE (1 << 2) +#define RADEON_CRTC_GEN_CNTL 0x0050 +# define RADEON_CRTC_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC_INTERLACE_EN (1 << 1) +# define RADEON_CRTC_CSYNC_EN (1 << 4) +# define RADEON_CRTC_ICON_EN (1 << 15) +# define RADEON_CRTC_CUR_EN (1 << 16) +# define RADEON_CRTC_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC_EXT_DISP_EN (1 << 24) +# define RADEON_CRTC_EN (1 << 25) +# define RADEON_CRTC_DISP_REQ_EN_B (1 << 26) +#define RADEON_CRTC2_GEN_CNTL 0x03f8 +# define RADEON_CRTC2_DBL_SCAN_EN (1 << 0) +# define RADEON_CRTC2_INTERLACE_EN (1 << 1) +# define RADEON_CRTC2_SYNC_TRISTAT (1 << 4) +# define RADEON_CRTC2_HSYNC_TRISTAT (1 << 5) +# define RADEON_CRTC2_VSYNC_TRISTAT (1 << 6) +# define RADEON_CRTC2_CRT2_ON (1 << 7) +# define RADEON_CRTC2_PIX_WIDTH_SHIFT 8 +# define RADEON_CRTC2_PIX_WIDTH_MASK (0xf << 8) +# define RADEON_CRTC2_ICON_EN (1 << 15) +# define RADEON_CRTC2_CUR_EN (1 << 16) +# define RADEON_CRTC2_CUR_MODE_MASK (7 << 20) +# define RADEON_CRTC2_DISP_DIS (1 << 23) +# define RADEON_CRTC2_EN (1 << 25) +# define RADEON_CRTC2_DISP_REQ_EN_B (1 << 26) +# define RADEON_CRTC2_CSYNC_EN (1 << 27) +# define RADEON_CRTC2_HSYNC_DIS (1 << 28) +# define RADEON_CRTC2_VSYNC_DIS (1 << 29) +#define RADEON_CRTC_MORE_CNTL 0x27c +# define RADEON_CRTC_AUTO_HORZ_CENTER_EN (1<<2) +# define RADEON_CRTC_AUTO_VERT_CENTER_EN (1<<3) +# define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) +# define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) +#define RADEON_CRTC_GUI_TRIG_VLINE 0x0218 +#define RADEON_CRTC_H_SYNC_STRT_WID 0x0204 +# define RADEON_CRTC_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_H_SYNC_POL (1 << 23) +#define RADEON_CRTC2_H_SYNC_STRT_WID 0x0304 +# define RADEON_CRTC2_H_SYNC_STRT_PIX (0x07 << 0) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR (0x3ff << 3) +# define RADEON_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3 +# define RADEON_CRTC2_H_SYNC_WID (0x3f << 16) +# define RADEON_CRTC2_H_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_H_SYNC_POL (1 << 23) +#define RADEON_CRTC_H_TOTAL_DISP 0x0200 +# define RADEON_CRTC_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC_H_TOTAL_SHIFT 0 +# define RADEON_CRTC_H_DISP (0x01ff << 16) +# define RADEON_CRTC_H_DISP_SHIFT 16 +#define RADEON_CRTC2_H_TOTAL_DISP 0x0300 +# define RADEON_CRTC2_H_TOTAL (0x03ff << 0) +# define RADEON_CRTC2_H_TOTAL_SHIFT 0 +# define RADEON_CRTC2_H_DISP (0x01ff << 16) +# define RADEON_CRTC2_H_DISP_SHIFT 16 + +#define RADEON_CRTC_OFFSET_RIGHT 0x0220 +#define RADEON_CRTC_OFFSET 0x0224 +# define RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET (1<<30) +# define RADEON_CRTC_OFFSET__OFFSET_LOCK (1<<31) + +#define RADEON_CRTC2_OFFSET 0x0324 +# define RADEON_CRTC2_OFFSET__GUI_TRIG_OFFSET (1<<30) +# define RADEON_CRTC2_OFFSET__OFFSET_LOCK (1<<31) +#define RADEON_CRTC_OFFSET_CNTL 0x0228 +# define RADEON_CRTC_TILE_LINE_SHIFT 0 +# define RADEON_CRTC_TILE_LINE_RIGHT_SHIFT 4 +# define R300_CRTC_X_Y_MODE_EN_RIGHT (1 << 6) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_MASK (3 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_AUTO (0 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_SINGLE (1 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DOUBLE (2 << 7) +# define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DIS (3 << 7) +# define R300_CRTC_X_Y_MODE_EN (1 << 9) +# define R300_CRTC_MICRO_TILE_BUFFER_MASK (3 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_AUTO (0 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_SINGLE (1 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_DOUBLE (2 << 10) +# define R300_CRTC_MICRO_TILE_BUFFER_DIS (3 << 10) +# define R300_CRTC_MICRO_TILE_EN_RIGHT (1 << 12) +# define R300_CRTC_MICRO_TILE_EN (1 << 13) +# define R300_CRTC_MACRO_TILE_EN_RIGHT (1 << 14) +# define R300_CRTC_MACRO_TILE_EN (1 << 15) +# define RADEON_CRTC_TILE_EN_RIGHT (1 << 14) +# define RADEON_CRTC_TILE_EN (1 << 15) +# define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16) +# define RADEON_CRTC_STEREO_OFFSET_EN (1 << 17) + +#define R300_CRTC_TILE_X0_Y0 0x0350 +#define R300_CRTC2_TILE_X0_Y0 0x0358 + +#define RADEON_CRTC2_OFFSET_CNTL 0x0328 +# define RADEON_CRTC2_OFFSET_FLIP_CNTL (1 << 16) +# define RADEON_CRTC2_TILE_EN (1 << 15) +#define RADEON_CRTC_PITCH 0x022c +# define RADEON_CRTC_PITCH__SHIFT 0 +# define RADEON_CRTC_PITCH__RIGHT_SHIFT 16 + +#define RADEON_CRTC2_PITCH 0x032c +#define RADEON_CRTC_STATUS 0x005c +# define RADEON_CRTC_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC2_STATUS 0x03fc +# define RADEON_CRTC2_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC_V_SYNC_STRT_WID 0x020c +# define RADEON_CRTC_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC_V_SYNC_POL (1 << 23) +#define RADEON_CRTC2_V_SYNC_STRT_WID 0x030c +# define RADEON_CRTC2_V_SYNC_STRT (0x7ff << 0) +# define RADEON_CRTC2_V_SYNC_STRT_SHIFT 0 +# define RADEON_CRTC2_V_SYNC_WID (0x1f << 16) +# define RADEON_CRTC2_V_SYNC_WID_SHIFT 16 +# define RADEON_CRTC2_V_SYNC_POL (1 << 23) +#define RADEON_CRTC_V_TOTAL_DISP 0x0208 +# define RADEON_CRTC_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC_V_TOTAL_SHIFT 0 +# define RADEON_CRTC_V_DISP (0x07ff << 16) +# define RADEON_CRTC_V_DISP_SHIFT 16 +#define RADEON_CRTC2_V_TOTAL_DISP 0x0308 +# define RADEON_CRTC2_V_TOTAL (0x07ff << 0) +# define RADEON_CRTC2_V_TOTAL_SHIFT 0 +# define RADEON_CRTC2_V_DISP (0x07ff << 16) +# define RADEON_CRTC2_V_DISP_SHIFT 16 +#define RADEON_CRTC_VLINE_CRNT_VLINE 0x0210 +# define RADEON_CRTC_CRNT_VLINE_MASK (0x7ff << 16) +#define RADEON_CRTC2_CRNT_FRAME 0x0314 +#define RADEON_CRTC2_GUI_TRIG_VLINE 0x0318 +#define RADEON_CRTC2_STATUS 0x03fc +#define RADEON_CRTC2_VLINE_CRNT_VLINE 0x0310 +#define RADEON_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ +#define RADEON_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ +#define RADEON_CUR_CLR0 0x026c +#define RADEON_CUR_CLR1 0x0270 +#define RADEON_CUR_HORZ_VERT_OFF 0x0268 +#define RADEON_CUR_HORZ_VERT_POSN 0x0264 +#define RADEON_CUR_OFFSET 0x0260 +# define RADEON_CUR_LOCK (1 << 31) +#define RADEON_CUR2_CLR0 0x036c +#define RADEON_CUR2_CLR1 0x0370 +#define RADEON_CUR2_HORZ_VERT_OFF 0x0368 +#define RADEON_CUR2_HORZ_VERT_POSN 0x0364 +#define RADEON_CUR2_OFFSET 0x0360 +# define RADEON_CUR2_LOCK (1 << 31) + +#define RADEON_DAC_CNTL 0x0058 +# define RADEON_DAC_RANGE_CNTL (3 << 0) +# define RADEON_DAC_RANGE_CNTL_PS2 (2 << 0) +# define RADEON_DAC_RANGE_CNTL_MASK 0x03 +# define RADEON_DAC_BLANKING (1 << 2) +# define RADEON_DAC_CMP_EN (1 << 3) +# define RADEON_DAC_CMP_OUTPUT (1 << 7) +# define RADEON_DAC_8BIT_EN (1 << 8) +# define RADEON_DAC_TVO_EN (1 << 10) +# define RADEON_DAC_VGA_ADR_EN (1 << 13) +# define RADEON_DAC_PDWN (1 << 15) +# define RADEON_DAC_MASK_ALL (0xff << 24) +#define RADEON_DAC_CNTL2 0x007c +# define RADEON_DAC2_TV_CLK_SEL (0 << 1) +# define RADEON_DAC2_DAC_CLK_SEL (1 << 0) +# define RADEON_DAC2_DAC2_CLK_SEL (1 << 1) +# define RADEON_DAC2_PALETTE_ACC_CTL (1 << 5) +# define RADEON_DAC2_CMP_EN (1 << 7) +# define RADEON_DAC2_CMP_OUT_R (1 << 8) +# define RADEON_DAC2_CMP_OUT_G (1 << 9) +# define RADEON_DAC2_CMP_OUT_B (1 << 10) +# define RADEON_DAC2_CMP_OUTPUT (1 << 11) +#define RADEON_DAC_EXT_CNTL 0x0280 +# define RADEON_DAC2_FORCE_BLANK_OFF_EN (1 << 0) +# define RADEON_DAC2_FORCE_DATA_EN (1 << 1) +# define RADEON_DAC_FORCE_BLANK_OFF_EN (1 << 4) +# define RADEON_DAC_FORCE_DATA_EN (1 << 5) +# define RADEON_DAC_FORCE_DATA_SEL_MASK (3 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_R (0 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_G (1 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_B (2 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_RGB (3 << 6) +# define RADEON_DAC_FORCE_DATA_MASK 0x0003ff00 +# define RADEON_DAC_FORCE_DATA_SHIFT 8 +#define RADEON_DAC_MACRO_CNTL 0x0d04 +# define RADEON_DAC_PDWN_R (1 << 16) +# define RADEON_DAC_PDWN_G (1 << 17) +# define RADEON_DAC_PDWN_B (1 << 18) +#define RADEON_TV_DAC_CNTL 0x088c +# define RADEON_TV_DAC_NBLANK (1 << 0) +# define RADEON_TV_DAC_NHOLD (1 << 1) +# define RADEON_TV_DAC_PEDESTAL (1 << 2) +# define RADEON_TV_MONITOR_DETECT_EN (1 << 4) +# define RADEON_TV_DAC_CMPOUT (1 << 5) +# define RADEON_TV_DAC_STD_MASK (3 << 8) +# define RADEON_TV_DAC_STD_PAL (0 << 8) +# define RADEON_TV_DAC_STD_NTSC (1 << 8) +# define RADEON_TV_DAC_STD_PS2 (2 << 8) +# define RADEON_TV_DAC_STD_RS343 (3 << 8) +# define RADEON_TV_DAC_BGSLEEP (1 << 6) +# define RADEON_TV_DAC_BGADJ_MASK (0xf << 16) +# define RADEON_TV_DAC_BGADJ_SHIFT 16 +# define RADEON_TV_DAC_DACADJ_MASK (0xf << 20) +# define RADEON_TV_DAC_DACADJ_SHIFT 20 +# define RADEON_TV_DAC_RDACPD (1 << 24) +# define RADEON_TV_DAC_GDACPD (1 << 25) +# define RADEON_TV_DAC_BDACPD (1 << 26) +# define RADEON_TV_DAC_RDACDET (1 << 29) +# define RADEON_TV_DAC_GDACDET (1 << 30) +# define RADEON_TV_DAC_BDACDET (1 << 31) +# define R420_TV_DAC_DACADJ_MASK (0x1f << 20) +# define R420_TV_DAC_RDACPD (1 << 25) +# define R420_TV_DAC_GDACPD (1 << 26) +# define R420_TV_DAC_BDACPD (1 << 27) +# define R420_TV_DAC_TVENABLE (1 << 28) +#define RADEON_DISP_HW_DEBUG 0x0d14 +# define RADEON_CRT2_DISP1_SEL (1 << 5) +#define RADEON_DISP_OUTPUT_CNTL 0x0d64 +# define RADEON_DISP_DAC_SOURCE_MASK 0x03 +# define RADEON_DISP_DAC2_SOURCE_MASK 0x0c +# define RADEON_DISP_DAC_SOURCE_CRTC2 0x01 +# define RADEON_DISP_DAC_SOURCE_RMX 0x02 +# define RADEON_DISP_DAC_SOURCE_LTU 0x03 +# define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04 +# define RADEON_DISP_TVDAC_SOURCE_MASK (0x03 << 2) +# define RADEON_DISP_TVDAC_SOURCE_CRTC 0x0 +# define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01 << 2) +# define RADEON_DISP_TVDAC_SOURCE_RMX (0x02 << 2) +# define RADEON_DISP_TVDAC_SOURCE_LTU (0x03 << 2) +# define RADEON_DISP_TRANS_MATRIX_MASK (0x03 << 4) +# define RADEON_DISP_TRANS_MATRIX_ALPHA_MSB (0x00 << 4) +# define RADEON_DISP_TRANS_MATRIX_GRAPHICS (0x01 << 4) +# define RADEON_DISP_TRANS_MATRIX_VIDEO (0x02 << 4) +# define RADEON_DISP_TV_SOURCE_CRTC (1 << 16) /* crtc1 or crtc2 */ +# define RADEON_DISP_TV_SOURCE_LTU (0 << 16) /* linear transform unit */ +#define RADEON_DISP_TV_OUT_CNTL 0x0d6c +# define RADEON_DISP_TV_PATH_SRC_CRTC2 (1 << 16) +# define RADEON_DISP_TV_PATH_SRC_CRTC1 (0 << 16) +#define RADEON_DAC_CRC_SIG 0x02cc +#define RADEON_DAC_DATA 0x03c9 /* VGA */ +#define RADEON_DAC_MASK 0x03c6 /* VGA */ +#define RADEON_DAC_R_INDEX 0x03c7 /* VGA */ +#define RADEON_DAC_W_INDEX 0x03c8 /* VGA */ +#define RADEON_DDA_CONFIG 0x02e0 +#define RADEON_DDA_ON_OFF 0x02e4 +#define RADEON_DEFAULT_OFFSET 0x16e0 +#define RADEON_DEFAULT_PITCH 0x16e4 +#define RADEON_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +# define RADEON_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) +# define RADEON_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) +#define RADEON_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define RADEON_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define RADEON_DEVICE_ID 0x0f02 /* PCI */ +#define RADEON_DISP_MISC_CNTL 0x0d00 +# define RADEON_SOFT_RESET_GRPH_PP (1 << 0) +#define RADEON_DISP_MERGE_CNTL 0x0d60 +# define RADEON_DISP_ALPHA_MODE_MASK 0x03 +# define RADEON_DISP_ALPHA_MODE_KEY 0 +# define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1 +# define RADEON_DISP_ALPHA_MODE_GLOBAL 2 +# define RADEON_DISP_RGB_OFFSET_EN (1 << 8) +# define RADEON_DISP_GRPH_ALPHA_MASK (0xff << 16) +# define RADEON_DISP_OV0_ALPHA_MASK (0xff << 24) +# define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9) +#define RADEON_DISP2_MERGE_CNTL 0x0d68 +# define RADEON_DISP2_RGB_OFFSET_EN (1 << 8) +#define RADEON_DISP_LIN_TRANS_GRPH_A 0x0d80 +#define RADEON_DISP_LIN_TRANS_GRPH_B 0x0d84 +#define RADEON_DISP_LIN_TRANS_GRPH_C 0x0d88 +#define RADEON_DISP_LIN_TRANS_GRPH_D 0x0d8c +#define RADEON_DISP_LIN_TRANS_GRPH_E 0x0d90 +#define RADEON_DISP_LIN_TRANS_GRPH_F 0x0d98 +#define RADEON_DP_BRUSH_BKGD_CLR 0x1478 +#define RADEON_DP_BRUSH_FRGD_CLR 0x147c +#define RADEON_DP_CNTL 0x16c0 +# define RADEON_DST_X_LEFT_TO_RIGHT (1 << 0) +# define RADEON_DST_Y_TOP_TO_BOTTOM (1 << 1) +# define RADEON_DP_DST_TILE_LINEAR (0 << 3) +# define RADEON_DP_DST_TILE_MACRO (1 << 3) +# define RADEON_DP_DST_TILE_MICRO (2 << 3) +# define RADEON_DP_DST_TILE_BOTH (3 << 3) +#define RADEON_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +# define RADEON_DST_Y_MAJOR (1 << 2) +# define RADEON_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) +# define RADEON_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) +#define RADEON_DP_DATATYPE 0x16c4 +# define RADEON_HOST_BIG_ENDIAN_EN (1 << 29) +#define RADEON_DP_GUI_MASTER_CNTL 0x146c +# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define RADEON_GMC_SRC_CLIPPING (1 << 2) +# define RADEON_GMC_DST_CLIPPING (1 << 3) +# define RADEON_GMC_BRUSH_DATATYPE_MASK (0x0f << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4) +# define RADEON_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4) +# define RADEON_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4) +# define RADEON_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4) +# define RADEON_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4) +# define RADEON_GMC_BRUSH_8x8_COLOR (10 << 4) +# define RADEON_GMC_BRUSH_1X8_COLOR (12 << 4) +# define RADEON_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define RADEON_GMC_BRUSH_NONE (15 << 4) +# define RADEON_GMC_DST_8BPP_CI (2 << 8) +# define RADEON_GMC_DST_15BPP (3 << 8) +# define RADEON_GMC_DST_16BPP (4 << 8) +# define RADEON_GMC_DST_24BPP (5 << 8) +# define RADEON_GMC_DST_32BPP (6 << 8) +# define RADEON_GMC_DST_8BPP_RGB (7 << 8) +# define RADEON_GMC_DST_Y8 (8 << 8) +# define RADEON_GMC_DST_RGB8 (9 << 8) +# define RADEON_GMC_DST_VYUY (11 << 8) +# define RADEON_GMC_DST_YVYU (12 << 8) +# define RADEON_GMC_DST_AYUV444 (14 << 8) +# define RADEON_GMC_DST_ARGB4444 (15 << 8) +# define RADEON_GMC_DST_DATATYPE_MASK (0x0f << 8) +# define RADEON_GMC_DST_DATATYPE_SHIFT 8 +# define RADEON_GMC_SRC_DATATYPE_MASK (3 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12) +# define RADEON_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) +# define RADEON_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define RADEON_GMC_BYTE_PIX_ORDER (1 << 14) +# define RADEON_GMC_BYTE_MSB_TO_LSB (0 << 14) +# define RADEON_GMC_BYTE_LSB_TO_MSB (1 << 14) +# define RADEON_GMC_CONVERSION_TEMP (1 << 15) +# define RADEON_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define RADEON_GMC_CONVERSION_TEMP_9300 (1 << 15) +# define RADEON_GMC_ROP3_MASK (0xff << 16) +# define RADEON_DP_SRC_SOURCE_MASK (7 << 24) +# define RADEON_DP_SRC_SOURCE_MEMORY (2 << 24) +# define RADEON_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define RADEON_GMC_3D_FCN_EN (1 << 27) +# define RADEON_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define RADEON_GMC_AUX_CLIP_DIS (1 << 29) +# define RADEON_GMC_WR_MSK_DIS (1 << 30) +# define RADEON_GMC_LD_BRUSH_Y_X (1 << 31) +# define RADEON_ROP3_ZERO 0x00000000 +# define RADEON_ROP3_DSa 0x00880000 +# define RADEON_ROP3_SDna 0x00440000 +# define RADEON_ROP3_S 0x00cc0000 +# define RADEON_ROP3_DSna 0x00220000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DSx 0x00660000 +# define RADEON_ROP3_DSo 0x00ee0000 +# define RADEON_ROP3_DSon 0x00110000 +# define RADEON_ROP3_DSxn 0x00990000 +# define RADEON_ROP3_Dn 0x00550000 +# define RADEON_ROP3_SDno 0x00dd0000 +# define RADEON_ROP3_Sn 0x00330000 +# define RADEON_ROP3_DSno 0x00bb0000 +# define RADEON_ROP3_DSan 0x00770000 +# define RADEON_ROP3_ONE 0x00ff0000 +# define RADEON_ROP3_DPa 0x00a00000 +# define RADEON_ROP3_PDna 0x00500000 +# define RADEON_ROP3_P 0x00f00000 +# define RADEON_ROP3_DPna 0x000a0000 +# define RADEON_ROP3_D 0x00aa0000 +# define RADEON_ROP3_DPx 0x005a0000 +# define RADEON_ROP3_DPo 0x00fa0000 +# define RADEON_ROP3_DPon 0x00050000 +# define RADEON_ROP3_PDxn 0x00a50000 +# define RADEON_ROP3_PDno 0x00f50000 +# define RADEON_ROP3_Pn 0x000f0000 +# define RADEON_ROP3_DPno 0x00af0000 +# define RADEON_ROP3_DPan 0x005f0000 +#define RADEON_DP_GUI_MASTER_CNTL_C 0x1c84 +#define RADEON_DP_MIX 0x16c8 +#define RADEON_DP_SRC_BKGD_CLR 0x15dc +#define RADEON_DP_SRC_FRGD_CLR 0x15d8 +#define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_DST_BRES_DEC 0x1630 +#define RADEON_DST_BRES_ERR 0x1628 +#define RADEON_DST_BRES_INC 0x162c +#define RADEON_DST_BRES_LNTH 0x1634 +#define RADEON_DST_BRES_LNTH_SUB 0x1638 +#define RADEON_DST_HEIGHT 0x1410 +#define RADEON_DST_HEIGHT_WIDTH 0x143c +#define RADEON_DST_HEIGHT_WIDTH_8 0x158c +#define RADEON_DST_HEIGHT_WIDTH_BW 0x15b4 +#define RADEON_DST_HEIGHT_Y 0x15a0 +#define RADEON_DST_LINE_START 0x1600 +#define RADEON_DST_LINE_END 0x1604 +#define RADEON_DST_LINE_PATCOUNT 0x1608 +# define RADEON_BRES_CNTL_SHIFT 8 +#define RADEON_DST_OFFSET 0x1404 +#define RADEON_DST_PITCH 0x1408 +#define RADEON_DST_PITCH_OFFSET 0x142c +#define RADEON_DST_PITCH_OFFSET_C 0x1c80 +# define RADEON_PITCH_SHIFT 21 +# define RADEON_DST_TILE_LINEAR (0 << 30) +# define RADEON_DST_TILE_MACRO (1 << 30) +# define RADEON_DST_TILE_MICRO (2 << 30) +# define RADEON_DST_TILE_BOTH (3 << 30) +#define RADEON_DST_WIDTH 0x140c +#define RADEON_DST_WIDTH_HEIGHT 0x1598 +#define RADEON_DST_WIDTH_X 0x1588 +#define RADEON_DST_WIDTH_X_INCY 0x159c +#define RADEON_DST_X 0x141c +#define RADEON_DST_X_SUB 0x15a4 +#define RADEON_DST_X_Y 0x1594 +#define RADEON_DST_Y 0x1420 +#define RADEON_DST_Y_SUB 0x15a8 +#define RADEON_DST_Y_X 0x1438 + +#define RADEON_FCP_CNTL 0x0910 +# define RADEON_FCP0_SRC_PCICLK 0 +# define RADEON_FCP0_SRC_PCLK 1 +# define RADEON_FCP0_SRC_PCLKb 2 +# define RADEON_FCP0_SRC_HREF 3 +# define RADEON_FCP0_SRC_GND 4 +# define RADEON_FCP0_SRC_HREFb 5 +#define RADEON_FLUSH_1 0x1704 +#define RADEON_FLUSH_2 0x1708 +#define RADEON_FLUSH_3 0x170c +#define RADEON_FLUSH_4 0x1710 +#define RADEON_FLUSH_5 0x1714 +#define RADEON_FLUSH_6 0x1718 +#define RADEON_FLUSH_7 0x171c +#define RADEON_FOG_3D_TABLE_START 0x1810 +#define RADEON_FOG_3D_TABLE_END 0x1814 +#define RADEON_FOG_3D_TABLE_DENSITY 0x181c +#define RADEON_FOG_TABLE_INDEX 0x1a14 +#define RADEON_FOG_TABLE_DATA 0x1a18 +#define RADEON_FP_CRTC_H_TOTAL_DISP 0x0250 +#define RADEON_FP_CRTC_V_TOTAL_DISP 0x0254 +# define RADEON_FP_CRTC_H_TOTAL_MASK 0x000003ff +# define RADEON_FP_CRTC_H_DISP_MASK 0x01ff0000 +# define RADEON_FP_CRTC_V_TOTAL_MASK 0x00000fff +# define RADEON_FP_CRTC_V_DISP_MASK 0x0fff0000 +# define RADEON_FP_H_SYNC_STRT_CHAR_MASK 0x00001ff8 +# define RADEON_FP_H_SYNC_WID_MASK 0x003f0000 +# define RADEON_FP_V_SYNC_STRT_MASK 0x00000fff +# define RADEON_FP_V_SYNC_WID_MASK 0x001f0000 +# define RADEON_FP_CRTC_H_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_H_DISP_SHIFT 0x00000010 +# define RADEON_FP_CRTC_V_TOTAL_SHIFT 0x00000000 +# define RADEON_FP_CRTC_V_DISP_SHIFT 0x00000010 +# define RADEON_FP_H_SYNC_STRT_CHAR_SHIFT 0x00000003 +# define RADEON_FP_H_SYNC_WID_SHIFT 0x00000010 +# define RADEON_FP_V_SYNC_STRT_SHIFT 0x00000000 +# define RADEON_FP_V_SYNC_WID_SHIFT 0x00000010 +#define RADEON_FP_GEN_CNTL 0x0284 +# define RADEON_FP_FPON (1 << 0) +# define RADEON_FP_BLANK_EN (1 << 1) +# define RADEON_FP_TMDS_EN (1 << 2) +# define RADEON_FP_PANEL_FORMAT (1 << 3) +# define RADEON_FP_EN_TMDS (1 << 7) +# define RADEON_FP_DETECT_SENSE (1 << 8) +# define R200_FP_SOURCE_SEL_MASK (3 << 10) +# define R200_FP_SOURCE_SEL_CRTC1 (0 << 10) +# define R200_FP_SOURCE_SEL_CRTC2 (1 << 10) +# define R200_FP_SOURCE_SEL_RMX (2 << 10) +# define R200_FP_SOURCE_SEL_TRANS (3 << 10) +# define RADEON_FP_SEL_CRTC1 (0 << 13) +# define RADEON_FP_SEL_CRTC2 (1 << 13) +# define RADEON_FP_CRTC_DONT_SHADOW_HPAR (1 << 15) +# define RADEON_FP_CRTC_DONT_SHADOW_VPAR (1 << 16) +# define RADEON_FP_CRTC_DONT_SHADOW_HEND (1 << 17) +# define RADEON_FP_CRTC_USE_SHADOW_VEND (1 << 18) +# define RADEON_FP_RMX_HVSYNC_CONTROL_EN (1 << 20) +# define RADEON_FP_DFP_SYNC_SEL (1 << 21) +# define RADEON_FP_CRTC_LOCK_8DOT (1 << 22) +# define RADEON_FP_CRT_SYNC_SEL (1 << 23) +# define RADEON_FP_USE_SHADOW_EN (1 << 24) +# define RADEON_FP_CRT_SYNC_ALT (1 << 26) +#define RADEON_FP2_GEN_CNTL 0x0288 +# define RADEON_FP2_BLANK_EN (1 << 1) +# define RADEON_FP2_ON (1 << 2) +# define RADEON_FP2_PANEL_FORMAT (1 << 3) +# define RADEON_FP2_DETECT_SENSE (1 << 8) +# define R200_FP2_SOURCE_SEL_MASK (3 << 10) +# define R200_FP2_SOURCE_SEL_CRTC1 (0 << 10) +# define R200_FP2_SOURCE_SEL_CRTC2 (1 << 10) +# define R200_FP2_SOURCE_SEL_RMX (2 << 10) +# define R200_FP2_SOURCE_SEL_TRANS_UNIT (3 << 10) +# define RADEON_FP2_SRC_SEL_MASK (3 << 13) +# define RADEON_FP2_SRC_SEL_CRTC2 (1 << 13) +# define RADEON_FP2_FP_POL (1 << 16) +# define RADEON_FP2_LP_POL (1 << 17) +# define RADEON_FP2_SCK_POL (1 << 18) +# define RADEON_FP2_LCD_CNTL_MASK (7 << 19) +# define RADEON_FP2_PAD_FLOP_EN (1 << 22) +# define RADEON_FP2_CRC_EN (1 << 23) +# define RADEON_FP2_CRC_READ_EN (1 << 24) +# define RADEON_FP2_DVO_EN (1 << 25) +# define RADEON_FP2_DVO_RATE_SEL_SDR (1 << 26) +# define R200_FP2_DVO_RATE_SEL_SDR (1 << 27) +# define R300_FP2_DVO_CLOCK_MODE_SINGLE (1 << 28) +# define R300_FP2_DVO_DUAL_CHANNEL_EN (1 << 29) +#define RADEON_FP_H_SYNC_STRT_WID 0x02c4 +#define RADEON_FP_H2_SYNC_STRT_WID 0x03c4 +#define RADEON_FP_HORZ_STRETCH 0x028c +#define RADEON_FP_HORZ2_STRETCH 0x038c +# define RADEON_HORZ_STRETCH_RATIO_MASK 0xffff +# define RADEON_HORZ_STRETCH_RATIO_MAX 4096 +# define RADEON_HORZ_PANEL_SIZE (0x1ff << 16) +# define RADEON_HORZ_PANEL_SHIFT 16 +# define RADEON_HORZ_STRETCH_PIXREP (0 << 25) +# define RADEON_HORZ_STRETCH_BLEND (1 << 26) +# define RADEON_HORZ_STRETCH_ENABLE (1 << 25) +# define RADEON_HORZ_AUTO_RATIO (1 << 27) +# define RADEON_HORZ_FP_LOOP_STRETCH (0x7 << 28) +# define RADEON_HORZ_AUTO_RATIO_INC (1 << 31) +#define RADEON_FP_HORZ_VERT_ACTIVE 0x0278 +#define RADEON_FP_V_SYNC_STRT_WID 0x02c8 +#define RADEON_FP_VERT_STRETCH 0x0290 +#define RADEON_FP_V2_SYNC_STRT_WID 0x03c8 +#define RADEON_FP_VERT2_STRETCH 0x0390 +# define RADEON_VERT_PANEL_SIZE (0xfff << 12) +# define RADEON_VERT_PANEL_SHIFT 12 +# define RADEON_VERT_STRETCH_RATIO_MASK 0xfff +# define RADEON_VERT_STRETCH_RATIO_SHIFT 0 +# define RADEON_VERT_STRETCH_RATIO_MAX 4096 +# define RADEON_VERT_STRETCH_ENABLE (1 << 25) +# define RADEON_VERT_STRETCH_LINEREP (0 << 26) +# define RADEON_VERT_STRETCH_BLEND (1 << 26) +# define RADEON_VERT_AUTO_RATIO_EN (1 << 27) +# define RADEON_VERT_STRETCH_RESERVED 0xf1000000 + +#define RADEON_GEN_INT_CNTL 0x0040 +#define RADEON_GEN_INT_STATUS 0x0044 +# define RADEON_VSYNC_INT_AK (1 << 2) +# define RADEON_VSYNC_INT (1 << 2) +# define RADEON_VSYNC2_INT_AK (1 << 6) +# define RADEON_VSYNC2_INT (1 << 6) +#define RADEON_GENENB 0x03c3 /* VGA */ +#define RADEON_GENFC_RD 0x03ca /* VGA */ +#define RADEON_GENFC_WT 0x03da /* VGA, 0x03ba */ +#define RADEON_GENMO_RD 0x03cc /* VGA */ +#define RADEON_GENMO_WT 0x03c2 /* VGA */ +#define RADEON_GENS0 0x03c2 /* VGA */ +#define RADEON_GENS1 0x03da /* VGA, 0x03ba */ +#define RADEON_GPIO_MONID 0x0068 /* DDC interface via I2C */ +#define RADEON_GPIO_MONIDB 0x006c +#define RADEON_GPIO_CRT2_DDC 0x006c +#define RADEON_GPIO_DVI_DDC 0x0064 +#define RADEON_GPIO_VGA_DDC 0x0060 +# define RADEON_GPIO_A_0 (1 << 0) +# define RADEON_GPIO_A_1 (1 << 1) +# define RADEON_GPIO_Y_0 (1 << 8) +# define RADEON_GPIO_Y_1 (1 << 9) +# define RADEON_GPIO_Y_SHIFT_0 8 +# define RADEON_GPIO_Y_SHIFT_1 9 +# define RADEON_GPIO_EN_0 (1 << 16) +# define RADEON_GPIO_EN_1 (1 << 17) +# define RADEON_GPIO_MASK_0 (1 << 24) /*??*/ +# define RADEON_GPIO_MASK_1 (1 << 25) /*??*/ +#define RADEON_GRPH8_DATA 0x03cf /* VGA */ +#define RADEON_GRPH8_IDX 0x03ce /* VGA */ +#define RADEON_GUI_SCRATCH_REG0 0x15e0 +#define RADEON_GUI_SCRATCH_REG1 0x15e4 +#define RADEON_GUI_SCRATCH_REG2 0x15e8 +#define RADEON_GUI_SCRATCH_REG3 0x15ec +#define RADEON_GUI_SCRATCH_REG4 0x15f0 +#define RADEON_GUI_SCRATCH_REG5 0x15f4 + +#define RADEON_HEADER 0x0f0e /* PCI */ +#define RADEON_HOST_DATA0 0x17c0 +#define RADEON_HOST_DATA1 0x17c4 +#define RADEON_HOST_DATA2 0x17c8 +#define RADEON_HOST_DATA3 0x17cc +#define RADEON_HOST_DATA4 0x17d0 +#define RADEON_HOST_DATA5 0x17d4 +#define RADEON_HOST_DATA6 0x17d8 +#define RADEON_HOST_DATA7 0x17dc +#define RADEON_HOST_DATA_LAST 0x17e0 +#define RADEON_HOST_PATH_CNTL 0x0130 +# define RADEON_HDP_SOFT_RESET (1 << 26) +# define RADEON_HDP_APER_CNTL (1 << 23) +#define RADEON_HTOTAL_CNTL 0x0009 /* PLL */ +# define RADEON_HTOT_CNTL_VGA_EN (1 << 28) +#define RADEON_HTOTAL2_CNTL 0x002e /* PLL */ + + /* Multimedia I2C bus */ +#define RADEON_I2C_CNTL_0 0x0090 +#define RADEON_I2C_DONE (1<<0) +#define RADEON_I2C_NACK (1<<1) +#define RADEON_I2C_HALT (1<<2) +#define RADEON_I2C_SOFT_RST (1<<5) +#define RADEON_I2C_DRIVE_EN (1<<6) +#define RADEON_I2C_DRIVE_SEL (1<<7) +#define RADEON_I2C_START (1<<8) +#define RADEON_I2C_STOP (1<<9) +#define RADEON_I2C_RECEIVE (1<<10) +#define RADEON_I2C_ABORT (1<<11) +#define RADEON_I2C_GO (1<<12) +#define RADEON_I2C_CNTL_1 0x0094 +#define RADEON_I2C_SEL (1<<16) +#define RADEON_I2C_EN (1<<17) +#define RADEON_I2C_DATA 0x0098 + +#define RADEON_DVI_I2C_CNTL_0 0x02e0 +#define RADEON_DVI_I2C_CNTL_1 0x02e4 /* ? */ +#define RADEON_DVI_I2C_DATA 0x02e8 + +#define RADEON_INTERRUPT_LINE 0x0f3c /* PCI */ +#define RADEON_INTERRUPT_PIN 0x0f3d /* PCI */ +#define RADEON_IO_BASE 0x0f14 /* PCI */ + +#define RADEON_LATENCY 0x0f0d /* PCI */ +#define RADEON_LEAD_BRES_DEC 0x1608 +#define RADEON_LEAD_BRES_LNTH 0x161c +#define RADEON_LEAD_BRES_LNTH_SUB 0x1624 +#define RADEON_LVDS_GEN_CNTL 0x02d0 +# define RADEON_LVDS_ON (1 << 0) +# define RADEON_LVDS_DISPLAY_DIS (1 << 1) +# define RADEON_LVDS_PANEL_TYPE (1 << 2) +# define RADEON_LVDS_PANEL_FORMAT (1 << 3) +# define RADEON_LVDS_RST_FM (1 << 6) +# define RADEON_LVDS_EN (1 << 7) +# define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 +# define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) +# define RADEON_LVDS_BL_MOD_EN (1 << 16) +# define RADEON_LVDS_DIGON (1 << 18) +# define RADEON_LVDS_BLON (1 << 19) +# define RADEON_LVDS_SEL_CRTC2 (1 << 23) +#define RADEON_LVDS_PLL_CNTL 0x02d4 +# define RADEON_HSYNC_DELAY_SHIFT 28 +# define RADEON_HSYNC_DELAY_MASK (0xf << 28) +# define RADEON_LVDS_PLL_EN (1 << 16) +# define RADEON_LVDS_PLL_RESET (1 << 17) +# define R300_LVDS_SRC_SEL_MASK (3 << 18) +# define R300_LVDS_SRC_SEL_CRTC1 (0 << 18) +# define R300_LVDS_SRC_SEL_CRTC2 (1 << 18) +# define R300_LVDS_SRC_SEL_RMX (2 << 18) + +#define RADEON_MAX_LATENCY 0x0f3f /* PCI */ +#define RADEON_MC_AGP_LOCATION 0x014c +#define RADEON_MC_FB_LOCATION 0x0148 +#define RADEON_DISPLAY_BASE_ADDR 0x23c +#define RADEON_DISPLAY2_BASE_ADDR 0x33c +#define RADEON_OV0_BASE_ADDR 0x43c +#define RADEON_NB_TOM 0x15c +#define R300_MC_INIT_MISC_LAT_TIMER 0x180 +#define RADEON_MCLK_CNTL 0x0012 /* PLL */ +# define RADEON_FORCEON_MCLKA (1 << 16) +# define RADEON_FORCEON_MCLKB (1 << 17) +# define RADEON_FORCEON_YCLKA (1 << 18) +# define RADEON_FORCEON_YCLKB (1 << 19) +# define RADEON_FORCEON_MC (1 << 20) +# define RADEON_FORCEON_AIC (1 << 21) +# define R300_DISABLE_MC_MCLKA (1 << 21) +# define R300_DISABLE_MC_MCLKB (1 << 21) +#define RADEON_MCLK_MISC 0x001f /* PLL */ +# define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1 << 12) +# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1 << 13) +# define RADEON_MC_MCLK_DYN_ENABLE (1 << 14) +# define RADEON_IO_MCLK_DYN_ENABLE (1 << 15) +#define RADEON_LCD_GPIO_MASK 0x01a0 +#define RADEON_LCD_GPIO_Y_REG 0x01a4 +#define RADEON_MDGPIO_A_REG 0x01ac +#define RADEON_MDGPIO_EN_REG 0x01b0 +#define RADEON_MDGPIO_MASK 0x0198 +#define RADEON_GPIOPAD_A 0x019c +#define RADEON_MDGPIO_Y_REG 0x01b4 +#define RADEON_MEM_ADDR_CONFIG 0x0148 +#define RADEON_MEM_BASE 0x0f10 /* PCI */ +#define RADEON_MEM_CNTL 0x0140 +# define RADEON_MEM_NUM_CHANNELS_MASK 0x01 +# define RADEON_MEM_USE_B_CH_ONLY (1 << 1) +# define RV100_HALF_MODE (1 << 3) +# define R300_MEM_NUM_CHANNELS_MASK 0x03 +# define R300_MEM_USE_CD_CH_ONLY (1 << 2) +#define RADEON_MEM_TIMING_CNTL 0x0144 /* EXT_MEM_CNTL */ +#define RADEON_MEM_INIT_LAT_TIMER 0x0154 +#define RADEON_MEM_INTF_CNTL 0x014c +#define RADEON_MEM_SDRAM_MODE_REG 0x0158 +# define RADEON_SDRAM_MODE_MASK 0xffff0000 +# define RADEON_B3MEM_RESET_MASK 0x6fffffff +#define RADEON_MEM_STR_CNTL 0x0150 +# define RADEON_MEM_PWRUP_COMPL_A (1 << 0) +# define RADEON_MEM_PWRUP_COMPL_B (1 << 1) +# define R300_MEM_PWRUP_COMPL_C (1 << 2) +# define R300_MEM_PWRUP_COMPL_D (1 << 3) +# define RADEON_MEM_PWRUP_COMPLETE 0x03 +# define R300_MEM_PWRUP_COMPLETE 0x0f +#define RADEON_MC_STATUS 0x0150 +# define RADEON_MC_IDLE (1 << 2) +# define R300_MC_IDLE (1 << 4) +#define RADEON_MEM_VGA_RP_SEL 0x003c +#define RADEON_MEM_VGA_WP_SEL 0x0038 +#define RADEON_MIN_GRANT 0x0f3e /* PCI */ +#define RADEON_MM_DATA 0x0004 +#define RADEON_MM_INDEX 0x0000 +#define RADEON_MPLL_CNTL 0x000e /* PLL */ +#define RADEON_MPP_TB_CONFIG 0x01c0 /* ? */ +#define RADEON_MPP_GP_CONFIG 0x01c8 /* ? */ +#define R300_MC_IND_INDEX 0x01f8 +# define R300_MC_IND_ADDR_MASK 0x3f +# define R300_MC_IND_WR_EN (1 << 8) +#define R300_MC_IND_DATA 0x01fc +#define R300_MC_READ_CNTL_AB 0x017c +# define R300_MEM_RBS_POSITION_A_MASK 0x03 +#define R300_MC_READ_CNTL_CD_mcind 0x24 +# define R300_MEM_RBS_POSITION_C_MASK 0x03 + +#define RADEON_N_VIF_COUNT 0x0248 + +#define RADEON_OV0_AUTO_FLIP_CNTL 0x0470 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_NUM 0x00000007 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_REPEAT_FIELD 0x00000008 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD 0x00000010 +# define RADEON_OV0_AUTO_FLIP_CNTL_IGNORE_REPEAT_FIELD 0x00000020 +# define RADEON_OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE 0x00000040 +# define RADEON_OV0_AUTO_FLIP_CNTL_VID_PORT_SELECT 0x00000300 +# define RADEON_OV0_AUTO_FLIP_CNTL_P1_FIRST_LINE_EVEN 0x00010000 +# define RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_EVEN_DOWN 0x00040000 +# define RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN 0x00080000 +# define RADEON_OV0_AUTO_FLIP_CNTL_FIELD_POL_SOURCE 0x00800000 + +#define RADEON_OV0_COLOUR_CNTL 0x04E0 +#define RADEON_OV0_DEINTERLACE_PATTERN 0x0474 +#define RADEON_OV0_EXCLUSIVE_HORZ 0x0408 +# define RADEON_EXCL_HORZ_START_MASK 0x000000ff +# define RADEON_EXCL_HORZ_END_MASK 0x0000ff00 +# define RADEON_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000 +# define RADEON_EXCL_HORZ_EXCLUSIVE_EN 0x80000000 +#define RADEON_OV0_EXCLUSIVE_VERT 0x040C +# define RADEON_EXCL_VERT_START_MASK 0x000003ff +# define RADEON_EXCL_VERT_END_MASK 0x03ff0000 +#define RADEON_OV0_FILTER_CNTL 0x04A0 +# define RADEON_FILTER_PROGRAMMABLE_COEF 0x0 +# define RADEON_FILTER_HC_COEF_HORZ_Y 0x1 +# define RADEON_FILTER_HC_COEF_HORZ_UV 0x2 +# define RADEON_FILTER_HC_COEF_VERT_Y 0x4 +# define RADEON_FILTER_HC_COEF_VERT_UV 0x8 +# define RADEON_FILTER_HARDCODED_COEF 0xf +# define RADEON_FILTER_COEF_MASK 0xf + +#define RADEON_OV0_FOUR_TAP_COEF_0 0x04B0 +#define RADEON_OV0_FOUR_TAP_COEF_1 0x04B4 +#define RADEON_OV0_FOUR_TAP_COEF_2 0x04B8 +#define RADEON_OV0_FOUR_TAP_COEF_3 0x04BC +#define RADEON_OV0_FOUR_TAP_COEF_4 0x04C0 +#define RADEON_OV0_FLAG_CNTL 0x04DC +#define RADEON_OV0_GAMMA_000_00F 0x0d40 +#define RADEON_OV0_GAMMA_010_01F 0x0d44 +#define RADEON_OV0_GAMMA_020_03F 0x0d48 +#define RADEON_OV0_GAMMA_040_07F 0x0d4c +#define RADEON_OV0_GAMMA_080_0BF 0x0e00 +#define RADEON_OV0_GAMMA_0C0_0FF 0x0e04 +#define RADEON_OV0_GAMMA_100_13F 0x0e08 +#define RADEON_OV0_GAMMA_140_17F 0x0e0c +#define RADEON_OV0_GAMMA_180_1BF 0x0e10 +#define RADEON_OV0_GAMMA_1C0_1FF 0x0e14 +#define RADEON_OV0_GAMMA_200_23F 0x0e18 +#define RADEON_OV0_GAMMA_240_27F 0x0e1c +#define RADEON_OV0_GAMMA_280_2BF 0x0e20 +#define RADEON_OV0_GAMMA_2C0_2FF 0x0e24 +#define RADEON_OV0_GAMMA_300_33F 0x0e28 +#define RADEON_OV0_GAMMA_340_37F 0x0e2c +#define RADEON_OV0_GAMMA_380_3BF 0x0d50 +#define RADEON_OV0_GAMMA_3C0_3FF 0x0d54 +#define RADEON_OV0_GRAPHICS_KEY_CLR_LOW 0x04EC +#define RADEON_OV0_GRAPHICS_KEY_CLR_HIGH 0x04F0 +#define RADEON_OV0_H_INC 0x0480 +#define RADEON_OV0_KEY_CNTL 0x04F4 +# define RADEON_VIDEO_KEY_FN_MASK 0x00000003L +# define RADEON_VIDEO_KEY_FN_FALSE 0x00000000L +# define RADEON_VIDEO_KEY_FN_TRUE 0x00000001L +# define RADEON_VIDEO_KEY_FN_EQ 0x00000002L +# define RADEON_VIDEO_KEY_FN_NE 0x00000003L +# define RADEON_GRAPHIC_KEY_FN_MASK 0x00000030L +# define RADEON_GRAPHIC_KEY_FN_FALSE 0x00000000L +# define RADEON_GRAPHIC_KEY_FN_TRUE 0x00000010L +# define RADEON_GRAPHIC_KEY_FN_EQ 0x00000020L +# define RADEON_GRAPHIC_KEY_FN_NE 0x00000030L +# define RADEON_CMP_MIX_MASK 0x00000100L +# define RADEON_CMP_MIX_OR 0x00000000L +# define RADEON_CMP_MIX_AND 0x00000100L +#define RADEON_OV0_LIN_TRANS_A 0x0d20 +#define RADEON_OV0_LIN_TRANS_B 0x0d24 +#define RADEON_OV0_LIN_TRANS_C 0x0d28 +#define RADEON_OV0_LIN_TRANS_D 0x0d2c +#define RADEON_OV0_LIN_TRANS_E 0x0d30 +#define RADEON_OV0_LIN_TRANS_F 0x0d34 +#define RADEON_OV0_P1_BLANK_LINES_AT_TOP 0x0430 +# define RADEON_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL +# define RADEON_P1_ACTIVE_LINES_M1 0x0fff0000L +#define RADEON_OV0_P1_H_ACCUM_INIT 0x0488 +#define RADEON_OV0_P1_V_ACCUM_INIT 0x0428 +# define RADEON_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L +# define RADEON_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L +#define RADEON_OV0_P1_X_START_END 0x0494 +#define RADEON_OV0_P2_X_START_END 0x0498 +#define RADEON_OV0_P23_BLANK_LINES_AT_TOP 0x0434 +# define RADEON_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL +# define RADEON_P23_ACTIVE_LINES_M1 0x07ff0000L +#define RADEON_OV0_P23_H_ACCUM_INIT 0x048C +#define RADEON_OV0_P23_V_ACCUM_INIT 0x042C +#define RADEON_OV0_P3_X_START_END 0x049C +#define RADEON_OV0_REG_LOAD_CNTL 0x0410 +# define RADEON_REG_LD_CTL_LOCK 0x00000001L +# define RADEON_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L +# define RADEON_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L +# define RADEON_REG_LD_CTL_LOCK_READBACK 0x00000008L +# define RADEON_REG_LD_CTL_FLIP_READBACK 0x00000010L +#define RADEON_OV0_SCALE_CNTL 0x0420 +# define RADEON_SCALER_HORZ_PICK_NEAREST 0x00000004L +# define RADEON_SCALER_VERT_PICK_NEAREST 0x00000008L +# define RADEON_SCALER_SIGNED_UV 0x00000010L +# define RADEON_SCALER_GAMMA_SEL_MASK 0x00000060L +# define RADEON_SCALER_GAMMA_SEL_BRIGHT 0x00000000L +# define RADEON_SCALER_GAMMA_SEL_G22 0x00000020L +# define RADEON_SCALER_GAMMA_SEL_G18 0x00000040L +# define RADEON_SCALER_GAMMA_SEL_G14 0x00000060L +# define RADEON_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L +# define RADEON_SCALER_SURFAC_FORMAT 0x00000f00L +# define RADEON_SCALER_SOURCE_15BPP 0x00000300L +# define RADEON_SCALER_SOURCE_16BPP 0x00000400L +# define RADEON_SCALER_SOURCE_32BPP 0x00000600L +# define RADEON_SCALER_SOURCE_YUV9 0x00000900L +# define RADEON_SCALER_SOURCE_YUV12 0x00000A00L +# define RADEON_SCALER_SOURCE_VYUY422 0x00000B00L +# define RADEON_SCALER_SOURCE_YVYU422 0x00000C00L +# define RADEON_SCALER_ADAPTIVE_DEINT 0x00001000L +# define RADEON_SCALER_TEMPORAL_DEINT 0x00002000L +# define RADEON_SCALER_CRTC_SEL 0x00004000L +# define RADEON_SCALER_SMART_SWITCH 0x00008000L +# define RADEON_SCALER_BURST_PER_PLANE 0x007F0000L +# define RADEON_SCALER_DOUBLE_BUFFER 0x01000000L +# define RADEON_SCALER_DIS_LIMIT 0x08000000L +# define RADEON_SCALER_LIN_TRANS_BYPASS 0x10000000L +# define RADEON_SCALER_INT_EMU 0x20000000L +# define RADEON_SCALER_ENABLE 0x40000000L +# define RADEON_SCALER_SOFT_RESET 0x80000000L +#define RADEON_OV0_STEP_BY 0x0484 +#define RADEON_OV0_TEST 0x04F8 +#define RADEON_OV0_V_INC 0x0424 +#define RADEON_OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define RADEON_OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define RADEON_OV0_VID_BUF0_BASE_ADRS 0x0440 +# define RADEON_VIF_BUF0_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF0_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF1_BASE_ADRS 0x0444 +# define RADEON_VIF_BUF1_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF1_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF2_BASE_ADRS 0x0448 +# define RADEON_VIF_BUF2_PITCH_SEL 0x00000001L +# define RADEON_VIF_BUF2_TILE_ADRS 0x00000002L +# define RADEON_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L +# define RADEON_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L +#define RADEON_OV0_VID_BUF3_BASE_ADRS 0x044C +#define RADEON_OV0_VID_BUF4_BASE_ADRS 0x0450 +#define RADEON_OV0_VID_BUF5_BASE_ADRS 0x0454 +#define RADEON_OV0_VIDEO_KEY_CLR_HIGH 0x04E8 +#define RADEON_OV0_VIDEO_KEY_CLR_LOW 0x04E4 +#define RADEON_OV0_Y_X_START 0x0400 +#define RADEON_OV0_Y_X_END 0x0404 +#define RADEON_OV1_Y_X_START 0x0600 +#define RADEON_OV1_Y_X_END 0x0604 +#define RADEON_OVR_CLR 0x0230 +#define RADEON_OVR_WID_LEFT_RIGHT 0x0234 +#define RADEON_OVR_WID_TOP_BOTTOM 0x0238 + +/* first capture unit */ + +#define RADEON_CAP0_BUF0_OFFSET 0x0920 +#define RADEON_CAP0_BUF1_OFFSET 0x0924 +#define RADEON_CAP0_BUF0_EVEN_OFFSET 0x0928 +#define RADEON_CAP0_BUF1_EVEN_OFFSET 0x092C + +#define RADEON_CAP0_BUF_PITCH 0x0930 +#define RADEON_CAP0_V_WINDOW 0x0934 +#define RADEON_CAP0_H_WINDOW 0x0938 +#define RADEON_CAP0_VBI0_OFFSET 0x093C +#define RADEON_CAP0_VBI1_OFFSET 0x0940 +#define RADEON_CAP0_VBI_V_WINDOW 0x0944 +#define RADEON_CAP0_VBI_H_WINDOW 0x0948 +#define RADEON_CAP0_PORT_MODE_CNTL 0x094C +#define RADEON_CAP0_TRIG_CNTL 0x0950 +#define RADEON_CAP0_DEBUG 0x0954 +#define RADEON_CAP0_CONFIG 0x0958 +# define RADEON_CAP0_CONFIG_CONTINUOS 0x00000001 +# define RADEON_CAP0_CONFIG_START_FIELD_EVEN 0x00000002 +# define RADEON_CAP0_CONFIG_START_BUF_GET 0x00000004 +# define RADEON_CAP0_CONFIG_START_BUF_SET 0x00000008 +# define RADEON_CAP0_CONFIG_BUF_TYPE_ALT 0x00000010 +# define RADEON_CAP0_CONFIG_BUF_TYPE_FRAME 0x00000020 +# define RADEON_CAP0_CONFIG_ONESHOT_MODE_FRAME 0x00000040 +# define RADEON_CAP0_CONFIG_BUF_MODE_DOUBLE 0x00000080 +# define RADEON_CAP0_CONFIG_BUF_MODE_TRIPLE 0x00000100 +# define RADEON_CAP0_CONFIG_MIRROR_EN 0x00000200 +# define RADEON_CAP0_CONFIG_ONESHOT_MIRROR_EN 0x00000400 +# define RADEON_CAP0_CONFIG_VIDEO_SIGNED_UV 0x00000800 +# define RADEON_CAP0_CONFIG_ANC_DECODE_EN 0x00001000 +# define RADEON_CAP0_CONFIG_VBI_EN 0x00002000 +# define RADEON_CAP0_CONFIG_SOFT_PULL_DOWN_EN 0x00004000 +# define RADEON_CAP0_CONFIG_VIP_EXTEND_FLAG_EN 0x00008000 +# define RADEON_CAP0_CONFIG_FAKE_FIELD_EN 0x00010000 +# define RADEON_CAP0_CONFIG_ODD_ONE_MORE_LINE 0x00020000 +# define RADEON_CAP0_CONFIG_EVEN_ONE_MORE_LINE 0x00040000 +# define RADEON_CAP0_CONFIG_HORZ_DIVIDE_2 0x00080000 +# define RADEON_CAP0_CONFIG_HORZ_DIVIDE_4 0x00100000 +# define RADEON_CAP0_CONFIG_VERT_DIVIDE_2 0x00200000 +# define RADEON_CAP0_CONFIG_VERT_DIVIDE_4 0x00400000 +# define RADEON_CAP0_CONFIG_FORMAT_BROOKTREE 0x00000000 +# define RADEON_CAP0_CONFIG_FORMAT_CCIR656 0x00800000 +# define RADEON_CAP0_CONFIG_FORMAT_ZV 0x01000000 +# define RADEON_CAP0_CONFIG_FORMAT_VIP 0x01800000 +# define RADEON_CAP0_CONFIG_FORMAT_TRANSPORT 0x02000000 +# define RADEON_CAP0_CONFIG_HORZ_DECIMATOR 0x04000000 +# define RADEON_CAP0_CONFIG_VIDEO_IN_YVYU422 0x00000000 +# define RADEON_CAP0_CONFIG_VIDEO_IN_VYUY422 0x20000000 +# define RADEON_CAP0_CONFIG_VBI_DIVIDE_2 0x40000000 +# define RADEON_CAP0_CONFIG_VBI_DIVIDE_4 0x80000000 +#define RADEON_CAP0_ANC_ODD_OFFSET 0x095C +#define RADEON_CAP0_ANC_EVEN_OFFSET 0x0960 +#define RADEON_CAP0_ANC_H_WINDOW 0x0964 +#define RADEON_CAP0_VIDEO_SYNC_TEST 0x0968 +#define RADEON_CAP0_ONESHOT_BUF_OFFSET 0x096C +#define RADEON_CAP0_BUF_STATUS 0x0970 +/* #define RADEON_CAP0_DWNSC_XRATIO 0x0978 */ +/* #define RADEON_CAP0_XSHARPNESS 0x097C */ +#define RADEON_CAP0_VBI2_OFFSET 0x0980 +#define RADEON_CAP0_VBI3_OFFSET 0x0984 +#define RADEON_CAP0_ANC2_OFFSET 0x0988 +#define RADEON_CAP0_ANC3_OFFSET 0x098C +#define RADEON_VID_BUFFER_CONTROL 0x0900 + +/* second capture unit */ + +#define RADEON_CAP1_BUF0_OFFSET 0x0990 +#define RADEON_CAP1_BUF1_OFFSET 0x0994 +#define RADEON_CAP1_BUF0_EVEN_OFFSET 0x0998 +#define RADEON_CAP1_BUF1_EVEN_OFFSET 0x099C + +#define RADEON_CAP1_BUF_PITCH 0x09A0 +#define RADEON_CAP1_V_WINDOW 0x09A4 +#define RADEON_CAP1_H_WINDOW 0x09A8 +#define RADEON_CAP1_VBI_ODD_OFFSET 0x09AC +#define RADEON_CAP1_VBI_EVEN_OFFSET 0x09B0 +#define RADEON_CAP1_VBI_V_WINDOW 0x09B4 +#define RADEON_CAP1_VBI_H_WINDOW 0x09B8 +#define RADEON_CAP1_PORT_MODE_CNTL 0x09BC +#define RADEON_CAP1_TRIG_CNTL 0x09C0 +#define RADEON_CAP1_DEBUG 0x09C4 +#define RADEON_CAP1_CONFIG 0x09C8 +#define RADEON_CAP1_ANC_ODD_OFFSET 0x09CC +#define RADEON_CAP1_ANC_EVEN_OFFSET 0x09D0 +#define RADEON_CAP1_ANC_H_WINDOW 0x09D4 +#define RADEON_CAP1_VIDEO_SYNC_TEST 0x09D8 +#define RADEON_CAP1_ONESHOT_BUF_OFFSET 0x09DC +#define RADEON_CAP1_BUF_STATUS 0x09E0 +#define RADEON_CAP1_DWNSC_XRATIO 0x09E8 +#define RADEON_CAP1_XSHARPNESS 0x09EC + +/* misc multimedia registers */ + +#define RADEON_IDCT_RUNS 0x1F80 +#define RADEON_IDCT_LEVELS 0x1F84 +#define RADEON_IDCT_CONTROL 0x1FBC +#define RADEON_IDCT_AUTH_CONTROL 0x1F88 +#define RADEON_IDCT_AUTH 0x1F8C + +#define RADEON_P2PLL_CNTL 0x002a /* P2PLL */ +# define RADEON_P2PLL_RESET (1 << 0) +# define RADEON_P2PLL_SLEEP (1 << 1) +# define RADEON_P2PLL_PVG_MASK (7 << 11) +# define RADEON_P2PLL_PVG_SHIFT 11 +# define RADEON_P2PLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_P2PLL_DIV_0 0x002c +# define RADEON_P2PLL_FB0_DIV_MASK 0x07ff +# define RADEON_P2PLL_POST0_DIV_MASK 0x00070000 +#define RADEON_P2PLL_REF_DIV 0x002B /* PLL */ +# define RADEON_P2PLL_REF_DIV_MASK 0x03ff +# define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +# define R300_PPLL_REF_DIV_ACC_MASK (0x3ff << 18) +# define R300_PPLL_REF_DIV_ACC_SHIFT 18 +#define RADEON_PALETTE_DATA 0x00b4 +#define RADEON_PALETTE_30_DATA 0x00b8 +#define RADEON_PALETTE_INDEX 0x00b0 +#define RADEON_PCI_GART_PAGE 0x017c +#define RADEON_PIXCLKS_CNTL 0x002d +# define RADEON_PIX2CLK_SRC_SEL_MASK 0x03 +# define RADEON_PIX2CLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_PIX2CLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_PIX2CLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 0x03 +# define RADEON_PIX2CLK_ALWAYS_ONb (1<<6) +# define RADEON_PIX2CLK_DAC_ALWAYS_ONb (1<<7) +# define RADEON_PIXCLK_TV_SRC_SEL (1 << 8) +# define RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb (1 << 9) +# define R300_DVOCLK_ALWAYS_ONb (1 << 10) +# define RADEON_PIXCLK_BLEND_ALWAYS_ONb (1 << 11) +# define RADEON_PIXCLK_GV_ALWAYS_ONb (1 << 12) +# define RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb (1 << 13) +# define R300_PIXCLK_DVO_ALWAYS_ONb (1 << 13) +# define RADEON_PIXCLK_LVDS_ALWAYS_ONb (1 << 14) +# define RADEON_PIXCLK_TMDS_ALWAYS_ONb (1 << 15) +# define R300_PIXCLK_TRANS_ALWAYS_ONb (1 << 16) +# define R300_PIXCLK_TVO_ALWAYS_ONb (1 << 17) +# define R300_P2G2CLK_ALWAYS_ONb (1 << 18) +# define R300_P2G2CLK_DAC_ALWAYS_ONb (1 << 19) +# define R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF (1 << 23) +#define RADEON_PLANE_3D_MASK_C 0x1d44 +#define RADEON_PLL_TEST_CNTL 0x0013 /* PLL */ +# define RADEON_PLL_MASK_READ_B (1 << 9) +#define RADEON_PMI_CAP_ID 0x0f5c /* PCI */ +#define RADEON_PMI_DATA 0x0f63 /* PCI */ +#define RADEON_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ +#define RADEON_PMI_PMC_REG 0x0f5e /* PCI */ +#define RADEON_PMI_PMCSR_REG 0x0f60 /* PCI */ +#define RADEON_PMI_REGISTER 0x0f5c /* PCI */ +#define RADEON_PPLL_CNTL 0x0002 /* PLL */ +# define RADEON_PPLL_RESET (1 << 0) +# define RADEON_PPLL_SLEEP (1 << 1) +# define RADEON_PPLL_PVG_MASK (7 << 11) +# define RADEON_PPLL_PVG_SHIFT 11 +# define RADEON_PPLL_ATOMIC_UPDATE_EN (1 << 16) +# define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +# define RADEON_PPLL_ATOMIC_UPDATE_VSYNC (1 << 18) +#define RADEON_PPLL_DIV_0 0x0004 /* PLL */ +#define RADEON_PPLL_DIV_1 0x0005 /* PLL */ +#define RADEON_PPLL_DIV_2 0x0006 /* PLL */ +#define RADEON_PPLL_DIV_3 0x0007 /* PLL */ +# define RADEON_PPLL_FB3_DIV_MASK 0x07ff +# define RADEON_PPLL_POST3_DIV_MASK 0x00070000 +#define RADEON_PPLL_REF_DIV 0x0003 /* PLL */ +# define RADEON_PPLL_REF_DIV_MASK 0x03ff +# define RADEON_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define RADEON_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +#define RADEON_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */ + +#define RADEON_RBBM_GUICNTL 0x172c +# define RADEON_HOST_DATA_SWAP_NONE (0 << 0) +# define RADEON_HOST_DATA_SWAP_16BIT (1 << 0) +# define RADEON_HOST_DATA_SWAP_32BIT (2 << 0) +# define RADEON_HOST_DATA_SWAP_HDW (3 << 0) +#define RADEON_RBBM_SOFT_RESET 0x00f0 +# define RADEON_SOFT_RESET_CP (1 << 0) +# define RADEON_SOFT_RESET_HI (1 << 1) +# define RADEON_SOFT_RESET_SE (1 << 2) +# define RADEON_SOFT_RESET_RE (1 << 3) +# define RADEON_SOFT_RESET_PP (1 << 4) +# define RADEON_SOFT_RESET_E2 (1 << 5) +# define RADEON_SOFT_RESET_RB (1 << 6) +# define RADEON_SOFT_RESET_HDP (1 << 7) +#define RADEON_RBBM_STATUS 0x0e40 +# define RADEON_RBBM_FIFOCNT_MASK 0x007f +# define RADEON_RBBM_ACTIVE (1 << 31) +#define RADEON_RB2D_DSTCACHE_CTLSTAT 0x342c +# define RADEON_RB2D_DC_FLUSH (3 << 0) +# define RADEON_RB2D_DC_FREE (3 << 2) +# define RADEON_RB2D_DC_FLUSH_ALL 0xf +# define RADEON_RB2D_DC_BUSY (1 << 31) +#define RADEON_RB2D_DSTCACHE_MODE 0x3428 + +#define RADEON_RB3D_ZCACHE_MODE 0x3250 +#define RADEON_RB3D_ZCACHE_CTLSTAT 0x3254 +# define RADEON_RB3D_ZC_FLUSH_ALL 0x5 +#define RADEON_RB3D_DSTCACHE_MODE 0x3258 +# define RADEON_RB3D_DC_CACHE_ENABLE (0) +# define RADEON_RB3D_DC_2D_CACHE_DISABLE (1) +# define RADEON_RB3D_DC_3D_CACHE_DISABLE (2) +# define RADEON_RB3D_DC_CACHE_DISABLE (3) +# define RADEON_RB3D_DC_2D_CACHE_LINESIZE_128 (1 << 2) +# define RADEON_RB3D_DC_3D_CACHE_LINESIZE_128 (2 << 2) +# define RADEON_RB3D_DC_2D_CACHE_AUTOFLUSH (1 << 8) +# define RADEON_RB3D_DC_3D_CACHE_AUTOFLUSH (2 << 8) +# define R200_RB3D_DC_2D_CACHE_AUTOFREE (1 << 10) +# define R200_RB3D_DC_3D_CACHE_AUTOFREE (2 << 10) +# define RADEON_RB3D_DC_FORCE_RMW (1 << 16) +# define RADEON_RB3D_DC_DISABLE_RI_FILL (1 << 24) +# define RADEON_RB3D_DC_DISABLE_RI_READ (1 << 25) + +#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325C +# define RADEON_RB3D_DC_FLUSH (3 << 0) +# define RADEON_RB3D_DC_FREE (3 << 2) +# define RADEON_RB3D_DC_FLUSH_ALL 0xf +# define RADEON_RB3D_DC_BUSY (1 << 31) + +#define RADEON_REG_BASE 0x0f18 /* PCI */ +#define RADEON_REGPROG_INF 0x0f09 /* PCI */ +#define RADEON_REVISION_ID 0x0f08 /* PCI */ + +#define RADEON_SC_BOTTOM 0x164c +#define RADEON_SC_BOTTOM_RIGHT 0x16f0 +#define RADEON_SC_BOTTOM_RIGHT_C 0x1c8c +#define RADEON_SC_LEFT 0x1640 +#define RADEON_SC_RIGHT 0x1644 +#define RADEON_SC_TOP 0x1648 +#define RADEON_SC_TOP_LEFT 0x16ec +#define RADEON_SC_TOP_LEFT_C 0x1c88 +# define RADEON_SC_SIGN_MASK_LO 0x8000 +# define RADEON_SC_SIGN_MASK_HI 0x80000000 +#define RADEON_SCLK_CNTL 0x000d /* PLL */ +# define RADEON_SCLK_SRC_SEL_MASK 0x0007 +# define RADEON_DYN_STOP_LAT_MASK 0x00007ff8 +# define RADEON_CP_MAX_DYN_STOP_LAT 0x0008 +# define RADEON_SCLK_FORCEON_MASK 0xffff8000 +# define RADEON_SCLK_FORCE_DISP2 (1<<15) +# define RADEON_SCLK_FORCE_CP (1<<16) +# define RADEON_SCLK_FORCE_HDP (1<<17) +# define RADEON_SCLK_FORCE_DISP1 (1<<18) +# define RADEON_SCLK_FORCE_TOP (1<<19) +# define RADEON_SCLK_FORCE_E2 (1<<20) +# define RADEON_SCLK_FORCE_SE (1<<21) +# define RADEON_SCLK_FORCE_IDCT (1<<22) +# define RADEON_SCLK_FORCE_VIP (1<<23) +# define RADEON_SCLK_FORCE_RE (1<<24) +# define RADEON_SCLK_FORCE_PB (1<<25) +# define RADEON_SCLK_FORCE_TAM (1<<26) +# define RADEON_SCLK_FORCE_TDM (1<<27) +# define RADEON_SCLK_FORCE_RB (1<<28) +# define RADEON_SCLK_FORCE_TV_SCLK (1<<29) +# define RADEON_SCLK_FORCE_SUBPIC (1<<30) +# define RADEON_SCLK_FORCE_OV0 (1<<31) +# define R300_SCLK_FORCE_VAP (1<<21) +# define R300_SCLK_FORCE_SR (1<<25) +# define R300_SCLK_FORCE_PX (1<<26) +# define R300_SCLK_FORCE_TX (1<<27) +# define R300_SCLK_FORCE_US (1<<28) +# define R300_SCLK_FORCE_SU (1<<30) +#define R300_SCLK_CNTL2 0x1e /* PLL */ +# define R300_SCLK_TCL_MAX_DYN_STOP_LAT (1<<10) +# define R300_SCLK_GA_MAX_DYN_STOP_LAT (1<<11) +# define R300_SCLK_CBA_MAX_DYN_STOP_LAT (1<<12) +# define R300_SCLK_FORCE_TCL (1<<13) +# define R300_SCLK_FORCE_CBA (1<<14) +# define R300_SCLK_FORCE_GA (1<<15) +#define RADEON_SCLK_MORE_CNTL 0x0035 /* PLL */ +# define RADEON_SCLK_MORE_MAX_DYN_STOP_LAT 0x0007 +# define RADEON_SCLK_MORE_FORCEON 0x0700 +#define RADEON_SDRAM_MODE_REG 0x0158 +#define RADEON_SEQ8_DATA 0x03c5 /* VGA */ +#define RADEON_SEQ8_IDX 0x03c4 /* VGA */ +#define RADEON_SNAPSHOT_F_COUNT 0x0244 +#define RADEON_SNAPSHOT_VH_COUNTS 0x0240 +#define RADEON_SNAPSHOT_VIF_COUNT 0x024c +#define RADEON_SRC_OFFSET 0x15ac +#define RADEON_SRC_PITCH 0x15b0 +#define RADEON_SRC_PITCH_OFFSET 0x1428 +#define RADEON_SRC_SC_BOTTOM 0x165c +#define RADEON_SRC_SC_BOTTOM_RIGHT 0x16f4 +#define RADEON_SRC_SC_RIGHT 0x1654 +#define RADEON_SRC_X 0x1414 +#define RADEON_SRC_X_Y 0x1590 +#define RADEON_SRC_Y 0x1418 +#define RADEON_SRC_Y_X 0x1434 +#define RADEON_STATUS 0x0f06 /* PCI */ +#define RADEON_SUBPIC_CNTL 0x0540 /* ? */ +#define RADEON_SUB_CLASS 0x0f0a /* PCI */ +#define RADEON_SURFACE_CNTL 0x0b00 +# define RADEON_SURF_TRANSLATION_DIS (1 << 8) +# define RADEON_NONSURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_NONSURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_NONSURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_NONSURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_INFO 0x0b0c +# define RADEON_SURF_TILE_COLOR_MACRO (0 << 16) +# define RADEON_SURF_TILE_COLOR_BOTH (1 << 16) +# define RADEON_SURF_TILE_DEPTH_32BPP (2 << 16) +# define RADEON_SURF_TILE_DEPTH_16BPP (3 << 16) +# define R200_SURF_TILE_NONE (0 << 16) +# define R200_SURF_TILE_COLOR_MACRO (1 << 16) +# define R200_SURF_TILE_COLOR_MICRO (2 << 16) +# define R200_SURF_TILE_COLOR_BOTH (3 << 16) +# define R200_SURF_TILE_DEPTH_32BPP (4 << 16) +# define R200_SURF_TILE_DEPTH_16BPP (5 << 16) +# define R300_SURF_TILE_NONE (0 << 16) +# define R300_SURF_TILE_COLOR_MACRO (1 << 16) +# define R300_SURF_TILE_DEPTH_32BPP (2 << 16) +# define RADEON_SURF_AP0_SWP_16BPP (1 << 20) +# define RADEON_SURF_AP0_SWP_32BPP (1 << 21) +# define RADEON_SURF_AP1_SWP_16BPP (1 << 22) +# define RADEON_SURF_AP1_SWP_32BPP (1 << 23) +#define RADEON_SURFACE0_LOWER_BOUND 0x0b04 +#define RADEON_SURFACE0_UPPER_BOUND 0x0b08 +#define RADEON_SURFACE1_INFO 0x0b1c +#define RADEON_SURFACE1_LOWER_BOUND 0x0b14 +#define RADEON_SURFACE1_UPPER_BOUND 0x0b18 +#define RADEON_SURFACE2_INFO 0x0b2c +#define RADEON_SURFACE2_LOWER_BOUND 0x0b24 +#define RADEON_SURFACE2_UPPER_BOUND 0x0b28 +#define RADEON_SURFACE3_INFO 0x0b3c +#define RADEON_SURFACE3_LOWER_BOUND 0x0b34 +#define RADEON_SURFACE3_UPPER_BOUND 0x0b38 +#define RADEON_SURFACE4_INFO 0x0b4c +#define RADEON_SURFACE4_LOWER_BOUND 0x0b44 +#define RADEON_SURFACE4_UPPER_BOUND 0x0b48 +#define RADEON_SURFACE5_INFO 0x0b5c +#define RADEON_SURFACE5_LOWER_BOUND 0x0b54 +#define RADEON_SURFACE5_UPPER_BOUND 0x0b58 +#define RADEON_SURFACE6_INFO 0x0b6c +#define RADEON_SURFACE6_LOWER_BOUND 0x0b64 +#define RADEON_SURFACE6_UPPER_BOUND 0x0b68 +#define RADEON_SURFACE7_INFO 0x0b7c +#define RADEON_SURFACE7_LOWER_BOUND 0x0b74 +#define RADEON_SURFACE7_UPPER_BOUND 0x0b78 +#define RADEON_SW_SEMAPHORE 0x013c + +#define RADEON_TEST_DEBUG_CNTL 0x0120 +#define RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN 0x00000001 + +#define RADEON_TEST_DEBUG_MUX 0x0124 +#define RADEON_TEST_DEBUG_OUT 0x012c +#define RADEON_TMDS_PLL_CNTL 0x02a8 +#define RADEON_TMDS_TRANSMITTER_CNTL 0x02a4 +# define RADEON_TMDS_TRANSMITTER_PLLEN 1 +# define RADEON_TMDS_TRANSMITTER_PLLRST 2 +#define RADEON_TRAIL_BRES_DEC 0x1614 +#define RADEON_TRAIL_BRES_ERR 0x160c +#define RADEON_TRAIL_BRES_INC 0x1610 +#define RADEON_TRAIL_X 0x1618 +#define RADEON_TRAIL_X_SUB 0x1620 + +#define RADEON_VCLK_ECP_CNTL 0x0008 /* PLL */ +# define RADEON_VCLK_SRC_SEL_MASK 0x03 +# define RADEON_VCLK_SRC_SEL_CPUCLK 0x00 +# define RADEON_VCLK_SRC_SEL_PSCANCLK 0x01 +# define RADEON_VCLK_SRC_SEL_BYTECLK 0x02 +# define RADEON_VCLK_SRC_SEL_PPLLCLK 0x03 +# define RADEON_PIXCLK_ALWAYS_ONb (1<<6) +# define RADEON_PIXCLK_DAC_ALWAYS_ONb (1<<7) +# define R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF (1<<23) + +#define RADEON_VENDOR_ID 0x0f00 /* PCI */ +#define RADEON_VGA_DDA_CONFIG 0x02e8 +#define RADEON_VGA_DDA_ON_OFF 0x02ec +#define RADEON_VID_BUFFER_CONTROL 0x0900 +#define RADEON_VIDEOMUX_CNTL 0x0190 + + /* VIP bus */ +#define RADEON_VIPH_CH0_DATA 0x0c00 +#define RADEON_VIPH_CH1_DATA 0x0c04 +#define RADEON_VIPH_CH2_DATA 0x0c08 +#define RADEON_VIPH_CH3_DATA 0x0c0c +#define RADEON_VIPH_CH0_ADDR 0x0c10 +#define RADEON_VIPH_CH1_ADDR 0x0c14 +#define RADEON_VIPH_CH2_ADDR 0x0c18 +#define RADEON_VIPH_CH3_ADDR 0x0c1c +#define RADEON_VIPH_CH0_SBCNT 0x0c20 +#define RADEON_VIPH_CH1_SBCNT 0x0c24 +#define RADEON_VIPH_CH2_SBCNT 0x0c28 +#define RADEON_VIPH_CH3_SBCNT 0x0c2c +#define RADEON_VIPH_CH0_ABCNT 0x0c30 +#define RADEON_VIPH_CH1_ABCNT 0x0c34 +#define RADEON_VIPH_CH2_ABCNT 0x0c38 +#define RADEON_VIPH_CH3_ABCNT 0x0c3c +#define RADEON_VIPH_CONTROL 0x0c40 +# define RADEON_VIP_BUSY 0 +# define RADEON_VIP_IDLE 1 +# define RADEON_VIP_RESET 2 +#define RADEON_VIPH_DV_LAT 0x0c44 +#define RADEON_VIPH_BM_CHUNK 0x0c48 +#define RADEON_VIPH_DV_INT 0x0c4c +#define RADEON_VIPH_TIMEOUT_STAT 0x0c50 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT 0x00000010 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK 0x00000010 +#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS 0x01000000 + +#define RADEON_VIPH_REG_DATA 0x0084 +#define RADEON_VIPH_REG_ADDR 0x0080 + + +#define RADEON_WAIT_UNTIL 0x1720 +# define RADEON_WAIT_CRTC_PFLIP (1 << 0) +# define RADEON_WAIT_2D_IDLECLEAN (1 << 16) +# define RADEON_WAIT_3D_IDLECLEAN (1 << 17) +# define RADEON_WAIT_HOST_IDLECLEAN (1 << 18) + +#define RADEON_X_MPLL_REF_FB_DIV 0x000a /* PLL */ +#define RADEON_XCLK_CNTL 0x000d /* PLL */ +#define RADEON_XDLL_CNTL 0x000c /* PLL */ +#define RADEON_XPLL_CNTL 0x000b /* PLL */ + + + + /* Registers for 3D/TCL */ +#define RADEON_PP_BORDER_COLOR_0 0x1d40 +#define RADEON_PP_BORDER_COLOR_1 0x1d44 +#define RADEON_PP_BORDER_COLOR_2 0x1d48 +#define RADEON_PP_CNTL 0x1c38 +# define RADEON_STIPPLE_ENABLE (1 << 0) +# define RADEON_SCISSOR_ENABLE (1 << 1) +# define RADEON_PATTERN_ENABLE (1 << 2) +# define RADEON_SHADOW_ENABLE (1 << 3) +# define RADEON_TEX_ENABLE_MASK (0xf << 4) +# define RADEON_TEX_0_ENABLE (1 << 4) +# define RADEON_TEX_1_ENABLE (1 << 5) +# define RADEON_TEX_2_ENABLE (1 << 6) +# define RADEON_TEX_3_ENABLE (1 << 7) +# define RADEON_TEX_BLEND_ENABLE_MASK (0xf << 12) +# define RADEON_TEX_BLEND_0_ENABLE (1 << 12) +# define RADEON_TEX_BLEND_1_ENABLE (1 << 13) +# define RADEON_TEX_BLEND_2_ENABLE (1 << 14) +# define RADEON_TEX_BLEND_3_ENABLE (1 << 15) +# define RADEON_PLANAR_YUV_ENABLE (1 << 20) +# define RADEON_SPECULAR_ENABLE (1 << 21) +# define RADEON_FOG_ENABLE (1 << 22) +# define RADEON_ALPHA_TEST_ENABLE (1 << 23) +# define RADEON_ANTI_ALIAS_NONE (0 << 24) +# define RADEON_ANTI_ALIAS_LINE (1 << 24) +# define RADEON_ANTI_ALIAS_POLY (2 << 24) +# define RADEON_ANTI_ALIAS_LINE_POLY (3 << 24) +# define RADEON_BUMP_MAP_ENABLE (1 << 26) +# define RADEON_BUMPED_MAP_T0 (0 << 27) +# define RADEON_BUMPED_MAP_T1 (1 << 27) +# define RADEON_BUMPED_MAP_T2 (2 << 27) +# define RADEON_TEX_3D_ENABLE_0 (1 << 29) +# define RADEON_TEX_3D_ENABLE_1 (1 << 30) +# define RADEON_MC_ENABLE (1 << 31) +#define RADEON_PP_FOG_COLOR 0x1c18 +# define RADEON_FOG_COLOR_MASK 0x00ffffff +# define RADEON_FOG_VERTEX (0 << 24) +# define RADEON_FOG_TABLE (1 << 24) +# define RADEON_FOG_USE_DEPTH (0 << 25) +# define RADEON_FOG_USE_DIFFUSE_ALPHA (2 << 25) +# define RADEON_FOG_USE_SPEC_ALPHA (3 << 25) +#define RADEON_PP_LUM_MATRIX 0x1d00 +#define RADEON_PP_MISC 0x1c14 +# define RADEON_REF_ALPHA_MASK 0x000000ff +# define RADEON_ALPHA_TEST_FAIL (0 << 8) +# define RADEON_ALPHA_TEST_LESS (1 << 8) +# define RADEON_ALPHA_TEST_LEQUAL (2 << 8) +# define RADEON_ALPHA_TEST_EQUAL (3 << 8) +# define RADEON_ALPHA_TEST_GEQUAL (4 << 8) +# define RADEON_ALPHA_TEST_GREATER (5 << 8) +# define RADEON_ALPHA_TEST_NEQUAL (6 << 8) +# define RADEON_ALPHA_TEST_PASS (7 << 8) +# define RADEON_ALPHA_TEST_OP_MASK (7 << 8) +# define RADEON_CHROMA_FUNC_FAIL (0 << 16) +# define RADEON_CHROMA_FUNC_PASS (1 << 16) +# define RADEON_CHROMA_FUNC_NEQUAL (2 << 16) +# define RADEON_CHROMA_FUNC_EQUAL (3 << 16) +# define RADEON_CHROMA_KEY_NEAREST (0 << 18) +# define RADEON_CHROMA_KEY_ZERO (1 << 18) +# define RADEON_SHADOW_ID_AUTO_INC (1 << 20) +# define RADEON_SHADOW_FUNC_EQUAL (0 << 21) +# define RADEON_SHADOW_FUNC_NEQUAL (1 << 21) +# define RADEON_SHADOW_PASS_1 (0 << 22) +# define RADEON_SHADOW_PASS_2 (1 << 22) +# define RADEON_RIGHT_HAND_CUBE_D3D (0 << 24) +# define RADEON_RIGHT_HAND_CUBE_OGL (1 << 24) +#define RADEON_PP_ROT_MATRIX_0 0x1d58 +#define RADEON_PP_ROT_MATRIX_1 0x1d5c +#define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXFILTER_1 0x1c6c +#define RADEON_PP_TXFILTER_2 0x1c84 +# define RADEON_MAG_FILTER_NEAREST (0 << 0) +# define RADEON_MAG_FILTER_LINEAR (1 << 0) +# define RADEON_MAG_FILTER_MASK (1 << 0) +# define RADEON_MIN_FILTER_NEAREST (0 << 1) +# define RADEON_MIN_FILTER_LINEAR (1 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define RADEON_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define RADEON_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define RADEON_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define RADEON_MIN_FILTER_MASK (15 << 1) +# define RADEON_MAX_ANISO_1_TO_1 (0 << 5) +# define RADEON_MAX_ANISO_2_TO_1 (1 << 5) +# define RADEON_MAX_ANISO_4_TO_1 (2 << 5) +# define RADEON_MAX_ANISO_8_TO_1 (3 << 5) +# define RADEON_MAX_ANISO_16_TO_1 (4 << 5) +# define RADEON_MAX_ANISO_MASK (7 << 5) +# define RADEON_LOD_BIAS_MASK (0xff << 8) +# define RADEON_LOD_BIAS_SHIFT 8 +# define RADEON_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define RADEON_MAX_MIP_LEVEL_SHIFT 16 +# define RADEON_YUV_TO_RGB (1 << 20) +# define RADEON_YUV_TEMPERATURE_COOL (0 << 21) +# define RADEON_YUV_TEMPERATURE_HOT (1 << 21) +# define RADEON_YUV_TEMPERATURE_MASK (1 << 21) +# define RADEON_WRAPEN_S (1 << 22) +# define RADEON_CLAMP_S_WRAP (0 << 23) +# define RADEON_CLAMP_S_MIRROR (1 << 23) +# define RADEON_CLAMP_S_CLAMP_LAST (2 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define RADEON_CLAMP_S_CLAMP_BORDER (4 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define RADEON_CLAMP_S_CLAMP_GL (6 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define RADEON_CLAMP_S_MASK (7 << 23) +# define RADEON_WRAPEN_T (1 << 26) +# define RADEON_CLAMP_T_WRAP (0 << 27) +# define RADEON_CLAMP_T_MIRROR (1 << 27) +# define RADEON_CLAMP_T_CLAMP_LAST (2 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define RADEON_CLAMP_T_CLAMP_BORDER (4 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define RADEON_CLAMP_T_CLAMP_GL (6 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define RADEON_CLAMP_T_MASK (7 << 27) +# define RADEON_BORDER_MODE_OGL (0 << 31) +# define RADEON_BORDER_MODE_D3D (1 << 31) +#define RADEON_PP_TXFORMAT_0 0x1c58 +#define RADEON_PP_TXFORMAT_1 0x1c70 +#define RADEON_PP_TXFORMAT_2 0x1c88 +# define RADEON_TXFORMAT_I8 (0 << 0) +# define RADEON_TXFORMAT_AI88 (1 << 0) +# define RADEON_TXFORMAT_RGB332 (2 << 0) +# define RADEON_TXFORMAT_ARGB1555 (3 << 0) +# define RADEON_TXFORMAT_RGB565 (4 << 0) +# define RADEON_TXFORMAT_ARGB4444 (5 << 0) +# define RADEON_TXFORMAT_ARGB8888 (6 << 0) +# define RADEON_TXFORMAT_RGBA8888 (7 << 0) +# define RADEON_TXFORMAT_Y8 (8 << 0) +# define RADEON_TXFORMAT_VYUY422 (10 << 0) +# define RADEON_TXFORMAT_YVYU422 (11 << 0) +# define RADEON_TXFORMAT_DXT1 (12 << 0) +# define RADEON_TXFORMAT_DXT23 (14 << 0) +# define RADEON_TXFORMAT_DXT45 (15 << 0) +# define RADEON_TXFORMAT_FORMAT_MASK (31 << 0) +# define RADEON_TXFORMAT_FORMAT_SHIFT 0 +# define RADEON_TXFORMAT_APPLE_YUV_MODE (1 << 5) +# define RADEON_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define RADEON_TXFORMAT_NON_POWER2 (1 << 7) +# define RADEON_TXFORMAT_WIDTH_MASK (15 << 8) +# define RADEON_TXFORMAT_WIDTH_SHIFT 8 +# define RADEON_TXFORMAT_HEIGHT_MASK (15 << 12) +# define RADEON_TXFORMAT_HEIGHT_SHIFT 12 +# define RADEON_TXFORMAT_F5_WIDTH_MASK (15 << 16) +# define RADEON_TXFORMAT_F5_WIDTH_SHIFT 16 +# define RADEON_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define RADEON_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define RADEON_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_MASK (3 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define RADEON_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define RADEON_TXFORMAT_ENDIAN_NO_SWAP (0 << 26) +# define RADEON_TXFORMAT_ENDIAN_16BPP_SWAP (1 << 26) +# define RADEON_TXFORMAT_ENDIAN_32BPP_SWAP (2 << 26) +# define RADEON_TXFORMAT_ENDIAN_HALFDW_SWAP (3 << 26) +# define RADEON_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define RADEON_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +# define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1 << 31) +#define RADEON_PP_CUBIC_FACES_0 0x1d24 +#define RADEON_PP_CUBIC_FACES_1 0x1d28 +#define RADEON_PP_CUBIC_FACES_2 0x1d2c +# define RADEON_FACE_WIDTH_1_SHIFT 0 +# define RADEON_FACE_HEIGHT_1_SHIFT 4 +# define RADEON_FACE_WIDTH_1_MASK (0xf << 0) +# define RADEON_FACE_HEIGHT_1_MASK (0xf << 4) +# define RADEON_FACE_WIDTH_2_SHIFT 8 +# define RADEON_FACE_HEIGHT_2_SHIFT 12 +# define RADEON_FACE_WIDTH_2_MASK (0xf << 8) +# define RADEON_FACE_HEIGHT_2_MASK (0xf << 12) +# define RADEON_FACE_WIDTH_3_SHIFT 16 +# define RADEON_FACE_HEIGHT_3_SHIFT 20 +# define RADEON_FACE_WIDTH_3_MASK (0xf << 16) +# define RADEON_FACE_HEIGHT_3_MASK (0xf << 20) +# define RADEON_FACE_WIDTH_4_SHIFT 24 +# define RADEON_FACE_HEIGHT_4_SHIFT 28 +# define RADEON_FACE_WIDTH_4_MASK (0xf << 24) +# define RADEON_FACE_HEIGHT_4_MASK (0xf << 28) + +#define RADEON_PP_TXOFFSET_0 0x1c5c +#define RADEON_PP_TXOFFSET_1 0x1c74 +#define RADEON_PP_TXOFFSET_2 0x1c8c +# define RADEON_TXO_ENDIAN_NO_SWAP (0 << 0) +# define RADEON_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define RADEON_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define RADEON_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define RADEON_TXO_MACRO_LINEAR (0 << 2) +# define RADEON_TXO_MACRO_TILE (1 << 2) +# define RADEON_TXO_MICRO_LINEAR (0 << 3) +# define RADEON_TXO_MICRO_TILE_X2 (1 << 3) +# define RADEON_TXO_MICRO_TILE_OPT (2 << 3) +# define RADEON_TXO_OFFSET_MASK 0xffffffe0 +# define RADEON_TXO_OFFSET_SHIFT 5 + +#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */ +#define RADEON_PP_CUBIC_OFFSET_T0_1 0x1dd4 +#define RADEON_PP_CUBIC_OFFSET_T0_2 0x1dd8 +#define RADEON_PP_CUBIC_OFFSET_T0_3 0x1ddc +#define RADEON_PP_CUBIC_OFFSET_T0_4 0x1de0 +#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00 +#define RADEON_PP_CUBIC_OFFSET_T1_1 0x1e04 +#define RADEON_PP_CUBIC_OFFSET_T1_2 0x1e08 +#define RADEON_PP_CUBIC_OFFSET_T1_3 0x1e0c +#define RADEON_PP_CUBIC_OFFSET_T1_4 0x1e10 +#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14 +#define RADEON_PP_CUBIC_OFFSET_T2_1 0x1e18 +#define RADEON_PP_CUBIC_OFFSET_T2_2 0x1e1c +#define RADEON_PP_CUBIC_OFFSET_T2_3 0x1e20 +#define RADEON_PP_CUBIC_OFFSET_T2_4 0x1e24 + +#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */ +#define RADEON_PP_TEX_SIZE_1 0x1d0c +#define RADEON_PP_TEX_SIZE_2 0x1d14 +# define RADEON_TEX_USIZE_MASK (0x7ff << 0) +# define RADEON_TEX_USIZE_SHIFT 0 +# define RADEON_TEX_VSIZE_MASK (0x7ff << 16) +# define RADEON_TEX_VSIZE_SHIFT 16 +# define RADEON_SIGNED_RGB_MASK (1 << 30) +# define RADEON_SIGNED_RGB_SHIFT 30 +# define RADEON_SIGNED_ALPHA_MASK (1 << 31) +# define RADEON_SIGNED_ALPHA_SHIFT 31 +#define RADEON_PP_TEX_PITCH_0 0x1d08 /* NPOT */ +#define RADEON_PP_TEX_PITCH_1 0x1d10 /* NPOT */ +#define RADEON_PP_TEX_PITCH_2 0x1d18 /* NPOT */ +/* note: bits 13-5: 32 byte aligned stride of texture map */ + +#define RADEON_PP_TXCBLEND_0 0x1c60 +#define RADEON_PP_TXCBLEND_1 0x1c78 +#define RADEON_PP_TXCBLEND_2 0x1c90 +# define RADEON_COLOR_ARG_A_SHIFT 0 +# define RADEON_COLOR_ARG_A_MASK (0x1f << 0) +# define RADEON_COLOR_ARG_A_ZERO (0 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_COLOR (2 << 0) +# define RADEON_COLOR_ARG_A_CURRENT_ALPHA (3 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_COLOR (4 << 0) +# define RADEON_COLOR_ARG_A_DIFFUSE_ALPHA (5 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_COLOR (6 << 0) +# define RADEON_COLOR_ARG_A_SPECULAR_ALPHA (7 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_COLOR (8 << 0) +# define RADEON_COLOR_ARG_A_TFACTOR_ALPHA (9 << 0) +# define RADEON_COLOR_ARG_A_T0_COLOR (10 << 0) +# define RADEON_COLOR_ARG_A_T0_ALPHA (11 << 0) +# define RADEON_COLOR_ARG_A_T1_COLOR (12 << 0) +# define RADEON_COLOR_ARG_A_T1_ALPHA (13 << 0) +# define RADEON_COLOR_ARG_A_T2_COLOR (14 << 0) +# define RADEON_COLOR_ARG_A_T2_ALPHA (15 << 0) +# define RADEON_COLOR_ARG_A_T3_COLOR (16 << 0) +# define RADEON_COLOR_ARG_A_T3_ALPHA (17 << 0) +# define RADEON_COLOR_ARG_B_SHIFT 5 +# define RADEON_COLOR_ARG_B_MASK (0x1f << 5) +# define RADEON_COLOR_ARG_B_ZERO (0 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_COLOR (2 << 5) +# define RADEON_COLOR_ARG_B_CURRENT_ALPHA (3 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_COLOR (4 << 5) +# define RADEON_COLOR_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_COLOR (6 << 5) +# define RADEON_COLOR_ARG_B_SPECULAR_ALPHA (7 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_COLOR (8 << 5) +# define RADEON_COLOR_ARG_B_TFACTOR_ALPHA (9 << 5) +# define RADEON_COLOR_ARG_B_T0_COLOR (10 << 5) +# define RADEON_COLOR_ARG_B_T0_ALPHA (11 << 5) +# define RADEON_COLOR_ARG_B_T1_COLOR (12 << 5) +# define RADEON_COLOR_ARG_B_T1_ALPHA (13 << 5) +# define RADEON_COLOR_ARG_B_T2_COLOR (14 << 5) +# define RADEON_COLOR_ARG_B_T2_ALPHA (15 << 5) +# define RADEON_COLOR_ARG_B_T3_COLOR (16 << 5) +# define RADEON_COLOR_ARG_B_T3_ALPHA (17 << 5) +# define RADEON_COLOR_ARG_C_SHIFT 10 +# define RADEON_COLOR_ARG_C_MASK (0x1f << 10) +# define RADEON_COLOR_ARG_C_ZERO (0 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_COLOR (2 << 10) +# define RADEON_COLOR_ARG_C_CURRENT_ALPHA (3 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_COLOR (4 << 10) +# define RADEON_COLOR_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_COLOR (6 << 10) +# define RADEON_COLOR_ARG_C_SPECULAR_ALPHA (7 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_COLOR (8 << 10) +# define RADEON_COLOR_ARG_C_TFACTOR_ALPHA (9 << 10) +# define RADEON_COLOR_ARG_C_T0_COLOR (10 << 10) +# define RADEON_COLOR_ARG_C_T0_ALPHA (11 << 10) +# define RADEON_COLOR_ARG_C_T1_COLOR (12 << 10) +# define RADEON_COLOR_ARG_C_T1_ALPHA (13 << 10) +# define RADEON_COLOR_ARG_C_T2_COLOR (14 << 10) +# define RADEON_COLOR_ARG_C_T2_ALPHA (15 << 10) +# define RADEON_COLOR_ARG_C_T3_COLOR (16 << 10) +# define RADEON_COLOR_ARG_C_T3_ALPHA (17 << 10) +# define RADEON_COMP_ARG_A (1 << 15) +# define RADEON_COMP_ARG_A_SHIFT 15 +# define RADEON_COMP_ARG_B (1 << 16) +# define RADEON_COMP_ARG_B_SHIFT 16 +# define RADEON_COMP_ARG_C (1 << 17) +# define RADEON_COMP_ARG_C_SHIFT 17 +# define RADEON_BLEND_CTL_MASK (7 << 18) +# define RADEON_BLEND_CTL_ADD (0 << 18) +# define RADEON_BLEND_CTL_SUBTRACT (1 << 18) +# define RADEON_BLEND_CTL_ADDSIGNED (2 << 18) +# define RADEON_BLEND_CTL_BLEND (3 << 18) +# define RADEON_BLEND_CTL_DOT3 (4 << 18) +# define RADEON_SCALE_SHIFT 21 +# define RADEON_SCALE_MASK (3 << 21) +# define RADEON_SCALE_1X (0 << 21) +# define RADEON_SCALE_2X (1 << 21) +# define RADEON_SCALE_4X (2 << 21) +# define RADEON_CLAMP_TX (1 << 23) +# define RADEON_T0_EQ_TCUR (1 << 24) +# define RADEON_T1_EQ_TCUR (1 << 25) +# define RADEON_T2_EQ_TCUR (1 << 26) +# define RADEON_T3_EQ_TCUR (1 << 27) +# define RADEON_COLOR_ARG_MASK 0x1f +# define RADEON_COMP_ARG_SHIFT 15 +#define RADEON_PP_TXABLEND_0 0x1c64 +#define RADEON_PP_TXABLEND_1 0x1c7c +#define RADEON_PP_TXABLEND_2 0x1c94 +# define RADEON_ALPHA_ARG_A_SHIFT 0 +# define RADEON_ALPHA_ARG_A_MASK (0xf << 0) +# define RADEON_ALPHA_ARG_A_ZERO (0 << 0) +# define RADEON_ALPHA_ARG_A_CURRENT_ALPHA (1 << 0) +# define RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA (2 << 0) +# define RADEON_ALPHA_ARG_A_SPECULAR_ALPHA (3 << 0) +# define RADEON_ALPHA_ARG_A_TFACTOR_ALPHA (4 << 0) +# define RADEON_ALPHA_ARG_A_T0_ALPHA (5 << 0) +# define RADEON_ALPHA_ARG_A_T1_ALPHA (6 << 0) +# define RADEON_ALPHA_ARG_A_T2_ALPHA (7 << 0) +# define RADEON_ALPHA_ARG_A_T3_ALPHA (8 << 0) +# define RADEON_ALPHA_ARG_B_SHIFT 4 +# define RADEON_ALPHA_ARG_B_MASK (0xf << 4) +# define RADEON_ALPHA_ARG_B_ZERO (0 << 4) +# define RADEON_ALPHA_ARG_B_CURRENT_ALPHA (1 << 4) +# define RADEON_ALPHA_ARG_B_DIFFUSE_ALPHA (2 << 4) +# define RADEON_ALPHA_ARG_B_SPECULAR_ALPHA (3 << 4) +# define RADEON_ALPHA_ARG_B_TFACTOR_ALPHA (4 << 4) +# define RADEON_ALPHA_ARG_B_T0_ALPHA (5 << 4) +# define RADEON_ALPHA_ARG_B_T1_ALPHA (6 << 4) +# define RADEON_ALPHA_ARG_B_T2_ALPHA (7 << 4) +# define RADEON_ALPHA_ARG_B_T3_ALPHA (8 << 4) +# define RADEON_ALPHA_ARG_C_SHIFT 8 +# define RADEON_ALPHA_ARG_C_MASK (0xf << 8) +# define RADEON_ALPHA_ARG_C_ZERO (0 << 8) +# define RADEON_ALPHA_ARG_C_CURRENT_ALPHA (1 << 8) +# define RADEON_ALPHA_ARG_C_DIFFUSE_ALPHA (2 << 8) +# define RADEON_ALPHA_ARG_C_SPECULAR_ALPHA (3 << 8) +# define RADEON_ALPHA_ARG_C_TFACTOR_ALPHA (4 << 8) +# define RADEON_ALPHA_ARG_C_T0_ALPHA (5 << 8) +# define RADEON_ALPHA_ARG_C_T1_ALPHA (6 << 8) +# define RADEON_ALPHA_ARG_C_T2_ALPHA (7 << 8) +# define RADEON_ALPHA_ARG_C_T3_ALPHA (8 << 8) +# define RADEON_DOT_ALPHA_DONT_REPLICATE (1 << 9) +# define RADEON_ALPHA_ARG_MASK 0xf + +#define RADEON_PP_TFACTOR_0 0x1c68 +#define RADEON_PP_TFACTOR_1 0x1c80 +#define RADEON_PP_TFACTOR_2 0x1c98 + +#define RADEON_RB3D_BLENDCNTL 0x1c20 +# define RADEON_COMB_FCN_MASK (3 << 12) +# define RADEON_COMB_FCN_ADD_CLAMP (0 << 12) +# define RADEON_COMB_FCN_ADD_NOCLAMP (1 << 12) +# define RADEON_COMB_FCN_SUB_CLAMP (2 << 12) +# define RADEON_COMB_FCN_SUB_NOCLAMP (3 << 12) +# define RADEON_SRC_BLEND_GL_ZERO (32 << 16) +# define RADEON_SRC_BLEND_GL_ONE (33 << 16) +# define RADEON_SRC_BLEND_GL_SRC_COLOR (34 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16) +# define RADEON_SRC_BLEND_GL_DST_COLOR (36 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA (38 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16) +# define RADEON_SRC_BLEND_GL_DST_ALPHA (40 << 16) +# define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16) +# define RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE (42 << 16) +# define RADEON_SRC_BLEND_MASK (63 << 16) +# define RADEON_DST_BLEND_GL_ZERO (32 << 24) +# define RADEON_DST_BLEND_GL_ONE (33 << 24) +# define RADEON_DST_BLEND_GL_SRC_COLOR (34 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24) +# define RADEON_DST_BLEND_GL_DST_COLOR (36 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24) +# define RADEON_DST_BLEND_GL_SRC_ALPHA (38 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24) +# define RADEON_DST_BLEND_GL_DST_ALPHA (40 << 24) +# define RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24) +# define RADEON_DST_BLEND_MASK (63 << 24) +#define RADEON_RB3D_CNTL 0x1c3c +# define RADEON_ALPHA_BLEND_ENABLE (1 << 0) +# define RADEON_PLANE_MASK_ENABLE (1 << 1) +# define RADEON_DITHER_ENABLE (1 << 2) +# define RADEON_ROUND_ENABLE (1 << 3) +# define RADEON_SCALE_DITHER_ENABLE (1 << 4) +# define RADEON_DITHER_INIT (1 << 5) +# define RADEON_ROP_ENABLE (1 << 6) +# define RADEON_STENCIL_ENABLE (1 << 7) +# define RADEON_Z_ENABLE (1 << 8) +# define RADEON_DEPTH_XZ_OFFEST_ENABLE (1 << 9) +# define RADEON_COLOR_FORMAT_ARGB1555 (3 << 10) +# define RADEON_COLOR_FORMAT_RGB565 (4 << 10) +# define RADEON_COLOR_FORMAT_ARGB8888 (6 << 10) +# define RADEON_COLOR_FORMAT_RGB332 (7 << 10) +# define RADEON_COLOR_FORMAT_Y8 (8 << 10) +# define RADEON_COLOR_FORMAT_RGB8 (9 << 10) +# define RADEON_COLOR_FORMAT_YUV422_VYUY (11 << 10) +# define RADEON_COLOR_FORMAT_YUV422_YVYU (12 << 10) +# define RADEON_COLOR_FORMAT_aYUV444 (14 << 10) +# define RADEON_COLOR_FORMAT_ARGB4444 (15 << 10) +# define RADEON_CLRCMP_FLIP_ENABLE (1 << 14) +#define RADEON_RB3D_COLOROFFSET 0x1c40 +# define RADEON_COLOROFFSET_MASK 0xfffffff0 +#define RADEON_RB3D_COLORPITCH 0x1c48 +# define RADEON_COLORPITCH_MASK 0x000001ff8 +# define RADEON_COLOR_TILE_ENABLE (1 << 16) +# define RADEON_COLOR_MICROTILE_ENABLE (1 << 17) +# define RADEON_COLOR_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_COLOR_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_COLOR_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_DEPTHOFFSET 0x1c24 +#define RADEON_RB3D_DEPTHPITCH 0x1c28 +# define RADEON_DEPTHPITCH_MASK 0x00001ff8 +# define RADEON_DEPTH_ENDIAN_NO_SWAP (0 << 18) +# define RADEON_DEPTH_ENDIAN_WORD_SWAP (1 << 18) +# define RADEON_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) +#define RADEON_RB3D_PLANEMASK 0x1d84 +#define RADEON_RB3D_ROPCNTL 0x1d80 +# define RADEON_ROP_MASK (15 << 8) +# define RADEON_ROP_CLEAR (0 << 8) +# define RADEON_ROP_NOR (1 << 8) +# define RADEON_ROP_AND_INVERTED (2 << 8) +# define RADEON_ROP_COPY_INVERTED (3 << 8) +# define RADEON_ROP_AND_REVERSE (4 << 8) +# define RADEON_ROP_INVERT (5 << 8) +# define RADEON_ROP_XOR (6 << 8) +# define RADEON_ROP_NAND (7 << 8) +# define RADEON_ROP_AND (8 << 8) +# define RADEON_ROP_EQUIV (9 << 8) +# define RADEON_ROP_NOOP (10 << 8) +# define RADEON_ROP_OR_INVERTED (11 << 8) +# define RADEON_ROP_COPY (12 << 8) +# define RADEON_ROP_OR_REVERSE (13 << 8) +# define RADEON_ROP_OR (14 << 8) +# define RADEON_ROP_SET (15 << 8) +#define RADEON_RB3D_STENCILREFMASK 0x1d7c +# define RADEON_STENCIL_REF_SHIFT 0 +# define RADEON_STENCIL_REF_MASK (0xff << 0) +# define RADEON_STENCIL_MASK_SHIFT 16 +# define RADEON_STENCIL_VALUE_MASK (0xff << 16) +# define RADEON_STENCIL_WRITEMASK_SHIFT 24 +# define RADEON_STENCIL_WRITE_MASK (0xff << 24) +#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c +# define RADEON_DEPTH_FORMAT_MASK (0xf << 0) +# define RADEON_DEPTH_FORMAT_16BIT_INT_Z (0 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_INT_Z (2 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_Z (3 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_INT_Z (4 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_Z (5 << 0) +# define RADEON_DEPTH_FORMAT_16BIT_FLOAT_W (7 << 0) +# define RADEON_DEPTH_FORMAT_24BIT_FLOAT_W (9 << 0) +# define RADEON_DEPTH_FORMAT_32BIT_FLOAT_W (11 << 0) +# define RADEON_Z_TEST_NEVER (0 << 4) +# define RADEON_Z_TEST_LESS (1 << 4) +# define RADEON_Z_TEST_LEQUAL (2 << 4) +# define RADEON_Z_TEST_EQUAL (3 << 4) +# define RADEON_Z_TEST_GEQUAL (4 << 4) +# define RADEON_Z_TEST_GREATER (5 << 4) +# define RADEON_Z_TEST_NEQUAL (6 << 4) +# define RADEON_Z_TEST_ALWAYS (7 << 4) +# define RADEON_Z_TEST_MASK (7 << 4) +# define RADEON_STENCIL_TEST_NEVER (0 << 12) +# define RADEON_STENCIL_TEST_LESS (1 << 12) +# define RADEON_STENCIL_TEST_LEQUAL (2 << 12) +# define RADEON_STENCIL_TEST_EQUAL (3 << 12) +# define RADEON_STENCIL_TEST_GEQUAL (4 << 12) +# define RADEON_STENCIL_TEST_GREATER (5 << 12) +# define RADEON_STENCIL_TEST_NEQUAL (6 << 12) +# define RADEON_STENCIL_TEST_ALWAYS (7 << 12) +# define RADEON_STENCIL_TEST_MASK (0x7 << 12) +# define RADEON_STENCIL_FAIL_KEEP (0 << 16) +# define RADEON_STENCIL_FAIL_ZERO (1 << 16) +# define RADEON_STENCIL_FAIL_REPLACE (2 << 16) +# define RADEON_STENCIL_FAIL_INC (3 << 16) +# define RADEON_STENCIL_FAIL_DEC (4 << 16) +# define RADEON_STENCIL_FAIL_INVERT (5 << 16) +# define RADEON_STENCIL_FAIL_MASK (0x7 << 16) +# define RADEON_STENCIL_ZPASS_KEEP (0 << 20) +# define RADEON_STENCIL_ZPASS_ZERO (1 << 20) +# define RADEON_STENCIL_ZPASS_REPLACE (2 << 20) +# define RADEON_STENCIL_ZPASS_INC (3 << 20) +# define RADEON_STENCIL_ZPASS_DEC (4 << 20) +# define RADEON_STENCIL_ZPASS_INVERT (5 << 20) +# define RADEON_STENCIL_ZPASS_MASK (0x7 << 20) +# define RADEON_STENCIL_ZFAIL_KEEP (0 << 24) +# define RADEON_STENCIL_ZFAIL_ZERO (1 << 24) +# define RADEON_STENCIL_ZFAIL_REPLACE (2 << 24) +# define RADEON_STENCIL_ZFAIL_INC (3 << 24) +# define RADEON_STENCIL_ZFAIL_DEC (4 << 24) +# define RADEON_STENCIL_ZFAIL_INVERT (5 << 24) +# define RADEON_STENCIL_ZFAIL_MASK (0x7 << 24) +# define RADEON_Z_COMPRESSION_ENABLE (1 << 28) +# define RADEON_FORCE_Z_DIRTY (1 << 29) +# define RADEON_Z_WRITE_ENABLE (1 << 30) +#define RADEON_RE_LINE_PATTERN 0x1cd0 +# define RADEON_LINE_PATTERN_MASK 0x0000ffff +# define RADEON_LINE_REPEAT_COUNT_SHIFT 16 +# define RADEON_LINE_PATTERN_START_SHIFT 24 +# define RADEON_LINE_PATTERN_LITTLE_BIT_ORDER (0 << 28) +# define RADEON_LINE_PATTERN_BIG_BIT_ORDER (1 << 28) +# define RADEON_LINE_PATTERN_AUTO_RESET (1 << 29) +#define RADEON_RE_LINE_STATE 0x1cd4 +# define RADEON_LINE_CURRENT_PTR_SHIFT 0 +# define RADEON_LINE_CURRENT_COUNT_SHIFT 8 +#define RADEON_RE_MISC 0x26c4 +# define RADEON_STIPPLE_COORD_MASK 0x1f +# define RADEON_STIPPLE_X_OFFSET_SHIFT 0 +# define RADEON_STIPPLE_X_OFFSET_MASK (0x1f << 0) +# define RADEON_STIPPLE_Y_OFFSET_SHIFT 8 +# define RADEON_STIPPLE_Y_OFFSET_MASK (0x1f << 8) +# define RADEON_STIPPLE_LITTLE_BIT_ORDER (0 << 16) +# define RADEON_STIPPLE_BIG_BIT_ORDER (1 << 16) +#define RADEON_RE_SOLID_COLOR 0x1c1c +#define RADEON_RE_TOP_LEFT 0x26c0 +# define RADEON_RE_LEFT_SHIFT 0 +# define RADEON_RE_TOP_SHIFT 16 +#define RADEON_RE_WIDTH_HEIGHT 0x1c44 +# define RADEON_RE_WIDTH_SHIFT 0 +# define RADEON_RE_HEIGHT_SHIFT 16 + +#define RADEON_SE_CNTL 0x1c4c +# define RADEON_FFACE_CULL_CW (0 << 0) +# define RADEON_FFACE_CULL_CCW (1 << 0) +# define RADEON_FFACE_CULL_DIR_MASK (1 << 0) +# define RADEON_BFACE_CULL (0 << 1) +# define RADEON_BFACE_SOLID (3 << 1) +# define RADEON_FFACE_CULL (0 << 3) +# define RADEON_FFACE_SOLID (3 << 3) +# define RADEON_FFACE_CULL_MASK (3 << 3) +# define RADEON_BADVTX_CULL_DISABLE (1 << 5) +# define RADEON_FLAT_SHADE_VTX_0 (0 << 6) +# define RADEON_FLAT_SHADE_VTX_1 (1 << 6) +# define RADEON_FLAT_SHADE_VTX_2 (2 << 6) +# define RADEON_FLAT_SHADE_VTX_LAST (3 << 6) +# define RADEON_DIFFUSE_SHADE_SOLID (0 << 8) +# define RADEON_DIFFUSE_SHADE_FLAT (1 << 8) +# define RADEON_DIFFUSE_SHADE_GOURAUD (2 << 8) +# define RADEON_DIFFUSE_SHADE_MASK (3 << 8) +# define RADEON_ALPHA_SHADE_SOLID (0 << 10) +# define RADEON_ALPHA_SHADE_FLAT (1 << 10) +# define RADEON_ALPHA_SHADE_GOURAUD (2 << 10) +# define RADEON_ALPHA_SHADE_MASK (3 << 10) +# define RADEON_SPECULAR_SHADE_SOLID (0 << 12) +# define RADEON_SPECULAR_SHADE_FLAT (1 << 12) +# define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12) +# define RADEON_SPECULAR_SHADE_MASK (3 << 12) +# define RADEON_FOG_SHADE_SOLID (0 << 14) +# define RADEON_FOG_SHADE_FLAT (1 << 14) +# define RADEON_FOG_SHADE_GOURAUD (2 << 14) +# define RADEON_FOG_SHADE_MASK (3 << 14) +# define RADEON_ZBIAS_ENABLE_POINT (1 << 16) +# define RADEON_ZBIAS_ENABLE_LINE (1 << 17) +# define RADEON_ZBIAS_ENABLE_TRI (1 << 18) +# define RADEON_WIDELINE_ENABLE (1 << 20) +# define RADEON_VPORT_XY_XFORM_ENABLE (1 << 24) +# define RADEON_VPORT_Z_XFORM_ENABLE (1 << 25) +# define RADEON_VTX_PIX_CENTER_D3D (0 << 27) +# define RADEON_VTX_PIX_CENTER_OGL (1 << 27) +# define RADEON_ROUND_MODE_TRUNC (0 << 28) +# define RADEON_ROUND_MODE_ROUND (1 << 28) +# define RADEON_ROUND_MODE_ROUND_EVEN (2 << 28) +# define RADEON_ROUND_MODE_ROUND_ODD (3 << 28) +# define RADEON_ROUND_PREC_16TH_PIX (0 << 30) +# define RADEON_ROUND_PREC_8TH_PIX (1 << 30) +# define RADEON_ROUND_PREC_4TH_PIX (2 << 30) +# define RADEON_ROUND_PREC_HALF_PIX (3 << 30) +#define R200_RE_CNTL 0x1c50 +# define R200_STIPPLE_ENABLE 0x1 +# define R200_SCISSOR_ENABLE 0x2 +# define R200_PATTERN_ENABLE 0x4 +# define R200_PERSPECTIVE_ENABLE 0x8 +# define R200_POINT_SMOOTH 0x20 +# define R200_VTX_STQ0_D3D 0x00010000 +# define R200_VTX_STQ1_D3D 0x00040000 +# define R200_VTX_STQ2_D3D 0x00100000 +# define R200_VTX_STQ3_D3D 0x00400000 +# define R200_VTX_STQ4_D3D 0x01000000 +# define R200_VTX_STQ5_D3D 0x04000000 +#define RADEON_SE_CNTL_STATUS 0x2140 +# define RADEON_VC_NO_SWAP (0 << 0) +# define RADEON_VC_16BIT_SWAP (1 << 0) +# define RADEON_VC_32BIT_SWAP (2 << 0) +# define RADEON_VC_HALF_DWORD_SWAP (3 << 0) +# define RADEON_TCL_BYPASS (1 << 8) +#define RADEON_SE_COORD_FMT 0x1c50 +# define RADEON_VTX_XY_PRE_MULT_1_OVER_W0 (1 << 0) +# define RADEON_VTX_Z_PRE_MULT_1_OVER_W0 (1 << 1) +# define RADEON_VTX_ST0_NONPARAMETRIC (1 << 8) +# define RADEON_VTX_ST1_NONPARAMETRIC (1 << 9) +# define RADEON_VTX_ST2_NONPARAMETRIC (1 << 10) +# define RADEON_VTX_ST3_NONPARAMETRIC (1 << 11) +# define RADEON_VTX_W0_NORMALIZE (1 << 12) +# define RADEON_VTX_W0_IS_NOT_1_OVER_W0 (1 << 16) +# define RADEON_VTX_ST0_PRE_MULT_1_OVER_W0 (1 << 17) +# define RADEON_VTX_ST1_PRE_MULT_1_OVER_W0 (1 << 19) +# define RADEON_VTX_ST2_PRE_MULT_1_OVER_W0 (1 << 21) +# define RADEON_VTX_ST3_PRE_MULT_1_OVER_W0 (1 << 23) +# define RADEON_TEX1_W_ROUTING_USE_W0 (0 << 26) +# define RADEON_TEX1_W_ROUTING_USE_Q1 (1 << 26) +#define RADEON_SE_LINE_WIDTH 0x1db8 +#define RADEON_SE_TCL_LIGHT_MODEL_CTL 0x226c +# define RADEON_LIGHTING_ENABLE (1 << 0) +# define RADEON_LIGHT_IN_MODELSPACE (1 << 1) +# define RADEON_LOCAL_VIEWER (1 << 2) +# define RADEON_NORMALIZE_NORMALS (1 << 3) +# define RADEON_RESCALE_NORMALS (1 << 4) +# define RADEON_SPECULAR_LIGHTS (1 << 5) +# define RADEON_DIFFUSE_SPECULAR_COMBINE (1 << 6) +# define RADEON_LIGHT_ALPHA (1 << 7) +# define RADEON_LOCAL_LIGHT_VEC_GL (1 << 8) +# define RADEON_LIGHT_NO_NORMAL_AMBIENT_ONLY (1 << 9) +# define RADEON_LM_SOURCE_STATE_PREMULT 0 +# define RADEON_LM_SOURCE_STATE_MULT 1 +# define RADEON_LM_SOURCE_VERTEX_DIFFUSE 2 +# define RADEON_LM_SOURCE_VERTEX_SPECULAR 3 +# define RADEON_EMISSIVE_SOURCE_SHIFT 16 +# define RADEON_AMBIENT_SOURCE_SHIFT 18 +# define RADEON_DIFFUSE_SOURCE_SHIFT 20 +# define RADEON_SPECULAR_SOURCE_SHIFT 22 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_RED 0x2220 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN 0x2224 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE 0x2228 +#define RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA 0x222c +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_RED 0x2230 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN 0x2234 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE 0x2238 +#define RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA 0x223c +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED 0x2210 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN 0x2214 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE 0x2218 +#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA 0x221c +#define RADEON_SE_TCL_MATERIAL_SPECULAR_RED 0x2240 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN 0x2244 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE 0x2248 +#define RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA 0x224c +#define RADEON_SE_TCL_MATRIX_SELECT_0 0x225c +# define RADEON_MODELVIEW_0_SHIFT 0 +# define RADEON_MODELVIEW_1_SHIFT 4 +# define RADEON_MODELVIEW_2_SHIFT 8 +# define RADEON_MODELVIEW_3_SHIFT 12 +# define RADEON_IT_MODELVIEW_0_SHIFT 16 +# define RADEON_IT_MODELVIEW_1_SHIFT 20 +# define RADEON_IT_MODELVIEW_2_SHIFT 24 +# define RADEON_IT_MODELVIEW_3_SHIFT 28 +#define RADEON_SE_TCL_MATRIX_SELECT_1 0x2260 +# define RADEON_MODELPROJECT_0_SHIFT 0 +# define RADEON_MODELPROJECT_1_SHIFT 4 +# define RADEON_MODELPROJECT_2_SHIFT 8 +# define RADEON_MODELPROJECT_3_SHIFT 12 +# define RADEON_TEXMAT_0_SHIFT 16 +# define RADEON_TEXMAT_1_SHIFT 20 +# define RADEON_TEXMAT_2_SHIFT 24 +# define RADEON_TEXMAT_3_SHIFT 28 + + +#define RADEON_SE_TCL_OUTPUT_VTX_FMT 0x2254 +# define RADEON_TCL_VTX_W0 (1 << 0) +# define RADEON_TCL_VTX_FP_DIFFUSE (1 << 1) +# define RADEON_TCL_VTX_FP_ALPHA (1 << 2) +# define RADEON_TCL_VTX_PK_DIFFUSE (1 << 3) +# define RADEON_TCL_VTX_FP_SPEC (1 << 4) +# define RADEON_TCL_VTX_FP_FOG (1 << 5) +# define RADEON_TCL_VTX_PK_SPEC (1 << 6) +# define RADEON_TCL_VTX_ST0 (1 << 7) +# define RADEON_TCL_VTX_ST1 (1 << 8) +# define RADEON_TCL_VTX_Q1 (1 << 9) +# define RADEON_TCL_VTX_ST2 (1 << 10) +# define RADEON_TCL_VTX_Q2 (1 << 11) +# define RADEON_TCL_VTX_ST3 (1 << 12) +# define RADEON_TCL_VTX_Q3 (1 << 13) +# define RADEON_TCL_VTX_Q0 (1 << 14) +# define RADEON_TCL_VTX_WEIGHT_COUNT_SHIFT 15 +# define RADEON_TCL_VTX_NORM0 (1 << 18) +# define RADEON_TCL_VTX_XY1 (1 << 27) +# define RADEON_TCL_VTX_Z1 (1 << 28) +# define RADEON_TCL_VTX_W1 (1 << 29) +# define RADEON_TCL_VTX_NORM1 (1 << 30) +# define RADEON_TCL_VTX_Z0 (1 << 31) + +#define RADEON_SE_TCL_OUTPUT_VTX_SEL 0x2258 +# define RADEON_TCL_COMPUTE_XYZW (1 << 0) +# define RADEON_TCL_COMPUTE_DIFFUSE (1 << 1) +# define RADEON_TCL_COMPUTE_SPECULAR (1 << 2) +# define RADEON_TCL_FORCE_NAN_IF_COLOR_NAN (1 << 3) +# define RADEON_TCL_FORCE_INORDER_PROC (1 << 4) +# define RADEON_TCL_TEX_INPUT_TEX_0 0 +# define RADEON_TCL_TEX_INPUT_TEX_1 1 +# define RADEON_TCL_TEX_INPUT_TEX_2 2 +# define RADEON_TCL_TEX_INPUT_TEX_3 3 +# define RADEON_TCL_TEX_COMPUTED_TEX_0 8 +# define RADEON_TCL_TEX_COMPUTED_TEX_1 9 +# define RADEON_TCL_TEX_COMPUTED_TEX_2 10 +# define RADEON_TCL_TEX_COMPUTED_TEX_3 11 +# define RADEON_TCL_TEX_0_OUTPUT_SHIFT 16 +# define RADEON_TCL_TEX_1_OUTPUT_SHIFT 20 +# define RADEON_TCL_TEX_2_OUTPUT_SHIFT 24 +# define RADEON_TCL_TEX_3_OUTPUT_SHIFT 28 + +#define RADEON_SE_TCL_PER_LIGHT_CTL_0 0x2270 +# define RADEON_LIGHT_0_ENABLE (1 << 0) +# define RADEON_LIGHT_0_ENABLE_AMBIENT (1 << 1) +# define RADEON_LIGHT_0_ENABLE_SPECULAR (1 << 2) +# define RADEON_LIGHT_0_IS_LOCAL (1 << 3) +# define RADEON_LIGHT_0_IS_SPOT (1 << 4) +# define RADEON_LIGHT_0_DUAL_CONE (1 << 5) +# define RADEON_LIGHT_0_ENABLE_RANGE_ATTEN (1 << 6) +# define RADEON_LIGHT_0_CONSTANT_RANGE_ATTEN (1 << 7) +# define RADEON_LIGHT_0_SHIFT 0 +# define RADEON_LIGHT_1_ENABLE (1 << 16) +# define RADEON_LIGHT_1_ENABLE_AMBIENT (1 << 17) +# define RADEON_LIGHT_1_ENABLE_SPECULAR (1 << 18) +# define RADEON_LIGHT_1_IS_LOCAL (1 << 19) +# define RADEON_LIGHT_1_IS_SPOT (1 << 20) +# define RADEON_LIGHT_1_DUAL_CONE (1 << 21) +# define RADEON_LIGHT_1_ENABLE_RANGE_ATTEN (1 << 22) +# define RADEON_LIGHT_1_CONSTANT_RANGE_ATTEN (1 << 23) +# define RADEON_LIGHT_1_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_1 0x2274 +# define RADEON_LIGHT_2_SHIFT 0 +# define RADEON_LIGHT_3_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_2 0x2278 +# define RADEON_LIGHT_4_SHIFT 0 +# define RADEON_LIGHT_5_SHIFT 16 +#define RADEON_SE_TCL_PER_LIGHT_CTL_3 0x227c +# define RADEON_LIGHT_6_SHIFT 0 +# define RADEON_LIGHT_7_SHIFT 16 + +#define RADEON_SE_TCL_SHININESS 0x2250 + +#define RADEON_SE_TCL_TEXTURE_PROC_CTL 0x2268 +# define RADEON_TEXGEN_TEXMAT_0_ENABLE (1 << 0) +# define RADEON_TEXGEN_TEXMAT_1_ENABLE (1 << 1) +# define RADEON_TEXGEN_TEXMAT_2_ENABLE (1 << 2) +# define RADEON_TEXGEN_TEXMAT_3_ENABLE (1 << 3) +# define RADEON_TEXMAT_0_ENABLE (1 << 4) +# define RADEON_TEXMAT_1_ENABLE (1 << 5) +# define RADEON_TEXMAT_2_ENABLE (1 << 6) +# define RADEON_TEXMAT_3_ENABLE (1 << 7) +# define RADEON_TEXGEN_INPUT_MASK 0xf +# define RADEON_TEXGEN_INPUT_TEXCOORD_0 0 +# define RADEON_TEXGEN_INPUT_TEXCOORD_1 1 +# define RADEON_TEXGEN_INPUT_TEXCOORD_2 2 +# define RADEON_TEXGEN_INPUT_TEXCOORD_3 3 +# define RADEON_TEXGEN_INPUT_OBJ 4 +# define RADEON_TEXGEN_INPUT_EYE 5 +# define RADEON_TEXGEN_INPUT_EYE_NORMAL 6 +# define RADEON_TEXGEN_INPUT_EYE_REFLECT 7 +# define RADEON_TEXGEN_INPUT_EYE_NORMALIZED 8 +# define RADEON_TEXGEN_0_INPUT_SHIFT 16 +# define RADEON_TEXGEN_1_INPUT_SHIFT 20 +# define RADEON_TEXGEN_2_INPUT_SHIFT 24 +# define RADEON_TEXGEN_3_INPUT_SHIFT 28 + +#define RADEON_SE_TCL_UCP_VERT_BLEND_CTL 0x2264 +# define RADEON_UCP_IN_CLIP_SPACE (1 << 0) +# define RADEON_UCP_IN_MODEL_SPACE (1 << 1) +# define RADEON_UCP_ENABLE_0 (1 << 2) +# define RADEON_UCP_ENABLE_1 (1 << 3) +# define RADEON_UCP_ENABLE_2 (1 << 4) +# define RADEON_UCP_ENABLE_3 (1 << 5) +# define RADEON_UCP_ENABLE_4 (1 << 6) +# define RADEON_UCP_ENABLE_5 (1 << 7) +# define RADEON_TCL_FOG_MASK (3 << 8) +# define RADEON_TCL_FOG_DISABLE (0 << 8) +# define RADEON_TCL_FOG_EXP (1 << 8) +# define RADEON_TCL_FOG_EXP2 (2 << 8) +# define RADEON_TCL_FOG_LINEAR (3 << 8) +# define RADEON_RNG_BASED_FOG (1 << 10) +# define RADEON_LIGHT_TWOSIDE (1 << 11) +# define RADEON_BLEND_OP_COUNT_MASK (7 << 12) +# define RADEON_BLEND_OP_COUNT_SHIFT 12 +# define RADEON_POSITION_BLEND_OP_ENABLE (1 << 16) +# define RADEON_NORMAL_BLEND_OP_ENABLE (1 << 17) +# define RADEON_VERTEX_BLEND_SRC_0_PRIMARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_0_SECONDARY (1 << 18) +# define RADEON_VERTEX_BLEND_SRC_1_PRIMARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_1_SECONDARY (1 << 19) +# define RADEON_VERTEX_BLEND_SRC_2_PRIMARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_2_SECONDARY (1 << 20) +# define RADEON_VERTEX_BLEND_SRC_3_PRIMARY (1 << 21) +# define RADEON_VERTEX_BLEND_SRC_3_SECONDARY (1 << 21) +# define RADEON_VERTEX_BLEND_WGT_MINUS_ONE (1 << 22) +# define RADEON_CULL_FRONT_IS_CW (0 << 28) +# define RADEON_CULL_FRONT_IS_CCW (1 << 28) +# define RADEON_CULL_FRONT (1 << 29) +# define RADEON_CULL_BACK (1 << 30) +# define RADEON_FORCE_W_TO_ONE (1 << 31) + +#define RADEON_SE_VPORT_XSCALE 0x1d98 +#define RADEON_SE_VPORT_XOFFSET 0x1d9c +#define RADEON_SE_VPORT_YSCALE 0x1da0 +#define RADEON_SE_VPORT_YOFFSET 0x1da4 +#define RADEON_SE_VPORT_ZSCALE 0x1da8 +#define RADEON_SE_VPORT_ZOFFSET 0x1dac +#define RADEON_SE_ZBIAS_FACTOR 0x1db0 +#define RADEON_SE_ZBIAS_CONSTANT 0x1db4 + +#define RADEON_SE_VTX_FMT 0x2080 +# define RADEON_SE_VTX_FMT_XY 0x00000000 +# define RADEON_SE_VTX_FMT_W0 0x00000001 +# define RADEON_SE_VTX_FMT_FPCOLOR 0x00000002 +# define RADEON_SE_VTX_FMT_FPALPHA 0x00000004 +# define RADEON_SE_VTX_FMT_PKCOLOR 0x00000008 +# define RADEON_SE_VTX_FMT_FPSPEC 0x00000010 +# define RADEON_SE_VTX_FMT_FPFOG 0x00000020 +# define RADEON_SE_VTX_FMT_PKSPEC 0x00000040 +# define RADEON_SE_VTX_FMT_ST0 0x00000080 +# define RADEON_SE_VTX_FMT_ST1 0x00000100 +# define RADEON_SE_VTX_FMT_Q1 0x00000200 +# define RADEON_SE_VTX_FMT_ST2 0x00000400 +# define RADEON_SE_VTX_FMT_Q2 0x00000800 +# define RADEON_SE_VTX_FMT_ST3 0x00001000 +# define RADEON_SE_VTX_FMT_Q3 0x00002000 +# define RADEON_SE_VTX_FMT_Q0 0x00004000 +# define RADEON_SE_VTX_FMT_BLND_WEIGHT_CNT_MASK 0x00038000 +# define RADEON_SE_VTX_FMT_N0 0x00040000 +# define RADEON_SE_VTX_FMT_XY1 0x08000000 +# define RADEON_SE_VTX_FMT_Z1 0x10000000 +# define RADEON_SE_VTX_FMT_W1 0x20000000 +# define RADEON_SE_VTX_FMT_N1 0x40000000 +# define RADEON_SE_VTX_FMT_Z 0x80000000 + +#define RADEON_SE_VF_CNTL 0x2084 +# define RADEON_VF_PRIM_TYPE_POINT_LIST 1 +# define RADEON_VF_PRIM_TYPE_LINE_LIST 2 +# define RADEON_VF_PRIM_TYPE_LINE_STRIP 3 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_LIST 4 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_FAN 5 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_STRIP 6 +# define RADEON_VF_PRIM_TYPE_TRIANGLE_FLAG 7 +# define RADEON_VF_PRIM_TYPE_RECTANGLE_LIST 8 +# define RADEON_VF_PRIM_TYPE_POINT_LIST_3 9 +# define RADEON_VF_PRIM_TYPE_LINE_LIST_3 10 +# define RADEON_VF_PRIM_TYPE_SPIRIT_LIST 11 +# define RADEON_VF_PRIM_TYPE_LINE_LOOP 12 +# define RADEON_VF_PRIM_TYPE_QUAD_LIST 13 +# define RADEON_VF_PRIM_TYPE_QUAD_STRIP 14 +# define RADEON_VF_PRIM_TYPE_POLYGON 15 +# define RADEON_VF_PRIM_WALK_STATE (0<<4) +# define RADEON_VF_PRIM_WALK_INDEX (1<<4) +# define RADEON_VF_PRIM_WALK_LIST (2<<4) +# define RADEON_VF_PRIM_WALK_DATA (3<<4) +# define RADEON_VF_COLOR_ORDER_RGBA (1<<6) +# define RADEON_VF_RADEON_MODE (1<<8) +# define RADEON_VF_TCL_OUTPUT_CTL_ENA (1<<9) +# define RADEON_VF_PROG_STREAM_ENA (1<<10) +# define RADEON_VF_INDEX_SIZE_SHIFT 11 +# define RADEON_VF_NUM_VERTICES_SHIFT 16 + +#define RADEON_SE_PORT_DATA0 0x2000 + +#define R200_SE_VAP_CNTL 0x2080 +# define R200_VAP_TCL_ENABLE 0x00000001 +# define R200_VAP_SINGLE_BUF_STATE_ENABLE 0x00000010 +# define R200_VAP_FORCE_W_TO_ONE 0x00010000 +# define R200_VAP_D3D_TEX_DEFAULT 0x00020000 +# define R200_VAP_VF_MAX_VTX_NUM__SHIFT 18 +# define R200_VAP_VF_MAX_VTX_NUM (9 << 18) +# define R200_VAP_DX_CLIP_SPACE_DEF 0x00400000 +#define R200_VF_MAX_VTX_INDX 0x210c +#define R200_VF_MIN_VTX_INDX 0x2110 +#define R200_SE_VTE_CNTL 0x20b0 +# define R200_VPORT_X_SCALE_ENA 0x00000001 +# define R200_VPORT_X_OFFSET_ENA 0x00000002 +# define R200_VPORT_Y_SCALE_ENA 0x00000004 +# define R200_VPORT_Y_OFFSET_ENA 0x00000008 +# define R200_VPORT_Z_SCALE_ENA 0x00000010 +# define R200_VPORT_Z_OFFSET_ENA 0x00000020 +# define R200_VTX_XY_FMT 0x00000100 +# define R200_VTX_Z_FMT 0x00000200 +# define R200_VTX_W0_FMT 0x00000400 +# define R200_VTX_W0_NORMALIZE 0x00000800 +# define R200_VTX_ST_DENORMALIZED 0x00001000 +#define R200_SE_VAP_CNTL_STATUS 0x2140 +# define R200_VC_NO_SWAP (0 << 0) +# define R200_VC_16BIT_SWAP (1 << 0) +# define R200_VC_32BIT_SWAP (2 << 0) +#define R200_PP_TXFILTER_0 0x2c00 +#define R200_PP_TXFILTER_1 0x2c20 +#define R200_PP_TXFILTER_2 0x2c40 +#define R200_PP_TXFILTER_3 0x2c60 +#define R200_PP_TXFILTER_4 0x2c80 +#define R200_PP_TXFILTER_5 0x2ca0 +# define R200_MAG_FILTER_NEAREST (0 << 0) +# define R200_MAG_FILTER_LINEAR (1 << 0) +# define R200_MAG_FILTER_MASK (1 << 0) +# define R200_MIN_FILTER_NEAREST (0 << 1) +# define R200_MIN_FILTER_LINEAR (1 << 1) +# define R200_MIN_FILTER_NEAREST_MIP_NEAREST (2 << 1) +# define R200_MIN_FILTER_NEAREST_MIP_LINEAR (3 << 1) +# define R200_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 1) +# define R200_MIN_FILTER_LINEAR_MIP_LINEAR (7 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST (8 << 1) +# define R200_MIN_FILTER_ANISO_LINEAR (9 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 << 1) +# define R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 << 1) +# define R200_MIN_FILTER_MASK (15 << 1) +# define R200_MAX_ANISO_1_TO_1 (0 << 5) +# define R200_MAX_ANISO_2_TO_1 (1 << 5) +# define R200_MAX_ANISO_4_TO_1 (2 << 5) +# define R200_MAX_ANISO_8_TO_1 (3 << 5) +# define R200_MAX_ANISO_16_TO_1 (4 << 5) +# define R200_MAX_ANISO_MASK (7 << 5) +# define R200_MAX_MIP_LEVEL_MASK (0x0f << 16) +# define R200_MAX_MIP_LEVEL_SHIFT 16 +# define R200_YUV_TO_RGB (1 << 20) +# define R200_YUV_TEMPERATURE_COOL (0 << 21) +# define R200_YUV_TEMPERATURE_HOT (1 << 21) +# define R200_YUV_TEMPERATURE_MASK (1 << 21) +# define R200_WRAPEN_S (1 << 22) +# define R200_CLAMP_S_WRAP (0 << 23) +# define R200_CLAMP_S_MIRROR (1 << 23) +# define R200_CLAMP_S_CLAMP_LAST (2 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) +# define R200_CLAMP_S_CLAMP_BORDER (4 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define R200_CLAMP_S_CLAMP_GL (6 << 23) +# define R200_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) +# define R200_CLAMP_S_MASK (7 << 23) +# define R200_WRAPEN_T (1 << 26) +# define R200_CLAMP_T_WRAP (0 << 27) +# define R200_CLAMP_T_MIRROR (1 << 27) +# define R200_CLAMP_T_CLAMP_LAST (2 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) +# define R200_CLAMP_T_CLAMP_BORDER (4 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define R200_CLAMP_T_CLAMP_GL (6 << 27) +# define R200_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) +# define R200_CLAMP_T_MASK (7 << 27) +# define R200_KILL_LT_ZERO (1 << 30) +# define R200_BORDER_MODE_OGL (0 << 31) +# define R200_BORDER_MODE_D3D (1 << 31) +#define R200_PP_TXFORMAT_0 0x2c04 +#define R200_PP_TXFORMAT_1 0x2c24 +#define R200_PP_TXFORMAT_2 0x2c44 +#define R200_PP_TXFORMAT_3 0x2c64 +#define R200_PP_TXFORMAT_4 0x2c84 +#define R200_PP_TXFORMAT_5 0x2ca4 +# define R200_TXFORMAT_I8 (0 << 0) +# define R200_TXFORMAT_AI88 (1 << 0) +# define R200_TXFORMAT_RGB332 (2 << 0) +# define R200_TXFORMAT_ARGB1555 (3 << 0) +# define R200_TXFORMAT_RGB565 (4 << 0) +# define R200_TXFORMAT_ARGB4444 (5 << 0) +# define R200_TXFORMAT_ARGB8888 (6 << 0) +# define R200_TXFORMAT_RGBA8888 (7 << 0) +# define R200_TXFORMAT_Y8 (8 << 0) +# define R200_TXFORMAT_AVYU4444 (9 << 0) +# define R200_TXFORMAT_VYUY422 (10 << 0) +# define R200_TXFORMAT_YVYU422 (11 << 0) +# define R200_TXFORMAT_DXT1 (12 << 0) +# define R200_TXFORMAT_DXT23 (14 << 0) +# define R200_TXFORMAT_DXT45 (15 << 0) +# define R200_TXFORMAT_ABGR8888 (22 << 0) +# define R200_TXFORMAT_FORMAT_MASK (31 << 0) +# define R200_TXFORMAT_FORMAT_SHIFT 0 +# define R200_TXFORMAT_ALPHA_IN_MAP (1 << 6) +# define R200_TXFORMAT_NON_POWER2 (1 << 7) +# define R200_TXFORMAT_WIDTH_MASK (15 << 8) +# define R200_TXFORMAT_WIDTH_SHIFT 8 +# define R200_TXFORMAT_HEIGHT_MASK (15 << 12) +# define R200_TXFORMAT_HEIGHT_SHIFT 12 +# define R200_TXFORMAT_F5_WIDTH_MASK (15 << 16) /* cube face 5 */ +# define R200_TXFORMAT_F5_WIDTH_SHIFT 16 +# define R200_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define R200_TXFORMAT_F5_HEIGHT_SHIFT 20 +# define R200_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ2 (2 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ3 (3 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ4 (4 << 24) +# define R200_TXFORMAT_ST_ROUTE_STQ5 (5 << 24) +# define R200_TXFORMAT_ST_ROUTE_MASK (7 << 24) +# define R200_TXFORMAT_ST_ROUTE_SHIFT 24 +# define R200_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) +# define R200_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) +# define R200_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) +#define R200_PP_TXFORMAT_X_0 0x2c08 +#define R200_PP_TXFORMAT_X_1 0x2c28 +#define R200_PP_TXFORMAT_X_2 0x2c48 +#define R200_PP_TXFORMAT_X_3 0x2c68 +#define R200_PP_TXFORMAT_X_4 0x2c88 +#define R200_PP_TXFORMAT_X_5 0x2ca8 + +#define R200_PP_TXSIZE_0 0x2c0c /* NPOT only */ +#define R200_PP_TXSIZE_1 0x2c2c /* NPOT only */ +#define R200_PP_TXSIZE_2 0x2c4c /* NPOT only */ +#define R200_PP_TXSIZE_3 0x2c6c /* NPOT only */ +#define R200_PP_TXSIZE_4 0x2c8c /* NPOT only */ +#define R200_PP_TXSIZE_5 0x2cac /* NPOT only */ + +#define R200_PP_TXPITCH_0 0x2c10 /* NPOT only */ +#define R200_PP_TXPITCH_1 0x2c30 /* NPOT only */ +#define R200_PP_TXPITCH_2 0x2c50 /* NPOT only */ +#define R200_PP_TXPITCH_3 0x2c70 /* NPOT only */ +#define R200_PP_TXPITCH_4 0x2c90 /* NPOT only */ +#define R200_PP_TXPITCH_5 0x2cb0 /* NPOT only */ + +#define R200_PP_TXOFFSET_0 0x2d00 +# define R200_TXO_ENDIAN_NO_SWAP (0 << 0) +# define R200_TXO_ENDIAN_BYTE_SWAP (1 << 0) +# define R200_TXO_ENDIAN_WORD_SWAP (2 << 0) +# define R200_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define R200_TXO_MACRO_LINEAR (0 << 2) +# define R200_TXO_MACRO_TILE (1 << 2) +# define R200_TXO_MICRO_LINEAR (0 << 3) +# define R200_TXO_MICRO_TILE (1 << 3) +# define R200_TXO_OFFSET_MASK 0xffffffe0 +# define R200_TXO_OFFSET_SHIFT 5 +#define R200_PP_TXOFFSET_1 0x2d18 +#define R200_PP_TXOFFSET_2 0x2d30 +#define R200_PP_TXOFFSET_3 0x2d48 +#define R200_PP_TXOFFSET_4 0x2d60 +#define R200_PP_TXOFFSET_5 0x2d78 + +#define R200_PP_TFACTOR_0 0x2ee0 +#define R200_PP_TFACTOR_1 0x2ee4 +#define R200_PP_TFACTOR_2 0x2ee8 +#define R200_PP_TFACTOR_3 0x2eec +#define R200_PP_TFACTOR_4 0x2ef0 +#define R200_PP_TFACTOR_5 0x2ef4 + +#define R200_PP_TXCBLEND_0 0x2f00 +# define R200_TXC_ARG_A_ZERO (0) +# define R200_TXC_ARG_A_CURRENT_COLOR (2) +# define R200_TXC_ARG_A_CURRENT_ALPHA (3) +# define R200_TXC_ARG_A_DIFFUSE_COLOR (4) +# define R200_TXC_ARG_A_DIFFUSE_ALPHA (5) +# define R200_TXC_ARG_A_SPECULAR_COLOR (6) +# define R200_TXC_ARG_A_SPECULAR_ALPHA (7) +# define R200_TXC_ARG_A_TFACTOR_COLOR (8) +# define R200_TXC_ARG_A_TFACTOR_ALPHA (9) +# define R200_TXC_ARG_A_R0_COLOR (10) +# define R200_TXC_ARG_A_R0_ALPHA (11) +# define R200_TXC_ARG_A_R1_COLOR (12) +# define R200_TXC_ARG_A_R1_ALPHA (13) +# define R200_TXC_ARG_A_R2_COLOR (14) +# define R200_TXC_ARG_A_R2_ALPHA (15) +# define R200_TXC_ARG_A_R3_COLOR (16) +# define R200_TXC_ARG_A_R3_ALPHA (17) +# define R200_TXC_ARG_A_R4_COLOR (18) +# define R200_TXC_ARG_A_R4_ALPHA (19) +# define R200_TXC_ARG_A_R5_COLOR (20) +# define R200_TXC_ARG_A_R5_ALPHA (21) +# define R200_TXC_ARG_A_TFACTOR1_COLOR (26) +# define R200_TXC_ARG_A_TFACTOR1_ALPHA (27) +# define R200_TXC_ARG_A_MASK (31 << 0) +# define R200_TXC_ARG_A_SHIFT 0 +# define R200_TXC_ARG_B_ZERO (0 << 5) +# define R200_TXC_ARG_B_CURRENT_COLOR (2 << 5) +# define R200_TXC_ARG_B_CURRENT_ALPHA (3 << 5) +# define R200_TXC_ARG_B_DIFFUSE_COLOR (4 << 5) +# define R200_TXC_ARG_B_DIFFUSE_ALPHA (5 << 5) +# define R200_TXC_ARG_B_SPECULAR_COLOR (6 << 5) +# define R200_TXC_ARG_B_SPECULAR_ALPHA (7 << 5) +# define R200_TXC_ARG_B_TFACTOR_COLOR (8 << 5) +# define R200_TXC_ARG_B_TFACTOR_ALPHA (9 << 5) +# define R200_TXC_ARG_B_R0_COLOR (10 << 5) +# define R200_TXC_ARG_B_R0_ALPHA (11 << 5) +# define R200_TXC_ARG_B_R1_COLOR (12 << 5) +# define R200_TXC_ARG_B_R1_ALPHA (13 << 5) +# define R200_TXC_ARG_B_R2_COLOR (14 << 5) +# define R200_TXC_ARG_B_R2_ALPHA (15 << 5) +# define R200_TXC_ARG_B_R3_COLOR (16 << 5) +# define R200_TXC_ARG_B_R3_ALPHA (17 << 5) +# define R200_TXC_ARG_B_R4_COLOR (18 << 5) +# define R200_TXC_ARG_B_R4_ALPHA (19 << 5) +# define R200_TXC_ARG_B_R5_COLOR (20 << 5) +# define R200_TXC_ARG_B_R5_ALPHA (21 << 5) +# define R200_TXC_ARG_B_TFACTOR1_COLOR (26 << 5) +# define R200_TXC_ARG_B_TFACTOR1_ALPHA (27 << 5) +# define R200_TXC_ARG_B_MASK (31 << 5) +# define R200_TXC_ARG_B_SHIFT 5 +# define R200_TXC_ARG_C_ZERO (0 << 10) +# define R200_TXC_ARG_C_CURRENT_COLOR (2 << 10) +# define R200_TXC_ARG_C_CURRENT_ALPHA (3 << 10) +# define R200_TXC_ARG_C_DIFFUSE_COLOR (4 << 10) +# define R200_TXC_ARG_C_DIFFUSE_ALPHA (5 << 10) +# define R200_TXC_ARG_C_SPECULAR_COLOR (6 << 10) +# define R200_TXC_ARG_C_SPECULAR_ALPHA (7 << 10) +# define R200_TXC_ARG_C_TFACTOR_COLOR (8 << 10) +# define R200_TXC_ARG_C_TFACTOR_ALPHA (9 << 10) +# define R200_TXC_ARG_C_R0_COLOR (10 << 10) +# define R200_TXC_ARG_C_R0_ALPHA (11 << 10) +# define R200_TXC_ARG_C_R1_COLOR (12 << 10) +# define R200_TXC_ARG_C_R1_ALPHA (13 << 10) +# define R200_TXC_ARG_C_R2_COLOR (14 << 10) +# define R200_TXC_ARG_C_R2_ALPHA (15 << 10) +# define R200_TXC_ARG_C_R3_COLOR (16 << 10) +# define R200_TXC_ARG_C_R3_ALPHA (17 << 10) +# define R200_TXC_ARG_C_R4_COLOR (18 << 10) +# define R200_TXC_ARG_C_R4_ALPHA (19 << 10) +# define R200_TXC_ARG_C_R5_COLOR (20 << 10) +# define R200_TXC_ARG_C_R5_ALPHA (21 << 10) +# define R200_TXC_ARG_C_TFACTOR1_COLOR (26 << 10) +# define R200_TXC_ARG_C_TFACTOR1_ALPHA (27 << 10) +# define R200_TXC_ARG_C_MASK (31 << 10) +# define R200_TXC_ARG_C_SHIFT 10 +# define R200_TXC_COMP_ARG_A (1 << 16) +# define R200_TXC_COMP_ARG_A_SHIFT (16) +# define R200_TXC_BIAS_ARG_A (1 << 17) +# define R200_TXC_SCALE_ARG_A (1 << 18) +# define R200_TXC_NEG_ARG_A (1 << 19) +# define R200_TXC_COMP_ARG_B (1 << 20) +# define R200_TXC_COMP_ARG_B_SHIFT (20) +# define R200_TXC_BIAS_ARG_B (1 << 21) +# define R200_TXC_SCALE_ARG_B (1 << 22) +# define R200_TXC_NEG_ARG_B (1 << 23) +# define R200_TXC_COMP_ARG_C (1 << 24) +# define R200_TXC_COMP_ARG_C_SHIFT (24) +# define R200_TXC_BIAS_ARG_C (1 << 25) +# define R200_TXC_SCALE_ARG_C (1 << 26) +# define R200_TXC_NEG_ARG_C (1 << 27) +# define R200_TXC_OP_MADD (0 << 28) +# define R200_TXC_OP_CND0 (2 << 28) +# define R200_TXC_OP_LERP (3 << 28) +# define R200_TXC_OP_DOT3 (4 << 28) +# define R200_TXC_OP_DOT4 (5 << 28) +# define R200_TXC_OP_CONDITIONAL (6 << 28) +# define R200_TXC_OP_DOT2_ADD (7 << 28) +# define R200_TXC_OP_MASK (7 << 28) +#define R200_PP_TXCBLEND2_0 0x2f04 +# define R200_TXC_TFACTOR_SEL_SHIFT 0 +# define R200_TXC_TFACTOR_SEL_MASK 0x7 +# define R200_TXC_TFACTOR1_SEL_SHIFT 4 +# define R200_TXC_TFACTOR1_SEL_MASK (0x7 << 4) +# define R200_TXC_SCALE_SHIFT 8 +# define R200_TXC_SCALE_MASK (7 << 8) +# define R200_TXC_SCALE_1X (0 << 8) +# define R200_TXC_SCALE_2X (1 << 8) +# define R200_TXC_SCALE_4X (2 << 8) +# define R200_TXC_SCALE_8X (3 << 8) +# define R200_TXC_SCALE_INV2 (5 << 8) +# define R200_TXC_SCALE_INV4 (6 << 8) +# define R200_TXC_SCALE_INV8 (7 << 8) +# define R200_TXC_CLAMP_SHIFT 12 +# define R200_TXC_CLAMP_MASK (3 << 12) +# define R200_TXC_CLAMP_WRAP (0 << 12) +# define R200_TXC_CLAMP_0_1 (1 << 12) +# define R200_TXC_CLAMP_8_8 (2 << 12) +# define R200_TXC_OUTPUT_REG_MASK (7 << 16) +# define R200_TXC_OUTPUT_REG_NONE (0 << 16) +# define R200_TXC_OUTPUT_REG_R0 (1 << 16) +# define R200_TXC_OUTPUT_REG_R1 (2 << 16) +# define R200_TXC_OUTPUT_REG_R2 (3 << 16) +# define R200_TXC_OUTPUT_REG_R3 (4 << 16) +# define R200_TXC_OUTPUT_REG_R4 (5 << 16) +# define R200_TXC_OUTPUT_REG_R5 (6 << 16) +# define R200_TXC_OUTPUT_MASK_MASK (7 << 20) +# define R200_TXC_OUTPUT_MASK_RGB (0 << 20) +# define R200_TXC_OUTPUT_MASK_RG (1 << 20) +# define R200_TXC_OUTPUT_MASK_RB (2 << 20) +# define R200_TXC_OUTPUT_MASK_R (3 << 20) +# define R200_TXC_OUTPUT_MASK_GB (4 << 20) +# define R200_TXC_OUTPUT_MASK_G (5 << 20) +# define R200_TXC_OUTPUT_MASK_B (6 << 20) +# define R200_TXC_OUTPUT_MASK_NONE (7 << 20) +# define R200_TXC_REPL_NORMAL 0 +# define R200_TXC_REPL_RED 1 +# define R200_TXC_REPL_GREEN 2 +# define R200_TXC_REPL_BLUE 3 +# define R200_TXC_REPL_ARG_A_SHIFT 26 +# define R200_TXC_REPL_ARG_A_MASK (3 << 26) +# define R200_TXC_REPL_ARG_B_SHIFT 28 +# define R200_TXC_REPL_ARG_B_MASK (3 << 28) +# define R200_TXC_REPL_ARG_C_SHIFT 30 +# define R200_TXC_REPL_ARG_C_MASK (3 << 30) +#define R200_PP_TXABLEND_0 0x2f08 +# define R200_TXA_ARG_A_ZERO (0) +# define R200_TXA_ARG_A_CURRENT_ALPHA (2) /* guess */ +# define R200_TXA_ARG_A_CURRENT_BLUE (3) /* guess */ +# define R200_TXA_ARG_A_DIFFUSE_ALPHA (4) +# define R200_TXA_ARG_A_DIFFUSE_BLUE (5) +# define R200_TXA_ARG_A_SPECULAR_ALPHA (6) +# define R200_TXA_ARG_A_SPECULAR_BLUE (7) +# define R200_TXA_ARG_A_TFACTOR_ALPHA (8) +# define R200_TXA_ARG_A_TFACTOR_BLUE (9) +# define R200_TXA_ARG_A_R0_ALPHA (10) +# define R200_TXA_ARG_A_R0_BLUE (11) +# define R200_TXA_ARG_A_R1_ALPHA (12) +# define R200_TXA_ARG_A_R1_BLUE (13) +# define R200_TXA_ARG_A_R2_ALPHA (14) +# define R200_TXA_ARG_A_R2_BLUE (15) +# define R200_TXA_ARG_A_R3_ALPHA (16) +# define R200_TXA_ARG_A_R3_BLUE (17) +# define R200_TXA_ARG_A_R4_ALPHA (18) +# define R200_TXA_ARG_A_R4_BLUE (19) +# define R200_TXA_ARG_A_R5_ALPHA (20) +# define R200_TXA_ARG_A_R5_BLUE (21) +# define R200_TXA_ARG_A_TFACTOR1_ALPHA (26) +# define R200_TXA_ARG_A_TFACTOR1_BLUE (27) +# define R200_TXA_ARG_A_MASK (31 << 0) +# define R200_TXA_ARG_A_SHIFT 0 +# define R200_TXA_ARG_B_ZERO (0 << 5) +# define R200_TXA_ARG_B_CURRENT_ALPHA (2 << 5) /* guess */ +# define R200_TXA_ARG_B_CURRENT_BLUE (3 << 5) /* guess */ +# define R200_TXA_ARG_B_DIFFUSE_ALPHA (4 << 5) +# define R200_TXA_ARG_B_DIFFUSE_BLUE (5 << 5) +# define R200_TXA_ARG_B_SPECULAR_ALPHA (6 << 5) +# define R200_TXA_ARG_B_SPECULAR_BLUE (7 << 5) +# define R200_TXA_ARG_B_TFACTOR_ALPHA (8 << 5) +# define R200_TXA_ARG_B_TFACTOR_BLUE (9 << 5) +# define R200_TXA_ARG_B_R0_ALPHA (10 << 5) +# define R200_TXA_ARG_B_R0_BLUE (11 << 5) +# define R200_TXA_ARG_B_R1_ALPHA (12 << 5) +# define R200_TXA_ARG_B_R1_BLUE (13 << 5) +# define R200_TXA_ARG_B_R2_ALPHA (14 << 5) +# define R200_TXA_ARG_B_R2_BLUE (15 << 5) +# define R200_TXA_ARG_B_R3_ALPHA (16 << 5) +# define R200_TXA_ARG_B_R3_BLUE (17 << 5) +# define R200_TXA_ARG_B_R4_ALPHA (18 << 5) +# define R200_TXA_ARG_B_R4_BLUE (19 << 5) +# define R200_TXA_ARG_B_R5_ALPHA (20 << 5) +# define R200_TXA_ARG_B_R5_BLUE (21 << 5) +# define R200_TXA_ARG_B_TFACTOR1_ALPHA (26 << 5) +# define R200_TXA_ARG_B_TFACTOR1_BLUE (27 << 5) +# define R200_TXA_ARG_B_MASK (31 << 5) +# define R200_TXA_ARG_B_SHIFT 5 +# define R200_TXA_ARG_C_ZERO (0 << 10) +# define R200_TXA_ARG_C_CURRENT_ALPHA (2 << 10) /* guess */ +# define R200_TXA_ARG_C_CURRENT_BLUE (3 << 10) /* guess */ +# define R200_TXA_ARG_C_DIFFUSE_ALPHA (4 << 10) +# define R200_TXA_ARG_C_DIFFUSE_BLUE (5 << 10) +# define R200_TXA_ARG_C_SPECULAR_ALPHA (6 << 10) +# define R200_TXA_ARG_C_SPECULAR_BLUE (7 << 10) +# define R200_TXA_ARG_C_TFACTOR_ALPHA (8 << 10) +# define R200_TXA_ARG_C_TFACTOR_BLUE (9 << 10) +# define R200_TXA_ARG_C_R0_ALPHA (10 << 10) +# define R200_TXA_ARG_C_R0_BLUE (11 << 10) +# define R200_TXA_ARG_C_R1_ALPHA (12 << 10) +# define R200_TXA_ARG_C_R1_BLUE (13 << 10) +# define R200_TXA_ARG_C_R2_ALPHA (14 << 10) +# define R200_TXA_ARG_C_R2_BLUE (15 << 10) +# define R200_TXA_ARG_C_R3_ALPHA (16 << 10) +# define R200_TXA_ARG_C_R3_BLUE (17 << 10) +# define R200_TXA_ARG_C_R4_ALPHA (18 << 10) +# define R200_TXA_ARG_C_R4_BLUE (19 << 10) +# define R200_TXA_ARG_C_R5_ALPHA (20 << 10) +# define R200_TXA_ARG_C_R5_BLUE (21 << 10) +# define R200_TXA_ARG_C_TFACTOR1_ALPHA (26 << 10) +# define R200_TXA_ARG_C_TFACTOR1_BLUE (27 << 10) +# define R200_TXA_ARG_C_MASK (31 << 10) +# define R200_TXA_ARG_C_SHIFT 10 +# define R200_TXA_COMP_ARG_A (1 << 16) +# define R200_TXA_COMP_ARG_A_SHIFT (16) +# define R200_TXA_BIAS_ARG_A (1 << 17) +# define R200_TXA_SCALE_ARG_A (1 << 18) +# define R200_TXA_NEG_ARG_A (1 << 19) +# define R200_TXA_COMP_ARG_B (1 << 20) +# define R200_TXA_COMP_ARG_B_SHIFT (20) +# define R200_TXA_BIAS_ARG_B (1 << 21) +# define R200_TXA_SCALE_ARG_B (1 << 22) +# define R200_TXA_NEG_ARG_B (1 << 23) +# define R200_TXA_COMP_ARG_C (1 << 24) +# define R200_TXA_COMP_ARG_C_SHIFT (24) +# define R200_TXA_BIAS_ARG_C (1 << 25) +# define R200_TXA_SCALE_ARG_C (1 << 26) +# define R200_TXA_NEG_ARG_C (1 << 27) +# define R200_TXA_OP_MADD (0 << 28) +# define R200_TXA_OP_CND0 (2 << 28) +# define R200_TXA_OP_LERP (3 << 28) +# define R200_TXA_OP_CONDITIONAL (6 << 28) +# define R200_TXA_OP_MASK (7 << 28) +#define R200_PP_TXABLEND2_0 0x2f0c +# define R200_TXA_TFACTOR_SEL_SHIFT 0 +# define R200_TXA_TFACTOR_SEL_MASK 0x7 +# define R200_TXA_TFACTOR1_SEL_SHIFT 4 +# define R200_TXA_TFACTOR1_SEL_MASK (0x7 << 4) +# define R200_TXA_SCALE_SHIFT 8 +# define R200_TXA_SCALE_MASK (7 << 8) +# define R200_TXA_SCALE_1X (0 << 8) +# define R200_TXA_SCALE_2X (1 << 8) +# define R200_TXA_SCALE_4X (2 << 8) +# define R200_TXA_SCALE_8X (3 << 8) +# define R200_TXA_SCALE_INV2 (5 << 8) +# define R200_TXA_SCALE_INV4 (6 << 8) +# define R200_TXA_SCALE_INV8 (7 << 8) +# define R200_TXA_CLAMP_SHIFT 12 +# define R200_TXA_CLAMP_MASK (3 << 12) +# define R200_TXA_CLAMP_WRAP (0 << 12) +# define R200_TXA_CLAMP_0_1 (1 << 12) +# define R200_TXA_CLAMP_8_8 (2 << 12) +# define R200_TXA_OUTPUT_REG_MASK (7 << 16) +# define R200_TXA_OUTPUT_REG_NONE (0 << 16) +# define R200_TXA_OUTPUT_REG_R0 (1 << 16) +# define R200_TXA_OUTPUT_REG_R1 (2 << 16) +# define R200_TXA_OUTPUT_REG_R2 (3 << 16) +# define R200_TXA_OUTPUT_REG_R3 (4 << 16) +# define R200_TXA_OUTPUT_REG_R4 (5 << 16) +# define R200_TXA_OUTPUT_REG_R5 (6 << 16) +# define R200_TXA_DOT_ALPHA (1 << 20) +# define R200_TXA_REPL_NORMAL 0 +# define R200_TXA_REPL_RED 1 +# define R200_TXA_REPL_GREEN 2 +# define R200_TXA_REPL_ARG_A_SHIFT 26 +# define R200_TXA_REPL_ARG_A_MASK (3 << 26) +# define R200_TXA_REPL_ARG_B_SHIFT 28 +# define R200_TXA_REPL_ARG_B_MASK (3 << 28) +# define R200_TXA_REPL_ARG_C_SHIFT 30 +# define R200_TXA_REPL_ARG_C_MASK (3 << 30) + +#define R200_SE_VTX_FMT_0 0x2088 +# define R200_VTX_XY 0 /* always have xy */ +# define R200_VTX_Z0 (1<<0) +# define R200_VTX_W0 (1<<1) +# define R200_VTX_WEIGHT_COUNT_SHIFT (2) +# define R200_VTX_PV_MATRIX_SEL (1<<5) +# define R200_VTX_N0 (1<<6) +# define R200_VTX_POINT_SIZE (1<<7) +# define R200_VTX_DISCRETE_FOG (1<<8) +# define R200_VTX_SHININESS_0 (1<<9) +# define R200_VTX_SHININESS_1 (1<<10) +# define R200_VTX_COLOR_NOT_PRESENT 0 +# define R200_VTX_PK_RGBA 1 +# define R200_VTX_FP_RGB 2 +# define R200_VTX_FP_RGBA 3 +# define R200_VTX_COLOR_MASK 3 +# define R200_VTX_COLOR_0_SHIFT 11 +# define R200_VTX_COLOR_1_SHIFT 13 +# define R200_VTX_COLOR_2_SHIFT 15 +# define R200_VTX_COLOR_3_SHIFT 17 +# define R200_VTX_COLOR_4_SHIFT 19 +# define R200_VTX_COLOR_5_SHIFT 21 +# define R200_VTX_COLOR_6_SHIFT 23 +# define R200_VTX_COLOR_7_SHIFT 25 +# define R200_VTX_XY1 (1<<28) +# define R200_VTX_Z1 (1<<29) +# define R200_VTX_W1 (1<<30) +# define R200_VTX_N1 (1<<31) +#define R200_SE_VTX_FMT_1 0x208c +# define R200_VTX_TEX0_COMP_CNT_SHIFT 0 +# define R200_VTX_TEX1_COMP_CNT_SHIFT 3 +# define R200_VTX_TEX2_COMP_CNT_SHIFT 6 +# define R200_VTX_TEX3_COMP_CNT_SHIFT 9 +# define R200_VTX_TEX4_COMP_CNT_SHIFT 12 +# define R200_VTX_TEX5_COMP_CNT_SHIFT 15 + +#define R200_SE_TCL_OUTPUT_VTX_FMT_0 0x2090 +#define R200_SE_TCL_OUTPUT_VTX_FMT_1 0x2094 +#define R200_SE_TCL_OUTPUT_VTX_COMP_SEL 0x2250 +# define R200_OUTPUT_XYZW (1<<0) +# define R200_OUTPUT_COLOR_0 (1<<8) +# define R200_OUTPUT_COLOR_1 (1<<9) +# define R200_OUTPUT_TEX_0 (1<<16) +# define R200_OUTPUT_TEX_1 (1<<17) +# define R200_OUTPUT_TEX_2 (1<<18) +# define R200_OUTPUT_TEX_3 (1<<19) +# define R200_OUTPUT_TEX_4 (1<<20) +# define R200_OUTPUT_TEX_5 (1<<21) +# define R200_OUTPUT_TEX_MASK (0x3f<<16) +# define R200_OUTPUT_DISCRETE_FOG (1<<24) +# define R200_OUTPUT_PT_SIZE (1<<25) +# define R200_FORCE_INORDER_PROC (1<<31) +#define R200_PP_CNTL_X 0x2cc4 +#define R200_PP_TXMULTI_CTL_0 0x2c1c +#define R200_SE_VTX_STATE_CNTL 0x2180 +# define R200_UPDATE_USER_COLOR_0_ENA_MASK (1<<16) + + /* Registers for CP and Microcode Engine */ +#define RADEON_CP_ME_RAM_ADDR 0x07d4 +#define RADEON_CP_ME_RAM_RADDR 0x07d8 +#define RADEON_CP_ME_RAM_DATAH 0x07dc +#define RADEON_CP_ME_RAM_DATAL 0x07e0 + +#define RADEON_CP_RB_BASE 0x0700 +#define RADEON_CP_RB_CNTL 0x0704 +#define RADEON_CP_RB_RPTR_ADDR 0x070c +#define RADEON_CP_RB_RPTR 0x0710 +#define RADEON_CP_RB_WPTR 0x0714 + +#define RADEON_CP_IB_BASE 0x0738 +#define RADEON_CP_IB_BUFSZ 0x073c + +#define RADEON_CP_CSQ_CNTL 0x0740 +# define RADEON_CSQ_CNT_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_PRIDIS_INDDIS (0 << 28) +# define RADEON_CSQ_PRIPIO_INDDIS (1 << 28) +# define RADEON_CSQ_PRIBM_INDDIS (2 << 28) +# define RADEON_CSQ_PRIPIO_INDBM (3 << 28) +# define RADEON_CSQ_PRIBM_INDBM (4 << 28) +# define RADEON_CSQ_PRIPIO_INDPIO (15 << 28) +#define RADEON_CP_CSQ_STAT 0x07f8 +# define RADEON_CSQ_RPTR_PRIMARY_MASK (0xff << 0) +# define RADEON_CSQ_WPTR_PRIMARY_MASK (0xff << 8) +# define RADEON_CSQ_RPTR_INDIRECT_MASK (0xff << 16) +# define RADEON_CSQ_WPTR_INDIRECT_MASK (0xff << 24) +#define RADEON_CP_CSQ_ADDR 0x07f0 +#define RADEON_CP_CSQ_DATA 0x07f4 +#define RADEON_CP_CSQ_APER_PRIMARY 0x1000 +#define RADEON_CP_CSQ_APER_INDIRECT 0x1300 + +#define RADEON_CP_RB_WPTR_DELAY 0x0718 +# define RADEON_PRE_WRITE_TIMER_SHIFT 0 +# define RADEON_PRE_WRITE_LIMIT_SHIFT 23 + +#define RADEON_AIC_CNTL 0x01d0 +# define RADEON_PCIGART_TRANSLATE_EN (1 << 0) +#define RADEON_AIC_LO_ADDR 0x01dc + + + + /* Constants */ +#define RADEON_LAST_FRAME_REG RADEON_GUI_SCRATCH_REG0 +#define RADEON_LAST_CLEAR_REG RADEON_GUI_SCRATCH_REG2 + + + + /* CP packet types */ +#define RADEON_CP_PACKET0 0x00000000 +#define RADEON_CP_PACKET1 0x40000000 +#define RADEON_CP_PACKET2 0x80000000 +#define RADEON_CP_PACKET3 0xC0000000 +# define RADEON_CP_PACKET_MASK 0xC0000000 +# define RADEON_CP_PACKET_COUNT_MASK 0x3fff0000 +# define RADEON_CP_PACKET_MAX_DWORDS (1 << 12) +# define RADEON_CP_PACKET0_REG_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG0_MASK 0x000007ff +# define RADEON_CP_PACKET1_REG1_MASK 0x003ff800 + +#define RADEON_CP_PACKET0_ONE_REG_WR 0x00008000 + +#define RADEON_CP_PACKET3_NOP 0xC0001000 +#define RADEON_CP_PACKET3_NEXT_CHAR 0xC0001900 +#define RADEON_CP_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define RADEON_CP_PACKET3_SET_SCISSORS 0xC0001E00 +#define RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define RADEON_CP_PACKET3_LOAD_MICROCODE 0xC0002400 +#define RADEON_CP_PACKET3_WAIT_FOR_IDLE 0xC0002600 +#define RADEON_CP_PACKET3_3D_DRAW_VBUF 0xC0002800 +#define RADEON_CP_PACKET3_3D_DRAW_IMMD 0xC0002900 +#define RADEON_CP_PACKET3_3D_DRAW_INDX 0xC0002A00 +#define RADEON_CP_PACKET3_LOAD_PALETTE 0xC0002C00 +#define R200_CP_PACKET3_3D_DRAW_IMMD_2 0xc0003500 +#define RADEON_CP_PACKET3_3D_LOAD_VBPNTR 0xC0002F00 +#define RADEON_CP_PACKET3_CNTL_PAINT 0xC0009100 +#define RADEON_CP_PACKET3_CNTL_BITBLT 0xC0009200 +#define RADEON_CP_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define RADEON_CP_PACKET3_CNTL_POLYLINE 0xC0009500 +#define RADEON_CP_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define RADEON_CP_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define RADEON_CP_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define RADEON_CP_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 + + +#define RADEON_CP_VC_FRMT_XY 0x00000000 +#define RADEON_CP_VC_FRMT_W0 0x00000001 +#define RADEON_CP_VC_FRMT_FPCOLOR 0x00000002 +#define RADEON_CP_VC_FRMT_FPALPHA 0x00000004 +#define RADEON_CP_VC_FRMT_PKCOLOR 0x00000008 +#define RADEON_CP_VC_FRMT_FPSPEC 0x00000010 +#define RADEON_CP_VC_FRMT_FPFOG 0x00000020 +#define RADEON_CP_VC_FRMT_PKSPEC 0x00000040 +#define RADEON_CP_VC_FRMT_ST0 0x00000080 +#define RADEON_CP_VC_FRMT_ST1 0x00000100 +#define RADEON_CP_VC_FRMT_Q1 0x00000200 +#define RADEON_CP_VC_FRMT_ST2 0x00000400 +#define RADEON_CP_VC_FRMT_Q2 0x00000800 +#define RADEON_CP_VC_FRMT_ST3 0x00001000 +#define RADEON_CP_VC_FRMT_Q3 0x00002000 +#define RADEON_CP_VC_FRMT_Q0 0x00004000 +#define RADEON_CP_VC_FRMT_BLND_WEIGHT_CNT_MASK 0x00038000 +#define RADEON_CP_VC_FRMT_N0 0x00040000 +#define RADEON_CP_VC_FRMT_XY1 0x08000000 +#define RADEON_CP_VC_FRMT_Z1 0x10000000 +#define RADEON_CP_VC_FRMT_W1 0x20000000 +#define RADEON_CP_VC_FRMT_N1 0x40000000 +#define RADEON_CP_VC_FRMT_Z 0x80000000 + +#define RADEON_CP_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP 0x00000003 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_TYPE_2 0x00000007 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST 0x00000008 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST 0x00000009 +#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST 0x0000000a +#define RADEON_CP_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define RADEON_CP_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define RADEON_CP_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_BGRA 0x00000000 +#define RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA 0x00000040 +#define RADEON_CP_VC_CNTL_MAOS_ENABLE 0x00000080 +#define RADEON_CP_VC_CNTL_VTX_FMT_NON_RADEON_MODE 0x00000000 +#define RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE 0x00000100 +#define RADEON_CP_VC_CNTL_TCL_DISABLE 0x00000000 +#define RADEON_CP_VC_CNTL_TCL_ENABLE 0x00000200 +#define RADEON_CP_VC_CNTL_NUM_SHIFT 16 + +#define RADEON_VS_MATRIX_0_ADDR 0 +#define RADEON_VS_MATRIX_1_ADDR 4 +#define RADEON_VS_MATRIX_2_ADDR 8 +#define RADEON_VS_MATRIX_3_ADDR 12 +#define RADEON_VS_MATRIX_4_ADDR 16 +#define RADEON_VS_MATRIX_5_ADDR 20 +#define RADEON_VS_MATRIX_6_ADDR 24 +#define RADEON_VS_MATRIX_7_ADDR 28 +#define RADEON_VS_MATRIX_8_ADDR 32 +#define RADEON_VS_MATRIX_9_ADDR 36 +#define RADEON_VS_MATRIX_10_ADDR 40 +#define RADEON_VS_MATRIX_11_ADDR 44 +#define RADEON_VS_MATRIX_12_ADDR 48 +#define RADEON_VS_MATRIX_13_ADDR 52 +#define RADEON_VS_MATRIX_14_ADDR 56 +#define RADEON_VS_MATRIX_15_ADDR 60 +#define RADEON_VS_LIGHT_AMBIENT_ADDR 64 +#define RADEON_VS_LIGHT_DIFFUSE_ADDR 72 +#define RADEON_VS_LIGHT_SPECULAR_ADDR 80 +#define RADEON_VS_LIGHT_DIRPOS_ADDR 88 +#define RADEON_VS_LIGHT_HWVSPOT_ADDR 96 +#define RADEON_VS_LIGHT_ATTENUATION_ADDR 104 +#define RADEON_VS_MATRIX_EYE2CLIP_ADDR 112 +#define RADEON_VS_UCP_ADDR 116 +#define RADEON_VS_GLOBAL_AMBIENT_ADDR 122 +#define RADEON_VS_FOG_PARAM_ADDR 123 +#define RADEON_VS_EYE_VECTOR_ADDR 124 + +#define RADEON_SS_LIGHT_DCD_ADDR 0 +#define RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR 8 +#define RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR 16 +#define RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR 24 +#define RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR 32 +#define RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR 48 +#define RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR 49 +#define RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR 50 +#define RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR 51 +#define RADEON_SS_SHININESS 60 + +#define RADEON_TV_MASTER_CNTL 0x0800 +# define RADEON_TV_ASYNC_RST (1 << 0) +# define RADEON_CRT_ASYNC_RST (1 << 1) +# define RADEON_RESTART_PHASE_FIX (1 << 3) +# define RADEON_TV_FIFO_ASYNC_RST (1 << 4) +# define RADEON_VIN_ASYNC_RST (1 << 5) +# define RADEON_AUD_ASYNC_RST (1 << 6) +# define RADEON_DVS_ASYNC_RST (1 << 7) +# define RADEON_CRT_FIFO_CE_EN (1 << 9) +# define RADEON_TV_FIFO_CE_EN (1 << 10) +# define RADEON_RE_SYNC_NOW_SEL_MASK (3 << 14) +# define RADEON_TVCLK_ALWAYS_ONb (1 << 30) +# define RADEON_TV_ON (1 << 31) +#define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 +# define RADEON_Y_RED_EN (1 << 0) +# define RADEON_C_GRN_EN (1 << 1) +# define RADEON_CMP_BLU_EN (1 << 2) +# define RADEON_DAC_DITHER_EN (1 << 3) +# define RADEON_RED_MX_FORCE_DAC_DATA (6 << 4) +# define RADEON_GRN_MX_FORCE_DAC_DATA (6 << 8) +# define RADEON_BLU_MX_FORCE_DAC_DATA (6 << 12) +# define RADEON_TV_FORCE_DAC_DATA_SHIFT 16 +#define RADEON_TV_RGB_CNTL 0x0804 +# define RADEON_SWITCH_TO_BLUE (1 << 4) +# define RADEON_RGB_DITHER_EN (1 << 5) +# define RADEON_RGB_SRC_SEL_MASK (3 << 8) +# define RADEON_RGB_SRC_SEL_CRTC1 (0 << 8) +# define RADEON_RGB_SRC_SEL_RMX (1 << 8) +# define RADEON_RGB_SRC_SEL_CRTC2 (2 << 8) +# define RADEON_RGB_CONVERT_BY_PASS (1 << 10) +# define RADEON_UVRAM_READ_MARGIN_SHIFT 16 +# define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT 20 +# define RADEON_TVOUT_SCALE_EN (1 << 26) +#define RADEON_TV_SYNC_CNTL 0x0808 +# define RADEON_SYNC_OE (1 << 0) +# define RADEON_SYNC_OUT (1 << 1) +# define RADEON_SYNC_IN (1 << 2) +# define RADEON_SYNC_PUB (1 << 3) +# define RADEON_SYNC_PD (1 << 4) +# define RADEON_TV_SYNC_IO_DRIVE (1 << 5) +#define RADEON_TV_HTOTAL 0x080c +#define RADEON_TV_HDISP 0x0810 +#define RADEON_TV_HSTART 0x0818 +#define RADEON_TV_HCOUNT 0x081C +#define RADEON_TV_VTOTAL 0x0820 +#define RADEON_TV_VDISP 0x0824 +#define RADEON_TV_VCOUNT 0x0828 +#define RADEON_TV_FTOTAL 0x082c +#define RADEON_TV_FCOUNT 0x0830 +#define RADEON_TV_FRESTART 0x0834 +#define RADEON_TV_HRESTART 0x0838 +#define RADEON_TV_VRESTART 0x083c +#define RADEON_TV_HOST_READ_DATA 0x0840 +#define RADEON_TV_HOST_WRITE_DATA 0x0844 +#define RADEON_TV_HOST_RD_WT_CNTL 0x0848 +# define RADEON_HOST_FIFO_RD (1 << 12) +# define RADEON_HOST_FIFO_RD_ACK (1 << 13) +# define RADEON_HOST_FIFO_WT (1 << 14) +# define RADEON_HOST_FIFO_WT_ACK (1 << 15) +#define RADEON_TV_VSCALER_CNTL1 0x084c +# define RADEON_UV_INC_MASK 0xffff +# define RADEON_UV_INC_SHIFT 0 +# define RADEON_Y_W_EN (1 << 24) +# define RADEON_RESTART_FIELD (1 << 29) /* restart on field 0 */ +# define RADEON_Y_DEL_W_SIG_SHIFT 26 +#define RADEON_TV_TIMING_CNTL 0x0850 +# define RADEON_H_INC_MASK 0xfff +# define RADEON_H_INC_SHIFT 0 +# define RADEON_REQ_Y_FIRST (1 << 19) +# define RADEON_FORCE_BURST_ALWAYS (1 << 21) +# define RADEON_UV_POST_SCALE_BYPASS (1 << 23) +# define RADEON_UV_OUTPUT_POST_SCALE_SHIFT 24 +#define RADEON_TV_VSCALER_CNTL2 0x0854 +# define RADEON_DITHER_MODE (1 << 0) +# define RADEON_Y_OUTPUT_DITHER_EN (1 << 1) +# define RADEON_UV_OUTPUT_DITHER_EN (1 << 2) +# define RADEON_UV_TO_BUF_DITHER_EN (1 << 3) +#define RADEON_TV_Y_FALL_CNTL 0x0858 +# define RADEON_Y_FALL_PING_PONG (1 << 16) +# define RADEON_Y_COEF_EN (1 << 17) +#define RADEON_TV_Y_RISE_CNTL 0x085c +# define RADEON_Y_RISE_PING_PONG (1 << 16) +#define RADEON_TV_Y_SAW_TOOTH_CNTL 0x0860 +#define RADEON_TV_UPSAMP_AND_GAIN_CNTL 0x0864 +# define RADEON_YUPSAMP_EN (1 << 0) +# define RADEON_UVUPSAMP_EN (1 << 2) +#define RADEON_TV_GAIN_LIMIT_SETTINGS 0x0868 +# define RADEON_Y_GAIN_LIMIT_SHIFT 0 +# define RADEON_UV_GAIN_LIMIT_SHIFT 16 +#define RADEON_TV_LINEAR_GAIN_SETTINGS 0x086c +# define RADEON_Y_GAIN_SHIFT 0 +# define RADEON_UV_GAIN_SHIFT 16 +#define RADEON_TV_MODULATOR_CNTL1 0x0870 +# define RADEON_YFLT_EN (1 << 2) +# define RADEON_UVFLT_EN (1 << 3) +# define RADEON_ALT_PHASE_EN (1 << 6) +# define RADEON_SYNC_TIP_LEVEL (1 << 7) +# define RADEON_BLANK_LEVEL_SHIFT 8 +# define RADEON_SET_UP_LEVEL_SHIFT 16 +# define RADEON_SLEW_RATE_LIMIT (1 << 23) +# define RADEON_CY_FILT_BLEND_SHIFT 28 +#define RADEON_TV_MODULATOR_CNTL2 0x0874 +# define RADEON_TV_U_BURST_LEVEL_MASK 0x1ff +# define RADEON_TV_V_BURST_LEVEL_MASK 0x1ff +# define RADEON_TV_V_BURST_LEVEL_SHIFT 16 +#define RADEON_TV_CRC_CNTL 0x0890 +#define RADEON_TV_UV_ADR 0x08ac +# define RADEON_MAX_UV_ADR_MASK 0x000000ff +# define RADEON_MAX_UV_ADR_SHIFT 0 +# define RADEON_TABLE1_BOT_ADR_MASK 0x0000ff00 +# define RADEON_TABLE1_BOT_ADR_SHIFT 8 +# define RADEON_TABLE3_TOP_ADR_MASK 0x00ff0000 +# define RADEON_TABLE3_TOP_ADR_SHIFT 16 +# define RADEON_HCODE_TABLE_SEL_MASK 0x06000000 +# define RADEON_HCODE_TABLE_SEL_SHIFT 25 +# define RADEON_VCODE_TABLE_SEL_MASK 0x18000000 +# define RADEON_VCODE_TABLE_SEL_SHIFT 27 +# define RADEON_TV_MAX_FIFO_ADDR 0x1a7 +# define RADEON_TV_MAX_FIFO_ADDR_INTERNAL 0x1ff +#define RADEON_TV_PLL_FINE_CNTL 0x0020 /* PLL */ +#define RADEON_TV_PLL_CNTL 0x0021 /* PLL */ +# define RADEON_TV_M0LO_MASK 0xff +# define RADEON_TV_M0HI_MASK 0x7 +# define RADEON_TV_M0HI_SHIFT 18 +# define RADEON_TV_N0LO_MASK 0x1ff +# define RADEON_TV_N0LO_SHIFT 8 +# define RADEON_TV_N0HI_MASK 0x3 +# define RADEON_TV_N0HI_SHIFT 21 +# define RADEON_TV_P_MASK 0xf +# define RADEON_TV_P_SHIFT 24 +# define RADEON_TV_SLIP_EN (1 << 23) +# define RADEON_TV_DTO_EN (1 << 28) +#define RADEON_TV_PLL_CNTL1 0x0022 /* PLL */ +# define RADEON_TVPLL_RESET (1 << 1) +# define RADEON_TVPLL_SLEEP (1 << 3) +# define RADEON_TVPLL_REFCLK_SEL (1 << 4) +# define RADEON_TVPCP_SHIFT 8 +# define RADEON_TVPCP_MASK (7 << 8) +# define RADEON_TVPVG_SHIFT 11 +# define RADEON_TVPVG_MASK (7 << 11) +# define RADEON_TVPDC_SHIFT 14 +# define RADEON_TVPDC_MASK (3 << 14) +# define RADEON_TVPLL_TEST_DIS (1 << 31) +# define RADEON_TVCLK_SRC_SEL_TVPLL (1 << 30) + +#define RADEON_RS480_UNK_e30 0xe30 +#define RADEON_RS480_UNK_e34 0xe34 +#define RADEON_RS480_UNK_e38 0xe38 +#define RADEON_RS480_UNK_e3c 0xe3c + +#define RS690_MC_INDEX 0x78 +# define RS690_MC_INDEX_MASK 0x1ff +# define RS690_MC_INDEX_WR_EN (1 << 9) +# define RS690_MC_INDEX_WR_ACK 0x7f +#define RS690_MC_DATA 0x7c + +#define RS690_MC_FB_LOCATION 0x100 +#define RS690_MC_AGP_LOCATION 0x101 +#define RS690_MC_AGP_BASE 0x102 +#define RS690_MC_STATUS 0x90 +#define RS690_MC_STATUS_IDLE (1 << 0) + +#define AVIVO_MC_INDEX 0x0070 +#define R520_MC_STATUS 0x00 +#define R520_MC_STATUS_IDLE (1<<1) +#define RV515_MC_STATUS 0x08 +#define RV515_MC_STATUS_IDLE (1<<4) +#define AVIVO_MC_DATA 0x0074 + +#define RV515_MC_FB_LOCATION 0x1 +#define RV515_MC_AGP_LOCATION 0x2 +#define R520_MC_FB_LOCATION 0x4 +#define R520_MC_AGP_LOCATION 0x5 + +#define AVIVO_HDP_FB_LOCATION 0x134 + +#define AVIVO_D1VGA_CONTROL 0x0330 +# define AVIVO_DVGA_CONTROL_MODE_ENABLE (1<<0) +# define AVIVO_DVGA_CONTROL_TIMING_SELECT (1<<8) +# define AVIVO_DVGA_CONTROL_SYNC_POLARITY_SELECT (1<<9) +# define AVIVO_DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1<<10) +# define AVIVO_DVGA_CONTROL_OVERSCAN_COLOR_EN (1<<16) +# define AVIVO_DVGA_CONTROL_ROTATE (1<<24) +#define AVIVO_D2VGA_CONTROL 0x0338 + +#define AVIVO_EXT1_PPLL_REF_DIV_SRC 0x400 +#define AVIVO_EXT1_PPLL_REF_DIV 0x404 +#define AVIVO_EXT1_PPLL_UPDATE_LOCK 0x408 +#define AVIVO_EXT1_PPLL_UPDATE_CNTL 0x40c + +#define AVIVO_EXT2_PPLL_REF_DIV_SRC 0x410 +#define AVIVO_EXT2_PPLL_REF_DIV 0x414 +#define AVIVO_EXT2_PPLL_UPDATE_LOCK 0x418 +#define AVIVO_EXT2_PPLL_UPDATE_CNTL 0x41c + +#define AVIVO_EXT1_PPLL_FB_DIV 0x430 +#define AVIVO_EXT2_PPLL_FB_DIV 0x434 + +#define AVIVO_EXT1_PPLL_POST_DIV_SRC 0x438 +#define AVIVO_EXT1_PPLL_POST_DIV 0x43c + +#define AVIVO_EXT2_PPLL_POST_DIV_SRC 0x440 +#define AVIVO_EXT2_PPLL_POST_DIV 0x444 + +#define AVIVO_EXT1_PPLL_CNTL 0x448 +#define AVIVO_EXT2_PPLL_CNTL 0x44c + +#define AVIVO_P1PLL_CNTL 0x450 +#define AVIVO_P2PLL_CNTL 0x454 +#define AVIVO_P1PLL_INT_SS_CNTL 0x458 +#define AVIVO_P2PLL_INT_SS_CNTL 0x45c +#define AVIVO_P1PLL_TMDSA_CNTL 0x460 +#define AVIVO_P2PLL_LVTMA_CNTL 0x464 + +#define AVIVO_PCLK_CRTC1_CNTL 0x480 +#define AVIVO_PCLK_CRTC2_CNTL 0x484 + +#define AVIVO_D1CRTC_H_TOTAL 0x6000 +#define AVIVO_D1CRTC_H_BLANK_START_END 0x6004 +#define AVIVO_D1CRTC_H_SYNC_A 0x6008 +#define AVIVO_D1CRTC_H_SYNC_A_CNTL 0x600c +#define AVIVO_D1CRTC_H_SYNC_B 0x6010 +#define AVIVO_D1CRTC_H_SYNC_B_CNTL 0x6014 + +#define AVIVO_D1CRTC_V_TOTAL 0x6020 +#define AVIVO_D1CRTC_V_BLANK_START_END 0x6024 +#define AVIVO_D1CRTC_V_SYNC_A 0x6028 +#define AVIVO_D1CRTC_V_SYNC_A_CNTL 0x602c +#define AVIVO_D1CRTC_V_SYNC_B 0x6030 +#define AVIVO_D1CRTC_V_SYNC_B_CNTL 0x6034 + +#define AVIVO_D1CRTC_CONTROL 0x6080 +# define AVIVO_CRTC_EN (1<<0) +#define AVIVO_D1CRTC_BLANK_CONTROL 0x6084 +#define AVIVO_D1CRTC_INTERLACE_CONTROL 0x6088 +#define AVIVO_D1CRTC_INTERLACE_STATUS 0x608c +#define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 + +/* master controls */ +#define AVIVO_DC_CRTC_MASTER_EN 0x60f8 +#define AVIVO_DC_CRTC_TV_CONTROL 0x60fc + +#define AVIVO_D1GRPH_ENABLE 0x6100 +#define AVIVO_D1GRPH_CONTROL 0x6104 +# define AVIVO_D1GRPH_CONTROL_DEPTH_8BPP (0<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_16BPP (1<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_32BPP (2<<0) +# define AVIVO_D1GRPH_CONTROL_DEPTH_64BPP (3<<0) + +# define AVIVO_D1GRPH_CONTROL_8BPP_INDEXED (0<<8) + +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555 (0<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_RGB565 (1<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444 (2<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_AI88 (3<<8) +# define AVIVO_D1GRPH_CONTROL_16BPP_MONO16 (4<<8) + +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888 (0<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010 (1<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_DIGITAL (2<<8) +# define AVIVO_D1GRPH_CONTROL_32BPP_8B_ARGB2101010 (3<<8) + + +# define AVIVO_D1GRPH_CONTROL_64BPP_ARGB16161616 (0<<8) + +# define AVIVO_D1GRPH_SWAP_RB (1<<16) +# define AVIVO_D1GRPH_TILED (1<<20) +# define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1<<21) + +#define AVIVO_D1GRPH_LUT_SEL 0x6108 +#define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 +#define AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 +#define AVIVO_D1GRPH_PITCH 0x6120 +#define AVIVO_D1GRPH_SURFACE_OFFSET_X 0x6124 +#define AVIVO_D1GRPH_SURFACE_OFFSET_Y 0x6128 +#define AVIVO_D1GRPH_X_START 0x612c +#define AVIVO_D1GRPH_Y_START 0x6130 +#define AVIVO_D1GRPH_X_END 0x6134 +#define AVIVO_D1GRPH_Y_END 0x6138 +#define AVIVO_D1GRPH_UPDATE 0x6144 +# define AVIVO_D1GRPH_UPDATE_LOCK (1<<16) +#define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 + +#define AVIVO_D1CUR_CONTROL 0x6400 +# define AVIVO_D1CURSOR_EN (1<<0) +# define AVIVO_D1CURSOR_MODE_SHIFT 8 +# define AVIVO_D1CURSOR_MODE_MASK (0x3<<8) +# define AVIVO_D1CURSOR_MODE_24BPP (0x2) +#define AVIVO_D1CUR_SURFACE_ADDRESS 0x6408 +#define AVIVO_D1CUR_SIZE 0x6410 +#define AVIVO_D1CUR_POSITION 0x6414 +#define AVIVO_D1CUR_HOT_SPOT 0x6418 + +#define AVIVO_DC_LUT_RW_SELECT 0x6480 +#define AVIVO_DC_LUT_RW_MODE 0x6484 +#define AVIVO_DC_LUT_RW_INDEX 0x6488 +#define AVIVO_DC_LUT_SEQ_COLOR 0x648c +#define AVIVO_DC_LUT_PWL_DATA 0x6490 +#define AVIVO_DC_LUT_30_COLOR 0x6494 +#define AVIVO_DC_LUT_READ_PIPE_SELECT 0x6498 +#define AVIVO_DC_LUT_WRITE_EN_MASK 0x649c +#define AVIVO_DC_LUT_AUTOFILL 0x64a0 + +#define AVIVO_DC_LUTA_CONTROL 0x64c0 +#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE 0x64c4 +#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN 0x64c8 +#define AVIVO_DC_LUTA_BLACK_OFFSET_RED 0x64cc +#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE 0x64d0 +#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN 0x64d4 +#define AVIVO_DC_LUTA_WHITE_OFFSET_RED 0x64d8 + + +#define AVIVO_D1MODE_DESKTOP_HEIGHT 0x652C +#define AVIVO_D1MODE_VIEWPORT_START 0x6580 +#define AVIVO_D1MODE_VIEWPORT_SIZE 0x6584 +#define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6588 +#define AVIVO_D1MODE_EXT_OVERSCAN_TOP_BOTTOM 0x658c + +#define AVIVO_D1SCL_SCALER_ENABLE 0x6590 +#define AVIVO_D1SCL_SCALER_TAP_CONTROL 0x6594 +#define AVIVO_D1SCL_UPDATE 0x65cc +# define AVIVO_D1SCL_UPDATE_LOCK (1<<16) + +/* second crtc */ +#define AVIVO_D2CRTC_H_TOTAL 0x6800 +#define AVIVO_D2CRTC_H_BLANK_START_END 0x6804 +#define AVIVO_D2CRTC_H_SYNC_A 0x6808 +#define AVIVO_D2CRTC_H_SYNC_A_CNTL 0x680c +#define AVIVO_D2CRTC_H_SYNC_B 0x6810 +#define AVIVO_D2CRTC_H_SYNC_B_CNTL 0x6814 + +#define AVIVO_D2CRTC_V_TOTAL 0x6820 +#define AVIVO_D2CRTC_V_BLANK_START_END 0x6824 +#define AVIVO_D2CRTC_V_SYNC_A 0x6828 +#define AVIVO_D2CRTC_V_SYNC_A_CNTL 0x682c +#define AVIVO_D2CRTC_V_SYNC_B 0x6830 +#define AVIVO_D2CRTC_V_SYNC_B_CNTL 0x6834 + +#define AVIVO_D2CRTC_CONTROL 0x6880 +#define AVIVO_D2CRTC_BLANK_CONTROL 0x6884 +#define AVIVO_D2CRTC_INTERLACE_CONTROL 0x6888 +#define AVIVO_D2CRTC_INTERLACE_STATUS 0x688c +#define AVIVO_D2CRTC_STEREO_CONTROL 0x68c4 + +#define AVIVO_D2GRPH_ENABLE 0x6900 +#define AVIVO_D2GRPH_CONTROL 0x6904 +#define AVIVO_D2GRPH_LUT_SEL 0x6908 +#define AVIVO_D2GRPH_PRIMARY_SURFACE_ADDRESS 0x6910 +#define AVIVO_D2GRPH_SECONDARY_SURFACE_ADDRESS 0x6918 +#define AVIVO_D2GRPH_PITCH 0x6920 +#define AVIVO_D2GRPH_SURFACE_OFFSET_X 0x6924 +#define AVIVO_D2GRPH_SURFACE_OFFSET_Y 0x6928 +#define AVIVO_D2GRPH_X_START 0x692c +#define AVIVO_D2GRPH_Y_START 0x6930 +#define AVIVO_D2GRPH_X_END 0x6934 +#define AVIVO_D2GRPH_Y_END 0x6938 +#define AVIVO_D2GRPH_UPDATE 0x6944 +#define AVIVO_D2GRPH_FLIP_CONTROL 0x6948 + +#define AVIVO_D2CUR_CONTROL 0x6c00 +#define AVIVO_D2CUR_SURFACE_ADDRESS 0x6c08 +#define AVIVO_D2CUR_SIZE 0x6c10 +#define AVIVO_D2CUR_POSITION 0x6c14 + +#define AVIVO_D2MODE_VIEWPORT_START 0x6d80 +#define AVIVO_D2MODE_VIEWPORT_SIZE 0x6d84 +#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT 0x6d88 +#define AVIVO_D2MODE_EXT_OVERSCAN_TOP_BOTTOM 0x6d8c + +#define AVIVO_D2SCL_SCALER_ENABLE 0x6d90 +#define AVIVO_D2SCL_SCALER_TAP_CONTROL 0x6d94 + +#define AVIVO_DACA_ENABLE 0x7800 +# define AVIVO_DAC_ENABLE (1 << 0) +#define AVIVO_DACA_SOURCE_SELECT 0x7804 +# define AVIVO_DAC_SOURCE_CRTC1 (0 << 0) +# define AVIVO_DAC_SOURCE_CRTC2 (1 << 0) +# define AVIVO_DAC_SOURCE_TV (2 << 0) + +#define AVIVO_DACA_FORCE_OUTPUT_CNTL 0x783c +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_FORCE_DATA_EN (1 << 0) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT (8) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE (1 << 0) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN (1 << 1) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_RED (1 << 2) +# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY (1 << 24) +#define AVIVO_DACA_POWERDOWN 0x7850 +# define AVIVO_DACA_POWERDOWN_POWERDOWN (1 << 0) +# define AVIVO_DACA_POWERDOWN_BLUE (1 << 8) +# define AVIVO_DACA_POWERDOWN_GREEN (1 << 16) +# define AVIVO_DACA_POWERDOWN_RED (1 << 24) + +#define AVIVO_DACB_ENABLE 0x7a00 +#define AVIVO_DACB_SOURCE_SELECT 0x7a04 +#define AVIVO_DACB_FORCE_OUTPUT_CNTL 0x7a3c +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_FORCE_DATA_EN (1 << 0) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT (8) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE (1 << 0) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN (1 << 1) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_RED (1 << 2) +# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY (1 << 24) +#define AVIVO_DACB_POWERDOWN 0x7a50 +# define AVIVO_DACB_POWERDOWN_POWERDOWN (1 << 0) +# define AVIVO_DACB_POWERDOWN_BLUE (1 << 8) +# define AVIVO_DACB_POWERDOWN_GREEN (1 << 16) +# define AVIVO_DACB_POWERDOWN_RED + +#define AVIVO_TMDSA_CNTL 0x7880 +# define AVIVO_TMDSA_CNTL_ENABLE (1 << 0) +# define AVIVO_TMDSA_CNTL_HPD_MASK (1 << 4) +# define AVIVO_TMDSA_CNTL_HPD_SELECT (1 << 8) +# define AVIVO_TMDSA_CNTL_SYNC_PHASE (1 << 12) +# define AVIVO_TMDSA_CNTL_PIXEL_ENCODING (1 << 16) +# define AVIVO_TMDSA_CNTL_DUAL_LINK_ENABLE (1 << 24) +# define AVIVO_TMDSA_CNTL_SWAP (1 << 28) +#define AVIVO_TMDSA_SOURCE_SELECT 0x7884 +/* 78a8 appears to be some kind of (reasonably tolerant) clock? + * 78d0 definitely hits the transmitter, definitely clock. */ +/* MYSTERY1 This appears to control dithering? */ +#define AVIVO_TMDSA_BIT_DEPTH_CONTROL 0x7894 +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN (1 << 0) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH (1 << 4) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN (1 << 8) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH (1 << 12) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN (1 << 16) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL (1 << 24) +# define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26) +#define AVIVO_TMDSA_DCBALANCER_CONTROL 0x78d0 +# define AVIVO_TMDSA_DCBALANCER_CONTROL_EN (1 << 0) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_EN (1 << 8) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_IN_SHIFT (16) +# define AVIVO_TMDSA_DCBALANCER_CONTROL_FORCE (1 << 24) +#define AVIVO_TMDSA_DATA_SYNCHRONIZATION 0x78d8 +# define AVIVO_TMDSA_DATA_SYNCHRONIZATION_DSYNSEL (1 << 0) +# define AVIVO_TMDSA_DATA_SYNCHRONIZATION_PFREQCHG (1 << 8) +#define AVIVO_TMDSA_CLOCK_ENABLE 0x7900 +#define AVIVO_TMDSA_TRANSMITTER_ENABLE 0x7904 +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX0_ENABLE (1 << 0) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKC0EN (1 << 1) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD00EN (1 << 2) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD01EN (1 << 3) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD02EN (1 << 4) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX1_ENABLE (1 << 8) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD10EN (1 << 10) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD11EN (1 << 11) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD12EN (1 << 12) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX_ENABLE_HPD_MASK (1 << 16) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK (1 << 17) +# define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK (1 << 18) + +#define AVIVO_TMDSA_TRANSMITTER_CONTROL 0x7910 +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_ENABLE (1 << 0) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_RESET (1 << 1) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_IDSCKSEL (1 << 4) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_BGSLEEP (1 << 5) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK (1 << 8) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS (1 << 13) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK (1 << 14) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS (1 << 15) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_BYPASS_PLL (1 << 28) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_USE_CLK_DATA (1 << 29) +# define AVIVO_TMDSA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31) + +#define AVIVO_LVTMA_CNTL 0x7a80 +# define AVIVO_LVTMA_CNTL_ENABLE (1 << 0) +# define AVIVO_LVTMA_CNTL_HPD_MASK (1 << 4) +# define AVIVO_LVTMA_CNTL_HPD_SELECT (1 << 8) +# define AVIVO_LVTMA_CNTL_SYNC_PHASE (1 << 12) +# define AVIVO_LVTMA_CNTL_PIXEL_ENCODING (1 << 16) +# define AVIVO_LVTMA_CNTL_DUAL_LINK_ENABLE (1 << 24) +# define AVIVO_LVTMA_CNTL_SWAP (1 << 28) +#define AVIVO_LVTMA_SOURCE_SELECT 0x7a84 +#define AVIVO_LVTMA_COLOR_FORMAT 0x7a88 +#define AVIVO_LVTMA_BIT_DEPTH_CONTROL 0x7a94 +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN (1 << 0) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH (1 << 4) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN (1 << 8) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH (1 << 12) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN (1 << 16) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL (1 << 24) +# define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26) + + + +#define AVIVO_LVTMA_DCBALANCER_CONTROL 0x7ad0 +# define AVIVO_LVTMA_DCBALANCER_CONTROL_EN (1 << 0) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_EN (1 << 8) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_IN_SHIFT (16) +# define AVIVO_LVTMA_DCBALANCER_CONTROL_FORCE (1 << 24) + +#define AVIVO_LVTMA_DATA_SYNCHRONIZATION 0x78d8 +# define AVIVO_LVTMA_DATA_SYNCHRONIZATION_DSYNSEL (1 << 0) +# define AVIVO_LVTMA_DATA_SYNCHRONIZATION_PFREQCHG (1 << 8) +#define R500_LVTMA_CLOCK_ENABLE 0x7b00 +#define R600_LVTMA_CLOCK_ENABLE 0x7b04 + +#define R500_LVTMA_TRANSMITTER_ENABLE 0x7b04 +#define R600_LVTMA_TRANSMITTER_ENABLE 0x7b08 +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC0EN (1 << 1) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD00EN (1 << 2) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD01EN (1 << 3) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD02EN (1 << 4) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD03EN (1 << 5) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC1EN (1 << 9) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD10EN (1 << 10) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD11EN (1 << 11) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD12EN (1 << 12) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK (1 << 17) +# define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK (1 << 18) + +#define R500_LVTMA_TRANSMITTER_CONTROL 0x7b10 +#define R600_LVTMA_TRANSMITTER_CONTROL 0x7b14 +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_ENABLE (1 << 0) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_RESET (1 << 1) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_IDSCKSEL (1 << 4) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_BGSLEEP (1 << 5) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK (1 << 8) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS (1 << 13) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK (1 << 14) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS (1 << 15) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_BYPASS_PLL (1 << 28) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_USE_CLK_DATA (1 << 29) +# define AVIVO_LVTMA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31) + +#define R500_LVTMA_PWRSEQ_CNTL 0x7af0 +#define R600_LVTMA_PWRSEQ_CNTL 0x7af4 +# define AVIVO_LVTMA_PWRSEQ_EN (1 << 0) +# define AVIVO_LVTMA_PWRSEQ_PLL_ENABLE_MASK (1 << 2) +# define AVIVO_LVTMA_PWRSEQ_PLL_RESET_MASK (1 << 3) +# define AVIVO_LVTMA_PWRSEQ_TARGET_STATE (1 << 4) +# define AVIVO_LVTMA_SYNCEN (1 << 8) +# define AVIVO_LVTMA_SYNCEN_OVRD (1 << 9) +# define AVIVO_LVTMA_SYNCEN_POL (1 << 10) +# define AVIVO_LVTMA_DIGON (1 << 16) +# define AVIVO_LVTMA_DIGON_OVRD (1 << 17) +# define AVIVO_LVTMA_DIGON_POL (1 << 18) +# define AVIVO_LVTMA_BLON (1 << 24) +# define AVIVO_LVTMA_BLON_OVRD (1 << 25) +# define AVIVO_LVTMA_BLON_POL (1 << 26) + +#define R500_LVTMA_PWRSEQ_STATE 0x7af4 +#define R600_LVTMA_PWRSEQ_STATE 0x7af8 +# define AVIVO_LVTMA_PWRSEQ_STATE_TARGET_STATE_R (1 << 0) +# define AVIVO_LVTMA_PWRSEQ_STATE_DIGON (1 << 1) +# define AVIVO_LVTMA_PWRSEQ_STATE_SYNCEN (1 << 2) +# define AVIVO_LVTMA_PWRSEQ_STATE_BLON (1 << 3) +# define AVIVO_LVTMA_PWRSEQ_STATE_DONE (1 << 4) +# define AVIVO_LVTMA_PWRSEQ_STATE_STATUS_SHIFT (8) + +#define AVIVO_LVDS_BACKLIGHT_CNTL 0x7af8 +# define AVIVO_LVDS_BACKLIGHT_CNTL_EN (1 << 0) +# define AVIVO_LVDS_BACKLIGHT_LEVEL_MASK 0x0000ff00 +# define AVIVO_LVDS_BACKLIGHT_LEVEL_SHIFT 8 + +#define AVIVO_GPIO_0 0x7e30 +#define AVIVO_GPIO_1 0x7e40 +#define AVIVO_GPIO_2 0x7e50 +#define AVIVO_GPIO_3 0x7e60 + +#define AVIVO_DC_GPIO_HPD_Y 0x7e9c + +#define AVIVO_I2C_STATUS 0x7d30 +# define AVIVO_I2C_STATUS_DONE (1 << 0) +# define AVIVO_I2C_STATUS_NACK (1 << 1) +# define AVIVO_I2C_STATUS_HALT (1 << 2) +# define AVIVO_I2C_STATUS_GO (1 << 3) +# define AVIVO_I2C_STATUS_MASK 0x7 +/* If radeon_mm_i2c is to be believed, this is HALT, NACK, and maybe + * DONE? */ +# define AVIVO_I2C_STATUS_CMD_RESET 0x7 +# define AVIVO_I2C_STATUS_CMD_WAIT (1 << 3) +#define AVIVO_I2C_STOP 0x7d34 +#define AVIVO_I2C_START_CNTL 0x7d38 +# define AVIVO_I2C_START (1 << 8) +# define AVIVO_I2C_CONNECTOR0 (0 << 16) +# define AVIVO_I2C_CONNECTOR1 (1 << 16) +#define R520_I2C_START (1<<0) +#define R520_I2C_STOP (1<<1) +#define R520_I2C_RX (1<<2) +#define R520_I2C_EN (1<<8) +#define R520_I2C_DDC1 (0<<16) +#define R520_I2C_DDC2 (1<<16) +#define R520_I2C_DDC3 (2<<16) +#define R520_I2C_DDC_MASK (3<<16) +#define AVIVO_I2C_CONTROL2 0x7d3c +# define AVIVO_I2C_7D3C_SIZE_SHIFT 8 +# define AVIVO_I2C_7D3C_SIZE_MASK (0xf << 8) +#define AVIVO_I2C_CONTROL3 0x7d40 +/* Reading is done 4 bytes at a time: read the bottom 8 bits from + * 7d44, four times in a row. + * Writing is a little more complex. First write DATA with + * 0xnnnnnnzz, then 0xnnnnnnyy, where nnnnnn is some non-deterministic + * magic number, zz is, I think, the slave address, and yy is the byte + * you want to write. */ +#define AVIVO_I2C_DATA 0x7d44 +#define R520_I2C_ADDR_COUNT_MASK (0x7) +#define R520_I2C_DATA_COUNT_SHIFT (8) +#define R520_I2C_DATA_COUNT_MASK (0xF00) +#define AVIVO_I2C_CNTL 0x7d50 +# define AVIVO_I2C_EN (1 << 0) +# define AVIVO_I2C_RESET (1 << 8) + +#define R600_MC_VM_FB_LOCATION 0x2180 +#define R600_MC_VM_AGP_TOP 0x2184 +#define R600_MC_VM_AGP_BOT 0x2188 +#define R600_MC_VM_AGP_BASE 0x218c +#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2190 +#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2194 +#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x2198 + +#define R600_HDP_NONSURFACE_BASE 0x2c04 + +#define R600_BUS_CNTL 0x5420 +#define R600_CONFIG_CNTL 0x5424 +#define R600_CONFIG_MEMSIZE 0x5428 +#define R600_CONFIG_F0_BASE 0x542C +#define R600_CONFIG_APER_SIZE 0x5430 + +#define R600_BIOS_0_SCRATCH 0x1724 +#define R600_BIOS_1_SCRATCH 0x1728 +#define R600_BIOS_2_SCRATCH 0x172c +#define R600_BIOS_3_SCRATCH 0x1730 +#define R600_BIOS_4_SCRATCH 0x1734 +#define R600_BIOS_5_SCRATCH 0x1738 +#define R600_BIOS_6_SCRATCH 0x173c +#define R600_BIOS_7_SCRATCH 0x1740 + +#define R300_GB_TILE_CONFIG 0x4018 +# define R300_ENABLE_TILING (1 << 0) +# define R300_PIPE_COUNT_RV350 (0 << 1) +# define R300_PIPE_COUNT_R300 (3 << 1) +# define R300_PIPE_COUNT_R420_3P (6 << 1) +# define R300_PIPE_COUNT_R420 (7 << 1) +# define R300_TILE_SIZE_8 (0 << 4) +# define R300_TILE_SIZE_16 (1 << 4) +# define R300_TILE_SIZE_32 (2 << 4) +# define R300_SUBPIXEL_1_12 (0 << 16) +# define R300_SUBPIXEL_1_16 (1 << 16) +#define R300_GB_SELECT 0x401c +#define R300_GB_ENABLE 0x4008 +#define R300_GB_AA_CONFIG 0x4020 +#define R300_GB_MSPOS0 0x4010 +# define R300_MS_X0_SHIFT 0 +# define R300_MS_Y0_SHIFT 4 +# define R300_MS_X1_SHIFT 8 +# define R300_MS_Y1_SHIFT 12 +# define R300_MS_X2_SHIFT 16 +# define R300_MS_Y2_SHIFT 20 +# define R300_MSBD0_Y_SHIFT 24 +# define R300_MSBD0_X_SHIFT 28 +#define R300_GB_MSPOS1 0x4014 +# define R300_MS_X3_SHIFT 0 +# define R300_MS_Y3_SHIFT 4 +# define R300_MS_X4_SHIFT 8 +# define R300_MS_Y4_SHIFT 12 +# define R300_MS_X5_SHIFT 16 +# define R300_MS_Y5_SHIFT 20 +# define R300_MSBD1_SHIFT 24 + +#define R300_GA_POLY_MODE 0x4288 +# define R300_FRONT_PTYPE_POINT (0 << 4) +# define R300_FRONT_PTYPE_LINE (1 << 4) +# define R300_FRONT_PTYPE_TRIANGE (2 << 4) +# define R300_BACK_PTYPE_POINT (0 << 7) +# define R300_BACK_PTYPE_LINE (1 << 7) +# define R300_BACK_PTYPE_TRIANGE (2 << 7) +#define R300_GA_ROUND_MODE 0x428c +# define R300_GEOMETRY_ROUND_TRUNC (0 << 0) +# define R300_GEOMETRY_ROUND_NEAREST (1 << 0) +# define R300_COLOR_ROUND_TRUNC (0 << 2) +# define R300_COLOR_ROUND_NEAREST (1 << 2) +#define R300_GA_COLOR_CONTROL 0x4278 +# define R300_RGB0_SHADING_SOLID (0 << 0) +# define R300_RGB0_SHADING_FLAT (1 << 0) +# define R300_RGB0_SHADING_GOURAUD (2 << 0) +# define R300_ALPHA0_SHADING_SOLID (0 << 2) +# define R300_ALPHA0_SHADING_FLAT (1 << 2) +# define R300_ALPHA0_SHADING_GOURAUD (2 << 2) +# define R300_RGB1_SHADING_SOLID (0 << 4) +# define R300_RGB1_SHADING_FLAT (1 << 4) +# define R300_RGB1_SHADING_GOURAUD (2 << 4) +# define R300_ALPHA1_SHADING_SOLID (0 << 6) +# define R300_ALPHA1_SHADING_FLAT (1 << 6) +# define R300_ALPHA1_SHADING_GOURAUD (2 << 6) +# define R300_RGB2_SHADING_SOLID (0 << 8) +# define R300_RGB2_SHADING_FLAT (1 << 8) +# define R300_RGB2_SHADING_GOURAUD (2 << 8) +# define R300_ALPHA2_SHADING_SOLID (0 << 10) +# define R300_ALPHA2_SHADING_FLAT (1 << 10) +# define R300_ALPHA2_SHADING_GOURAUD (2 << 10) +# define R300_RGB3_SHADING_SOLID (0 << 12) +# define R300_RGB3_SHADING_FLAT (1 << 12) +# define R300_RGB3_SHADING_GOURAUD (2 << 12) +# define R300_ALPHA3_SHADING_SOLID (0 << 14) +# define R300_ALPHA3_SHADING_FLAT (1 << 14) +# define R300_ALPHA3_SHADING_GOURAUD (2 << 14) +#define R300_GA_OFFSET 0x4290 + +#define R300_VAP_CNTL_STATUS 0x2140 +# define R300_PVS_BYPASS (1 << 8) +#define R300_VAP_PVS_STATE_FLUSH_REG 0x2284 +#define R300_VAP_CNTL 0x2080 +# define R300_PVS_NUM_SLOTS_SHIFT 0 +# define R300_PVS_NUM_CNTLRS_SHIFT 4 +# define R300_PVS_NUM_FPUS_SHIFT 8 +# define R300_VF_MAX_VTX_NUM_SHIFT 18 +# define R300_GL_CLIP_SPACE_DEF (0 << 22) +# define R300_DX_CLIP_SPACE_DEF (1 << 22) +#define R300_VAP_VTE_CNTL 0x20B0 +# define R300_VPORT_X_SCALE_ENA (1 << 0) +# define R300_VPORT_X_OFFSET_ENA (1 << 1) +# define R300_VPORT_Y_SCALE_ENA (1 << 2) +# define R300_VPORT_Y_OFFSET_ENA (1 << 3) +# define R300_VPORT_Z_SCALE_ENA (1 << 4) +# define R300_VPORT_Z_OFFSET_ENA (1 << 5) +# define R300_VTX_XY_FMT (1 << 8) +# define R300_VTX_Z_FMT (1 << 9) +# define R300_VTX_W0_FMT (1 << 10) +#define R300_VAP_PSC_SGN_NORM_CNTL 0x21DC +#define R300_VAP_PROG_STREAM_CNTL_0 0x2150 +# define R300_DATA_TYPE_0_SHIFT 0 +# define R300_DATA_TYPE_FLOAT_1 0 +# define R300_DATA_TYPE_FLOAT_2 1 +# define R300_DATA_TYPE_FLOAT_3 2 +# define R300_DATA_TYPE_FLOAT_4 3 +# define R300_DATA_TYPE_BYTE 4 +# define R300_DATA_TYPE_D3DCOLOR 5 +# define R300_DATA_TYPE_SHORT_2 6 +# define R300_DATA_TYPE_SHORT_4 7 +# define R300_DATA_TYPE_VECTOR_3_TTT 8 +# define R300_DATA_TYPE_VECTOR_3_EET 9 +# define R300_SKIP_DWORDS_0_SHIFT 4 +# define R300_DST_VEC_LOC_0_SHIFT 8 +# define R300_LAST_VEC_0 (1 << 13) +# define R300_SIGNED_0 (1 << 14) +# define R300_NORMALIZE_0 (1 << 15) +# define R300_DATA_TYPE_1_SHIFT 16 +# define R300_SKIP_DWORDS_1_SHIFT 20 +# define R300_DST_VEC_LOC_1_SHIFT 24 +# define R300_LAST_VEC_1 (1 << 29) +# define R300_SIGNED_1 (1 << 30) +# define R300_NORMALIZE_1 (1 << 31) +#define R300_VAP_PROG_STREAM_CNTL_1 0x2154 +# define R300_DATA_TYPE_2_SHIFT 0 +# define R300_SKIP_DWORDS_2_SHIFT 4 +# define R300_DST_VEC_LOC_2_SHIFT 8 +# define R300_LAST_VEC_2 (1 << 13) +# define R300_SIGNED_2 (1 << 14) +# define R300_NORMALIZE_2 (1 << 15) +# define R300_DATA_TYPE_3_SHIFT 16 +# define R300_SKIP_DWORDS_3_SHIFT 20 +# define R300_DST_VEC_LOC_3_SHIFT 24 +# define R300_LAST_VEC_3 (1 << 29) +# define R300_SIGNED_3 (1 << 30) +# define R300_NORMALIZE_3 (1 << 31) +#define R300_VAP_PROG_STREAM_CNTL_EXT_0 0x21e0 +# define R300_SWIZZLE_SELECT_X_0_SHIFT 0 +# define R300_SWIZZLE_SELECT_Y_0_SHIFT 3 +# define R300_SWIZZLE_SELECT_Z_0_SHIFT 6 +# define R300_SWIZZLE_SELECT_W_0_SHIFT 9 +# define R300_SWIZZLE_SELECT_X 0 +# define R300_SWIZZLE_SELECT_Y 1 +# define R300_SWIZZLE_SELECT_Z 2 +# define R300_SWIZZLE_SELECT_W 3 +# define R300_SWIZZLE_SELECT_FP_ZERO 4 +# define R300_SWIZZLE_SELECT_FP_ONE 5 +# define R300_WRITE_ENA_0_SHIFT 12 +# define R300_WRITE_ENA_X 1 +# define R300_WRITE_ENA_Y 2 +# define R300_WRITE_ENA_Z 4 +# define R300_WRITE_ENA_W 8 +# define R300_SWIZZLE_SELECT_X_1_SHIFT 16 +# define R300_SWIZZLE_SELECT_Y_1_SHIFT 19 +# define R300_SWIZZLE_SELECT_Z_1_SHIFT 22 +# define R300_SWIZZLE_SELECT_W_1_SHIFT 25 +# define R300_WRITE_ENA_1_SHIFT 28 +#define R300_VAP_PROG_STREAM_CNTL_EXT_1 0x21e4 +# define R300_SWIZZLE_SELECT_X_2_SHIFT 0 +# define R300_SWIZZLE_SELECT_Y_2_SHIFT 3 +# define R300_SWIZZLE_SELECT_Z_2_SHIFT 6 +# define R300_SWIZZLE_SELECT_W_2_SHIFT 9 +# define R300_WRITE_ENA_2_SHIFT 12 +# define R300_SWIZZLE_SELECT_X_3_SHIFT 16 +# define R300_SWIZZLE_SELECT_Y_3_SHIFT 19 +# define R300_SWIZZLE_SELECT_Z_3_SHIFT 22 +# define R300_SWIZZLE_SELECT_W_3_SHIFT 25 +# define R300_WRITE_ENA_3_SHIFT 28 +#define R300_VAP_PVS_CODE_CNTL_0 0x22D0 +# define R300_PVS_FIRST_INST_SHIFT 0 +# define R300_PVS_XYZW_VALID_INST_SHIFT 10 +# define R300_PVS_LAST_INST_SHIFT 20 +#define R300_VAP_PVS_CODE_CNTL_1 0x22D8 +# define R300_PVS_LAST_VTX_SRC_INST_SHIFT 0 +#define R300_VAP_PVS_VECTOR_INDX_REG 0x2200 +#define R300_VAP_PVS_VECTOR_DATA_REG 0x2204 +#define R300_VAP_PVS_FLOW_CNTL_OPC 0x22DC +#define R300_VAP_OUT_VTX_FMT_0 0x2090 +# define R300_VTX_POS_PRESENT (1 << 0) +# define R300_VTX_COLOR_0_PRESENT (1 << 1) +# define R300_VTX_COLOR_1_PRESENT (1 << 2) +# define R300_VTX_COLOR_2_PRESENT (1 << 3) +# define R300_VTX_COLOR_3_PRESENT (1 << 4) +# define R300_VTX_PT_SIZE_PRESENT (1 << 16) +#define R300_VAP_OUT_VTX_FMT_1 0x2094 +# define R300_TEX_0_COMP_CNT_SHIFT 0 +# define R300_TEX_1_COMP_CNT_SHIFT 3 +# define R300_TEX_2_COMP_CNT_SHIFT 6 +# define R300_TEX_3_COMP_CNT_SHIFT 9 +# define R300_TEX_4_COMP_CNT_SHIFT 12 +# define R300_TEX_5_COMP_CNT_SHIFT 15 +# define R300_TEX_6_COMP_CNT_SHIFT 18 +# define R300_TEX_7_COMP_CNT_SHIFT 21 +#define R300_VAP_VTX_SIZE 0x20b4 +#define R300_VAP_GB_VERT_CLIP_ADJ 0x2220 +#define R300_VAP_GB_VERT_DISC_ADJ 0x2224 +#define R300_VAP_GB_HORZ_CLIP_ADJ 0x2228 +#define R300_VAP_GB_HORZ_DISC_ADJ 0x222c +#define R300_VAP_CLIP_CNTL 0x221c +# define R300_UCP_ENA_0 (1 << 0) +# define R300_UCP_ENA_1 (1 << 1) +# define R300_UCP_ENA_2 (1 << 2) +# define R300_UCP_ENA_3 (1 << 3) +# define R300_UCP_ENA_4 (1 << 4) +# define R300_UCP_ENA_5 (1 << 5) +# define R300_PS_UCP_MODE_SHIFT 14 +# define R300_CLIP_DISABLE (1 << 16) +# define R300_UCP_CULL_ONLY_ENA (1 << 17) +# define R300_BOUNDARY_EDGE_FLAG_ENA (1 << 18) + +#define R300_SU_TEX_WRAP 0x42a0 +#define R300_SU_POLY_OFFSET_ENABLE 0x42b4 +#define R300_SU_CULL_MODE 0x42b8 +# define R300_CULL_FRONT (1 << 0) +# define R300_CULL_BACK (1 << 1) +# define R300_FACE_POS (0 << 2) +# define R300_FACE_NEG (1 << 2) +#define R300_SU_DEPTH_SCALE 0x42c0 +#define R300_SU_DEPTH_OFFSET 0x42c4 + +#define R300_RS_COUNT 0x4300 +# define R300_RS_COUNT_IT_COUNT_SHIFT 0 +# define R300_RS_COUNT_IC_COUNT_SHIFT 7 +# define R300_RS_COUNT_HIRES_EN (1 << 18) + +#define R300_RS_IP_0 0x4310 +# define R300_RS_TEX_PTR(x) (x << 0) +# define R300_RS_COL_PTR(x) (x << 6) +# define R300_RS_COL_FMT(x) (x << 9) +# define R300_RS_COL_FMT_RGBA 0 +# define R300_RS_COL_FMT_RGB0 2 +# define R300_RS_COL_FMT_RGB1 3 +# define R300_RS_COL_FMT_000A 4 +# define R300_RS_COL_FMT_0000 5 +# define R300_RS_COL_FMT_0001 6 +# define R300_RS_COL_FMT_111A 8 +# define R300_RS_COL_FMT_1110 9 +# define R300_RS_COL_FMT_1111 10 +# define R300_RS_SEL_S(x) (x << 13) +# define R300_RS_SEL_T(x) (x << 16) +# define R300_RS_SEL_R(x) (x << 19) +# define R300_RS_SEL_Q(x) (x << 22) +# define R300_RS_SEL_C0 0 +# define R300_RS_SEL_C1 1 +# define R300_RS_SEL_C2 2 +# define R300_RS_SEL_C3 3 +# define R300_RS_SEL_K0 4 +# define R300_RS_SEL_K1 5 +#define R300_RS_INST_COUNT 0x4304 +# define R300_INST_COUNT_RS(x) (x << 0) +# define R300_RS_W_EN (1 << 4) +# define R300_TX_OFFSET_RS(x) (x << 5) +#define R300_RS_INST_0 0x4330 +# define R300_RS_INST_TEX_CN_WRITE (1 << 3) + +#define R300_TX_INVALTAGS 0x4100 +#define R300_TX_FILTER0_0 0x4400 +# define R300_TX_CLAMP_S(x) (x << 0) +# define R300_TX_CLAMP_T(x) (x << 3) +# define R300_TX_CLAMP_R(x) (x << 6) +# define R300_TX_CLAMP_WRAP 0 +# define R300_TX_CLAMP_MIRROR 1 +# define R300_TX_CLAMP_CLAMP_LAST 2 +# define R300_TX_CLAMP_MIRROR_CLAMP_LAST 3 +# define R300_TX_CLAMP_CLAMP_BORDER 4 +# define R300_TX_CLAMP_MIRROR_CLAMP_BORDER 5 +# define R300_TX_CLAMP_CLAMP_GL 6 +# define R300_TX_CLAMP_MIRROR_CLAMP_GL 7 +# define R300_TX_MAG_FILTER_NEAREST (1 << 9) +# define R300_TX_MIN_FILTER_NEAREST (1 << 11) +# define R300_TX_MAG_FILTER_LINEAR (2 << 9) +# define R300_TX_MIN_FILTER_LINEAR (2 << 11) +#define R300_TX_FILTER1_0 0x4440 +#define R300_TX_FORMAT0_0 0x4480 +# define R300_TXWIDTH_SHIFT 0 +# define R300_TXHEIGHT_SHIFT 11 +# define R300_NUM_LEVELS_SHIFT 26 +# define R300_NUM_LEVELS_MASK 0x +# define R300_TXPROJECTED (1 << 30) +# define R300_TXPITCH_EN (1 << 31) +#define R300_TX_FORMAT1_0 0x44c0 +# define R300_TX_FORMAT_X8 0x0 +# define R300_TX_FORMAT_X16 0x1 +# define R300_TX_FORMAT_Y4X4 0x2 +# define R300_TX_FORMAT_Y8X8 0x3 +# define R300_TX_FORMAT_Y16X16 0x4 +# define R300_TX_FORMAT_Z3Y3X2 0x5 +# define R300_TX_FORMAT_Z5Y6X5 0x6 +# define R300_TX_FORMAT_Z6Y5X5 0x7 +# define R300_TX_FORMAT_Z11Y11X10 0x8 +# define R300_TX_FORMAT_Z10Y11X11 0x9 +# define R300_TX_FORMAT_W4Z4Y4X4 0xA +# define R300_TX_FORMAT_W1Z5Y5X5 0xB +# define R300_TX_FORMAT_W8Z8Y8X8 0xC +# define R300_TX_FORMAT_W2Z10Y10X10 0xD +# define R300_TX_FORMAT_W16Z16Y16X16 0xE +# define R300_TX_FORMAT_DXT1 0xF +# define R300_TX_FORMAT_DXT3 0x10 +# define R300_TX_FORMAT_DXT5 0x11 +# define R300_TX_FORMAT_D3DMFT_CxV8U8 0x12 /* no swizzle */ +# define R300_TX_FORMAT_A8R8G8B8 0x13 /* no swizzle */ +# define R300_TX_FORMAT_B8G8_B8G8 0x14 /* no swizzle */ +# define R300_TX_FORMAT_G8R8_G8B8 0x15 /* no swizzle */ +# define R300_TX_FORMAT_VYUY422 0x14 /* no swizzle */ +# define R300_TX_FORMAT_YVYU422 0x15 /* no swizzle */ +# define R300_TX_FORMAT_X24_Y8 0x1e +# define R300_TX_FORMAT_X32 0x1e + /* Floating point formats */ + /* Note - hardware supports both 16 and 32 bit floating point */ +# define R300_TX_FORMAT_FL_I16 0x18 +# define R300_TX_FORMAT_FL_I16A16 0x19 +# define R300_TX_FORMAT_FL_R16G16B16A16 0x1A +# define R300_TX_FORMAT_FL_I32 0x1B +# define R300_TX_FORMAT_FL_I32A32 0x1C +# define R300_TX_FORMAT_FL_R32G32B32A32 0x1D + /* alpha modes, convenience mostly */ + /* if you have alpha, pick constant appropriate to the + number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */ +# define R300_TX_FORMAT_ALPHA_1CH 0x000 +# define R300_TX_FORMAT_ALPHA_2CH 0x200 +# define R300_TX_FORMAT_ALPHA_4CH 0x600 +# define R300_TX_FORMAT_ALPHA_NONE 0xA00 + /* Swizzling */ + /* constants */ +# define R300_TX_FORMAT_X 0 +# define R300_TX_FORMAT_Y 1 +# define R300_TX_FORMAT_Z 2 +# define R300_TX_FORMAT_W 3 +# define R300_TX_FORMAT_ZERO 4 +# define R300_TX_FORMAT_ONE 5 + /* 2.0*Z, everything above 1.0 is set to 0.0 */ +# define R300_TX_FORMAT_CUT_Z 6 + /* 2.0*W, everything above 1.0 is set to 0.0 */ +# define R300_TX_FORMAT_CUT_W 7 + +# define R300_TX_FORMAT_B_SHIFT 18 +# define R300_TX_FORMAT_G_SHIFT 15 +# define R300_TX_FORMAT_R_SHIFT 12 +# define R300_TX_FORMAT_A_SHIFT 9 + + /* Convenience macro to take care of layout and swizzling */ +# define R300_EASY_TX_FORMAT(B, G, R, A, FMT) ( \ + ((R300_TX_FORMAT_##B)<device) + { + if(dev==list->device) + return list; + list++; + } + return 0; +} + +const char * +xf86TokenToString(SymTabPtr table, int token) +{ + int i; + + for (i = 0; table[i].token >= 0 && table[i].token != token; i++){}; + + if (table[i].token < 0) + return NULL; + else + return(table[i].name); +} + +int FindPciDevice() +{ + const PciChipset_t *dev; + u32_t bus, last_bus; + + if( (last_bus = _PciApi(1))==-1) + return 0; + + for(bus=0;bus<=last_bus;bus++) + { + u32_t devfn; + + for(devfn=0;devfn<256;devfn++) + { + u32_t id; + id = PciRead32(bus,devfn, 0); + + if( (CARD16)id != VENDOR_ATI) + continue; + + if( (dev=PciDevMatch(id>>16,RHDPCIchipsets))!=0) + { + + rhd.PciDeviceID = (id>>16); + + rhd.bus = bus; + rhd.pci.bus = bus; + rhd.devfn = devfn; + rhd.pci.devfn = devfn; + rhd.PciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); + + rhd.ChipSet = dev->family; + // rhd.IsMobility = dev->mobility; + // rhd.IsIGP = dev->igp; + // rhd.HasCRTC2 = !dev->nocrtc2; + // rhd.HasSingleDAC = dev->singledac; + // rhd.InternalTVOut = !dev->nointtvout; + + pciGetInfo(&rhd.pci); + + rhd.subvendor_id = rhd.pci.subsysVendor; + rhd.subdevice_id = rhd.pci.subsysCard; + + //rhd.chipset = (char*)xf86TokenToString(RADEONChipsets, rhd.device_id); + + return 1; + }; + }; + }; + + dbgprintf("Device not found\n"); + + return 0; +} + + +static Bool +rhdMapMMIO() +{ + + rhd.MMIOMapSize = 1 << rhd.pci.size[RHD_MMIO_BAR]; + rhd.MMIOBase = MapIoMem(rhd.pci.memBase[RHD_MMIO_BAR], + rhd.MMIOMapSize,PG_SW+PG_NOCACHE); + if( !rhd.MMIOBase) + return 0; + + DBG(dbgprintf("Mapped IO at %x (size %x)\n", rhd.MMIOBase, rhd.MMIOMapSize)); + + return 1; +} + +#define RADEON_NB_TOM 0x15c +static CARD32 +rhdGetVideoRamSize(RHDPtr rhdPtr) +{ + CARD32 RamSize, BARSize; + + if (rhdPtr->ChipSet == RHD_RS690) + RamSize = (_RHDRegRead(rhdPtr, R5XX_CONFIG_MEMSIZE))>>10; + else + if (rhdPtr->IsIGP) + { + CARD32 tom = _RHDRegRead(rhdPtr, RADEON_NB_TOM); + RamSize = (((tom >> 16) - (tom & 0xffff) + 1) << 6); + _RHDRegWrite(rhdPtr,R5XX_CONFIG_MEMSIZE, RamSize<<10); + } + else + { + if (rhdPtr->ChipSet < RHD_R600) + { + RamSize = (_RHDRegRead(rhdPtr, R5XX_CONFIG_MEMSIZE)) >> 10; + if(RamSize==0) RamSize=8192; + } + else + RamSize = (_RHDRegRead(rhdPtr, R6XX_CONFIG_MEMSIZE)) >> 10; + }; + + BARSize = 1 << (rhdPtr->pci.size[RHD_FB_BAR] - 10); + if(BARSize==0) + BARSize = 0x20000; + + if (RamSize > BARSize) { + DBG(dbgprintf("The detected amount of videoram" + " exceeds the PCI BAR aperture.\n")); + DBG(dbgprintf("Using only %dkB of the total " + "%dkB.\n", (int) BARSize, (int) RamSize)); + return BARSize; + } + else return RamSize; +} + + +Bool RHDScalePolicy(struct rhdMonitor *Monitor, struct rhdConnector *Connector) +{ + if (!Monitor || !Monitor->UseFixedModes || !Monitor->NativeMode) + return FALSE; + + if (Connector->Type != RHD_CONNECTOR_PANEL) + return FALSE; + + return TRUE; +} + +static void +rhdOutputConnectorCheck(struct rhdConnector *Connector) +{ + struct rhdOutput *Output; + int i; + + /* First, try to sense */ + for (i = 0; i < 2; i++) { + Output = Connector->Output[i]; + if (Output && Output->Sense) { + /* + * This is ugly and needs to change when the TV support patches are in. + * The problem here is that the Output struct can be used for two connectors + * and thus two different devices + */ + if (Output->SensedType == RHD_SENSED_NONE) { + /* Do this before sensing as AtomBIOS sense needs this info */ + if ((Output->SensedType = Output->Sense(Output, Connector)) != RHD_SENSED_NONE) { + RHDOutputPrintSensedType(Output); + Output->Connector = Connector; + break; + } + } + } + } + + if (i == 2) { + /* now just enable the ones without sensing */ + for (i = 0; i < 2; i++) { + Output = Connector->Output[i]; + if (Output && !Output->Sense) { + Output->Connector = Connector; + break; + } + } + } +} + +static Bool +rhdModeLayoutSelect(RHDPtr rhdPtr) +{ + struct rhdOutput *Output; + struct rhdConnector *Connector; + Bool Found = FALSE; + char *ignore = NULL; + Bool ConnectorIsDMS59 = FALSE; + int i = 0; + + RHDFUNC(rhdPtr); + + /* housekeeping */ + rhdPtr->Crtc[0]->PLL = rhdPtr->PLLs[0]; + rhdPtr->Crtc[0]->LUT = rhdPtr->LUT[0]; + + rhdPtr->Crtc[1]->PLL = rhdPtr->PLLs[1]; + rhdPtr->Crtc[1]->LUT = rhdPtr->LUT[1]; + + /* start layout afresh */ + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + { + Output->Active = FALSE; + Output->Crtc = NULL; + Output->Connector = NULL; + } + + /* quick and dirty option so that some output choice exists */ +// ignore = xf86GetOptValString(rhdPtr->Options, OPTION_IGNORECONNECTOR); + + /* handle cards with DMS-59 connectors appropriately. The DMS-59 to VGA + adapter does not raise HPD at all, so we need a fallback there. */ + if (rhdPtr->Card) + { + ConnectorIsDMS59 = rhdPtr->Card->flags & RHD_CARD_FLAG_DMS59; + if (ConnectorIsDMS59) + dbgprintf("Card %s has a DMS-59 connector.\n", rhdPtr->Card->name); + } + + /* Check on the basis of Connector->HPD */ + for (i = 0; i < RHD_CONNECTORS_MAX; i++) + { + Connector = rhdPtr->Connector[i]; + + if (!Connector) + continue; + + if (Connector->HPDCheck) + { + if (Connector->HPDCheck(Connector)) + { + Connector->HPDAttached = TRUE; + rhdOutputConnectorCheck(Connector); + } + else + { + Connector->HPDAttached = FALSE; + if (ConnectorIsDMS59) + rhdOutputConnectorCheck(Connector); + } + } + else + rhdOutputConnectorCheck(Connector); + } + + i = 0; /* counter for CRTCs */ + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + if (Output->Connector) + { + struct rhdMonitor *Monitor = NULL; + + Connector = Output->Connector; + + Monitor = RHDMonitorInit(Connector); + + if (!Monitor && (Connector->Type == RHD_CONNECTOR_PANEL)) + { + xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Unable to attach a" + " monitor to connector \"%s\"\n", Connector->Name); + Output->Active = FALSE; + } + else + { + Connector->Monitor = Monitor; + + Output->Active = TRUE; + + Output->Crtc = rhdPtr->Crtc[i & 1]; /* ;) */ + i++; + + Output->Crtc->Active = TRUE; + + if (RHDScalePolicy(Monitor, Connector)) + { + Output->Crtc->ScaledToMode = RHDModeCopy(Monitor->NativeMode); + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, + "Crtc[%i]: found native mode from Monitor[%s]: ", + Output->Crtc->Id, Monitor->Name); + RHDPrintModeline(Output->Crtc->ScaledToMode); + } + Found = TRUE; + + if (Monitor) + { + /* If this is a DVI attached monitor, enable reduced blanking. + * TODO: iiyama vm pro 453: CRT with DVI-D == No reduced. + */ + if ((Output->Id == RHD_OUTPUT_TMDSA) || + (Output->Id == RHD_OUTPUT_LVTMA) || + (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) || + (Output->Id == RHD_OUTPUT_UNIPHYA) || + (Output->Id == RHD_OUTPUT_UNIPHYB)) + Monitor->ReducedAllowed = TRUE; + + /* allow user to override settings globally */ + if (rhdPtr->forceReduced.set) + Monitor->ReducedAllowed = rhdPtr->forceReduced.val.bool; + + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, + "Connector \"%s\" uses Monitor \"%s\":\n", + Connector->Name, Monitor->Name); + RHDMonitorPrint(Monitor); + } + else + xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, + "Connector \"%s\": Failed to retrieve Monitor" + " information.\n", Connector->Name); + } + } + + /* Now validate the scaled modes attached to crtcs */ + for (i = 0; i < 2; i++) + { + struct rhdCrtc *crtc = rhdPtr->Crtc[i]; + if (crtc->ScaledToMode && RHDValidateScaledToMode(crtc, crtc->ScaledToMode) != MODE_OK) + { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Crtc[%i]: scaled mode invalid.\n", crtc->Id); + xfree(crtc->ScaledToMode); + crtc->ScaledToMode = NULL; + } + }; + return Found; +} + +void rhdModeLayoutPrint(RHDPtr rhdPtr) +{ + struct rhdCrtc *Crtc; + struct rhdOutput *Output; + Bool Found; + + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Listing modesetting layout:\n\n"); + + /* CRTC 1 */ + Crtc = rhdPtr->Crtc[0]; + if (Crtc->Active) { + xf86Msg(X_NONE, "\t%s: tied to %s and %s:\n", + Crtc->Name, Crtc->PLL->Name, Crtc->LUT->Name); + + Found = FALSE; + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + if (Output->Active && (Output->Crtc == Crtc)) { + if (!Found) { + xf86Msg(X_NONE, "\t\tOutputs: %s (%s)", + Output->Name, Output->Connector->Name); + Found = TRUE; + } else + xf86Msg(X_NONE, ", %s (%s)", Output->Name, + Output->Connector->Name); + } + + if (!Found) + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "%s is active without outputs\n", Crtc->Name); + else + xf86Msg(X_NONE, "\n"); + } else + xf86Msg(X_NONE, "\t%s: unused\n", Crtc->Name); + xf86Msg(X_NONE, "\n"); + + /* CRTC 2 */ + Crtc = rhdPtr->Crtc[1]; + if (Crtc->Active) { + xf86Msg(X_NONE, "\t%s: tied to %s and %s:\n", + Crtc->Name, Crtc->PLL->Name, Crtc->LUT->Name); + + Found = FALSE; + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + if (Output->Active && (Output->Crtc == Crtc)) { + if (!Found) { + xf86Msg(X_NONE, "\t\tOutputs: %s (%s)", + Output->Name, Output->Connector->Name); + Found = TRUE; + } else + xf86Msg(X_NONE, ", %s (%s)", Output->Name, + Output->Connector->Name); + } + + if (!Found) + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "%s is active without outputs\n", Crtc->Name); + else + xf86Msg(X_NONE, "\n"); + } else + xf86Msg(X_NONE, "\t%s: unused\n", Crtc->Name); + xf86Msg(X_NONE, "\n"); + + /* Print out unused Outputs */ + Found = FALSE; + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + if (!Output->Active) { + if (!Found) { + xf86Msg(X_NONE, "\t\tUnused Outputs: %s", Output->Name); + Found = TRUE; + } else + xf86Msg(X_NONE, ", %s", Output->Name); + } + + if (Found) + xf86Msg(X_NONE, "\n"); + xf86Msg(X_NONE, "\n"); +} + +DisplayModePtr +rhdCreateModesListAndValidate(ScrnInfoPtr pScrn, Bool Silent); +void RHDPrintModeline(DisplayModePtr mode); + +int RHDPreInit() +{ + RHDI2CDataArg i2cArg; + + if (rhd.Card && rhd.Card->flags & RHD_CARD_FLAG_HPDSWAP && + rhd.hpdUsage == RHD_HPD_USAGE_AUTO) + rhd.hpdUsage = RHD_HPD_USAGE_AUTO_SWAP; + if (rhd.Card && rhd.Card->flags & RHD_CARD_FLAG_HPDOFF && + rhd.hpdUsage == RHD_HPD_USAGE_AUTO) + rhd.hpdUsage = RHD_HPD_USAGE_AUTO_OFF; + + /* We need access to IO space already */ + if (!rhdMapMMIO()) { + dbgprintf("Failed to map MMIO.\n"); + return 0; + }; + + rhd.videoRam = rhdGetVideoRamSize(&rhd); + if (!rhd.videoRam) + { + dbgprintf("No Video RAM detected.\n"); + goto error1; + } + dbgprintf("VideoRAM: %d kByte\n",rhd.videoRam); + + rhd.FbFreeStart = 0; + rhd.FbFreeSize = rhd.videoRam << 10; + +#ifdef ATOM_BIOS + { + AtomBiosArgRec atomBiosArg; + + rhd.UseAtomFlags = (RHD_ATOMBIOS_ON << RHD_ATOMBIOS_CRTC) | + (RHD_ATOMBIOS_ON << RHD_ATOMBIOS_OUTPUT) | + (RHD_ATOMBIOS_ON << RHD_ATOMBIOS_PLL); + + // rhd.UseAtomFlags = 0; + + if (RHDAtomBiosFunc(&rhd, NULL, ATOMBIOS_INIT, &atomBiosArg) + == ATOM_SUCCESS) + { + rhd.atomBIOS = atomBiosArg.atomhandle; + } + } + + if (rhd.atomBIOS) /* for testing functions */ + { + AtomBiosArgRec atomBiosArg; + + atomBiosArg.fb.start = rhd.FbFreeStart; + atomBiosArg.fb.size = rhd.FbFreeSize; + if (RHDAtomBiosFunc(&rhd, rhd.atomBIOS, ATOMBIOS_ALLOCATE_FB_SCRATCH, + &atomBiosArg) == ATOM_SUCCESS) + { + rhd.FbFreeStart = atomBiosArg.fb.start; + rhd.FbFreeSize = atomBiosArg.fb.size; + }; + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_DEFAULT_ENGINE_CLOCK, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_DEFAULT_MEMORY_CLOCK, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MAX_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MIN_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MAX_PIXEL_CLK, &atomBiosArg); + RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_REF_CLOCK, &atomBiosArg); + } +#endif + + if (RHDI2CFunc((int)&rhd, NULL, RHD_I2C_INIT, &i2cArg) == RHD_I2C_SUCCESS) + rhd.I2C = i2cArg.I2CBusList; + else + { + dbgprintf("I2C init failed\n"); + goto error1; + }; + + if (!rhd.atomBIOS) + { + dbgprintf("No ATOMBIOS detected. Done.\n"); + return 0; + } + + rhdMapFB(&rhd); + + Scrn.rhdPtr = &rhd; + Scrn.driverName = "Radeon HD driver"; + Scrn.bitsPerPixel = 32; + Scrn.depth = 32; + Scrn.virtualX = 1280; + Scrn.virtualY = 1024; + Scrn.displayWidth = 1280; + + rhd.pScrn = &Scrn; + + rhd.FbScanoutStart = 0; + rhd.FbScanoutSize = 8*1024*1024; + rhd.FbFreeStart = 8*1024*1024; + rhd.FbFreeSize = rhd.FbMapSize - 8*1024*1024; + + rhdInitHeap(&rhd); + + RHDVGAInit(&rhd); + RHDMCInit(&rhd); + if (!RHDCrtcsInit(&rhd)) + RHDAtomCrtcsInit(&rhd); + if (!RHDPLLsInit(&rhd)) + RHDAtomPLLsInit(&rhd); + + RHDLUTsInit(&rhd); + + if (!RHDConnectorsInit(&rhd, rhd.Card)) + { + dbgprintf("Card information has invalid connector information\n"); + goto error1; + } + + if (!rhdModeLayoutSelect(&rhd)) + { + dbgprintf("Failed to detect a connected monitor\n"); + goto error1; + } + RHDConfigMonitorSet(&rhd, FALSE); + rhdModeLayoutPrint(&rhd); + + { + DisplayModePtr Modes, tmp; + + Modes = RHDModesPoolCreate(&Scrn, FALSE); + Scrn.modePool = Modes; + + tmp = Modes; + SupportedModes=0; + while(tmp) + { + dbgprintf("%dx%d@%3.1fHz\n",tmp->CrtcHDisplay, + tmp->CrtcVDisplay,tmp->VRefresh); + tmp=tmp->next; + SupportedModes++; + }; +// rhdModeInit(&Scrn,Modes); + //RHDAdjustFrame(&rhd,0,0,0); + }; + dbgprintf("All done\n"); + return 1; + +error1: + return 0; +}; + +int __stdcall drvEntry(int action) +{ + int i; + + if(action != 1) + return 0; + + if(!dbg_open("/rd/1/ati.txt")) + { + printf("Can't open /rd/1/ati.txt\nExit\n"); + return 0; + } + if(!FindPciDevice()) + return 0; + + rhd.scrnIndex = (int)&rhd; + + rhd.Card = RHDCardIdentify(&rhd); + if (rhd.Card) + dbgprintf("Detected an %s on a %s\n", rhd.chipset_name, rhd.Card->name); + else + dbgprintf("Detected an %s on an unidentified card\n", rhd.chipset_name); + + for(i=0;i<6;i++) + { + if(rhd.pci.memBase[i]) + dbgprintf("Memory base_%d 0x%x size 0x%x\n", + i,rhd.pci.memBase[i],(1<Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_RESET); + rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_RESET); +} + + +static void +rhdModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + RHDPtr rhdPtr = pScrn->rhdPtr; + + RHDFUNC(rhdPtr); +// pScrn->vtSema = TRUE; + + /* Stop crap from being shown: gets reenabled through SaveScreen */ +// rhdPtr->Crtc[0]->Blank(rhdPtr->Crtc[0], TRUE); +// rhdPtr->Crtc[1]->Blank(rhdPtr->Crtc[1], TRUE); + + rhdPrepareMode(rhdPtr); + + /* now disable our VGA Mode */ + RHDVGADisable(rhdPtr); + + /* now set up the MC */ + RHDMCSetup(rhdPtr); + + rhdSetMode(pScrn, mode); +} + +static void +rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + RHDPtr rhdPtr = RHDPTR(pScrn); + int i; + + RHDFUNC(rhdPtr); + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting up \"%s\" (%dx%d@%3.1fHz)\n", + mode->name, mode->CrtcHDisplay, mode->CrtcVDisplay, + mode->VRefresh); + + /* Set up D1/D2 and appendages */ + for (i = 0; i < 2; i++) { + struct rhdCrtc *Crtc; + + Crtc = rhdPtr->Crtc[i]; + if (Crtc->Active) { + Crtc->FBSet(Crtc, pScrn->displayWidth, pScrn->virtualX, pScrn->virtualY, + pScrn->depth, rhdPtr->FbScanoutStart); + if (Crtc->ScaledToMode) { + Crtc->ModeSet(Crtc, Crtc->ScaledToMode); + if (Crtc->ScaleSet) + Crtc->ScaleSet(Crtc, Crtc->ScaleType, mode, Crtc->ScaledToMode); + } else { + Crtc->ModeSet(Crtc, mode); + if (Crtc->ScaleSet) + Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL); + } + RHDPLLSet(Crtc->PLL, mode->Clock); + Crtc->LUTSelect(Crtc, Crtc->LUT); + RHDOutputsMode(rhdPtr, Crtc, Crtc->ScaledToMode + ? Crtc->ScaledToMode : mode); + } + } + + /* shut down that what we don't use */ + RHDPLLsShutdownInactive(rhdPtr); + RHDOutputsShutdownInactive(rhdPtr); + + if (rhdPtr->Crtc[0]->Active) + rhdPtr->Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_ON); + else + rhdPtr->Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_SHUTDOWN); + + if (rhdPtr->Crtc[1]->Active) + rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_ON); + else + rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_SHUTDOWN); + + RHDOutputsPower(rhdPtr, RHD_POWER_ON); +} + + + +static void +RHDAdjustFrame(RHDPtr rhdPtr, int x, int y, int flags) +{ +// ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; +// RHDPtr rhdPtr = RHDPTR(pScrn); + struct rhdCrtc *Crtc; + + Crtc = rhdPtr->Crtc[0]; + if (Crtc->Active) + Crtc->FrameSet(Crtc, x, y); + + Crtc = rhdPtr->Crtc[1]; + if ( Crtc->Active) + Crtc->FrameSet(Crtc, x, y); + +} + +static Bool +rhdMapFB(RHDPtr rhdPtr) +{ + CARD32 membase; + RHDFUNC(rhdPtr); + + rhdPtr->FbMapSize = 1 << rhdPtr->pci.size[RHD_FB_BAR]; + membase = rhdPtr->pci.memBase[RHD_FB_BAR]; + + rhdPtr->FbBase = MapIoMem(membase, rhdPtr->FbMapSize,PG_SW+PG_NOCACHE); + + if (!rhdPtr->FbBase) + return FALSE; + + /* These devices have an internal address reference, which some other + * address registers in there also use. This can be different from the + * address in the BAR */ + if (rhdPtr->ChipSet < RHD_R600) + rhdPtr->FbIntAddress = _RHDRegRead(rhdPtr, HDP_FB_LOCATION)<< 16; + else + rhdPtr->FbIntAddress = _RHDRegRead(rhdPtr, R6XX_CONFIG_FB_BASE); + + if (rhdPtr->FbIntAddress != membase) + dbgprintf("PCI FB Address (BAR) is at " + "0x%08X while card Internal Address is 0x%08X\n", + (unsigned int) membase,rhdPtr->FbIntAddress); + dbgprintf("Mapped FB at %p (size 0x%08X)\n",rhdPtr->FbBase, rhdPtr->FbMapSize); + return TRUE; +} + + +#define ERR_PARAM -1 + +#pragma pack (push,1) +typedef struct +{ + short width; + short height; + short bpp; + short freq; +}mode_t; +#pragma pack (pop) + +int get_modes(mode_t *mode, int count) +{ + if(count==0) + count = SupportedModes; + else + { + DisplayModePtr tmp; + int i; + + if(count>SupportedModes) + count = SupportedModes; + + for(i=0,tmp = Scrn.modePool;inext,mode++) + { + mode->width = tmp->CrtcHDisplay; + mode->height = tmp->CrtcVDisplay; + mode->bpp = 32; + mode->freq = (short)__builtin_ceilf(tmp->VRefresh); + } + } + return count; +} + +int set_mode(mode_t *mode) +{ + DisplayModePtr tmp; + int i; + + for(i=0,tmp = Scrn.modePool;inext) + { + if( (mode->width == tmp->CrtcHDisplay) && + (mode->height == tmp->CrtcVDisplay) && + (mode->freq == (short)__builtin_ceilf(tmp->VRefresh))) + { + Scrn.virtualX = mode->width ; + Scrn.virtualY = mode->height; + Scrn.displayWidth = mode->width; + rhdModeInit(&Scrn,tmp); + sysSetScreen(mode->width,mode->height); + dbgprintf("set_mode OK\n"); + return 1; + }; + } + return 0; +}; + +#define API_VERSION 0x01000100 + +#define SRV_GETVERSION 0 +#define SRV_ENUM_MODES 1 +#define SRV_SET_MODE 2 + +int _stdcall srv_proc(ioctl_t *io) +{ + u32_t *inp; + u32_t *outp; + + inp = io->input; + outp = io->output; + + switch(io->io_code) + { + case SRV_GETVERSION: + if(io->out_size==4) + { + *(u32_t*)io->output = API_VERSION; + return 0; + } + break; + case SRV_ENUM_MODES: + if(io->inp_size==8) + { + int count; + count = get_modes((mode_t*)(*inp),(int)*(inp+1)); + + if(io->out_size==4) + { + *outp = count; + return 0; + } + }; + break; + case SRV_SET_MODE: + if(io->inp_size==8) + { + int err; + err = set_mode((mode_t*)inp); + + if(io->out_size==4) + { + *outp = err; + return 0; + } + }; + break; + + }; + + return -1; +} + + +CARD32 +_RHDReadMC(int scrnIndex, CARD32 addr) +{ + RHDPtr rhdPtr = (RHDPtr)scrnIndex; + CARD32 ret; + + if (rhdPtr->ChipSet < RHD_RS600) { + _RHDRegWrite(rhdPtr, MC_IND_INDEX, addr); + ret = _RHDRegRead(rhdPtr, MC_IND_DATA); + } else if (rhdPtr->ChipSet == RHD_RS600) { + _RHDRegWrite(rhdPtr, RS60_MC_NB_MC_INDEX, addr); + ret = _RHDRegRead(rhdPtr, RS60_MC_NB_MC_DATA); + } else if (rhdPtr->ChipSet == RHD_RS690 || rhdPtr->ChipSet == RHD_RS740) { + pciWriteLong(rhdPtr->NBPciTag, RS69_MC_INDEX, addr & ~RS69_MC_IND_WR_EN); + ret = pciReadLong(rhdPtr->NBPciTag, RS69_MC_DATA); + } else { + pciWriteLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_INDEX, (addr & ~RS78_MC_IND_WR_EN)); + ret = pciReadLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_DATA); + } + + RHDDebug(scrnIndex,"%s(0x%08X) = 0x%08X\n",__func__,(unsigned int)addr, + (unsigned int)ret); + return ret; +} + +void +_RHDWriteMC(int scrnIndex, CARD32 addr, CARD32 data) +{ + RHDPtr rhdPtr = (RHDPtr)scrnIndex; + + RHDDebug(scrnIndex,"%s(0x%08X, 0x%08X)\n",__func__,(unsigned int)addr, + (unsigned int)data); + + if (rhdPtr->ChipSet < RHD_RS600) { + _RHDRegWrite(rhdPtr, MC_IND_INDEX, addr | MC_IND_WR_EN); + _RHDRegWrite(rhdPtr, MC_IND_DATA, data); + } else if (rhdPtr->ChipSet == RHD_RS600) { + _RHDRegWrite(rhdPtr, RS60_MC_NB_MC_INDEX, addr | RS60_NB_MC_IND_WR_EN); + _RHDRegWrite(rhdPtr, RS60_MC_NB_MC_DATA, data); + } else if (rhdPtr->ChipSet == RHD_RS690 || rhdPtr->ChipSet == RHD_RS740) { + pciWriteLong(rhdPtr->NBPciTag, RS69_MC_INDEX, addr | RS69_MC_IND_WR_EN); + pciWriteLong(rhdPtr->NBPciTag, RS69_MC_DATA, data); + } else { + pciWriteLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_INDEX, addr | RS78_MC_IND_WR_EN); + pciWriteLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_DATA, data); + } +} + diff --git a/programs/system/drivers/rhd/rhd.h b/programs/system/drivers/rhd/rhd.h new file mode 100644 index 000000000..eb9b5110c --- /dev/null +++ b/programs/system/drivers/rhd/rhd.h @@ -0,0 +1,657 @@ +#include "pci.h" +#include "rhd_regs.h" + +typedef struct _ScrnInfoRec *ScrnInfoPtr; +typedef struct RHDRec *RHDPtr; + +typedef struct { + int frameX0; + int frameY0; + int virtualX; + int virtualY; + int depth; + int fbbpp; + // rgb weight; + // rgb blackColour; + // rgb whiteColour; + int defaultVisual; + char ** modes; + pointer options; +} DispRec, *DispPtr; + + +typedef struct _ScrnInfoRec +{ + int scrnIndex; + RHDPtr rhdPtr; +// int driverVersion; + char * driverName; /* canonical name used in */ + /* the config file */ +// ScreenPtr pScreen; /* Pointer to the ScreenRec */ +// int scrnIndex; /* Number of this screen */ +// Bool configured; /* Is this screen valid */ +// int origIndex; /* initial number assigned to +// * this screen before +// * finalising the number of +// * available screens */ + + /* Display-wide screenInfo values needed by this screen */ +// int imageByteOrder; +// int bitmapScanlineUnit; +// int bitmapScanlinePad; +// int bitmapBitOrder; +// int numFormats; +// PixmapFormatRec formats[MAXFORMATS]; +// PixmapFormatRec fbFormat; + + int bitsPerPixel; /* fb bpp */ +// Pix24Flags pixmap24; /* pixmap pref for depth 24 */ + int depth; /* depth of default visual */ +// MessageType depthFrom; /* set from config? */ +// MessageType bitsPerPixelFrom; /* set from config? */ +// rgb weight; /* r/g/b weights */ +// rgb mask; /* rgb masks */ +// rgb offset; /* rgb offsets */ +// int rgbBits; /* Number of bits in r/g/b */ +// Gamma gamma; /* Gamma of the monitor */ +// int defaultVisual; /* default visual class */ + int maxHValue; /* max horizontal timing */ + int maxVValue; /* max vertical timing value */ + int virtualX; /* Virtual width */ + int virtualY; /* Virtual height */ + int xInc; /* Horizontal timing increment */ +// MessageType virtualFrom; /* set from config? */ + int displayWidth; /* memory pitch */ + int frameX0; /* viewport position */ + int frameY0; + int frameX1; + int frameY1; + int zoomLocked; /* Disallow mode changes */ + DisplayModePtr modePool; /* list of compatible modes */ + DisplayModePtr modes; /* list of actual modes */ + DisplayModePtr currentMode; /* current mode + * This was previously + * overloaded with the modes + * field, which is a pointer + * into a circular list */ +// confScreenPtr confScreen; /* Screen config info */ +// MonPtr monitor; /* Monitor information */ + DispPtr display; /* Display information */ +// int * entityList; /* List of device entities */ +// int numEntities; + int widthmm; /* physical display dimensions in mm */ + int heightmm; + int xDpi; /* width DPI */ + int yDpi; /* height DPI */ + char * name; /* Name to prefix messages */ +// pointer driverPrivate; /* Driver private area */ +// DevUnion * privates; /* Other privates can hook in +// * here */ +// DriverPtr drv; /* xf86DriverList[] entry */ +// pointer module; /* Pointer to module head */ +// int colorKey; +// int overlayFlags; + + /* Some of these may be moved out of here into the driver private area */ + +// char * chipset; /* chipset name */ +// char * ramdac; /* ramdac name */ +// char * clockchip; /* clock name */ + // Bool progClock; /* clock is programmable */ +// int numClocks; /* number of clocks */ +// int clock[MAXCLOCKS]; /* list of clock frequencies */ +// int videoRam; /* amount of video ram (kb) */ +// unsigned long biosBase; /* Base address of video BIOS */ +// unsigned long memPhysBase; /* Physical address of FB */ +// unsigned long fbOffset; /* Offset of FB in the above */ +// IOADDRESS domainIOBase; /* Domain I/O base address */ +// int memClk; /* memory clock */ +// int textClockFreq; /* clock of text mode */ +// Bool flipPixels; /* swap default black/white */ +// pointer options; + +// int chipID; +// int chipRev; +// int racMemFlags; +// int racIoFlags; +// pointer access; +// xf86CurrentAccessPtr CurrentAccess; +// resType resourceType; +// pointer busAccess; + + /* Allow screens to be enabled/disabled individually */ +// Bool vtSema; +// DevUnion pixmapPrivate; /* saved devPrivate from pixmap */ + + /* hw cursor moves at SIGIO time */ +// Bool silkenMouse; + + /* Storage for clockRanges and adjustFlags for use with the VidMode ext */ +// ClockRangesPtr clockRanges; +// int adjustFlags; + + /* + * These can be used when the minor ABI version is incremented. + * The NUM_* parameters must be reduced appropriately to keep the + * structure size and alignment unchanged. + */ +// int reservedInt[NUM_RESERVED_INTS]; + +// int * entityInstanceList; +// pointer reservedPtr[NUM_RESERVED_POINTERS]; + + /* + * Driver entry points. + * + */ + +/* + xf86ProbeProc *Probe; + xf86PreInitProc *PreInit; + xf86ScreenInitProc *ScreenInit; + xf86SwitchModeProc *SwitchMode; + xf86AdjustFrameProc *AdjustFrame; + xf86EnterVTProc *EnterVT; + xf86LeaveVTProc *LeaveVT; + xf86FreeScreenProc *FreeScreen; + xf86ValidModeProc *ValidMode; + xf86EnableDisableFBAccessProc *EnableDisableFBAccess; + xf86SetDGAModeProc *SetDGAMode; + xf86ChangeGammaProc *ChangeGamma; + xf86PointerMovedProc *PointerMoved; + xf86PMEventProc *PMEvent; + xf86HandleMessageProc *HandleMessage; + xf86DPMSSetProc *DPMSSet; + xf86LoadPaletteProc *LoadPalette; + xf86SetOverscanProc *SetOverscan; + xorgRRFuncProc *RRFunc; +*/ + /* + * This can be used when the minor ABI version is incremented. + * The NUM_* parameter must be reduced appropriately to keep the + * structure size and alignment unchanged. + */ +// funcPointer reservedFuncs[NUM_RESERVED_FUNCS]; + +} ScrnInfoRec; + + + +#pragma pack(push, 1) +typedef struct +{ + CARD16 device; + CARD16 family; +}PciChipset_t; +#pragma pack(pop) + +#define VENDOR_ATI 0x1002 + +enum RHD_CHIPSETS { + RHD_UNKNOWN = 0, + /* R500 */ + RHD_RV505, + RHD_RV515, + RHD_RV516, + RHD_R520, + RHD_RV530, + RHD_RV535, + RHD_RV550, + RHD_RV560, + RHD_RV570, + RHD_R580, + /* R500 Mobility */ + RHD_M52, + RHD_M54, + RHD_M56, + RHD_M58, + RHD_M62, + RHD_M64, + RHD_M66, + RHD_M68, + RHD_M71, + /* R500 integrated */ + RHD_RS600, + RHD_RS690, + RHD_RS740, + /* R600 */ + RHD_R600, + RHD_RV610, + RHD_RV630, + /* R600 Mobility */ + RHD_M72, + RHD_M74, + RHD_M76, + /* RV670 came into existence after RV6x0 and M7x */ + RHD_RV670, + RHD_M88, + RHD_R680, + RHD_RV620, + RHD_M82, + RHD_RV635, + RHD_M86, + RHD_RS780, + RHD_RV770, + RHD_R700, + RHD_M98, + RHD_RV730, + RHD_M96, + RHD_RV710, + RHD_CHIP_END +}; + +enum RHD_FAMILIES { + RHD_FAMILY_UNKNOWN = 0, + RHD_FAMILY_RV515, + RHD_FAMILY_R520, + RHD_FAMILY_RV530, + RHD_FAMILY_RV560, + RHD_FAMILY_RV570, + RHD_FAMILY_R580, + RHD_FAMILY_RS690, + RHD_FAMILY_R600, + RHD_FAMILY_RV610, + RHD_FAMILY_RV630, + RHD_FAMILY_RV670, + RHD_FAMILY_RV620, + RHD_FAMILY_RV635, + RHD_FAMILY_RS780 +}; + +enum RHD_HPD_USAGE { + RHD_HPD_USAGE_AUTO = 0, + RHD_HPD_USAGE_OFF, + RHD_HPD_USAGE_NORMAL, + RHD_HPD_USAGE_SWAP, + RHD_HPD_USAGE_AUTO_SWAP, + RHD_HPD_USAGE_AUTO_OFF +}; + +enum RHD_TV_MODE { + RHD_TV_NONE = 0, + RHD_TV_NTSC = 1, + RHD_TV_NTSCJ = 1 << 2, + RHD_TV_PAL = 1 << 3, + RHD_TV_PALM = 1 << 4, + RHD_TV_PALCN = 1 << 5, + RHD_TV_PALN = 1 << 6, + RHD_TV_PAL60 = 1 << 7, + RHD_TV_SECAM = 1 << 8, + RHD_TV_CV = 1 << 9 +}; + +enum rhdPropertyAction { + rhdPropertyCheck, + rhdPropertyGet, + rhdPropertySet +}; + +union rhdPropertyData +{ + CARD32 integer; + char *string; + Bool Bool; +}; + +#define RHD_CONNECTORS_MAX 6 + +/* Just define where which PCI BAR lives for now. Will deal with different + * locations as soon as cards with a different BAR layout arrives. + */ +#define RHD_FB_BAR 0 +#define RHD_MMIO_BAR 2 + +/* More realistic powermanagement */ +#define RHD_POWER_ON 0 +#define RHD_POWER_RESET 1 /* off temporarily */ +#define RHD_POWER_SHUTDOWN 2 /* long term shutdown */ +#define RHD_POWER_UNKNOWN 3 /* initial state */ + +#define RHD_MEM_GART 1 +#define RHD_MEM_FB 2 + + +enum rhdCardType { + RHD_CARD_NONE, + RHD_CARD_AGP, + RHD_CARD_PCIE +}; + +enum { + RHD_PCI_CAPID_AGP = 0x02, + RHD_PCI_CAPID_PCIE = 0x10 +}; + +typedef struct BIOSScratchOutputPrivate rhdOutputDriverPrivate; +typedef struct _rhdI2CRec *rhdI2CPtr; +typedef struct _atomBiosHandle *atomBiosHandlePtr; +typedef struct _rhdShadowRec *rhdShadowPtr; + +typedef struct _RHDopt { + Bool set; + union { + Bool bool; + int integer; + unsigned long uslong; + double real; + double freq; + char *string; + } val; +} RHDOpt, *RHDOptPtr; + + +//////////////////////////// +typedef enum +{ + CONNECTOR_NONE, // 0 + CONNECTOR_VGA, // 1 + CONNECTOR_DVI_I, // 2 + CONNECTOR_DVI_D, // 3 + CONNECTOR_DVI_A, // 4 + CONNECTOR_STV, // 5 + CONNECTOR_CTV, // 6 + CONNECTOR_LVDS, // 7 + CONNECTOR_DIGITAL, // 8 + CONNECTOR_SCART, // 9 + CONNECTOR_HDMI_TYPE_A, // 10 + CONNECTOR_HDMI_TYPE_B, // 11 + CONNECTOR_0XC, // 12 + CONNECTOR_0XD, // 13 + CONNECTOR_DIN, // 14 + CONNECTOR_DISPLAY_PORT, // 15 + CONNECTOR_UNSUPPORTED +} RADEONConnectorType; + +typedef enum +{ + DAC_NONE = 0, + DAC_PRIMARY = 1, + DAC_TVDAC = 2, + DAC_EXT = 3 +} RADEONDacType; + +typedef enum +{ + TMDS_NONE = 0, + TMDS_INT = 1, + TMDS_EXT = 2, + TMDS_LVTMA = 3, + TMDS_DDIA = 4 +} RADEONTmdsType; + +typedef struct +{ + Bool valid; + CARD32 mask_clk_reg; + CARD32 mask_data_reg; + CARD32 put_clk_reg; + CARD32 put_data_reg; + CARD32 get_clk_reg; + CARD32 get_data_reg; + CARD32 mask_clk_mask; + CARD32 mask_data_mask; + CARD32 put_clk_mask; + CARD32 put_data_mask; + CARD32 get_clk_mask; + CARD32 get_data_mask; +} RADEONI2CBusRec, *RADEONI2CBusPtr; + +typedef struct { + RADEONDacType DACType; + RADEONTmdsType TMDSType; + RADEONConnectorType ConnectorType; + Bool valid; + int output_id; + int devices; + int hpd_mask; + RADEONI2CBusRec ddc_i2c; +} RADEONBIOSConnector; + +/////////////////////////////////////////// + + + +typedef struct RHDRec +{ + ScrnInfoPtr pScrn; + int scrnIndex; + + CARD32 MMIOBase; + CARD32 MMIOMapSize; + CARD32 videoRam; + + enum RHD_HPD_USAGE hpdUsage; + RHDOpt forceReduced; + + CARD32 FbBase; /* map base of fb */ + CARD32 FbIntAddress; /* card internal address of FB */ + CARD32 FbMapSize; + + CARD32 FbFreeStart; + CARD32 FbFreeSize; + + /* visible part of the framebuffer */ + unsigned int FbScanoutStart; + unsigned int FbScanoutSize; + + unsigned char* BIOSCopy; + + enum RHD_CHIPSETS ChipSet; + struct rhdCard *Card; + char *chipset_name; + + Bool IsMobility; + Bool IsIGP; + Bool HasCRTC2; + Bool HasSingleDAC; + Bool InternalTVOut; + + u32_t bus; + u32_t devfn; + + PCITAG PciTag; + PCITAG NBPciTag; + + CARD16 PciDeviceID; + CARD16 subvendor_id; + CARD16 subdevice_id; + pciVideoRec pci; + + struct _I2CBusRec **I2C; /* I2C bus list */ + atomBiosHandlePtr atomBIOS; /* handle for AtomBIOS */ + + struct rhdMC *MC; + struct rhdVGA *VGA; + struct rhdCrtc *Crtc[2]; + struct rhdPLL *PLLs[2]; /* Pixelclock PLLs */ + + struct rhdLUTStore *LUTStore; + struct rhdLUT *LUT[2]; + + struct rhdConnector *Connector[RHD_CONNECTORS_MAX]; + + struct rhdOutput *Outputs; + + struct rhdHPD *HPD; /* Hot plug detect subsystem */ + enum RHD_TV_MODE tvMode; + struct rhdMonitor *ConfigMonitor; + + struct mem_block *fb_heap; + struct mem_block *gart_heap; + + RHDOpt scaleTypeOpt; + + int verbosity; + + + /* AtomBIOS usage */ + RHDOpt UseAtomBIOS; + CARD32 UseAtomFlags; + + struct rhdOutput *DigEncoderOutput[2]; +}RHD_t; + +typedef struct { + int token; /* id of the token */ + const char * name; /* token name */ +} SymTabRec, *SymTabPtr; + +extern inline CARD32 _RHDRegRead(RHDPtr rhdPtr, CARD16 offset) +{ + return *(volatile CARD32 *)((CARD8*)(rhdPtr->MMIOBase + offset)); +} + +extern inline void +_RHDRegWrite(RHDPtr rhdPtr, CARD16 offset, CARD32 value) +{ + *(volatile CARD32 *)((CARD8 *)(rhdPtr->MMIOBase + offset)) = value; +} + +extern inline void +_RHDRegMask(RHDPtr rhdPtr, CARD16 offset, CARD32 value, CARD32 mask) +{ + CARD32 tmp; + + tmp = _RHDRegRead(rhdPtr, offset); + tmp &= ~mask; + tmp |= (value & mask); + _RHDRegWrite(rhdPtr, offset, tmp); +}; + +extern inline CARD32 +_RHDReadPLL(RHDPtr rhdPtr, CARD16 offset) +{ + _RHDRegWrite(rhdPtr, CLOCK_CNTL_INDEX, (offset & PLL_ADDR)); + return _RHDRegRead(rhdPtr, CLOCK_CNTL_DATA); +} + +extern inline void +_RHDWritePLL(RHDPtr rhdPtr, CARD16 offset, CARD32 data) +{ + _RHDRegWrite(rhdPtr, CLOCK_CNTL_INDEX, (offset & PLL_ADDR) | PLL_WR_EN); + _RHDRegWrite(rhdPtr, CLOCK_CNTL_DATA, data); +} + + +enum RHD_FAMILIES RHDFamily(enum RHD_CHIPSETS chipset); + +extern CARD32 _RHDReadMC(int scrnIndex, CARD32 addr); +#define RHDReadMC(ptr,addr) _RHDReadMC((int)(ptr),(addr)) + +extern void _RHDWriteMC(int scrnIndex, CARD32 addr, CARD32 data); +#define RHDWriteMC(ptr,addr,value) _RHDWriteMC((int)(ptr),(addr),(value)) + +#define RHDRegRead(ptr, offset) \ + _RHDRegRead((RHDPtr)((ptr)->scrnIndex), (offset)) + +#define RHDRegWrite(ptr, offset, value) \ + _RHDRegWrite((RHDPtr)((ptr)->scrnIndex), (offset), (value)) + +#define RHDRegMask(ptr, offset, value, mask) \ + _RHDRegMask((RHDPtr)((ptr)->scrnIndex), (offset), (value), (mask)) + +#define RHDRegMaskD(ptr, offset, value, mask) \ + RHDRegMask(ptr, offset, value, mask) + +char * RhdAppendString(char *s1, const char *s2); + +#ifndef PCI_DOM_MASK +# define PCI_DOM_MASK 0x0ffu +#endif +#define PCI_DOMBUS_MASK (((PCI_DOM_MASK) << 8) | 0x0ffu) + +#define PCI_MAKE_TAG(b,d,f) ((((b) & (PCI_DOMBUS_MASK)) << 16) | \ + (((d) & 0x00001fu) << 11) | \ + (((f) & 0x000007u) << 8)) + +#define PCI_BUS_FROM_TAG(tag) (((tag) >> 16) & (PCI_DOMBUS_MASK)) +#define PCI_DEV_FROM_TAG(tag) (((tag) & 0x0000f800u) >> 11) +#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8) +#define PCI_DFN_FROM_TAG(tag) (((tag) & 0x0000ff00u) >> 8) + +extern inline PCITAG +pciTag(int busnum, int devnum, int funcnum) +{ + return(PCI_MAKE_TAG(busnum,devnum,funcnum)); +} + +#define LOG_DEBUG 0 + +#define X_ERROR 0 +#define X_WARNING 1 +#define X_INFO 2 +#define X_NONE 3 +#define X_PROBED 4 + +/* +#ifdef DBG_ALL + #undef DBG_CALL + #undef DBG_MSG + #undef DBG_CAIL + + #define DBG_CALL + #define DBG_MSG + #define DBG_CAIL +#endif +*/ + + +#ifdef DBG_CALL + #define RHDFUNC(ptr) dbgprintf("FUNCTION: %s\n", __func__) +#else + #define RHDFUNC(ptr) +#endif + +#ifdef DBG_MSG + #define xf86Msg(a, format,...) dbgprintf(format,##__VA_ARGS__) + #define xf86MsgVerb(a,b,format,...) dbgprintf(format,##__VA_ARGS__) + #define xf86DrvMsg(a,b,format,...) dbgprintf(format,##__VA_ARGS__) + #define xf86DrvMsgVerb(a,b,c,format,...) dbgprintf(format,##__VA_ARGS__) + #define xf86VDrvMsgVerb(a,b,c,format,...) dbgprintf(format,##__VA_ARGS__) + + #define RHDDebug(a,format,...) dbgprintf(format,##__VA_ARGS__) + #define RHDDebugCont(format,...) dbgprintf(format,##__VA_ARGS__) + #define RHDDebugVerb(a,b,format,...) dbgprintf(format,##__VA_ARGS__) +#else + #define xf86Msg(a, format,...) + #define xf86MsgVerb(a,b,format,...) + #define xf86DrvMsg(a,b,format,...) + #define xf86DrvMsgVerb(a,b,c,format,...) + #define xf86VDrvMsgVerb(a,b,c,format,...) + + #define RHDDebug(a,format,...) + #define RHDDebugCont(format,...) + #define RHDDebugVerb(a,b,format,...) +#endif + +#ifdef DBG_CAIL + #define CAILFUNC(a) dbgprintf("CAIL: %s\n", __func__) + #define CailDebug(a,format,...) dbgprintf(format,##__VA_ARGS__) +#else + #define CAILFUNC(a) + #define CailDebug(a,format,...) +#endif + +#define DBG(x) x +#define ErrorF dbgprintf + +#define ASSERT(expr) + +#define ASSERTF(expr,format) + +#define RHDPTRI(p) ((RHDPtr)((p)->scrnIndex)) +#define RHDPTR(p) ((p)->rhdPtr) + +#define RHDFUNCI(scrnIndex) RHDDebug(scrnIndex, "FUNCTION: %s\n", __func__) + +enum atomSubSystem { + atomUsageCrtc, + atomUsagePLL, + atomUsageOutput, + atomUsageAny +}; + +extern Bool RHDUseAtom(RHDPtr rhdPtr, enum RHD_CHIPSETS *BlackList, enum atomSubSystem subsys); + +//git://anongit.freedesktop.org/git/xorg/driver/xf86-video-nv +//git://anongit.freedesktop.org/git/nouveau/xf86-video-nouveau diff --git a/programs/system/drivers/rhd/rhd.lk1 b/programs/system/drivers/rhd/rhd.lk1 new file mode 100644 index 000000000..1a1b7b004 --- /dev/null +++ b/programs/system/drivers/rhd/rhd.lk1 @@ -0,0 +1,56 @@ +IMP _AllocKernelSpace core.AllocKernelSpace, + _KernelAlloc core.KernelAlloc, + _MapIoMem core.MapIoMem, + _PciApi core.PciApi, + _PciRead8 core.PciRead8, + _PciRead16 core.PciRead16, + _PciRead32 core.PciRead32, + _PciWrite8 core.PciWrite8, + _PciWrite16 core.PciWrite16, + _PciWrite32 core.PciWrite32, + _RegService core.RegService, + _SysMsgBoardStr core.SysMsgBoardStr, + _Kmalloc core.Kmalloc, + _Kfree core.Kfree, + _SetScreen core.SetScreen + +FIL rhd.obj, + rhd_id.obj, + rhd_mem.obj, + + rhd_vga.obj, + rhd_mc.obj, + rhd_crtc.obj, + rhd_dac.obj, + rhd_pll.obj, + rhd_lut.obj, + + rhd_modes.obj, + rhd_i2c.obj, + rhd_edid.obj, + + rhd_connector.obj, + rhd_ddia.obj, + rhd_dig.obj, + rhd_monitor.obj, + rhd_output.obj, + rhd_lvtma.obj, + rhd_tmds.obj, + rhd_hdmi.obj, + + rhd_atombios.obj, + rhd_atomwrapper.obj, + rhd_atomout.obj, + rhd_atomcrtc.obj, + rhd_atompll.obj, + rhd_biosscratch.obj, + AtomBios/CD_Operations.obj, + AtomBios/Decoder.obj, + AtomBios/hwserv_drv.obj, + dbg.obj, string.obj, + pci.obj, xf86i2c.obj, + malloc.obj, + memset.obj, + icompute.obj, + vsprintf.obj, + s_ceilf.obj diff --git a/programs/system/drivers/rhd/rhd.mk b/programs/system/drivers/rhd/rhd.mk new file mode 100644 index 000000000..ee7580e64 --- /dev/null +++ b/programs/system/drivers/rhd/rhd.mk @@ -0,0 +1,5 @@ +rhd.exe: rhd.obj rhd_id.obj dbg.obj pci.obj rhd_crtc.obj rhd_vga.obj rhd_mc.obj rhd_atombios.obj + *wlink name rhd.exe SYS nt_dll op offset=0 op nod & +op maxe=25 op el op STUB=stub.exe op START=_drvEntry @rhd.lk1 + + diff --git a/programs/system/drivers/rhd/rhd_atombios.c b/programs/system/drivers/rhd/rhd_atombios.c new file mode 100644 index 000000000..40d49d6dc --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atombios.c @@ -0,0 +1,5409 @@ +/* + * Copyright 2007, 2008 Egbert Eich + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * 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. + */ +/* #define RHD_DEBUG */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + + +/* only for testing now */ + +#include "common.h" +#include "rhd.h" +#include "edid.h" +#include "rhd_atombios.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_biosscratch.h" +#include "rhd_monitor.h" +#include "rhd_card.h" +#include "rhd_regs.h" + +#ifdef ATOM_BIOS +# include "rhd_atomwrapper.h" +//# include "xf86int10.h" +# ifdef ATOM_BIOS_PARSER +# define INT8 INT8 +# define INT16 INT16 +# define INT32 INT32 +# include "AtomBios/includes/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/includes/atombios.h" +# include "atomBios/includes/ObjectID.h" + +typedef AtomBiosResult (*AtomBiosRequestFunc)(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data); +typedef struct rhdConnectorInfo *rhdConnectorInfoPtr; + +static AtomBiosResult rhdAtomInit(atomBiosHandlePtr unused1, + AtomBiosRequestID unused2, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomTearDown(atomBiosHandlePtr handle, + AtomBiosRequestID unused1, AtomBiosArgPtr unused2); +static AtomBiosResult rhdAtomGetDataInCodeTable(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomVramInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomTmdsInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomAllocateFbScratch(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomLvdsGetTimings(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomLvdsInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomConnectorInfo(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data); +static AtomBiosResult rhdAtomOutputDeviceList(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data); +static AtomBiosResult +rhdAtomAnalogTVInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult +rhdAtomGetConditionalGoldenSetting(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); + +# ifdef ATOM_BIOS_PARSER +static AtomBiosResult rhdAtomExec(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data); +# endif +static AtomBiosResult +rhdAtomCompassionateDataQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult +rhdAtomIntegratedSystemInfoQuery(atomBiosHandlePtr handle, AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult +atomSetRegisterListLocation(atomBiosHandlePtr handle, AtomBiosRequestID func, AtomBiosArgPtr data); +static AtomBiosResult +atomRestoreRegisters(atomBiosHandlePtr handle, AtomBiosRequestID func, AtomBiosArgPtr data); + + +enum msgDataFormat { + MSG_FORMAT_NONE, + MSG_FORMAT_HEX, + MSG_FORMAT_DEC +}; + +enum atomRegisterType { + atomRegisterMMIO, + atomRegisterMC, + atomRegisterPLL, + atomRegisterPCICFG +}; + +struct atomBIOSRequests { + AtomBiosRequestID id; + AtomBiosRequestFunc request; + char *message; + enum msgDataFormat message_format; +} AtomBiosRequestList [] = { + {ATOMBIOS_INIT, rhdAtomInit, + "AtomBIOS Init", MSG_FORMAT_NONE}, + {ATOMBIOS_TEARDOWN, rhdAtomTearDown, + "AtomBIOS Teardown", MSG_FORMAT_NONE}, +# ifdef ATOM_BIOS_PARSER + {ATOMBIOS_EXEC, rhdAtomExec, + "AtomBIOS Exec", MSG_FORMAT_NONE}, +#endif + {ATOMBIOS_ALLOCATE_FB_SCRATCH, rhdAtomAllocateFbScratch, + "AtomBIOS Set FB Space", MSG_FORMAT_NONE}, + {ATOMBIOS_GET_CONNECTORS, rhdAtomConnectorInfo, + "AtomBIOS Get Connectors", MSG_FORMAT_NONE}, + {ATOMBIOS_GET_OUTPUT_DEVICE_LIST, rhdAtomOutputDeviceList, + "AtomBIOS Get Output Info", MSG_FORMAT_NONE}, + {ATOMBIOS_GET_PANEL_MODE, rhdAtomLvdsGetTimings, + "AtomBIOS Get Panel Mode", MSG_FORMAT_NONE}, + {ATOMBIOS_GET_PANEL_EDID, rhdAtomLvdsGetTimings, + "AtomBIOS Get Panel EDID", MSG_FORMAT_NONE}, + {ATOMBIOS_GET_CODE_DATA_TABLE, rhdAtomGetDataInCodeTable, + "AtomBIOS Get Datatable from Codetable", MSG_FORMAT_NONE}, + {GET_DEFAULT_ENGINE_CLOCK, rhdAtomFirmwareInfoQuery, + "Default Engine Clock", MSG_FORMAT_DEC}, + {GET_DEFAULT_MEMORY_CLOCK, rhdAtomFirmwareInfoQuery, + "Default Memory Clock", MSG_FORMAT_DEC}, + {GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, rhdAtomFirmwareInfoQuery, + "Maximum Pixel ClockPLL Frequency Output", MSG_FORMAT_DEC}, + {GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, rhdAtomFirmwareInfoQuery, + "Minimum Pixel ClockPLL Frequency Output", MSG_FORMAT_DEC}, + {GET_MAX_PIXEL_CLOCK_PLL_INPUT, rhdAtomFirmwareInfoQuery, + "Maximum Pixel ClockPLL Frequency Input", MSG_FORMAT_DEC}, + {GET_MIN_PIXEL_CLOCK_PLL_INPUT, rhdAtomFirmwareInfoQuery, + "Minimum Pixel ClockPLL Frequency Input", MSG_FORMAT_DEC}, + {GET_MAX_PIXEL_CLK, rhdAtomFirmwareInfoQuery, + "Maximum Pixel Clock", MSG_FORMAT_DEC}, + {GET_REF_CLOCK, rhdAtomFirmwareInfoQuery, + "Reference Clock", MSG_FORMAT_DEC}, + {GET_FW_FB_START, rhdAtomVramInfoQuery, + "Start of VRAM area used by Firmware", MSG_FORMAT_HEX}, + {GET_FW_FB_SIZE, rhdAtomVramInfoQuery, + "Framebuffer space used by Firmware (kb)", MSG_FORMAT_DEC}, + {ATOM_TMDS_MAX_FREQUENCY, rhdAtomTmdsInfoQuery, + "TMDS Max Frequency", MSG_FORMAT_DEC}, + {ATOM_TMDS_PLL_CHARGE_PUMP, rhdAtomTmdsInfoQuery, + "TMDS PLL ChargePump", MSG_FORMAT_DEC}, + {ATOM_TMDS_PLL_DUTY_CYCLE, rhdAtomTmdsInfoQuery, + "TMDS PLL DutyCycle", MSG_FORMAT_DEC}, + {ATOM_TMDS_PLL_VCO_GAIN, rhdAtomTmdsInfoQuery, + "TMDS PLL VCO Gain", MSG_FORMAT_DEC}, + {ATOM_TMDS_PLL_VOLTAGE_SWING, rhdAtomTmdsInfoQuery, + "TMDS PLL VoltageSwing", MSG_FORMAT_DEC}, + {ATOM_LVDS_SUPPORTED_REFRESH_RATE, rhdAtomLvdsInfoQuery, + "LVDS Supported Refresh Rate", MSG_FORMAT_DEC}, + {ATOM_LVDS_OFF_DELAY, rhdAtomLvdsInfoQuery, + "LVDS Off Delay", MSG_FORMAT_DEC}, + {ATOM_LVDS_SEQ_DIG_ONTO_DE, rhdAtomLvdsInfoQuery, + "LVDS SEQ Dig onto DE", MSG_FORMAT_DEC}, + {ATOM_LVDS_SEQ_DE_TO_BL, rhdAtomLvdsInfoQuery, + "LVDS SEQ DE to BL", MSG_FORMAT_DEC}, + {ATOM_LVDS_TEMPORAL_DITHER, rhdAtomLvdsInfoQuery, + "LVDS Temporal Dither ", MSG_FORMAT_HEX}, + {ATOM_LVDS_SPATIAL_DITHER, rhdAtomLvdsInfoQuery, + "LVDS Spatial Dither ", MSG_FORMAT_HEX}, + {ATOM_LVDS_DUALLINK, rhdAtomLvdsInfoQuery, + "LVDS Duallink", MSG_FORMAT_HEX}, + {ATOM_LVDS_GREYLVL, rhdAtomLvdsInfoQuery, + "LVDS Grey Level", MSG_FORMAT_HEX}, + {ATOM_LVDS_FPDI, rhdAtomLvdsInfoQuery, + "LVDS FPDI", MSG_FORMAT_HEX}, + {ATOM_LVDS_24BIT, rhdAtomLvdsInfoQuery, + "LVDS 24Bit", MSG_FORMAT_HEX}, + {ATOM_GPIO_I2C_CLK_MASK, rhdAtomGPIOI2CInfoQuery, + "GPIO_I2C_Clk_Mask", MSG_FORMAT_HEX}, + {ATOM_GPIO_I2C_CLK_MASK_SHIFT, rhdAtomGPIOI2CInfoQuery, + "GPIO_I2C_Clk_Mask_Shift", MSG_FORMAT_HEX}, + {ATOM_GPIO_I2C_DATA_MASK, rhdAtomGPIOI2CInfoQuery, + "GPIO_I2C_Data_Mask", MSG_FORMAT_HEX}, + {ATOM_GPIO_I2C_DATA_MASK_SHIFT, rhdAtomGPIOI2CInfoQuery, + "GPIO_I2C_Data_Mask_Shift", MSG_FORMAT_HEX}, + {ATOM_DAC1_BG_ADJ, rhdAtomCompassionateDataQuery, + "DAC1 BG Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC1_DAC_ADJ, rhdAtomCompassionateDataQuery, + "DAC1 DAC Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC1_FORCE, rhdAtomCompassionateDataQuery, + "DAC1 Force Data", MSG_FORMAT_HEX}, + {ATOM_DAC2_CRTC2_BG_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_CRTC2 BG Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_NTSC_BG_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_NTSC BG Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_PAL_BG_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_PAL BG Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_CV_BG_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_CV BG Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_CRTC2_DAC_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_CRTC2 DAC Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_NTSC_DAC_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_NTSC DAC Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_PAL_DAC_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_PAL DAC Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_CV_DAC_ADJ, rhdAtomCompassionateDataQuery, + "DAC2_CV DAC Adjustment", MSG_FORMAT_HEX}, + {ATOM_DAC2_CRTC2_FORCE, rhdAtomCompassionateDataQuery, + "DAC2_CRTC2 Force", MSG_FORMAT_HEX}, + {ATOM_DAC2_CRTC2_MUX_REG_IND,rhdAtomCompassionateDataQuery, + "DAC2_CRTC2 Mux Register Index", MSG_FORMAT_HEX}, + {ATOM_DAC2_CRTC2_MUX_REG_INFO,rhdAtomCompassionateDataQuery, + "DAC2_CRTC2 Mux Register Info", MSG_FORMAT_HEX}, + {ATOM_ANALOG_TV_MODE, rhdAtomAnalogTVInfoQuery, + "Analog TV Mode", MSG_FORMAT_NONE}, + {ATOM_ANALOG_TV_DEFAULT_MODE, rhdAtomAnalogTVInfoQuery, + "Analog TV Default Mode", MSG_FORMAT_DEC}, + {ATOM_ANALOG_TV_SUPPORTED_MODES, rhdAtomAnalogTVInfoQuery, + "Analog TV Supported Modes", MSG_FORMAT_HEX}, + {ATOM_GET_CONDITIONAL_GOLDEN_SETTINGS, rhdAtomGetConditionalGoldenSetting, + "Conditional Golden Setting", MSG_FORMAT_NONE}, + {ATOM_GET_PCIENB_CFG_REG7, rhdAtomIntegratedSystemInfoQuery, + "PCIE NB Cfg7Reg", MSG_FORMAT_HEX}, + {ATOM_GET_CAPABILITY_FLAG, rhdAtomIntegratedSystemInfoQuery, + "CapabilityFlag", MSG_FORMAT_HEX}, + {ATOM_GET_PCIE_LANES, rhdAtomIntegratedSystemInfoQuery, + "PCI Lanes", MSG_FORMAT_NONE}, + {ATOM_SET_REGISTER_LIST_LOCATION, atomSetRegisterListLocation, + "Register List Location", MSG_FORMAT_NONE}, + {ATOM_RESTORE_REGISTERS, atomRestoreRegisters, + "Restore Registers", MSG_FORMAT_NONE}, + {FUNC_END, NULL, + NULL, MSG_FORMAT_NONE} +}; + +/* + * This works around a bug in atombios.h where + * ATOM_MAX_SUPPORTED_DEVICE_INFO is specified incorrectly. + */ + +#define ATOM_MAX_SUPPORTED_DEVICE_INFO_HD (ATOM_DEVICE_RESERVEDF_INDEX+1) +typedef struct _ATOM_SUPPORTED_DEVICES_INFO_HD +{ + ATOM_COMMON_TABLE_HEADER sHeader; + USHORT usDeviceSupport; + ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_HD]; + ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_HD]; +} ATOM_SUPPORTED_DEVICES_INFO_HD; + +typedef struct _atomDataTables +{ + unsigned char *UtilityPipeLine; + ATOM_MULTIMEDIA_CAPABILITY_INFO *MultimediaCapabilityInfo; + ATOM_MULTIMEDIA_CONFIG_INFO *MultimediaConfigInfo; + ATOM_STANDARD_VESA_TIMING *StandardVESA_Timing; + union { + void *base; + ATOM_FIRMWARE_INFO *FirmwareInfo; + ATOM_FIRMWARE_INFO_V1_2 *FirmwareInfo_V_1_2; + ATOM_FIRMWARE_INFO_V1_3 *FirmwareInfo_V_1_3; + ATOM_FIRMWARE_INFO_V1_4 *FirmwareInfo_V_1_4; + } FirmwareInfo; + ATOM_DAC_INFO *DAC_Info; + union { + void *base; + ATOM_LVDS_INFO *LVDS_Info; + ATOM_LVDS_INFO_V12 *LVDS_Info_v12; + } LVDS_Info; + ATOM_TMDS_INFO *TMDS_Info; + ATOM_ANALOG_TV_INFO *AnalogTV_Info; + union { + void *base; + ATOM_SUPPORTED_DEVICES_INFO *SupportedDevicesInfo; + ATOM_SUPPORTED_DEVICES_INFO_2 *SupportedDevicesInfo_2; + ATOM_SUPPORTED_DEVICES_INFO_2d1 *SupportedDevicesInfo_2d1; + ATOM_SUPPORTED_DEVICES_INFO_HD *SupportedDevicesInfo_HD; + } SupportedDevicesInfo; + ATOM_GPIO_I2C_INFO *GPIO_I2C_Info; + ATOM_VRAM_USAGE_BY_FIRMWARE *VRAM_UsageByFirmware; + ATOM_GPIO_PIN_LUT *GPIO_Pin_LUT; + ATOM_VESA_TO_INTENAL_MODE_LUT *VESA_ToInternalModeLUT; + union { + void *base; + ATOM_COMPONENT_VIDEO_INFO *ComponentVideoInfo; + ATOM_COMPONENT_VIDEO_INFO_V21 *ComponentVideoInfo_v21; + } ComponentVideoInfo; +/**/unsigned char *PowerPlayInfo; + COMPASSIONATE_DATA *CompassionateData; + ATOM_DISPLAY_DEVICE_PRIORITY_INFO *SaveRestoreInfo; +/**/unsigned char *PPLL_SS_Info; + ATOM_OEM_INFO *OemInfo; + ATOM_XTMDS_INFO *XTMDS_Info; + ATOM_ASIC_MVDD_INFO *MclkSS_Info; + ATOM_OBJECT_HEADER *Object_Header; + INDIRECT_IO_ACCESS *IndirectIOAccess; + ATOM_MC_INIT_PARAM_TABLE *MC_InitParameter; +/**/unsigned char *ASIC_VDDC_Info; + ATOM_ASIC_INTERNAL_SS_INFO *ASIC_InternalSS_Info; +/**/unsigned char *TV_VideoMode; + union { + void *base; + ATOM_VRAM_INFO_V2 *VRAM_Info_v2; + ATOM_VRAM_INFO_V3 *VRAM_Info_v3; + } VRAM_Info; + ATOM_MEMORY_TRAINING_INFO *MemoryTrainingInfo; + union { + void *base; + ATOM_INTEGRATED_SYSTEM_INFO *IntegratedSystemInfo; + ATOM_INTEGRATED_SYSTEM_INFO_V2 *IntegratedSystemInfo_v2; + } IntegratedSystemInfo; + ATOM_ASIC_PROFILING_INFO *ASIC_ProfilingInfo; + ATOM_VOLTAGE_OBJECT_INFO *VoltageObjectInfo; + ATOM_POWER_SOURCE_INFO *PowerSourceInfo; +} atomDataTables, *atomDataTablesPtr; + +struct atomSaveListRecord +{ + /* header */ + int Length; + int Last; + struct atomRegisterList{ + enum atomRegisterType Type; + CARD32 Address; + CARD32 Value; + } RegisterList[1]; +}; + +struct atomSaveListObject +{ + struct atomSaveListObject *next; + struct atomSaveListRecord **SaveList; +}; + +typedef struct _atomBiosHandle { + int scrnIndex; + RHDPtr rhdPtr; + unsigned char *BIOSBase; + atomDataTablesPtr atomDataPtr; + pointer *scratchBase; + CARD32 fbBase; + PCITAG PciTag; + unsigned int BIOSImageSize; + unsigned char *codeTable; + struct atomSaveListRecord **SaveList; + struct atomSaveListObject *SaveListObjects; +} atomBiosHandleRec; + +enum { + legacyBIOSLocation = 0xC0000, + legacyBIOSMax = 0x10000 +}; + +struct atomConnectorInfoPrivate { + enum atomDevice *Devices; +}; + +# ifdef ATOM_BIOS_PARSER + +# define LOG_CAIL LOG_DEBUG + 1 + +static void +atomDebugPrintPspace(atomBiosHandlePtr handle, AtomBiosArgPtr data, int size) +{ + CARD32 *pspace = (CARD32 *)data->exec.pspace; + int i = 0; + + size >>= 2; + + while (i++,size--) + RHDDebug(handle->scrnIndex, " Pspace[%2.2i]: 0x%8.8x\n", i, *(pspace++)); +} + +/* +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +typedef __builtin_va_list __gnuc_va_list; +typedef __gnuc_va_list va_list; + +#define arg(x) va_arg (ap, u32_t) + +static void +CailDebug(int scrnIndex, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + xf86VDrvMsgVerb(scrnIndex, X_INFO, LOG_CAIL, format, ap); + va_end(ap); +} +# define CAILFUNC(ptr) \ + CailDebug(((atomBiosHandlePtr)(ptr))->scrnIndex, "CAIL: %s\n", __func__) +*/ + +# endif + +# define DEBUG_VERSION(index, handle, version) \ + xf86DrvMsgVerb(handle->scrnIndex, X_INFO, 3, "%s returned version %i for index 0x%x\n" ,__func__,version.cref,index) +# define DEBUG_VERSION_NAME(index, handle, name, version) \ + xf86DrvMsgVerb(handle->scrnIndex, X_INFO, 3, "%s(%s) returned version %i for index 0x%x\n",\ + __func__,name,version.cref,index) + +static int +rhdAtomAnalyzeCommonHdr(ATOM_COMMON_TABLE_HEADER *hdr) +{ + if (hdr->usStructureSize == 0xaa55) + return FALSE; + + return TRUE; +} + +static int +rhdAtomAnalyzeRomHdr(unsigned char *rombase, + ATOM_ROM_HEADER *hdr, + unsigned int *data_offset, unsigned int *code_table) +{ + if (!rhdAtomAnalyzeCommonHdr(&hdr->sHeader)) { + return FALSE; + } + xf86DrvMsg(-1,X_NONE,"\tSubsystemVendorID: 0x%4.4x SubsystemID: 0x%4.4x\n", + hdr->usSubsystemVendorID,hdr->usSubsystemID); + xf86DrvMsg(-1,X_NONE,"\tIOBaseAddress: 0x%4.4x\n",hdr->usIoBaseAddress); + xf86DrvMsgVerb(-1,X_NONE,3,"\tFilename: %s\n",rombase + hdr->usConfigFilenameOffset); + xf86DrvMsgVerb(-1,X_NONE,3,"\tBIOS Bootup Message: %s\n", + rombase + hdr->usBIOS_BootupMessageOffset); + + *data_offset = hdr->usMasterDataTableOffset; + *code_table = hdr->usMasterCommandTableOffset; + + return TRUE; +} + +static int +rhdAtomAnalyzeRomDataTable(unsigned char *base, int offset, + void *ptr,unsigned short *size) +{ + ATOM_COMMON_TABLE_HEADER *table = (ATOM_COMMON_TABLE_HEADER *) + (base + offset); + + if (!*size || !rhdAtomAnalyzeCommonHdr(table)) { + if (*size) *size -= 2; + *(void **)ptr = NULL; + return FALSE; + } + *size -= 2; + *(void **)ptr = (void *)(table); + return TRUE; +} + +static Bool +rhdAtomGetTableRevisionAndSize(ATOM_COMMON_TABLE_HEADER *hdr, + CARD8 *contentRev, + CARD8 *formatRev, + unsigned short *size) +{ + if (!hdr) + return FALSE; + + if (contentRev) *contentRev = hdr->ucTableContentRevision; + if (formatRev) *formatRev = hdr->ucTableFormatRevision; + if (size) *size = (short)hdr->usStructureSize + - sizeof(ATOM_COMMON_TABLE_HEADER); + + return TRUE; +} + +static Bool +rhdAtomGetCommandTableRevisionSize(atomBiosHandlePtr handle, int index, + CARD8 *contentRev, CARD8 *formatRev, unsigned short *size) +{ + unsigned short offset = ((USHORT *)&(((ATOM_MASTER_COMMAND_TABLE *)handle->codeTable) + ->ListOfCommandTables))[index]; + ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *hdr = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)(handle->BIOSBase + offset); + ATOM_COMMON_TABLE_HEADER hdr1 = hdr->CommonHeader; + + if (!offset) { + *contentRev = *formatRev = 0; + return FALSE; + } + return rhdAtomGetTableRevisionAndSize(&hdr1, contentRev, formatRev, size); +} + +static Bool +rhdAtomAnalyzeMasterDataTable(unsigned char *base, + ATOM_MASTER_DATA_TABLE *table, + atomDataTablesPtr data) +{ + ATOM_MASTER_LIST_OF_DATA_TABLES *data_table = + &table->ListOfDataTables; + unsigned short size; + + if (!rhdAtomAnalyzeCommonHdr(&table->sHeader)) + return FALSE; + if (!rhdAtomGetTableRevisionAndSize(&table->sHeader,NULL,NULL, + &size)) + return FALSE; +# define SET_DATA_TABLE(x) {\ + rhdAtomAnalyzeRomDataTable(base,data_table->x,(void *)(&(data->x)),&size); \ + } + +# define SET_DATA_TABLE_VERS(x) {\ + rhdAtomAnalyzeRomDataTable(base,data_table->x,&(data->x.base),&size); \ + } + + SET_DATA_TABLE(UtilityPipeLine); + SET_DATA_TABLE(MultimediaCapabilityInfo); + SET_DATA_TABLE(MultimediaConfigInfo); + SET_DATA_TABLE(StandardVESA_Timing); + SET_DATA_TABLE_VERS(FirmwareInfo); + SET_DATA_TABLE(DAC_Info); + SET_DATA_TABLE_VERS(LVDS_Info); + SET_DATA_TABLE(TMDS_Info); + SET_DATA_TABLE(AnalogTV_Info); + SET_DATA_TABLE_VERS(SupportedDevicesInfo); + SET_DATA_TABLE(GPIO_I2C_Info); + SET_DATA_TABLE(VRAM_UsageByFirmware); + SET_DATA_TABLE(GPIO_Pin_LUT); + SET_DATA_TABLE(VESA_ToInternalModeLUT); + SET_DATA_TABLE_VERS(ComponentVideoInfo); + SET_DATA_TABLE(PowerPlayInfo); + SET_DATA_TABLE(CompassionateData); + SET_DATA_TABLE(SaveRestoreInfo); + SET_DATA_TABLE(PPLL_SS_Info); + SET_DATA_TABLE(OemInfo); + SET_DATA_TABLE(XTMDS_Info); + SET_DATA_TABLE(MclkSS_Info); + SET_DATA_TABLE(Object_Header); + SET_DATA_TABLE(IndirectIOAccess); + SET_DATA_TABLE(MC_InitParameter); + SET_DATA_TABLE(ASIC_VDDC_Info); + SET_DATA_TABLE(ASIC_InternalSS_Info); + SET_DATA_TABLE(TV_VideoMode); + SET_DATA_TABLE_VERS(VRAM_Info); + SET_DATA_TABLE(MemoryTrainingInfo); + SET_DATA_TABLE_VERS(IntegratedSystemInfo); + SET_DATA_TABLE(ASIC_ProfilingInfo); + SET_DATA_TABLE(VoltageObjectInfo); + SET_DATA_TABLE(PowerSourceInfo); +# undef SET_DATA_TABLE + + return TRUE; +} + +static Bool +rhdAtomGetTables(RHDPtr rhdPtr, unsigned char *base, + atomDataTables *atomDataPtr, unsigned char **codeTablePtr, + unsigned int BIOSImageSize) +{ + unsigned int data_offset; + unsigned int code_offset; + int scrnIndex=0; + + unsigned int atom_romhdr_off = *(unsigned short*) + (base + OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER); + ATOM_ROM_HEADER *atom_rom_hdr = + (ATOM_ROM_HEADER *)(base + atom_romhdr_off); + + RHDFUNCI(scrnIndex); + + if (atom_romhdr_off + sizeof(ATOM_ROM_HEADER) > BIOSImageSize) { + xf86DrvMsg(scrnIndex,X_ERROR, + "%s: AtomROM header extends beyond BIOS image\n",__func__); + return FALSE; + } + + if (memcmp("ATOM",&atom_rom_hdr->uaFirmWareSignature,4)) { + xf86DrvMsg(scrnIndex,X_ERROR,"%s: No AtomBios signature found\n", + __func__); + return FALSE; + } + xf86DrvMsg(scrnIndex, X_INFO, "ATOM BIOS Rom: \n"); + if (!rhdAtomAnalyzeRomHdr(base, atom_rom_hdr, &data_offset, &code_offset)) { + xf86DrvMsg(scrnIndex, X_ERROR, "RomHeader invalid\n"); + return FALSE; + } + + if (data_offset + sizeof (ATOM_MASTER_DATA_TABLE) > BIOSImageSize) { + xf86DrvMsg(scrnIndex,X_ERROR,"%s: Atom data table outside of BIOS\n", + __func__); + return FALSE; + } + + if (code_offset + sizeof (ATOM_MASTER_COMMAND_TABLE) > BIOSImageSize) { + xf86DrvMsg(scrnIndex, X_ERROR, "%s: Atom command table outside of BIOS\n", + __func__); + (*codeTablePtr) = NULL; + } else + (*codeTablePtr) = base + code_offset; + + if (!rhdAtomAnalyzeMasterDataTable(base, (ATOM_MASTER_DATA_TABLE *) + (base + data_offset), + atomDataPtr)) { + xf86DrvMsg(scrnIndex, X_ERROR, "%s: ROM Master Table invalid\n", + __func__); + return FALSE; + } + + return TRUE; +} + +static Bool +rhdAtomGetFbBaseAndSize(atomBiosHandlePtr handle, unsigned int *base, + unsigned int *size) +{ + AtomBiosArgRec data; + if (RHDAtomBiosFunc(handle->rhdPtr, handle, GET_FW_FB_SIZE, &data) + == ATOM_SUCCESS) { + if (data.val == 0) { + xf86DrvMsg(handle->scrnIndex, X_WARNING, "%s: AtomBIOS specified VRAM " + "scratch space size invalid\n", __func__); + return FALSE; + } + if (size) + *size = (int)data.val; + } else + return FALSE; + if (RHDAtomBiosFunc(handle->rhdPtr, handle, GET_FW_FB_START, &data) + == ATOM_SUCCESS) { + if (data.val == 0) + return FALSE; + if (base) + *base = (int)data.val; + } + return TRUE; +} + +/* + * Uses videoRam form ScrnInfoRec. + */ +static AtomBiosResult +rhdAtomAllocateFbScratch(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + unsigned int fb_base = 0; + unsigned int fb_size = 0; + unsigned int start = data->fb.start; + unsigned int size = data->fb.size; + handle->scratchBase = NULL; + handle->fbBase = 0; + + if (rhdAtomGetFbBaseAndSize(handle, &fb_base, &fb_size)) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "AtomBIOS requests %ikB" + " of VRAM scratch space\n",fb_size); + fb_size *= 1024; /* convert to bytes */ + xf86DrvMsg(handle->scrnIndex, X_INFO, "AtomBIOS VRAM scratch base: 0x%x\n", + fb_base); + } else { + fb_size = 20 * 1024; + xf86DrvMsg(handle->scrnIndex, X_INFO, " default to: %i\n",fb_size); + } + if (fb_base && fb_size && size) { + /* 4k align */ + fb_size = (fb_size & ~(CARD32)0xfff) + ((fb_size & 0xfff) ? 1 : 0); + if ((fb_base + fb_size) > (start + size)) { + xf86DrvMsg(handle->scrnIndex, X_WARNING, + "%s: FW FB scratch area %i (size: %i)" + " extends beyond available framebuffer size %i\n", + __func__, fb_base, fb_size, size); + } else if ((fb_base + fb_size) < (start + size)) { + xf86DrvMsg(handle->scrnIndex, X_WARNING, + "%s: FW FB scratch area not located " + "at the end of VRAM. Scratch End: " + "0x%x VRAM End: 0x%x\n", __func__, + (unsigned int)(fb_base + fb_size), + size); + } else if (fb_base < start) { + xf86DrvMsg(handle->scrnIndex, X_WARNING, + "%s: FW FB scratch area extends below " + "the base of the free VRAM: 0x%x Base: 0x%x\n", + __func__, (unsigned int)(fb_base), start); + } else { + size -= fb_size; + handle->fbBase = fb_base; + return ATOM_SUCCESS; + } + } + + if (!handle->fbBase) { + xf86DrvMsg(handle->scrnIndex, X_INFO, + "Cannot get VRAM scratch space. " + "Allocating in main memory instead\n"); + handle->scratchBase = xcalloc(fb_size,1); + return ATOM_SUCCESS; + } + return ATOM_FAILED; +} + +# ifdef ATOM_BIOS_PARSER +static Bool +rhdAtomASICInit(atomBiosHandlePtr handle) +{ + ASIC_INIT_PS_ALLOCATION asicInit; + AtomBiosArgRec data; + + RHDFUNC(handle); + + RHDAtomBiosFunc(handle->rhdPtr, handle, + GET_DEFAULT_ENGINE_CLOCK, + &data); + asicInit.sASICInitClocks.ulDefaultEngineClock = data.val / 10;/*in 10 Khz*/ + RHDAtomBiosFunc(handle->rhdPtr, handle, + GET_DEFAULT_MEMORY_CLOCK, + &data); + asicInit.sASICInitClocks.ulDefaultMemoryClock = data.val / 10;/*in 10 Khz*/ + data.exec.dataSpace = NULL; + data.exec.index = GetIndexIntoMasterTable(COMMAND, ASIC_Init); + data.exec.pspace = &asicInit; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling ASIC Init\n"); + atomDebugPrintPspace(handle, &data, sizeof(asicInit)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "ASIC_INIT Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "ASIC_INIT Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomASICInitVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, ASIC_Init); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + return version; +} + +/* + * + */ +Bool +rhdAtomSetScaler(atomBiosHandlePtr handle, enum atomScaler scalerID, enum atomScaleMode mode) +{ + ENABLE_SCALER_PARAMETERS scaler; + AtomBiosArgRec data; + + RHDFUNC(handle); + + switch (scalerID) { + case atomScaler1: + scaler.ucScaler = ATOM_SCALER1; + break; + case atomScaler2: + scaler.ucScaler = ATOM_SCALER2; + break; + } + + switch (mode) { + case atomScaleDisable: + scaler.ucEnable = ATOM_SCALER_DISABLE; + break; + case atomScaleCenter: + scaler.ucEnable = ATOM_SCALER_CENTER; + break; + case atomScaleExpand: + scaler.ucEnable = ATOM_SCALER_EXPANSION; + break; + case atomScaleMulttabExpand: + scaler.ucEnable = ATOM_SCALER_MULTI_EX; + break; + } + + data.exec.dataSpace = NULL; + data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + data.exec.pspace = &scaler; + atomDebugPrintPspace(handle, &data, sizeof(scaler)); + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling EnableScaler\n"); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "EnableScaler Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "EnableScaler Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomSetScalerVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + return version; +} + +/* + * + */ +Bool +rhdAtomSetTVEncoder(atomBiosHandlePtr handle, Bool enable, int mode) +{ + TV_ENCODER_CONTROL_PS_ALLOCATION tvEncoder; + AtomBiosArgRec data; + + RHDFUNC(handle); + + tvEncoder.sTVEncoder.ucTvStandard = mode; + tvEncoder.sTVEncoder.ucAction = enable ? 1 :0; + + data.exec.dataSpace = NULL; + data.exec.pspace = &tvEncoder; + data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling SetTVEncoder\n"); + atomDebugPrintPspace(handle, &data, sizeof(tvEncoder)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetTVEncoder Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetTVEncoder Failed\n"); + return FALSE; +} + +/* + * + */ +#if (ATOM_TRANSMITTER_CONFIG_COHERENT != ATOM_TRANSMITTER_CONFIG_V2_COHERENT) +# error +#endif + +Bool +rhdAtomDigTransmitterControl(atomBiosHandlePtr handle, enum atomTransmitter id, + enum atomTransmitterAction action, struct atomTransmitterConfig *config) +{ + DIG_TRANSMITTER_CONTROL_PARAMETERS Transmitter; + AtomBiosArgRec data; + char *name = NULL; + struct atomCodeTableVersion version; + + RHDFUNC(handle); + + switch (action) { + case atomTransDisable: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_DISABLE; + break; + case atomTransEnable: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_ENABLE; + break; + case atomTransEnableOutput: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT; + break; + case atomTransDisableOutput: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT; + break; + case atomTransLcdBlOff: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_LCD_BLOFF; + break; + case atomTransLcdBlOn: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_LCD_BLON; + break; + case atomTransLcdBlBrightness: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL; + break; + case atomTransSetup: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_SETUP; + break; + case atomTransInit: + Transmitter.ucAction = ATOM_TRANSMITTER_ACTION_INIT; + break; + } + + Transmitter.ucConfig = 0; + + /* INIT is only called by ASIC_Init, for our actions this is always the PXLCLK */ + switch (config->LinkCnt) { + case atomSingleLink: + Transmitter.usPixelClock = config->PixelClock * 4 / 10; + break; + + case atomDualLink: + Transmitter.usPixelClock = config->PixelClock * 2/ 10; + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; + break; + } + + if (config->Coherent) + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + + switch (id) { + case atomTransmitterDIG1: + case atomTransmitterUNIPHY: + case atomTransmitterUNIPHY1: + case atomTransmitterUNIPHY2: + case atomTransmitterPCIEPHY: + data.exec.index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + name = "UNIPHYTransmitterControl"; + + rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version.cref, &version.fref, NULL); + + if (version.fref > 1 || version.cref > 2) + return FALSE; + + switch (version.cref) { + case 1: + + switch (config->Link) { + case atomTransLinkA: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + break; + case atomTransLinkAB: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA_B; + break; + case atomTransLinkB: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; + break; + case atomTransLinkBA: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB_A; + break; + } + switch (config->Encoder) { + case atomEncoderDIG1: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + break; + + case atomEncoderDIG2: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s called with invalid encoder %x for DIG transmitter\n", + __func__, config->Encoder); + return FALSE; + } + if (id == atomTransmitterPCIEPHY) { + switch (config->Lanes) { + case atomPCIELaneNONE: + Transmitter.ucConfig |= 0; + break; + case atomPCIELane0_3: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + break; + case atomPCIELane0_7: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + break; + case atomPCIELane4_7: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; + break; + case atomPCIELane8_11: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; + break; + case atomPCIELane8_15: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; + break; + case atomPCIELane12_15: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + break; + } + /* According to ATI this is the only one used so far */ + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + } + break; + case 2: + if (id == atomTransmitterPCIEPHY) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s PCIPHY not valid for DCE 3.2\n", + __func__); + return FALSE; + } + switch (config->Link) { + case atomTransLinkA: + case atomTransLinkAB: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_LINKA; + break; + case atomTransLinkB: + case atomTransLinkBA: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_LINKB; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s called with invalid transmitter link selection %x for DIG transmitter\n", + __func__, config->Link); + return FALSE; + } + switch (config->Encoder) { + case atomEncoderDIG1: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER; + break; + case atomEncoderDIG2: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s called with invalid encoder %x for DIG transmitter\n", + __func__, config->Encoder); + return FALSE; + } + switch (id) { + case atomTransmitterUNIPHY: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1; + break; + case atomTransmitterUNIPHY1: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2; + break; + case atomTransmitterUNIPHY2: + Transmitter.ucConfig |= ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3; + break; + default: + break; + } + + if (config->Mode == atomDP) + Transmitter.ucConfig |= ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR; + break; + } + + break; + + case atomTransmitterLVTMA: + case atomTransmitterDIG2: + data.exec.index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl); + name = "DIG2TransmitterControl"; + break; + } + + data.exec.dataSpace = NULL; + data.exec.pspace = &Transmitter; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling %s\n",name); + atomDebugPrintPspace(handle, &data, sizeof(Transmitter)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "%s Successful\n",name); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "%s Failed\n",name); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomDigTransmitterControlVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + DEBUG_VERSION(index, handle, version); + return version; +} + +/* + * + */ +Bool +rhdAtomOutputControl(atomBiosHandlePtr handle, enum atomOutput OutputId, enum atomOutputAction Action) +{ + AtomBiosArgRec data; + CARD8 version; + char *name; + + union + { + DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS op; + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION opa; + } ps; + + RHDFUNC(handle); + + switch (Action) { + case atomOutputEnable: + ps.op.ucAction = ATOM_ENABLE; + break; + case atomOutputDisable: + ps.op.ucAction = ATOM_DISABLE; + break; + default: /* handle below */ + if (OutputId != atomLCDOutput) + return FALSE; + } + + switch (OutputId) { + case atomDVOOutput: + data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + name = "DVOOutputControl"; + if (!rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version, NULL, NULL)) + return FALSE; + switch (version) { + case 1: + case 2: + break; + case 3: /* For now. This needs to be treated like DIGTransmitterControl. @@@ */ + return FALSE; + } + break; + case atomLCDOutput: + data.exec.index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + name = "LCD1OutputControl"; + switch (Action) { + case atomOutputEnable: + case atomOutputDisable: + break; + case atomOutputLcdOn: + ps.op.ucAction = ATOM_LCD_BLON; + break; + case atomOutputLcdOff: + ps.op.ucAction = ATOM_LCD_BLOFF; + break; + case atomOutputLcdBrightnessControl: + ps.op.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL; + break; + case atomOutputLcdSelftestStart: + ps.op.ucAction = ATOM_LCD_SELFTEST_START; + break; + case atomOutputLcdSelftestStop: + ps.op.ucAction = ATOM_LCD_SELFTEST_STOP; + break; + case atomOutputEncoderInit: + ps.op.ucAction = ATOM_ENCODER_INIT; + break; + default: + return FALSE; + } + break; + case atomCVOutput: + data.exec.index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + name = "CV1OutputControl"; + break; + case atomTVOutput: + name = "TV1OutputControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + break; + case atomLVTMAOutput: + name = "LVTMAOutputControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + switch (Action) { + case atomOutputEnable: + case atomOutputDisable: + break; + case atomOutputLcdOn: + ps.op.ucAction = ATOM_LCD_BLON; + break; + case atomOutputLcdOff: + ps.op.ucAction = ATOM_LCD_BLOFF; + break; + case atomOutputLcdBrightnessControl: + ps.op.ucAction = ATOM_LCD_BL_BRIGHTNESS_CONTROL; + break; + case atomOutputLcdSelftestStart: + ps.op.ucAction = ATOM_LCD_SELFTEST_START; + break; + case atomOutputLcdSelftestStop: + ps.op.ucAction = ATOM_LCD_SELFTEST_STOP; + break; + case atomOutputEncoderInit: + ps.op.ucAction = ATOM_ENCODER_INIT; + break; + default: + return FALSE; + } + break; + case atomTMDSAOutput: + name = "TMDSAOutputControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + break; + case atomDAC1Output: + name = "DAC1OutputControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + break; + case atomDAC2Output: + name = "DAC2OutputControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + break; + default: + return FALSE; + } + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling %s\n",name); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "%s Successful\n",name); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "%s Failed\n",name); + + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomOutputControlVersion(atomBiosHandlePtr handle, enum atomOutput OutputId) +{ + struct atomCodeTableVersion version = {0 , 0}; + int index; + char *name; + + switch (OutputId) { + case atomDVOOutput: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + name = "DVOOutputControl"; + break; + case atomLCDOutput: + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + name = "LCD1OutputControl"; + break; + case atomCVOutput: + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + name = "CV1OutputControl"; + break; + case atomTVOutput: + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + name = "TV1OutputControl"; + break; + case atomLVTMAOutput: + index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + name = "LVTMAOutputControl"; + break; + case atomTMDSAOutput: + index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + name = "TMDSAOutputControl"; + break; + case atomDAC1Output: + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + name = "DAC1OutputControl"; + break; + case atomDAC2Output: + index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + name = "DAC2OutputContro"; + break; + default: + return version; + } + + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + DEBUG_VERSION_NAME(index, handle, name, version); + return version; +} + +/* + * + */ +Bool +AtomDACLoadDetection(atomBiosHandlePtr handle, enum atomDevice Device, enum atomDAC dac) +{ + AtomBiosArgRec data; + union + { + DAC_LOAD_DETECTION_PARAMETERS ld; + DAC_LOAD_DETECTION_PS_ALLOCATION lda; + } ps; + + RHDFUNC(handle); + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + ps.ld.ucMisc = 0; + + switch (Device) { + case atomCRT1: + ps.ld.usDeviceID = ATOM_DEVICE_CRT1_SUPPORT; + break; + case atomCRT2: + ps.ld.usDeviceID = ATOM_DEVICE_CRT2_SUPPORT; + break; + case atomTV1: + ps.ld.usDeviceID = ATOM_DEVICE_TV1_SUPPORT; + ps.ld.ucMisc = DAC_LOAD_MISC_YPrPb; + break; + case atomTV2: + ps.ld.usDeviceID = ATOM_DEVICE_TV2_SUPPORT; + ps.ld.ucMisc = DAC_LOAD_MISC_YPrPb; + break; + case atomCV: + ps.ld.usDeviceID = ATOM_DEVICE_CV_SUPPORT; + break; + case atomLCD1: + case atomDFP1: + case atomLCD2: + case atomDFP2: + case atomDFP3: + case atomDFP4: + case atomDFP5: + case atomNone: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "Unsupported device for load detection.\n"); + return FALSE; + } + switch (dac) { + case atomDACA: + ps.ld.ucDacType = ATOM_DAC_A; + break; + case atomDACB: + ps.ld.ucDacType = ATOM_DAC_B; + break; + case atomDACExt: + ps.ld.ucDacType = ATOM_EXT_DAC; + break; + } + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling DAC_LoadDetection\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "DAC_LoadDetection Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "DAC_LoadDetection Failed\n"); + + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +AtomDACLoadDetectionVersion(atomBiosHandlePtr handle, enum atomDevice id) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + + return version; +} + +/* + * + */ +Bool +rhdAtomEncoderControl(atomBiosHandlePtr handle, enum atomEncoder EncoderId, + enum atomEncoderAction Action, struct atomEncoderConfig *Config) +{ + AtomBiosArgRec data; + char *name = NULL; + CARD8 version; + + union + { + DAC_ENCODER_CONTROL_PARAMETERS dac; + DAC_ENCODER_CONTROL_PS_ALLOCATION dac_a; + TV_ENCODER_CONTROL_PARAMETERS tv; + TV_ENCODER_CONTROL_PS_ALLOCATION tv_a; + LVDS_ENCODER_CONTROL_PARAMETERS lvds; + LVDS_ENCODER_CONTROL_PS_ALLOCATION lvds_a; + DIG_ENCODER_CONTROL_PARAMETERS dig; + DIG_ENCODER_CONTROL_PS_ALLOCATION dig_a; + EXTERNAL_ENCODER_CONTROL_PARAMETER ext; + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION ext_a; + DVO_ENCODER_CONTROL_PARAMETERS dvo; + DVO_ENCODER_CONTROL_PS_ALLOCATION dvo_a; + DVO_ENCODER_CONTROL_PARAMETERS_V3 dvo_v3; + DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3_a; + LVDS_ENCODER_CONTROL_PARAMETERS_V2 lvdsv2; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 lvds2_a; + USHORT usPixelClock; + } ps; + + RHDFUNC(handle); + + ps.usPixelClock = Config->PixelClock / 10; + + switch (EncoderId) { + case atomEncoderDACA: + case atomEncoderDACB: + if (EncoderId == atomEncoderDACA) { + name = "DACAEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + } else { + name = "DACBEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + } + { + DAC_ENCODER_CONTROL_PARAMETERS *dac = &ps.dac; + switch (Config->u.dac.DacStandard) { + case atomDAC_VGA: + dac->ucDacStandard = ATOM_DAC1_PS2; + break; + case atomDAC_CV: + dac->ucDacStandard = ATOM_DAC1_CV; + break; + case atomDAC_NTSC: + dac->ucDacStandard = ATOM_DAC1_NTSC; + break; + case atomDAC_PAL: + dac->ucDacStandard = ATOM_DAC1_PAL; + break; + } + switch (Action) { + case atomEncoderOn: + dac->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + dac->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: DAC unknown action\n",__func__); + return FALSE; + } + } + break; + case atomEncoderTV: + data.exec.index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + name = "TVAEncoderControl"; + { + TV_ENCODER_CONTROL_PARAMETERS *tv = &ps.tv; + switch (Config->u.tv.TvStandard) { + case RHD_TV_NTSC: + tv->ucTvStandard = ATOM_TV_NTSC; + break; + case RHD_TV_NTSCJ: + tv->ucTvStandard = ATOM_TV_NTSCJ; + break; + case RHD_TV_PAL: + tv->ucTvStandard = ATOM_TV_PAL; + break; + case RHD_TV_PALM: + tv->ucTvStandard = ATOM_TV_PALM; + break; + case RHD_TV_PALCN: + tv->ucTvStandard = ATOM_TV_PALCN; + break; + case RHD_TV_PALN: + tv->ucTvStandard = ATOM_TV_PALN; + break; + case RHD_TV_PAL60: + tv->ucTvStandard = ATOM_TV_PAL60; + break; + case RHD_TV_SECAM: + tv->ucTvStandard = ATOM_TV_SECAM; + break; + case RHD_TV_CV: + tv->ucTvStandard = ATOM_TV_CV; + break; + case RHD_TV_NONE: + return FALSE; + } + switch (Action) { + case atomEncoderOn: + tv->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + tv->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: TV unknown action\n",__func__); + return FALSE; + } + } + break; + case atomEncoderTMDS1: + case atomEncoderTMDS2: + case atomEncoderLVDS: + if (EncoderId == atomEncoderLVDS) { + name = "LVDSEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + } else if (EncoderId == atomEncoderTMDS1) { + name = "TMDSAEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, TMDSAEncoderControl); + } else { + name = "LVTMAEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, LVTMAEncoderControl); + } + if (!rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version, NULL, NULL)) + return FALSE; + switch (version) { + case 1: + { + LVDS_ENCODER_CONTROL_PARAMETERS *lvds = &ps.lvds; + lvds->ucMisc = 0; + if (Config->u.lvds.LinkCnt == atomDualLink) + lvds->ucMisc |= 0x1; + if (Config->u.lvds.Is24bit) + lvds->ucMisc |= 0x1 << 1; + + switch (Action) { + case atomEncoderOn: + lvds->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + lvds->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: LVDS unknown action\n",__func__); + return FALSE; + } + break; + } + case 2: + case 3: + { + LVDS_ENCODER_CONTROL_PARAMETERS_V2 *lvds = &ps.lvdsv2; + + lvds->ucMisc = 0; + if (Config->u.lvds2.LinkCnt == atomDualLink) + lvds->ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (Config->u.lvds2.Coherent) + lvds->ucMisc |= PANEL_ENCODER_MISC_COHERENT; + if (Config->u.lvds2.LinkB) + lvds->ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (Config->u.lvds2.Hdmi) + lvds->ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + lvds->ucTruncate = 0; + lvds->ucSpatial = 0; + lvds->ucTemporal = 0; + lvds->ucFRC = 0; + + if (EncoderId == atomEncoderLVDS) { + if (Config->u.lvds2.Is24bit) { + lvds->ucTruncate |= PANEL_ENCODER_TRUNCATE_DEPTH; + lvds->ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + lvds->ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + } + switch (Config->u.lvds2.TemporalGrey) { + case atomTemporalDither0: + break; + case atomTemporalDither4: + lvds->ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; + case atomTemporalDither2: + lvds->ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_EN; + break; + } + switch (Config->u.lvds2.SpatialDither) + lvds->ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_EN; + } + + switch (Action) { + case atomEncoderOn: + lvds->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + lvds->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: LVDS2 unknown action\n",__func__); + return FALSE; + } + break; + } + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: LVDS unknown version\n",__func__); + return FALSE; + } + break; + case atomEncoderDIG1: + case atomEncoderDIG2: + case atomEncoderExternal: + { + DIG_ENCODER_CONTROL_PARAMETERS *dig = &ps.dig; + struct atomCodeTableVersion version; + + if (EncoderId == atomEncoderDIG1) { + name = "DIG1EncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + } else if (EncoderId == atomEncoderDIG2) { + name = "DIG2EncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + } else { + name = "ExternalEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + } + rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version.cref, &version.fref, NULL); + if (version.fref > 1 || version.cref > 2) + return FALSE; + + dig->ucConfig = 0; + switch (version.cref) { + case 1: + switch (Config->u.dig.Link) { + case atomTransLinkA: + dig->ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + break; + case atomTransLinkAB: + dig->ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B; + break; + case atomTransLinkB: + dig->ucConfig |= ATOM_ENCODER_CONFIG_LINKB; + break; + case atomTransLinkBA: + dig->ucConfig |= ATOM_ENCODER_CONFIG_LINKB_A; + break; + } + + if (EncoderId != atomEncoderExternal) { + switch (Config->u.dig.Transmitter) { + case atomTransmitterUNIPHY: + case atomTransmitterPCIEPHY: + case atomTransmitterDIG1: + dig->ucConfig |= ATOM_ENCODER_CONFIG_UNIPHY; + break; + case atomTransmitterLVTMA: + case atomTransmitterDIG2: + dig->ucConfig |= ATOM_ENCODER_CONFIG_LVTMA; + break; + /* + * these are not DCE3.0 but we need them here as DIGxEncoderControl tables for + * DCE3.2 still report cref 1. + */ + case atomTransmitterUNIPHY1: + dig->ucConfig |= ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; + break; + case atomTransmitterUNIPHY2: + dig->ucConfig |= ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: Invalid Transmitter for DCE3.0: %x\n", + __func__, Config->u.dig.Transmitter); + return FALSE; + } + } + break; + + case 2: + switch (Config->u.dig.Link) { + case atomTransLinkA: + case atomTransLinkAB: + dig->ucConfig |= ATOM_ENCODER_CONFIG_V2_LINKA; + break; + case atomTransLinkB: + case atomTransLinkBA: + dig->ucConfig |= ATOM_ENCODER_CONFIG_V2_LINKB; + break; + } + switch (Config->u.dig.Transmitter) { + case atomTransmitterUNIPHY: + dig->ucConfig |= ATOM_ENCODER_CONFIG_UNIPHY; + break; + case atomTransmitterUNIPHY1: + dig->ucConfig |= ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; + break; + case atomTransmitterUNIPHY2: + dig->ucConfig |= ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: Invalid Encoder for DCE3.2: %x\n", + __func__, Config->u.dig.Transmitter); + return FALSE; + } + break; + + default: + return FALSE; + } + + switch (Config->u.dig.EncoderMode) { + case atomDVI: + dig->ucEncoderMode = ATOM_ENCODER_MODE_DVI; + break; + case atomDP: + dig->ucEncoderMode = ATOM_ENCODER_MODE_DP; + break; + case atomLVDS: + dig->ucEncoderMode = ATOM_ENCODER_MODE_LVDS; + break; + case atomHDMI: + dig->ucEncoderMode = ATOM_ENCODER_MODE_HDMI; + break; + case atomSDVO: + dig->ucEncoderMode = ATOM_ENCODER_MODE_SDVO; + break; + case atomNoEncoder: + case atomTVComposite: + case atomTVSVideo: + case atomTVComponent: + case atomCRT: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s called with invalid DIG encoder mode %i\n", + __func__,Config->u.dig.EncoderMode); + return FALSE; + break; + } + + switch (Action) { + case atomEncoderOn: + dig->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + dig->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: DIG unknown action\n",__func__); + return FALSE; + } + + switch (Config->u.dig.LinkCnt) { + case atomSingleLink: + dig->ucLaneNum = 4; + break; + case atomDualLink: + dig->ucLaneNum = 8; + break; + } + break; + case atomEncoderDVO: + name = "DVOEncoderControl"; + data.exec.index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + if (!rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version.cref, NULL, NULL)) + return FALSE; + switch (version.cref) { + case 1: + case 2: + { + DVO_ENCODER_CONTROL_PARAMETERS *dvo = &ps.dvo; + dvo->usEncoderID = Config->u.dvo.EncoderID; + switch (Config->u.dvo.DvoDeviceType) { + case atomLCD1: + case atomLCD2: + dvo->ucDeviceType = ATOM_DEVICE_LCD1_INDEX; + break; + case atomCRT1: + case atomCRT2: + dvo->ucDeviceType = ATOM_DEVICE_CRT1_INDEX; + break; + case atomDFP1: + case atomDFP2: + case atomDFP3: + case atomDFP4: + case atomDFP5: + dvo->ucDeviceType = ATOM_DEVICE_DFP1_INDEX; + break; + case atomTV1: + case atomTV2: + dvo->ucDeviceType = ATOM_DEVICE_TV1_INDEX; + break; + case atomCV: + dvo->ucDeviceType = ATOM_DEVICE_CV_INDEX; + break; + case atomNone: + return FALSE; + } + if (Config->u.dvo.digital) { + dvo->usDevAttr.sDigAttrib.ucAttribute = 0; /* @@@ What do these attributes mean? */ + } else { + switch (Config->u.dvo.u.TVMode) { + case RHD_TV_NTSC: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_NTSC; + break; + case RHD_TV_NTSCJ: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_NTSCJ; + break; + case RHD_TV_PAL: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_PAL; + break; + case RHD_TV_PALM: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_PALM; + break; + case RHD_TV_PALCN: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_PALCN; + break; + case RHD_TV_PALN: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_PALN; + break; + case RHD_TV_PAL60: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_PAL60; + break; + case RHD_TV_SECAM: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_SECAM; + break; + case RHD_TV_CV: + dvo->usDevAttr.sAlgAttrib.ucTVStandard = ATOM_TV_CV; + break; + case RHD_TV_NONE: + return FALSE; + } + } + switch (Action) { + case atomEncoderOn: + dvo->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + dvo->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: DVO unknown action\n",__func__); + return FALSE; + } + break; + } + case 3: + { + DVO_ENCODER_CONTROL_PARAMETERS_V3 *dvo = &ps.dvo_v3; + dvo->ucDVOConfig = 0; + if (Config->u.dvo3.Rate == atomDVO_RateSDR) + dvo->ucDVOConfig |= DVO_ENCODER_CONFIG_SDR_SPEED; + else + dvo->ucDVOConfig |= DVO_ENCODER_CONFIG_DDR_SPEED; + switch (Config->u.dvo3.DvoOutput) { + case atomDVO_OutputLow12Bit: + dvo->ucDVOConfig = DVO_ENCODER_CONFIG_LOW12BIT; + break; + case atomDVO_OutputHigh12Bit: + dvo->ucDVOConfig = DVO_ENCODER_CONFIG_UPPER12BIT; + break; + case atomDVO_Output24Bit: + dvo->ucDVOConfig = DVO_ENCODER_CONFIG_24BIT; + break; + } + switch (Action) { + case atomEncoderOn: + dvo->ucAction = ATOM_ENABLE; + break; + case atomEncoderOff: + dvo->ucAction = ATOM_DISABLE; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: DVO3 unknown action\n",__func__); + return FALSE; + } + break; + } + } + break; + } + case atomEncoderNone: + return FALSE; + } + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling %s\n",name); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "%s Successful\n",name); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "%s Failed\n",name); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomEncoderControlVersion(atomBiosHandlePtr handle, enum atomEncoder EncoderId) +{ + struct atomCodeTableVersion version = { 0, 0 }; + int index; + char *name; + + switch (EncoderId) { + case atomEncoderDACA: + index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + name = "DAC1EncoderControl"; + break; + case atomEncoderDACB: + index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + name = "DAC2EncoderControl"; + break; + case atomEncoderTV: + index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + name = "TVEncoderControl"; + break; + case atomEncoderTMDS1: + case atomEncoderTMDS2: + index = GetIndexIntoMasterTable(COMMAND, TMDSAEncoderControl); + name = "TMDSAEncoderControl"; + break; + case atomEncoderLVDS: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + name = " LVDSEncoderControl"; + break; + case atomEncoderDIG1: + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + name = "DIG1EncoderControl"; + break; + case atomEncoderDIG2: + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + name = "DIG2EncoderControl"; + break; + case atomEncoderExternal: + index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + name = "ExternalEncoderControl"; + break; + case atomEncoderDVO: + index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + name = "DVOEncoderControl"; + break; + default: + return version; + } + + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION_NAME(index, handle, name, version); + + return version; +} + +/* + * + */ +Bool +rhdAtomUpdateCRTC_DoubleBufferRegisters(atomBiosHandlePtr handle, enum atomCrtc CrtcId, + enum atomCrtcAction Action) +{ + AtomBiosArgRec data; + union + { + ENABLE_CRTC_PARAMETERS crtc; + ENABLE_CRTC_PS_ALLOCATION crtc_a; + } ps; + + RHDFUNC(handle); + + switch (CrtcId) { + case atomCrtc1: + ps.crtc.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.crtc.ucCRTC = ATOM_CRTC2; + break; + } + + switch (Action) { + case atomCrtcEnable: + ps.crtc.ucEnable = ATOM_ENABLE; + break; + case atomCrtcDisable: + ps.crtc.ucEnable = ATOM_DISABLE; + break; + } + + data.exec.index = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling UpdateCRTC_DoubleBufferRegisters\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "UpdateCRTC_DoubleBufferRegisters Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "UpdateCRTC_DoubleBufferRegisters Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomUpdateCRTC_DoubleBufferRegistersVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + + return version; +} + +/* + * + */ +Bool +rhdAtomEnableCrtc(atomBiosHandlePtr handle, enum atomCrtc CrtcId, + enum atomCrtcAction Action) +{ + AtomBiosArgRec data; + union + { + ENABLE_CRTC_PARAMETERS crtc; + ENABLE_CRTC_PS_ALLOCATION crtc_a; + } ps; + + RHDFUNC(handle); + + switch (CrtcId) { + case atomCrtc1: + ps.crtc.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.crtc.ucCRTC = ATOM_CRTC2; + break; + } + + switch (Action) { + case atomCrtcEnable: + ps.crtc.ucEnable = ATOM_ENABLE; + break; + case atomCrtcDisable: + ps.crtc.ucEnable = ATOM_DISABLE; + break; + } + + data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling EnableCRTC\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "EnableCRTC Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "EnableCRTC Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomEnableCrtcVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + + return version; +} + +/* + * + */ +Bool +rhdAtomEnableCrtcMemReq(atomBiosHandlePtr handle, enum atomCrtc CrtcId, + enum atomCrtcAction Action) +{ + AtomBiosArgRec data; + union + { + ENABLE_CRTC_PARAMETERS crtc; + ENABLE_CRTC_PS_ALLOCATION crtc_a; + } ps; + + RHDFUNC(handle); + + switch (CrtcId) { + case atomCrtc1: + ps.crtc.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.crtc.ucCRTC = ATOM_CRTC2; + break; + } + + switch (Action) { + case atomCrtcEnable: + ps.crtc.ucEnable = ATOM_ENABLE; + break; + case atomCrtcDisable: + ps.crtc.ucEnable = ATOM_DISABLE; + break; + } + + data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling EnableCRTCMemReq\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "EnableCRTCMemReq Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "EnableCRTCMemReq Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomEnableCrtcMemReqVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + + return version; + +} + +/* + * + */ +Bool +rhdAtomSetCRTCTimings(atomBiosHandlePtr handle, enum atomCrtc id, DisplayModePtr mode, int depth) +{ + AtomBiosArgRec data; + union + { + SET_CRTC_TIMING_PARAMETERS crtc; +/* SET_CRTC_TIMING_PS_ALLOCATION crtc_a; */ + } ps; + ATOM_MODE_MISC_INFO_ACCESS* msc = &(ps.crtc.susModeMiscInfo); + + RHDFUNC(handle); + + ps.crtc.usH_Total = mode->CrtcHTotal; + ps.crtc.usH_Disp = mode->CrtcHDisplay; + ps.crtc.usH_SyncStart = mode->CrtcHSyncStart; + ps.crtc.usH_SyncWidth = mode->CrtcHSyncEnd - mode->CrtcHSyncStart; + ps.crtc.usV_Total = mode->CrtcVTotal; + ps.crtc.usV_Disp = mode->CrtcVDisplay; + ps.crtc.usV_SyncStart = mode->CrtcVSyncStart; + ps.crtc.usV_SyncWidth = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + ps.crtc.ucOverscanRight = mode->CrtcHBlankStart - mode->CrtcHDisplay; + ps.crtc.ucOverscanLeft = mode->CrtcVTotal - mode->CrtcVBlankEnd; + ps.crtc.ucOverscanBottom = mode->CrtcVBlankStart - mode->CrtcVDisplay; + ps.crtc.ucOverscanTop = mode->CrtcVTotal - mode->CrtcVBlankEnd; + switch (id) { + case atomCrtc1: + ps.crtc.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.crtc.ucCRTC = ATOM_CRTC2; + break; + } + + msc->sbfAccess.HorizontalCutOff = 0; + msc->sbfAccess.HSyncPolarity = (mode->Flags & V_NHSYNC) ? 1 : 0; + msc->sbfAccess.VSyncPolarity = (mode->Flags & V_NVSYNC) ? 1 : 0; + msc->sbfAccess.VerticalCutOff = 0; + msc->sbfAccess.H_ReplicationBy2 = 0; + msc->sbfAccess.V_ReplicationBy2 = (mode->Flags & V_DBLSCAN) ? 1 : 0; + msc->sbfAccess.CompositeSync = (mode->Flags & V_CSYNC); + msc->sbfAccess.Interlace = (mode->Flags & V_INTERLACE) ? 1 : 0; + msc->sbfAccess.DoubleClock = (mode->Flags & V_DBLCLK) ? 1 : 0; + msc->sbfAccess.RGB888 = (depth == 24) ? 1 : 0; + + data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling SetCRTC_Timing\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetCRTC_Timing Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetCRTC_Timing Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomSetCRTCTimingsVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + return version; + +} + +/* + * + */ +Bool +rhdAtomSetCRTCOverscan(atomBiosHandlePtr handle, enum atomCrtc id, struct atomCrtcOverscan *config) +{ + AtomBiosArgRec data; + union + { + SET_CRTC_OVERSCAN_PARAMETERS ovscn; + SET_CRTC_OVERSCAN_PS_ALLOCATION ovscn_a; + } ps; + + RHDFUNC(handle); + + data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + switch(id) { + case atomCrtc1: + ps.ovscn.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.ovscn.ucCRTC = ATOM_CRTC2; + break; + } + ps.ovscn.usOverscanRight = config->ovscnRight; + ps.ovscn.usOverscanLeft = config->ovscnLeft; + ps.ovscn.usOverscanBottom = config->ovscnBottom; + ps.ovscn.usOverscanTop = config->ovscnTop; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "CallingSetCRTC_OverScan\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "Set CRTC_OverScan Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetCRTC_OverScan Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomSetCRTCOverscanVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + return version; +} + +/* + * + */ +Bool +rhdAtomBlankCRTC(atomBiosHandlePtr handle, enum atomCrtc id, struct atomCrtcBlank *config) +{ + AtomBiosArgRec data; + union + { + BLANK_CRTC_PARAMETERS blank; + BLANK_CRTC_PS_ALLOCATION blank_a; + } ps; + + RHDFUNC(handle); + + data.exec.index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); + data.exec.pspace = &ps; + data.exec.dataSpace = NULL; + + switch(id) { + case atomCrtc1: + ps.blank.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.blank.ucCRTC = ATOM_CRTC2; + break; + } + + switch (config->Action) { + case atomBlankOn: + ps.blank.ucBlanking = ATOM_BLANKING; + break; + case atomBlankOff: + ps.blank.ucBlanking = ATOM_BLANKING_OFF; + break; + } + ps.blank.usBlackColorRCr = config->r; + ps.blank.usBlackColorGY = config->g; + ps.blank.usBlackColorBCb = config->b; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling BlankCRTC\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "BlankCRTC Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "BlankCRTC Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomBlankCRTCVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + return version; +} + +/* + * + */ +static int +atomGetDevice(atomBiosHandlePtr handle, enum atomDevice Device) +{ + switch (Device) { + case atomCRT1: + return ATOM_DEVICE_CRT1_INDEX; + case atomLCD1: + return ATOM_DEVICE_LCD1_INDEX; + case atomTV1: + return ATOM_DEVICE_TV1_INDEX; + case atomDFP1: + return ATOM_DEVICE_DFP1_INDEX; + case atomCRT2: + return ATOM_DEVICE_CRT2_INDEX; + case atomLCD2: + return ATOM_DEVICE_LCD2_INDEX; + case atomTV2: + return ATOM_DEVICE_TV2_INDEX; + case atomDFP2: + return ATOM_DEVICE_DFP2_INDEX; + case atomCV: + return ATOM_DEVICE_CV_INDEX; + case atomDFP3: + return ATOM_DEVICE_DFP3_INDEX; + case atomDFP4: + return ATOM_DEVICE_DFP4_INDEX; + case atomDFP5: + return ATOM_DEVICE_DFP5_INDEX; + case atomNone: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "Invalid Device\n"); + return ATOM_MAX_SUPPORTED_DEVICE; + } + + return ATOM_MAX_SUPPORTED_DEVICE; +} + +/* + * + */ +Bool +rhdAtomSetPixelClock(atomBiosHandlePtr handle, enum atomPxclk PCLKId, struct atomPixelClockConfig *Config) +{ + AtomBiosArgRec data; + CARD8 version; + Bool NeedMode = FALSE; + union { + PIXEL_CLOCK_PARAMETERS pclk; + PIXEL_CLOCK_PARAMETERS_V2 pclk_v2; + PIXEL_CLOCK_PARAMETERS_V3 pclk_v3; + SET_PIXEL_CLOCK_PS_ALLOCATION pclk_a; + } ps; + + data.exec.index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + + if (!rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version, NULL, NULL)) + return FALSE; + switch (version) { + case 1: + if (Config->Enable) + ps.pclk.usPixelClock = Config->PixelClock / 10; + else + ps.pclk.usPixelClock = 0; + ps.pclk.usRefDiv = Config->RefDiv; + ps.pclk.usFbDiv = Config->FbDiv; + ps.pclk.ucPostDiv = Config->PostDiv; + ps.pclk.ucFracFbDiv = Config->FracFbDiv; + ps.pclk.ucRefDivSrc = 0; /* What's this? @@@ */ + switch (PCLKId) { + case atomPclk1: + ps.pclk.ucPpll = ATOM_PPLL1; + break; + case atomPclk2: + ps.pclk.ucPpll = ATOM_PPLL2; + break; + } + switch (Config->Crtc) { + case atomCrtc1: + ps.pclk.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.pclk.ucCRTC = ATOM_CRTC2; + break; + } + break; + case 2: + if (Config->Enable) + ps.pclk_v2.usPixelClock = Config->PixelClock / 10; + else + ps.pclk_v2.usPixelClock = 0; + ps.pclk_v2.usRefDiv = Config->RefDiv; + ps.pclk_v2.usFbDiv = Config->FbDiv; + ps.pclk_v2.ucPostDiv = Config->PostDiv; + ps.pclk_v2.ucFracFbDiv = Config->FracFbDiv; + switch (PCLKId) { + case atomPclk1: + ps.pclk_v2.ucPpll = ATOM_PPLL1; + break; + case atomPclk2: + ps.pclk_v2.ucPpll = ATOM_PPLL2; + break; + } + ps.pclk_v2.ucRefDivSrc = 1; /* See above... @@@ */ + switch (Config->Crtc) { + case atomCrtc1: + ps.pclk_v2.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.pclk_v2.ucCRTC = ATOM_CRTC2; + break; + } + ASSERTF((!Config->Enable || Config->u.v2.Device != atomNone), "Invalid Device Id\n"); + ps.pclk_v2.ucMiscInfo = 0; + ps.pclk_v2.ucMiscInfo |= (Config->u.v2.Force ? MISC_FORCE_REPROG_PIXEL_CLOCK : 0); + if (Config->u.v2.Device != atomNone) + ps.pclk_v2.ucMiscInfo |= (atomGetDevice(handle, Config->u.v2.Device) + << MISC_DEVICE_INDEX_SHIFT); + RHDDebug(handle->scrnIndex,"%s Device: %i PixelClock: %i RefDiv: 0x%x FbDiv: 0x%x PostDiv: 0x%x " + "PLL: %i Crtc: %i MiscInfo: 0x%x\n", + __func__, + Config->u.v2.Device, + ps.pclk_v2.usPixelClock, + ps.pclk_v2.usRefDiv, + ps.pclk_v2.usFbDiv, + ps.pclk_v2.ucPostDiv, + ps.pclk_v2.ucPpll, + ps.pclk_v2.ucCRTC, + ps.pclk_v2.ucMiscInfo + ); + break; + case 3: + if (Config->Enable) + ps.pclk_v3.usPixelClock = Config->PixelClock / 10; + else + ps.pclk.usPixelClock = 0; + ps.pclk_v3.usRefDiv = Config->RefDiv; + ps.pclk_v3.usFbDiv = Config->FbDiv; + ps.pclk_v3.ucPostDiv = Config->PostDiv; + ps.pclk_v3.ucFracFbDiv = Config->FracFbDiv; + switch (PCLKId) { + case atomPclk1: + ps.pclk_v3.ucPpll = ATOM_PPLL1; + break; + case atomPclk2: + ps.pclk_v3.ucPpll = ATOM_PPLL2; + break; + } + switch (Config->u.v3.OutputType) { + case atomOutputKldskpLvtma: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA; + NeedMode = TRUE; + break; + case atomOutputUniphyA: + case atomOutputUniphyB: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_UNIPHY; + NeedMode = TRUE; + break; + case atomOutputUniphyC: + case atomOutputUniphyD: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_UNIPHY1; + NeedMode = TRUE; + break; + case atomOutputUniphyE: + case atomOutputUniphyF: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_UNIPHY2; + NeedMode = TRUE; + break; + + case atomOutputDacA: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1; + break; + case atomOutputDacB: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2; + break; + case atomOutputDvo: + ps.pclk_v3.ucTransmitterId = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1; + NeedMode = TRUE; + break; + case atomOutputTmdsa: + case atomOutputLvtma: + case atomOutputNone: + return FALSE; + } + if (NeedMode) { + switch (Config->u.v3.EncoderMode) { + case atomNoEncoder: + ps.pclk_v3.ucEncoderMode = 0; + case atomDVI: + ps.pclk_v3.ucEncoderMode = ATOM_ENCODER_MODE_DVI; + break; + case atomDP: + ps.pclk_v3.ucEncoderMode = ATOM_ENCODER_MODE_DP; + break; + case atomLVDS: + ps.pclk_v3.ucEncoderMode = ATOM_ENCODER_MODE_LVDS; + break; + case atomHDMI: + ps.pclk_v3.ucEncoderMode = ATOM_ENCODER_MODE_HDMI; + break; + case atomSDVO: + ps.pclk_v3.ucEncoderMode = ATOM_ENCODER_MODE_SDVO; + break; + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR,"%s: invalid encoder type.\n",__func__); + return FALSE; + } + } + ps.pclk_v3.ucMiscInfo = (Config->u.v3.Force ? PIXEL_CLOCK_MISC_FORCE_PROG_PPLL : 0x0) + | (Config->u.v3.UsePpll ? PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK : 0x0) + | ((Config->Crtc == atomCrtc2) ? PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2 : PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1); + + RHDDebug(handle->scrnIndex,"%s PixelClock: %i RefDiv: 0x%x FbDiv: 0x%x PostDiv: 0x%x PLL: %i OutputType: %x " + "EncoderMode: %x MiscInfo: 0x%x\n", + __func__, + ps.pclk_v3.usPixelClock, + ps.pclk_v3.usRefDiv, + ps.pclk_v3.usFbDiv, + ps.pclk_v3.ucPostDiv, + ps.pclk_v3.ucPpll, + ps.pclk_v3.ucTransmitterId, + ps.pclk_v3.ucEncoderMode, + ps.pclk_v3.ucMiscInfo + ); + break; + default: + return FALSE; + } + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling SetPixelClock\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetPixelClock Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "SetPixelClock Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomSetPixelClockVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + + DEBUG_VERSION(index, handle, version); + + return version; + +} + +/* + * + */ +Bool +rhdAtomSelectCrtcSource(atomBiosHandlePtr handle, enum atomCrtc CrtcId, + struct atomCrtcSourceConfig *config) +{ + AtomBiosArgRec data; + CARD8 version; + Bool NeedMode = FALSE; + + union + { + SELECT_CRTC_SOURCE_PARAMETERS crtc; + SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_a; + SELECT_CRTC_SOURCE_PARAMETERS_V2 crtc2; +/* SELECT_CRTC_SOURCE_PS_ALLOCATION_V2 crtc2_a; */ + } ps; + + RHDFUNC(handle); + + data.exec.index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + + if (!rhdAtomGetCommandTableRevisionSize(handle, data.exec.index, &version, NULL, NULL)) + return FALSE; + + switch (version) { + case 1: + switch (CrtcId) { + case atomCrtc1: + ps.crtc.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.crtc.ucCRTC = ATOM_CRTC2; + break; + } + switch (config->u.Device) { + case atomCRT1: + ps.crtc.ucDevice = ATOM_DEVICE_CRT1_INDEX; + break; + case atomLCD1: + ps.crtc.ucDevice = ATOM_DEVICE_LCD1_INDEX; + break; + case atomTV1: + ps.crtc.ucDevice = ATOM_DEVICE_TV1_INDEX; + break; + case atomDFP1: + ps.crtc.ucDevice = ATOM_DEVICE_DFP1_INDEX; + break; + case atomCRT2: + ps.crtc.ucDevice = ATOM_DEVICE_CRT2_INDEX; + break; + case atomLCD2: + ps.crtc.ucDevice = ATOM_DEVICE_LCD2_INDEX; + break; + case atomTV2: + ps.crtc.ucDevice = ATOM_DEVICE_TV2_INDEX; + break; + case atomDFP2: + ps.crtc.ucDevice = ATOM_DEVICE_DFP2_INDEX; + break; + case atomCV: + ps.crtc.ucDevice = ATOM_DEVICE_CV_INDEX; + break; + case atomDFP3: + ps.crtc.ucDevice = ATOM_DEVICE_DFP3_INDEX; + break; + case atomDFP4: + ps.crtc.ucDevice = ATOM_DEVICE_DFP4_INDEX; + break; + case atomDFP5: + ps.crtc.ucDevice = ATOM_DEVICE_DFP5_INDEX; + break; + case atomNone: + return FALSE; + } + break; + case 2: + switch (CrtcId) { + case atomCrtc1: + ps.crtc2.ucCRTC = ATOM_CRTC1; + break; + case atomCrtc2: + ps.crtc2.ucCRTC = ATOM_CRTC2; + break; + } + switch (config->u.crtc2.Encoder) { + case atomEncoderDACA: + ps.crtc2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; + break; + case atomEncoderDACB: + ps.crtc2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; + break; + case atomEncoderTV: + ps.crtc2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + break; + case atomEncoderDVO: + ps.crtc2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; + NeedMode = TRUE; + break; + case atomEncoderDIG1: + ps.crtc2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + NeedMode = TRUE; + break; + + case atomEncoderDIG2: + ps.crtc2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case atomEncoderExternal: + ps.crtc2.ucEncoderID = ASIC_EXT_DIG_ENCODER_ID; + break; + case atomEncoderTMDS1: + case atomEncoderTMDS2: + case atomEncoderLVDS: + case atomEncoderNone: + return FALSE; + } + if (NeedMode) { + switch (config->u.crtc2.Mode) { + case atomDVI: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_DVI; + break; + case atomDP: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_DP; + break; + case atomLVDS: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; + break; + case atomHDMI: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_HDMI; + break; + case atomSDVO: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_SDVO; + break; + case atomTVComposite: + case atomTVSVideo: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_TV; + break; + case atomTVComponent: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_CV; + break; + case atomCRT: + ps.crtc2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; + break; + case atomNoEncoder: + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: invalid encoder type.\n",__func__); + return FALSE; + } + } + break; + } + + data.exec.dataSpace = NULL; + data.exec.pspace = &ps; + + xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling SelectCRTCSource\n"); + atomDebugPrintPspace(handle, &data, sizeof(ps)); + if (RHDAtomBiosFunc(handle->rhdPtr, handle, + ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + xf86DrvMsg(handle->scrnIndex, X_INFO, "SelectCRTCSource Successful\n"); + return TRUE; + } + xf86DrvMsg(handle->scrnIndex, X_INFO, "SelectCRTCSource Failed\n"); + return FALSE; +} + +/* + * + */ +struct atomCodeTableVersion +rhdAtomSelectCrtcSourceVersion(atomBiosHandlePtr handle) +{ + struct atomCodeTableVersion version; + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + rhdAtomGetCommandTableRevisionSize(handle, index, &version.cref, &version.fref, NULL); + DEBUG_VERSION(index, handle, version); + return version; +} + + +# endif /* ATOM_BIOS_PARSER */ + + +static AtomBiosResult +rhdAtomInit(atomBiosHandlePtr unused1, AtomBiosRequestID unused2, + AtomBiosArgPtr data) +{ + int scrnIndex = data->val; + RHDPtr rhdPtr = data->val; + unsigned char *ptr; + atomDataTablesPtr atomDataPtr; + atomBiosHandlePtr handle = NULL; + unsigned int BIOSImageSize = 0; + Bool unposted = FALSE; + unsigned char* codeTable; + + data->atomhandle = NULL; + + RHDFUNCI(scrnIndex); + + if (rhdPtr->BIOSCopy) { + xf86DrvMsg(scrnIndex,X_INFO,"Getting BIOS copy from INT10\n"); + ptr = rhdPtr->BIOSCopy; + rhdPtr->BIOSCopy = NULL; + + BIOSImageSize = ptr[2] * 512; + if (BIOSImageSize > legacyBIOSMax) { + xf86DrvMsg(scrnIndex,X_ERROR,"Invalid BIOS length field\n"); + return ATOM_FAILED; + } + } + else + { +// if (!xf86IsEntityPrimary(rhdPtr->entityIndex)) +// { +// if (!(BIOSImageSize = RHDReadPCIBios(rhdPtr, &ptr))) +// return ATOM_FAILED; +// unposted = TRUE; +// } +// else + { + int read_len; + unsigned char tmp[32]; + + DBG(dbgprintf("Getting BIOS copy from legacy VBIOS location\n")); + memcpy(tmp,(char*)(OS_BASE+legacyBIOSLocation), 32); + BIOSImageSize = tmp[2] * 512; + if (BIOSImageSize > legacyBIOSMax) { + xf86DrvMsg(0,X_ERROR,"Invalid BIOS length field\n"); + return ATOM_FAILED; + } + if (!(ptr = (char*)KernelAlloc(BIOSImageSize))) + { + DBG(dbgprintf("Cannot allocate %i bytes of memory " + "for BIOS image\n",BIOSImageSize)); + return ATOM_FAILED; + } + memcpy(ptr,(char*)(OS_BASE+legacyBIOSLocation), BIOSImageSize); + rhdPtr->BIOSCopy = ptr; + } + } + + if (!(atomDataPtr = xcalloc(1, sizeof(atomDataTables)))) { + xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory for " + "ATOM BIOS data tabes\n"); + goto error; + } + if (!rhdAtomGetTables(rhdPtr, ptr, atomDataPtr, &codeTable, BIOSImageSize)) + goto error1; + if (!(handle = xcalloc(1, sizeof(atomBiosHandleRec)))) { + xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory\n"); + goto error1; + } + handle->BIOSBase = ptr; + handle->atomDataPtr = atomDataPtr; + handle->scrnIndex = scrnIndex; + handle->rhdPtr = rhdPtr; + handle->PciTag = rhdPtr->PciTag; + handle->BIOSImageSize = BIOSImageSize; + handle->codeTable = codeTable; + handle->SaveListObjects = NULL; + +# ifdef ATOM_BIOS_PARSER + /* Try to find out if BIOS has been posted (either by system or int10 */ + if (unposted) { + /* run AsicInit */ + if (!rhdAtomASICInit(handle)) + xf86DrvMsg(scrnIndex, X_WARNING, + "%s: AsicInit failed. Won't be able to obtain in VRAM " + "FB scratch space\n",__func__); + } +# endif + + data->atomhandle = handle; + return ATOM_SUCCESS; + + error1: + xfree(atomDataPtr); + error: + xfree(ptr); + return ATOM_FAILED; +} + +static AtomBiosResult +rhdAtomTearDown(atomBiosHandlePtr handle, + AtomBiosRequestID unused1, AtomBiosArgPtr unused2) +{ + RHDFUNC(handle); + + xfree(handle->BIOSBase); + xfree(handle->atomDataPtr); + if (handle->scratchBase) xfree(handle->scratchBase); + xfree(handle); + return ATOM_SUCCESS; +} + +static AtomBiosResult +rhdAtomVramInfoQuery(atomBiosHandlePtr handle, AtomBiosRequestID func, + AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD32 *val = &data->val; + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + switch (func) { + case GET_FW_FB_START: + *val = atomDataPtr->VRAM_UsageByFirmware + ->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware; + break; + case GET_FW_FB_SIZE: + *val = atomDataPtr->VRAM_UsageByFirmware + ->asFirmwareVramReserveInfo[0].usFirmwareUseInKb; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + return ATOM_SUCCESS; +} + +static AtomBiosResult +rhdAtomTmdsInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD32 *val = &data->val; + int i = 0, clock = *val; + + atomDataPtr = handle->atomDataPtr; + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->TMDS_Info), + NULL,NULL,NULL)) { + return ATOM_FAILED; + } + + RHDFUNC(handle); + + if (func == ATOM_TMDS_MAX_FREQUENCY) + *val = atomDataPtr->TMDS_Info->usMaxFrequency * 10; + else { + if (clock > atomDataPtr->TMDS_Info->usMaxFrequency * 10) + return ATOM_FAILED; + + for (;i < ATOM_MAX_MISC_INFO; i++) { + if (clock < atomDataPtr->TMDS_Info->asMiscInfo[i].usFrequency * 10) { + switch (func) { + case ATOM_TMDS_PLL_CHARGE_PUMP: + *val = atomDataPtr->TMDS_Info->asMiscInfo[i].ucPLL_ChargePump; + break; + case ATOM_TMDS_PLL_DUTY_CYCLE: + *val = atomDataPtr->TMDS_Info->asMiscInfo[i].ucPLL_DutyCycle; + break; + case ATOM_TMDS_PLL_VCO_GAIN: + *val = atomDataPtr->TMDS_Info->asMiscInfo[i].ucPLL_VCO_Gain; + break; + case ATOM_TMDS_PLL_VOLTAGE_SWING: + *val = atomDataPtr->TMDS_Info->asMiscInfo[i].ucPLL_VoltageSwing; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + } + } + } + + if (i > ATOM_MAX_MISC_INFO) + return ATOM_FAILED; + + return ATOM_SUCCESS; +} + +static DisplayModePtr +rhdAtomLvdsTimings(atomBiosHandlePtr handle, ATOM_DTD_FORMAT *dtd) +{ + DisplayModePtr mode; +#define NAME_LEN 16 + char name[NAME_LEN]; + + RHDFUNC(handle); + + if (!(mode = (DisplayModePtr)xcalloc(1,sizeof(DisplayModeRec)))) + return NULL; + + mode->CrtcHDisplay = mode->HDisplay = dtd->usHActive; + mode->CrtcVDisplay = mode->VDisplay = dtd->usVActive; + mode->CrtcHBlankStart = dtd->usHActive + dtd->ucHBorder; + mode->CrtcHBlankEnd = mode->CrtcHBlankStart + dtd->usHBlanking_Time; + mode->CrtcHTotal = mode->HTotal = mode->CrtcHBlankEnd + dtd->ucHBorder; + mode->CrtcVBlankStart = dtd->usVActive + dtd->ucVBorder; + mode->CrtcVBlankEnd = mode->CrtcVBlankStart + dtd->usVBlanking_Time; + mode->CrtcVTotal = mode->VTotal = mode->CrtcVBlankEnd + dtd->ucVBorder; + mode->CrtcHSyncStart = mode->HSyncStart = dtd->usHActive + dtd->usHSyncOffset; + mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + dtd->usHSyncWidth; + mode->CrtcVSyncStart = mode->VSyncStart = dtd->usVActive + dtd->usVSyncOffset; + mode->CrtcVSyncEnd = mode->VSyncEnd = mode->VSyncStart + dtd->usVSyncWidth; + + mode->SynthClock = mode->Clock = dtd->usPixClk * 10; + + mode->HSync = ((float) mode->Clock) / ((float)mode->HTotal); + mode->VRefresh = (1000.0 * ((float) mode->Clock)) + / ((float)(((float)mode->HTotal) * ((float)mode->VTotal))); + + snprintf(name, NAME_LEN, "%dx%d", + mode->HDisplay, mode->VDisplay); + mode->name = strdup(name); + + RHDDebug(handle->scrnIndex,"%s: LVDS Modeline: %s " + "%2.d %i (%i) %i %i (%i) %i %i (%i) %i %i (%i) %i\n", + __func__, mode->name, mode->Clock, + mode->HDisplay, mode->CrtcHBlankStart, mode->HSyncStart, mode->CrtcHSyncEnd, + mode->CrtcHBlankEnd, mode->HTotal, + mode->VDisplay, mode->CrtcVBlankStart, mode->VSyncStart, mode->VSyncEnd, + mode->CrtcVBlankEnd, mode->VTotal); +#undef NAME_LEN + return mode; +} + +static unsigned char* +rhdAtomLvdsDDC(atomBiosHandlePtr handle, CARD32 offset, unsigned char *record) +{ + unsigned char *EDIDBlock; + + RHDFUNC(handle); + + while (*record != ATOM_RECORD_END_TYPE) { + + switch (*record) { + case LCD_MODE_PATCH_RECORD_MODE_TYPE: + offset += sizeof(ATOM_PATCH_RECORD_MODE); + if (offset > handle->BIOSImageSize) break; + record += sizeof(ATOM_PATCH_RECORD_MODE); + break; + + case LCD_RTS_RECORD_TYPE: + offset += sizeof(ATOM_LCD_RTS_RECORD); + if (offset > handle->BIOSImageSize) break; + record += sizeof(ATOM_LCD_RTS_RECORD); + break; + + case LCD_CAP_RECORD_TYPE: + offset += sizeof(ATOM_LCD_MODE_CONTROL_CAP); + if (offset > handle->BIOSImageSize) break; + record += sizeof(ATOM_LCD_MODE_CONTROL_CAP); + break; + + case LCD_FAKE_EDID_PATCH_RECORD_TYPE: + offset += sizeof(ATOM_FAKE_EDID_PATCH_RECORD); + /* check if the structure still fully lives in the BIOS image */ + if (offset > handle->BIOSImageSize) break; + offset += ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength + - sizeof(UCHAR); + if (offset > handle->BIOSImageSize) break; + /* dup string as we free it later */ + if (!(EDIDBlock = (unsigned char *)xalloc( + ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength))) + return NULL; + memcpy(EDIDBlock,&((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDString, + ((ATOM_FAKE_EDID_PATCH_RECORD*)record)->ucFakeEDIDLength); + + /* for testing */ + { + // xf86MonPtr mon = xf86InterpretEDID(handle->scrnIndex,EDIDBlock); + // xf86PrintEDID(mon); + // kfree(mon); + } + return EDIDBlock; + + case LCD_PANEL_RESOLUTION_RECORD_TYPE: + offset += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); + if (offset > handle->BIOSImageSize) break; + record += sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD); + break; + + default: + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: unknown record type: %x\n",__func__,*record); + return NULL; + } + } + + return NULL; +} + +static AtomBiosResult +rhdAtomLvdsGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func, + AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + unsigned long offset; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base), + &crev,&frev,NULL)) { + return ATOM_FAILED; + } + + switch (crev) { + + case 1: + switch (func) { + case ATOMBIOS_GET_PANEL_MODE: + data->mode = rhdAtomLvdsTimings(handle, + &atomDataPtr->LVDS_Info + .LVDS_Info->sLCDTiming); + if (data->mode) + return ATOM_SUCCESS; + default: + return ATOM_FAILED; + } + case 2: + switch (func) { + case ATOMBIOS_GET_PANEL_MODE: + data->mode = rhdAtomLvdsTimings(handle, + &atomDataPtr->LVDS_Info + .LVDS_Info_v12->sLCDTiming); + if (data->mode) + return ATOM_SUCCESS; + return ATOM_FAILED; + + case ATOMBIOS_GET_PANEL_EDID: + offset = (unsigned long)&atomDataPtr->LVDS_Info.base + - (unsigned long)handle->BIOSBase + + atomDataPtr->LVDS_Info + .LVDS_Info_v12->usExtInfoTableOffset; + + data->EDIDBlock + = rhdAtomLvdsDDC(handle, offset, + (unsigned char *) + &atomDataPtr->LVDS_Info.base + + atomDataPtr->LVDS_Info + .LVDS_Info_v12->usExtInfoTableOffset); + if (data->EDIDBlock) + return ATOM_SUCCESS; + default: + return ATOM_FAILED; + } + default: + return ATOM_NOT_IMPLEMENTED; + } +/*NOTREACHED*/ +} + +static AtomBiosResult +rhdAtomLvdsInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + CARD32 *val = &data->val; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base), + &crev,&frev,NULL)) { + return ATOM_FAILED; + } + + switch (crev) { + case 1: + switch (func) { + case ATOM_LVDS_SUPPORTED_REFRESH_RATE: + *val = atomDataPtr->LVDS_Info + .LVDS_Info->usSupportedRefreshRate; + break; + case ATOM_LVDS_OFF_DELAY: + *val = atomDataPtr->LVDS_Info + .LVDS_Info->usOffDelayInMs; + break; + case ATOM_LVDS_SEQ_DIG_ONTO_DE: + *val = atomDataPtr->LVDS_Info + .LVDS_Info->ucPowerSequenceDigOntoDEin10Ms * 10; + break; + case ATOM_LVDS_SEQ_DE_TO_BL: + *val = atomDataPtr->LVDS_Info + .LVDS_Info->ucPowerSequenceDEtoBLOnin10Ms * 10; + break; + case ATOM_LVDS_TEMPORAL_DITHER: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info->ucLVDS_Misc & 0x40) != 0; + break; + case ATOM_LVDS_SPATIAL_DITHER: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info->ucLVDS_Misc & 0x20) != 0; + break; + case ATOM_LVDS_FPDI: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info->ucLVDS_Misc & 0x10) != 0; + break; + case ATOM_LVDS_DUALLINK: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info->ucLVDS_Misc & 0x01) != 0; + break; + case ATOM_LVDS_24BIT: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info->ucLVDS_Misc & 0x02) != 0; + break; + case ATOM_LVDS_GREYLVL: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info->ucLVDS_Misc & ATOM_PANEL_MISC_GREY_LEVEL) + >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT ; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + case 2: + switch (func) { + case ATOM_LVDS_SUPPORTED_REFRESH_RATE: + *val = atomDataPtr->LVDS_Info + .LVDS_Info_v12->usSupportedRefreshRate; + break; + case ATOM_LVDS_OFF_DELAY: + *val = atomDataPtr->LVDS_Info + .LVDS_Info_v12->usOffDelayInMs; + break; + case ATOM_LVDS_SEQ_DIG_ONTO_DE: + *val = atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucPowerSequenceDigOntoDEin10Ms * 10; + break; + case ATOM_LVDS_SEQ_DE_TO_BL: + *val = atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucPowerSequenceDEtoBLOnin10Ms * 10; + break; + case ATOM_LVDS_FPDI: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucLVDS_Misc * 0x10) != 0; + break; + case ATOM_LVDS_SPATIAL_DITHER: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucLVDS_Misc & 0x20) != 0; + break; + case ATOM_LVDS_TEMPORAL_DITHER: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucLVDS_Misc & 0x40) != 0; + break; + case ATOM_LVDS_DUALLINK: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucLVDS_Misc & 0x01) != 0; + break; + case ATOM_LVDS_24BIT: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucLVDS_Misc & 0x02) != 0; + break; + case ATOM_LVDS_GREYLVL: + *val = (atomDataPtr->LVDS_Info + .LVDS_Info_v12->ucLVDS_Misc & 0x0C) >> 2; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + + return ATOM_SUCCESS; +} + +static AtomBiosResult +rhdAtomCompassionateDataQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + CARD32 *val = &data->val; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->CompassionateData), + &crev,&frev,NULL)) { + return ATOM_FAILED; + } + + switch (func) { + case ATOM_DAC1_BG_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC1_BG_Adjustment; + break; + case ATOM_DAC1_DAC_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC1_DAC_Adjustment; + break; + case ATOM_DAC1_FORCE: + *val = atomDataPtr->CompassionateData-> + usDAC1_FORCE_Data; + break; + case ATOM_DAC2_CRTC2_BG_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_CRT2_BG_Adjustment; + break; + case ATOM_DAC2_NTSC_BG_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_NTSC_BG_Adjustment; + break; + case ATOM_DAC2_PAL_BG_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_PAL_BG_Adjustment; + break; + case ATOM_DAC2_CV_BG_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_CV_BG_Adjustment; + break; + case ATOM_DAC2_CRTC2_DAC_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_CRT2_DAC_Adjustment; + break; + case ATOM_DAC2_NTSC_DAC_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_NTSC_DAC_Adjustment; + break; + case ATOM_DAC2_PAL_DAC_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_PAL_DAC_Adjustment; + break; + case ATOM_DAC2_CV_DAC_ADJ: + *val = atomDataPtr->CompassionateData-> + ucDAC2_CV_DAC_Adjustment; + break; + case ATOM_DAC2_CRTC2_FORCE: + *val = atomDataPtr->CompassionateData-> + usDAC2_CRT2_FORCE_Data; + break; + case ATOM_DAC2_CRTC2_MUX_REG_IND: + *val = atomDataPtr->CompassionateData-> + usDAC2_CRT2_MUX_RegisterIndex; + break; + case ATOM_DAC2_CRTC2_MUX_REG_INFO: + *val = atomDataPtr->CompassionateData-> + ucDAC2_CRT2_MUX_RegisterInfo; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + return ATOM_SUCCESS; +} + +/* + * + */ +enum atomPCIELanes atomPCIELanesMap[] = { + atomPCIELaneNONE, + atomPCIELane0_3, + atomPCIELane4_7, + atomPCIELane0_7, + atomPCIELane8_11, + atomPCIELaneNONE, + atomPCIELaneNONE, + atomPCIELaneNONE, + atomPCIELane12_15, + atomPCIELaneNONE, + atomPCIELaneNONE, + atomPCIELaneNONE, + atomPCIELane8_15, + atomPCIELaneNONE, + atomPCIELaneNONE, + atomPCIELaneNONE, + atomPCIELaneNONE +}; + +static AtomBiosResult +rhdAtomIntegratedSystemInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + CARD32 *val = &data->val; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), + &crev,&frev,NULL)) { + return ATOM_FAILED; + } + + switch (crev) { + case 1: + switch (func) { + case ATOM_GET_PCIENB_CFG_REG7: + *val = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usPCIENBCfgReg7; + break; + case ATOM_GET_CAPABILITY_FLAG: + *val = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usCapabilityFlag; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + case 2: + switch (func) { + case ATOM_GET_PCIE_LANES: + { + CARD32 n; + switch (*val) { + case 1: + n = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulDDISlot1Config; + break; + case 2: + n = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulDDISlot2Config; + break; + default: + return ATOM_FAILED; + } + data->pcieLanes.Chassis = atomPCIELanesMap[n & 0xf]; + data->pcieLanes.Docking = atomPCIELanesMap[(n >> 4) & 0xf]; + RHDDebug(handle->scrnIndex, "AtomBIOS IntegratedSystemInfo PCIELanes: Chassis=%x Docking=%x\n", + data->pcieLanes.Chassis, data->pcieLanes.Docking); + return ATOM_SUCCESS; + } + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + return ATOM_NOT_IMPLEMENTED; + } + + return ATOM_SUCCESS; +} + +static DisplayModePtr +rhdAtomAnalogTVTimings(atomBiosHandlePtr handle, + ATOM_ANALOG_TV_INFO *tv_info, + enum RHD_TV_MODE tvMode) +{ + atomDataTablesPtr atomDataPtr; + DisplayModePtr mode; + int mode_n; + char *name; + ATOM_MODE_TIMING *amt; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + switch (tvMode) { + case NTSC_SUPPORT: + case NTSCJ_SUPPORT: + mode_n = 0; + name = "TV_NTSC"; + break; + case PAL_SUPPORT: + case PALM_SUPPORT: + case PALCN_SUPPORT: + case PALN_SUPPORT: + case PAL60_SUPPORT: + case SECAM_SUPPORT: + mode_n = 1; + name = "TV_PAL/SECAM"; + break; + default: + return NULL; + } + + + if (!(tv_info->ucTV_SupportedStandard & (tvMode))) + return NULL; + + if (!(mode = (DisplayModePtr)xcalloc(1,sizeof(DisplayModeRec)))) + return NULL; + + amt = &tv_info->aModeTimings[mode_n]; + + mode->CrtcHDisplay = mode->HDisplay = amt->usCRTC_H_Disp; + mode->CrtcHSyncStart = mode->HSyncStart = amt->usCRTC_H_SyncStart; + mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + amt->usCRTC_H_SyncWidth; + mode->CrtcHTotal = mode->HTotal = amt->usCRTC_H_Total; + mode->CrtcHBlankStart = mode->HDisplay + amt->usCRTC_OverscanRight; + mode->CrtcHBlankEnd = mode->HTotal - amt->usCRTC_OverscanLeft; + + mode->CrtcVDisplay = mode->VDisplay = amt->usCRTC_V_Disp; + mode->CrtcVSyncStart = mode->VSyncStart = amt->usCRTC_V_SyncStart; + mode->CrtcVSyncEnd = mode->VSyncEnd = mode->VSyncStart + amt->usCRTC_V_SyncWidth; + mode->CrtcVTotal = mode->VTotal = amt->usCRTC_V_Total; + mode->CrtcVBlankStart = mode->VDisplay + amt->usCRTC_OverscanBottom; + mode->CrtcVBlankEnd = mode->CrtcVTotal - amt->usCRTC_OverscanTop; + + mode->SynthClock = mode->Clock = amt->usPixelClock * 10; + if (amt->susModeMiscInfo.usAccess & ATOM_HSYNC_POLARITY) + mode->Flags |= V_NHSYNC; + else + mode->Flags |= V_PHSYNC; + if (amt->susModeMiscInfo.usAccess & ATOM_VSYNC_POLARITY) + mode->Flags |= V_NVSYNC; + else + mode->Flags |= V_PVSYNC; + if (amt->susModeMiscInfo.usAccess & ATOM_INTERLACE) + mode->Flags |= V_INTERLACE; + if (amt->susModeMiscInfo.usAccess & ATOM_COMPOSITESYNC) + mode->Flags |= V_CSYNC; + if (amt->susModeMiscInfo.usAccess & ATOM_DOUBLE_CLOCK_MODE) + mode->Flags |= V_DBLCLK; + + mode->HSync = ((float) mode->Clock) / ((float)mode->HTotal); + mode->VRefresh = (1000.0 * ((float) mode->Clock)) + / ((float)(((float)mode->HTotal) * ((float)mode->VTotal))); + + mode->name = strdup(name); + + RHDDebug(handle->scrnIndex,"%s: TV Modeline: %s " + "%2.d %i (%i) %i %i (%i) %i %i (%i) %i %i (%i) %i\n", + __func__, mode->name, mode->Clock, + mode->HDisplay, mode->CrtcHBlankStart, mode->HSyncStart, mode->CrtcHSyncEnd, + mode->CrtcHBlankEnd, mode->HTotal, + mode->VDisplay, mode->CrtcVBlankStart, mode->VSyncStart, mode->VSyncEnd, + mode->CrtcVBlankEnd, mode->VTotal); + + + return mode; +} + +static AtomBiosResult +rhdAtomAnalogTVInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + CARD8 crev, frev; + atomDataTablesPtr atomDataPtr = handle->atomDataPtr; + int mode = 0, i; + struct { enum RHD_TV_MODE rhd_mode; int atomMode; } + tv_modes[] = { + { RHD_TV_NTSC, NTSC_SUPPORT }, + { RHD_TV_NTSCJ, NTSCJ_SUPPORT}, + { RHD_TV_PAL, PAL_SUPPORT }, + { RHD_TV_PALM, PALM_SUPPORT }, + { RHD_TV_PALCN, PALCN_SUPPORT}, + { RHD_TV_PALN, PALN_SUPPORT }, + { RHD_TV_PAL60, PAL60_SUPPORT}, + { RHD_TV_SECAM, SECAM_SUPPORT}, + { RHD_TV_NONE, 0 } + }; + + + RHDFUNC(handle); + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->AnalogTV_Info), + &crev,&frev,NULL)) { + return ATOM_FAILED; + } + switch (func) { + case ATOM_ANALOG_TV_MODE: + for (i = 0; tv_modes[i].atomMode; i++) { + if (data->tvMode == tv_modes[i].rhd_mode) { + mode = tv_modes[i].atomMode; + break; + } + } + data->mode = rhdAtomAnalogTVTimings(handle, + atomDataPtr->AnalogTV_Info, + mode); + if (!data->mode) + return ATOM_FAILED; + return ATOM_SUCCESS; + case ATOM_ANALOG_TV_DEFAULT_MODE: + data->tvMode = tv_modes[atomDataPtr->AnalogTV_Info->ucTV_BootUpDefaultStandard - 1].rhd_mode; + break; + case ATOM_ANALOG_TV_SUPPORTED_MODES: + mode = (CARD32)atomDataPtr->AnalogTV_Info->ucTV_SupportedStandard; + data->val = 0; + for (i = 0; tv_modes[i].atomMode; i++) { + if (tv_modes[i].atomMode & mode) { + data->val |= tv_modes[i].rhd_mode; + } + } + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + + return ATOM_SUCCESS; +} + +static AtomBiosResult +rhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + CARD32 *val = &data->val; + unsigned short size; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->GPIO_I2C_Info), + &crev,&frev,&size)) { + return ATOM_FAILED; + } + + if ((sizeof(ATOM_COMMON_TABLE_HEADER) + + (*val * sizeof(ATOM_GPIO_I2C_ASSIGMENT))) > size) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: GPIO_I2C Device " + "num %lu exeeds table size %u\n",__func__, + (unsigned long)val, + size); + return ATOM_FAILED; + } + + switch (func) { + case ATOM_GPIO_I2C_DATA_MASK: + *val = atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val] + .usDataMaskRegisterIndex; + break; + + case ATOM_GPIO_I2C_DATA_MASK_SHIFT: + *val = atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val] + .ucDataMaskShift; + break; + + case ATOM_GPIO_I2C_CLK_MASK: + *val = atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val] + .usClkMaskRegisterIndex; + break; + + case ATOM_GPIO_I2C_CLK_MASK_SHIFT: + *val = atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val] + .ucClkMaskShift; + break; + + default: + return ATOM_NOT_IMPLEMENTED; + } + return ATOM_SUCCESS; +} + +static AtomBiosResult +rhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + CARD32 *val = &data->val; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->FirmwareInfo.base), + &crev,&frev,NULL)) { + return ATOM_FAILED; + } + + switch (crev) { + case 1: + switch (func) { + case GET_DEFAULT_ENGINE_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->ulDefaultEngineClock * 10; + break; + case GET_DEFAULT_MEMORY_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->ulDefaultMemoryClock * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->ulMaxPixelClockPLL_Output * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->usMinPixelClockPLL_Output * 10; + case GET_MAX_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->usMaxPixelClockPLL_Input * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->usMinPixelClockPLL_Input * 10; + break; + case GET_MAX_PIXEL_CLK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->usMaxPixelClock * 10; + break; + case GET_REF_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo->usReferenceClock * 10; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + case 2: + switch (func) { + case GET_DEFAULT_ENGINE_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->ulDefaultEngineClock * 10; + break; + case GET_DEFAULT_MEMORY_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->ulDefaultMemoryClock * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->usMinPixelClockPLL_Output * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->usMinPixelClockPLL_Input * 10; + break; + case GET_MAX_PIXEL_CLK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->usMaxPixelClock * 10; + break; + case GET_REF_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_2->usReferenceClock * 10; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + case 3: + switch (func) { + case GET_DEFAULT_ENGINE_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->ulDefaultEngineClock * 10; + break; + case GET_DEFAULT_MEMORY_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->ulDefaultMemoryClock * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->ulMaxPixelClockPLL_Output * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->usMinPixelClockPLL_Output * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->usMaxPixelClockPLL_Input * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->usMinPixelClockPLL_Input * 10; + break; + case GET_MAX_PIXEL_CLK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->usMaxPixelClock * 10; + break; + case GET_REF_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_3->usReferenceClock * 10; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + case 4: + switch (func) { + case GET_DEFAULT_ENGINE_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->ulDefaultEngineClock * 10; + break; + case GET_DEFAULT_MEMORY_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->ulDefaultMemoryClock * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->usMaxPixelClockPLL_Input * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_INPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->usMinPixelClockPLL_Input * 10; + break; + case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->ulMaxPixelClockPLL_Output * 10; + break; + case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->usMinPixelClockPLL_Output * 10; + break; + case GET_MAX_PIXEL_CLK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->usMaxPixelClock * 10; + break; + case GET_REF_CLOCK: + *val = atomDataPtr->FirmwareInfo + .FirmwareInfo_V_1_4->usReferenceClock * 10; + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + break; + default: + return ATOM_NOT_IMPLEMENTED; + } + return ATOM_SUCCESS; +} + +/* + * + */ +static AtomBiosResult +rhdAtomGetConditionalGoldenSetting(atomBiosHandlePtr handle, + AtomBiosRequestID func, AtomBiosArgPtr data) +{ + unsigned short *table = (unsigned short *)data->GoldenSettings.BIOSPtr; + unsigned short entry_size = *(table++); + + RHDFUNC(handle); + + RHDDebug(handle->scrnIndex, "%s: testing 0x%4.4x\n",__func__, + data->GoldenSettings.value); + +/* @@@ endian! */ + while (table < (unsigned short *)data->GoldenSettings.End) { + RHDDebugCont("\t\t against: 0x%8.8x\n", table[1] << 16 | table[0]); + if ((data->GoldenSettings.value >> 16) == table[1]) { + if ((data->GoldenSettings.value & 0xffff) <= table[0]) { + data->GoldenSettings.BIOSPtr = (unsigned char *)(table + 2); + return ATOM_SUCCESS; + } + } + table = (unsigned short *)(((unsigned char *)table) + entry_size); + } + return ATOM_FAILED; +} + +#define Limit(n,max,name) ((n >= max) ? ( \ + dbgprintf(handle->scrnIndex,X_ERROR,"%s: %s %i exceeds maximum %i\n", \ + __func__,name,n,max), TRUE) : FALSE) + +static const struct _rhd_connector_objs +{ + char *name; + rhdConnectorType con; +} rhd_connector_objs[] = { + { "NONE", RHD_CONNECTOR_NONE }, + { "SINGLE_LINK_DVI_I", RHD_CONNECTOR_DVI_SINGLE }, + { "DUAL_LINK_DVI_I", RHD_CONNECTOR_DVI }, + { "SINGLE_LINK_DVI_D", RHD_CONNECTOR_DVI_SINGLE }, + { "DUAL_LINK_DVI_D", RHD_CONNECTOR_DVI }, + { "VGA", RHD_CONNECTOR_VGA }, + { "COMPOSITE", RHD_CONNECTOR_TV }, + { "SVIDEO", RHD_CONNECTOR_TV, }, + { "YPrPb", RHD_CONNECTOR_TV, }, + { "D_CONNECTOR", RHD_CONNECTOR_NONE, }, + { "9PIN_DIN", RHD_CONNECTOR_NONE }, + { "SCART", RHD_CONNECTOR_TV }, + { "HDMI_TYPE_A", RHD_CONNECTOR_DVI_SINGLE }, + { "HDMI_TYPE_B", RHD_CONNECTOR_DVI }, + { "LVDS", RHD_CONNECTOR_PANEL }, + { "7PIN_DIN", RHD_CONNECTOR_TV }, + { "PCIE_CONNECTOR", RHD_CONNECTOR_PCIE }, + { "CROSSFIRE", RHD_CONNECTOR_NONE }, + { "HARDCODE_DVI", RHD_CONNECTOR_NONE }, + { "DISPLAYPORT", RHD_CONNECTOR_NONE} +}; +static const int n_rhd_connector_objs = sizeof (rhd_connector_objs) / sizeof(struct _rhd_connector_objs); + +static const struct _rhd_encoders +{ + char *name; + rhdOutputType ot[2]; +} rhd_encoders[] = { + { "NONE", {RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_LVDS", { RHD_OUTPUT_LVDS, RHD_OUTPUT_NONE }}, + { "INTERNAL_TMDS1", { RHD_OUTPUT_TMDSA, RHD_OUTPUT_NONE }}, + { "INTERNAL_TMDS2", { RHD_OUTPUT_TMDSB, RHD_OUTPUT_NONE }}, + { "INTERNAL_DAC1", { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE }}, + { "INTERNAL_DAC2", { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, + { "INTERNAL_SDVOA", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_SDVOB", { RHD_OUTPUT_NONE , RHD_OUTPUT_NONE }}, + { "SI170B", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "CH7303", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "CH7301", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_DVO1", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "EXTERNAL_SDVOA", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "EXTERNAL_SDVOB", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "TITFP513", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_LVTM1", { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE }}, + { "VT1623", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "HDMI_SI1930", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "HDMI_INTERNAL", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_KLDSCP_TMDS1", { RHD_OUTPUT_TMDSA, RHD_OUTPUT_NONE }}, + { "INTERNAL_KLDSCP_DVO1", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_KLDSCP_DAC1", { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE }}, + { "INTERNAL_KLDSCP_DAC2", { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, + { "SI178", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "MVPU_FPGA", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "INTERNAL_DDI", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "VT1625", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "HDMI_SI1932", {RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "AN9801", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "DP501", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }}, + { "UNIPHY", { RHD_OUTPUT_UNIPHYA, RHD_OUTPUT_UNIPHYB }}, + { "KLDSCP_LVTMA", { RHD_OUTPUT_KLDSKP_LVTMA, RHD_OUTPUT_NONE }}, + { "UNIPHY1", { RHD_OUTPUT_UNIPHYC, RHD_OUTPUT_UNIPHYD }}, + { "UNIPHY2", { RHD_OUTPUT_UNIPHYE, RHD_OUTPUT_UNIPHYF }} +}; +static const int n_rhd_encoders = sizeof (rhd_encoders) / sizeof(struct _rhd_encoders); + +static const struct _rhd_connectors +{ + char *name; + rhdConnectorType con; + Bool dual; +} rhd_connectors[] = { + {"NONE", RHD_CONNECTOR_NONE, FALSE }, + {"VGA", RHD_CONNECTOR_VGA, FALSE }, + {"DVI-I", RHD_CONNECTOR_DVI, TRUE }, + {"DVI-D", RHD_CONNECTOR_DVI, FALSE }, + {"DVI-A", RHD_CONNECTOR_DVI, FALSE }, + {"SVIDEO", RHD_CONNECTOR_TV, FALSE }, + {"COMPOSITE", RHD_CONNECTOR_TV, FALSE }, + {"PANEL", RHD_CONNECTOR_PANEL, FALSE }, + {"DIGITAL_LINK", RHD_CONNECTOR_NONE, FALSE }, + {"SCART", RHD_CONNECTOR_TV, FALSE }, + {"HDMI Type A", RHD_CONNECTOR_DVI_SINGLE, FALSE }, + {"HDMI Type B", RHD_CONNECTOR_DVI, FALSE }, + {"UNKNOWN", RHD_CONNECTOR_NONE, FALSE }, + {"UNKNOWN", RHD_CONNECTOR_NONE, FALSE }, + {"DVI+DIN", RHD_CONNECTOR_NONE, FALSE } +}; +static const int n_rhd_connectors = sizeof(rhd_connectors) / sizeof(struct _rhd_connectors); + +static const struct _rhd_devices +{ + char *name; + rhdOutputType ot[2]; + enum atomDevice atomDevID; +} rhd_devices[] = { /* { RHD_CHIP_EXTERNAL, RHD_CHIP_IGP } */ + {" CRT1", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomCRT1 }, + {" LCD1", { RHD_OUTPUT_LVTMA, RHD_OUTPUT_LVTMA }, atomLCD1 }, + {" TV1", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomTV1 }, + {" DFP1", { RHD_OUTPUT_TMDSA, RHD_OUTPUT_NONE }, atomDFP1 }, + {" CRT2", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomCRT2 }, + {" LCD2", { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE }, atomLCD2 }, + {" TV2", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomTV2 }, + {" DFP2", { RHD_OUTPUT_LVTMA, RHD_OUTPUT_DVO }, atomDFP2 }, + {" CV", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomCV }, + {" DFP3", { RHD_OUTPUT_LVTMA, RHD_OUTPUT_LVTMA }, atomDFP3 }, + {" DFP4", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomDFP4 }, + {" DFP5", { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE }, atomDFP5 } +}; +static const int n_rhd_devices = sizeof(rhd_devices) / sizeof(struct _rhd_devices); + +static const rhdDDC hwddc[] = { RHD_DDC_0, RHD_DDC_1, RHD_DDC_2, RHD_DDC_3, RHD_DDC_4 }; +static const int n_hwddc = sizeof(hwddc) / sizeof(rhdDDC); + +static const rhdOutputType acc_dac[] = { RHD_OUTPUT_NONE, RHD_OUTPUT_DACA, + RHD_OUTPUT_DACB, RHD_OUTPUT_DAC_EXTERNAL }; +static const int n_acc_dac = sizeof(acc_dac) / sizeof (rhdOutputType); + +/* + * + */ +static Bool +rhdAtomInterpretObjectID(atomBiosHandlePtr handle, + CARD16 id, CARD8 *obj_type, CARD8 *obj_id, + CARD8 *num, char **name) +{ + *obj_id = (id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + *num = (id & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + *obj_type = (id & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; + + *name = NULL; + + switch (*obj_type) { + case GRAPH_OBJECT_TYPE_CONNECTOR: + if (!Limit(*obj_id, n_rhd_connector_objs, "connector_obj")) + *name = rhd_connector_objs[*obj_id].name; + break; + case GRAPH_OBJECT_TYPE_ENCODER: + if (!Limit(*obj_id, n_rhd_encoders, "encoder_obj")) + *name = rhd_encoders[*obj_id].name; + break; + default: + break; + } + return TRUE; +} + +/* + * + */ +static AtomBiosResult +rhdAtomGetDDCIndex(atomBiosHandlePtr handle, + rhdDDC *DDC, unsigned char i2c) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + int i; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + &(atomDataPtr->GPIO_I2C_Info->sHeader), &crev,&frev,NULL)) { + return ATOM_NOT_IMPLEMENTED; + } + for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + if (atomDataPtr->GPIO_I2C_Info->asGPIO_Info[i].sucI2cId.ucAccess == i2c) { + RHDDebug(handle->scrnIndex, " Found DDC GPIO Index: %i\n",i); + if (Limit(i, n_hwddc, "GPIO_DDC Index")) + return ATOM_FAILED; + *DDC = hwddc[i]; + return ATOM_SUCCESS; + } + } + return ATOM_FAILED; +} + +/* + * + */ +static void +rhdAtomDDCFromI2CRecord(atomBiosHandlePtr handle, + ATOM_I2C_RECORD *Record, rhdDDC *DDC) +{ + RHDDebug(handle->scrnIndex, + " %s: I2C Record: %s[%x] EngineID: %x I2CAddr: %x\n", + __func__, + Record->sucI2cId.bfHW_Capable ? "HW_Line" : "GPIO_ID", + Record->sucI2cId.bfI2C_LineMux, + Record->sucI2cId.bfHW_EngineID, + Record->ucI2CAddr); + + if (!*(unsigned char *)&(Record->sucI2cId)) + *DDC = RHD_DDC_NONE; + else { + union { + ATOM_I2C_ID_CONFIG i2cId; + unsigned char i2cChar; + } u; + if (Record->ucI2CAddr != 0) + return; + u.i2cId = Record->sucI2cId; + if (!u.i2cChar + || rhdAtomGetDDCIndex(handle, DDC, u.i2cChar) != ATOM_SUCCESS) + *DDC = RHD_DDC_NONE; + } +} + +/* + * + */ +static void +rhdAtomParseGPIOLutForHPD(atomBiosHandlePtr handle, + CARD8 pinID, rhdHPD *HPD) +{ + atomDataTablesPtr atomDataPtr; + ATOM_GPIO_PIN_LUT *gpio_pin_lut; + unsigned short size; + int i = 0; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + *HPD = RHD_HPD_NONE; + + if (!rhdAtomGetTableRevisionAndSize( + &atomDataPtr->GPIO_Pin_LUT->sHeader, NULL, NULL, &size)) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: No valid GPIO pin LUT in AtomBIOS\n",__func__); + return; + } + gpio_pin_lut = atomDataPtr->GPIO_Pin_LUT; + + while (1) { + if (gpio_pin_lut->asGPIO_Pin[i].ucGPIO_ID == pinID) { + + if ((sizeof(ATOM_COMMON_TABLE_HEADER) + + (i * sizeof(ATOM_GPIO_PIN_ASSIGNMENT))) > size) + return; + + RHDDebug(handle->scrnIndex, + " %s: GPIO PinID: %i Index: %x Shift: %i\n", + __func__, + pinID, + gpio_pin_lut->asGPIO_Pin[i].usGpioPin_AIndex, + gpio_pin_lut->asGPIO_Pin[i].ucGpioPinBitShift); + + /* grr... map backwards: register indices -> line numbers */ + if (gpio_pin_lut->asGPIO_Pin[i].usGpioPin_AIndex + == (DC_GPIO_HPD_A >> 2)) { + switch (gpio_pin_lut->asGPIO_Pin[i].ucGpioPinBitShift) { + case 0: + *HPD = RHD_HPD_0; + return; + case 8: + *HPD = RHD_HPD_1; + return; + case 16: + *HPD = RHD_HPD_2; + return; + case 24: + *HPD = RHD_HPD_3; + return; + } + } + } + i++; + } +} + +/* + * + */ +static void +rhdAtomHPDFromRecord(atomBiosHandlePtr handle, + ATOM_HPD_INT_RECORD *Record, rhdHPD *HPD) +{ + RHDDebug(handle->scrnIndex, + " %s: HPD Record: GPIO ID: %x Plugged_PinState: %x\n", + __func__, + Record->ucHPDIntGPIOID, + Record->ucPluggged_PinState); + rhdAtomParseGPIOLutForHPD(handle, Record->ucHPDIntGPIOID, HPD); +} + +/* + * + */ +static char * +rhdAtomDeviceTagsFromRecord(atomBiosHandlePtr handle, + ATOM_CONNECTOR_DEVICE_TAG_RECORD *Record) +{ + int i, j, k; + char *devices; + + RHDFUNC(handle); + + RHDDebug(handle->scrnIndex," NumberOfDevice: %i\n", + Record->ucNumberOfDevice); + + if (!Record->ucNumberOfDevice) return NULL; + + devices = (char *)xcalloc(Record->ucNumberOfDevice * 4 + 1,1); + + for (i = 0; i < Record->ucNumberOfDevice; i++) { + k = 0; + j = Record->asDeviceTag[i].usDeviceID; + + if (!j) continue; + + while (!(j & 0x1)) { j >>= 1; k++; }; + + if (!Limit(k,n_rhd_devices,"usDeviceID")) + strcat(devices, rhd_devices[k].name); + } + + RHDDebug(handle->scrnIndex," Devices:%s\n",devices); + + return devices; +} + +/* + * + */ +static rhdConnectorType +rhdAtomGetConnectorID(atomBiosHandlePtr handle, rhdConnectorType connector, int num) +{ + RHDFUNC(handle); + + switch (connector) { + case RHD_CONNECTOR_PCIE: + { + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + CARD32 val; + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + (ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), + &crev,&frev,NULL) || crev != 2) { + return RHD_CONNECTOR_NONE; /* sorry, we can't do any better */ + } + RHDDebug(handle->scrnIndex,"PCIE[%i]", num); + switch (num) { + case 1: + val = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulDDISlot1Config; + break; + case 2: + val = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulDDISlot2Config; + break; + default: + RHDDebugCont("\n"); + return RHD_CONNECTOR_NONE; + } + val >>= 16; + val &= 0xff; + RHDDebugCont(" ObjectID: %i",val); + if (Limit((int)val, n_rhd_connector_objs, "obj_id")) { + RHDDebugCont("\n"); + return RHD_CONNECTOR_NONE; + } + + RHDDebugCont(" ConnectorName: %s\n",rhd_connector_objs[val].name); + return rhd_connector_objs[val].con; + } + default: + return connector; + } +} + +/* + * + */ +static AtomBiosResult +rhdAtomOutputDeviceListFromObjectHeader(atomBiosHandlePtr handle, + struct rhdAtomOutputDeviceList **ptr) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + ATOM_DISPLAY_OBJECT_PATH_TABLE *disObjPathTable; + ATOM_DISPLAY_OBJECT_PATH *disObjPath; + rhdConnectorInfoPtr cp; + unsigned long object_header_end; + unsigned int i,j; + unsigned short object_header_size; + struct rhdAtomOutputDeviceList *DeviceList = NULL; + int cnt = 0; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + &atomDataPtr->Object_Header->sHeader, + &crev,&frev,&object_header_size)) { + return ATOM_NOT_IMPLEMENTED; + } + + if (crev < 2) /* don't bother with anything below rev 2 */ + return ATOM_NOT_IMPLEMENTED; + + if (!(cp = (rhdConnectorInfoPtr)xcalloc(sizeof(struct rhdConnectorInfo), + RHD_CONNECTORS_MAX))) + return ATOM_FAILED; + + object_header_end = + atomDataPtr->Object_Header->usConnectorObjectTableOffset + + object_header_size; + + RHDDebug(handle->scrnIndex,"ObjectTable - size: %u, BIOS - size: %u " + "TableOffset: %u object_header_end: %u\n", + object_header_size, handle->BIOSImageSize, + atomDataPtr->Object_Header->usConnectorObjectTableOffset, + object_header_end); + + if ((object_header_size > handle->BIOSImageSize) + || (atomDataPtr->Object_Header->usConnectorObjectTableOffset + > handle->BIOSImageSize) + || object_header_end > handle->BIOSImageSize) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: Object table information is bogus\n",__func__); + return ATOM_FAILED; + } + + if (((unsigned long)&atomDataPtr->Object_Header->sHeader + + object_header_end) > ((unsigned long)handle->BIOSBase + + handle->BIOSImageSize)) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: Object table extends beyond BIOS Image\n",__func__); + return ATOM_FAILED; + } + disObjPathTable = (ATOM_DISPLAY_OBJECT_PATH_TABLE *) + ((char *)&atomDataPtr->Object_Header->sHeader + + atomDataPtr->Object_Header->usDisplayPathTableOffset); + RHDDebug(handle->scrnIndex, "DisplayPathObjectTable: entries: %i version: %i\n", + disObjPathTable->ucNumOfDispPath, disObjPathTable->ucVersion); + + disObjPath = &disObjPathTable->asDispPath[0]; + for (i = 0; i < disObjPathTable->ucNumOfDispPath; i++) { + CARD8 objNum, cObjNum; + CARD8 objId; + CARD8 objType; + rhdConnectorType ct; + char *name; + + rhdAtomInterpretObjectID(handle, disObjPath->usConnObjectId, &objType, &objId, &objNum, &name); + RHDDebug(handle->scrnIndex, " DisplaPathTable[%i]: size: %i DeviceTag: 0x%x ConnObjId: 0x%x NAME: %s GPUObjId: 0x%x\n", + i, disObjPath->usSize, disObjPath->usDeviceTag, disObjPath->usConnObjectId, name, disObjPath->usGPUObjectId); + + if (objType != GRAPH_OBJECT_TYPE_CONNECTOR) + continue; + + ct = rhd_connector_objs[objId].con; + cObjNum = objNum; + + for (j = 0; j < disObjPath->usSize / sizeof(USHORT) - 4; j++) { + int k = 0,l; + + rhdAtomInterpretObjectID(handle, disObjPath->usGraphicObjIds[j], &objType, &objId, &objNum, &name); + RHDDebug(handle->scrnIndex, " GraphicsObj[%i] ID: 0x%x Type: 0x%x ObjID: 0x%x ENUM: 0x%x NAME: %s\n", + j, disObjPath->usGraphicObjIds[j], objType, objId, objNum, name); + + if (objType != GRAPH_OBJECT_TYPE_ENCODER) + continue; + + Limit(objId, n_rhd_encoders, "usGraphicsObjId"); + + l = disObjPath->usDeviceTag; + if (!l) continue; + + while (!(l & 0x1)) { l >>= 1; k++; }; + if (!Limit(k,n_rhd_devices,"usDeviceID")) { + if (!(DeviceList = (struct rhdAtomOutputDeviceList *)xrealloc(DeviceList, sizeof (struct rhdAtomOutputDeviceList) * (cnt + 1)))) + return ATOM_FAILED; + + DeviceList[cnt].DeviceId = rhd_devices[k].atomDevID; + DeviceList[cnt].ConnectorType = rhdAtomGetConnectorID(handle, ct, cObjNum); + DeviceList[cnt].OutputType = rhd_encoders[objId].ot[objNum - 1]; + cnt++; + RHDDebug(handle->scrnIndex, " DeviceIndex: 0x%x\n",k); + } + } + disObjPath = (ATOM_DISPLAY_OBJECT_PATH*)(((char *)disObjPath) + disObjPath->usSize); + if ((((unsigned long)&atomDataPtr->Object_Header->sHeader + object_header_end) + < (((unsigned long) disObjPath) + sizeof(ATOM_DISPLAY_OBJECT_PATH))) + || (((unsigned long)&atomDataPtr->Object_Header->sHeader + object_header_end) + < (((unsigned long) disObjPath) + disObjPath->usSize))) + break; + } + DeviceList = xrealloc(DeviceList, sizeof(struct rhdAtomOutputDeviceList) * (cnt + 1)); + DeviceList[cnt].DeviceId = atomNone; + + *ptr = DeviceList; + + return ATOM_SUCCESS; +} + +/* + * + */ +static AtomBiosResult +rhdAtomConnectorInfoFromObjectHeader(atomBiosHandlePtr handle, + rhdConnectorInfoPtr *ptr) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + ATOM_CONNECTOR_OBJECT_TABLE *con_obj; + rhdConnectorInfoPtr cp; + unsigned long object_header_end; + int ncon = 0; + int i,j; + unsigned short object_header_size; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + &atomDataPtr->Object_Header->sHeader, + &crev,&frev,&object_header_size)) { + return ATOM_NOT_IMPLEMENTED; + } + + if (crev < 2) /* don't bother with anything below rev 2 */ + return ATOM_NOT_IMPLEMENTED; + + if (!(cp = (rhdConnectorInfoPtr)xcalloc(sizeof(struct rhdConnectorInfo), + RHD_CONNECTORS_MAX))) + return ATOM_FAILED; + + object_header_end = + atomDataPtr->Object_Header->usConnectorObjectTableOffset + + object_header_size; + + RHDDebug(handle->scrnIndex,"ObjectTable - size: %u, BIOS - size: %u " + "TableOffset: %u object_header_end: %u\n", + object_header_size, handle->BIOSImageSize, + atomDataPtr->Object_Header->usConnectorObjectTableOffset, + object_header_end); + + if ((object_header_size > handle->BIOSImageSize) + || (atomDataPtr->Object_Header->usConnectorObjectTableOffset + > handle->BIOSImageSize) + || object_header_end > handle->BIOSImageSize) { + xfree(cp); + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: Object table information is bogus\n",__func__); + return ATOM_FAILED; + } + + if (((unsigned long)&atomDataPtr->Object_Header->sHeader + + object_header_end) > ((unsigned long)handle->BIOSBase + + handle->BIOSImageSize)) { + xfree(cp); + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: Object table extends beyond BIOS Image\n",__func__); + return ATOM_FAILED; + } + + con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *) + ((char *)&atomDataPtr->Object_Header->sHeader + + atomDataPtr->Object_Header->usConnectorObjectTableOffset); + + for (i = 0; i < con_obj->ucNumberOfObjects; i++) { + ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *SrcDstTable; + ATOM_COMMON_RECORD_HEADER *Record; + int record_base; + CARD8 obj_type, obj_id, num; + char *name; + + rhdAtomInterpretObjectID(handle, con_obj->asObjects[i].usObjectID, + &obj_type, &obj_id, &num, &name); + + RHDDebug(handle->scrnIndex, "Object: ID: %x name: %s type: %x id: %x\n", + con_obj->asObjects[i].usObjectID, name ? name : "", + obj_type, obj_id); + + + if (obj_type != GRAPH_OBJECT_TYPE_CONNECTOR) + continue; + + SrcDstTable = (ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *) + ((char *)&atomDataPtr->Object_Header->sHeader + + con_obj->asObjects[i].usSrcDstTableOffset); + + if (con_obj->asObjects[i].usSrcDstTableOffset + + (SrcDstTable->ucNumberOfSrc + * sizeof(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT)) + > handle->BIOSImageSize) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: SrcDstTable[%i] extends " + "beyond Object_Header table\n",__func__,i); + continue; + } + cp[ncon].Type = rhdAtomGetConnectorID(handle, rhd_connector_objs[obj_id].con, num); + cp[ncon].Name = RhdAppendString(cp[ncon].Name,name); + + for (j = 0; ((j < SrcDstTable->ucNumberOfSrc) && + (j < MAX_OUTPUTS_PER_CONNECTOR)); j++) { + CARD8 stype, sobj_id, snum; + char *sname; + + rhdAtomInterpretObjectID(handle, SrcDstTable->usSrcObjectID[j], + &stype, &sobj_id, &snum, &sname); + + RHDDebug(handle->scrnIndex, " * SrcObject: ID: %x name: %s enum: %i\n", + SrcDstTable->usSrcObjectID[j], sname, snum); + + if (snum <= 2) + cp[ncon].Output[j] = rhd_encoders[sobj_id].ot[snum - 1]; + } + + Record = (ATOM_COMMON_RECORD_HEADER *) + ((char *)&atomDataPtr->Object_Header->sHeader + + con_obj->asObjects[i].usRecordOffset); + + record_base = con_obj->asObjects[i].usRecordOffset; + + while (Record->ucRecordType > 0 + && Record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER ) { + char *taglist; + + if ((record_base += Record->ucRecordSize) + > object_header_size) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "%s: Object Records extend beyond Object Table\n", + __func__); + break; + } + + RHDDebug(handle->scrnIndex, " - Record Type: %x\n", + Record->ucRecordType); + + switch (Record->ucRecordType) { + + case ATOM_I2C_RECORD_TYPE: + rhdAtomDDCFromI2CRecord(handle, + (ATOM_I2C_RECORD *)Record, + &cp[ncon].DDC); + break; + + case ATOM_HPD_INT_RECORD_TYPE: + rhdAtomHPDFromRecord(handle, + (ATOM_HPD_INT_RECORD *)Record, + &cp[ncon].HPD); + break; + + case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE: + taglist = rhdAtomDeviceTagsFromRecord(handle, + (ATOM_CONNECTOR_DEVICE_TAG_RECORD *)Record); + if (taglist) { + cp[ncon].Name = RhdAppendString(cp[ncon].Name,taglist); + xfree(taglist); + } + break; + + default: + break; + } + + Record = (ATOM_COMMON_RECORD_HEADER*) + ((char *)Record + Record->ucRecordSize); + + } + + if ((++ncon) == RHD_CONNECTORS_MAX) + break; + } + *ptr = cp; + + RhdPrintConnectorInfo(handle->rhdPtr, cp); + + return ATOM_SUCCESS; +} + +/* + * + */ +static AtomBiosResult +rhdAtomOutputDeviceListFromSupportedDevices(atomBiosHandlePtr handle, + Bool igp, + struct rhdAtomOutputDeviceList **Ptr) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + int n; + int cnt = 0; + struct rhdAtomOutputDeviceList *DeviceList = NULL; + struct rhdConnectorInfo *cp; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + &(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader), + &crev,&frev,NULL)) { + return ATOM_NOT_IMPLEMENTED; + } + + if (!(cp = (rhdConnectorInfoPtr)xcalloc(RHD_CONNECTORS_MAX, + sizeof(struct rhdConnectorInfo)))) + return ATOM_FAILED; + + for (n = 0; n < ATOM_MAX_SUPPORTED_DEVICE; n++) { + ATOM_CONNECTOR_INFO_I2C ci + = atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[n]; + + if (!(atomDataPtr->SupportedDevicesInfo + .SupportedDevicesInfo->usDeviceSupport & (1 << n))) + continue; + + if (Limit(ci.sucConnectorInfo.sbfAccess.bfConnectorType, + n_rhd_connectors, "bfConnectorType")) + continue; + + if (!(DeviceList = (struct rhdAtomOutputDeviceList *)xrealloc(DeviceList, sizeof(struct rhdAtomOutputDeviceList) * (cnt + 1)))) + return ATOM_FAILED; + + DeviceList[cnt].ConnectorType = rhd_connectors[ci.sucConnectorInfo.sbfAccess.bfConnectorType].con; + DeviceList[cnt].DeviceId = rhd_devices[n].atomDevID; + + if (!Limit(ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC, + n_acc_dac, "bfAssociatedDAC")) { + if ((DeviceList[cnt].OutputType + = acc_dac[ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC]) + == RHD_OUTPUT_NONE) { + DeviceList[cnt].OutputType = rhd_devices[n].ot[igp ? 1 : 0]; + } + cnt++; + } + } + DeviceList = (struct rhdAtomOutputDeviceList *)xrealloc(DeviceList, sizeof(struct rhdAtomOutputDeviceList) * (cnt + 1)); + DeviceList[cnt].DeviceId = atomNone; + + *Ptr = DeviceList; + + return ATOM_SUCCESS; +} + +/* + * + */ +static AtomBiosResult +rhdAtomConnectorInfoFromSupportedDevices(atomBiosHandlePtr handle, + Bool igp, + rhdConnectorInfoPtr *ptr) +{ + atomDataTablesPtr atomDataPtr; + CARD8 crev, frev; + rhdConnectorInfoPtr cp; + struct { + rhdOutputType ot; + rhdConnectorType con; + rhdDDC ddc; + rhdHPD hpd; + Bool dual; + char *name; + char *outputName; + } devices[ATOM_MAX_SUPPORTED_DEVICE]; + int ncon = 0; + int n; + + RHDFUNC(handle); + + atomDataPtr = handle->atomDataPtr; + + if (!rhdAtomGetTableRevisionAndSize( + &(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader), + &crev,&frev,NULL)) { + return ATOM_NOT_IMPLEMENTED; + } + + if (!(cp = (rhdConnectorInfoPtr)xcalloc(RHD_CONNECTORS_MAX, + sizeof(struct rhdConnectorInfo)))) + return ATOM_FAILED; + + for (n = 0; n < ATOM_MAX_SUPPORTED_DEVICE; n++) { + ATOM_CONNECTOR_INFO_I2C ci + = atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[n]; + + devices[n].ot = RHD_OUTPUT_NONE; + + if (!(atomDataPtr->SupportedDevicesInfo + .SupportedDevicesInfo->usDeviceSupport & (1 << n))) + continue; + + if (Limit(ci.sucConnectorInfo.sbfAccess.bfConnectorType, + n_rhd_connectors, "bfConnectorType")) + continue; + + devices[n].con + = rhd_connectors[ci.sucConnectorInfo.sbfAccess.bfConnectorType].con; + if (devices[n].con == RHD_CONNECTOR_NONE) + continue; + + devices[n].dual + = rhd_connectors[ci.sucConnectorInfo.sbfAccess.bfConnectorType].dual; + devices[n].name + = rhd_connectors[ci.sucConnectorInfo.sbfAccess.bfConnectorType].name; + + RHDDebug(handle->scrnIndex,"AtomBIOS Connector[%i]: %s Device:%s ",n, + rhd_connectors[ci.sucConnectorInfo + .sbfAccess.bfConnectorType].name, + rhd_devices[n].name); + + devices[n].outputName = rhd_devices[n].name; + + if (!Limit(ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC, + n_acc_dac, "bfAssociatedDAC")) { + if ((devices[n].ot + = acc_dac[ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC]) + == RHD_OUTPUT_NONE) { + devices[n].ot = rhd_devices[n].ot[igp ? 1 : 0]; + } + } else + devices[n].ot = RHD_OUTPUT_NONE; + + RHDDebugCont("Output: %x ",devices[n].ot); + + if (!ci.sucI2cId.ucAccess + || rhdAtomGetDDCIndex(handle, &devices[n].ddc, ci.sucI2cId.ucAccess) != ATOM_SUCCESS) { + RHDDebugCont("NO DDC "); + devices[n].ddc = RHD_DDC_NONE; + } else + RHDDebugCont("HW DDC %i ", + ci.sucI2cId.sbfAccess.bfI2C_LineMux); + + if (crev > 1) { + ATOM_CONNECTOR_INC_SRC_BITMAP isb + = atomDataPtr->SupportedDevicesInfo + .SupportedDevicesInfo_HD->asIntSrcInfo[n]; + + switch (isb.ucIntSrcBitmap) { + case 0x4: + RHDDebugCont("HPD 0\n"); + devices[n].hpd = RHD_HPD_0; + break; + case 0xa: + RHDDebugCont("HPD 1\n"); + devices[n].hpd = RHD_HPD_1; + break; + default: + RHDDebugCont("NO HPD\n"); + devices[n].hpd = RHD_HPD_NONE; + break; + } + } else { + RHDDebugCont("NO HPD\n"); + devices[n].hpd = RHD_HPD_NONE; + } + } + /* sort devices for connectors */ + for (n = 0; n < ATOM_MAX_SUPPORTED_DEVICE; n++) { + int i; + + if (devices[n].ot == RHD_OUTPUT_NONE) + continue; + if (devices[n].con == RHD_CONNECTOR_NONE) + continue; + + cp[ncon].DDC = devices[n].ddc; + cp[ncon].HPD = devices[n].hpd; + cp[ncon].Output[0] = devices[n].ot; + cp[ncon].Output[1] = RHD_OUTPUT_NONE; + cp[ncon].Type = devices[n].con; + cp[ncon].Name = strdup(devices[n].name); + cp[ncon].Name = RhdAppendString(cp[ncon].Name, devices[n].outputName); + + if (devices[n].dual) { + if (devices[n].ddc == RHD_DDC_NONE) + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "No DDC channel for device %s found." + " Cannot find matching device.\n",devices[n].name); + else { + for (i = n + 1; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { + + if (!devices[i].dual) + continue; + + if (devices[n].ddc != devices[i].ddc) + continue; + + if (((devices[n].ot == RHD_OUTPUT_DACA + || devices[n].ot == RHD_OUTPUT_DACB) + && (devices[i].ot == RHD_OUTPUT_LVTMA + || devices[i].ot == RHD_OUTPUT_TMDSA)) + || ((devices[i].ot == RHD_OUTPUT_DACA + || devices[i].ot == RHD_OUTPUT_DACB) + && (devices[n].ot == RHD_OUTPUT_LVTMA + || devices[n].ot == RHD_OUTPUT_TMDSA))) { + + cp[ncon].Output[1] = devices[i].ot; + + if (cp[ncon].HPD == RHD_HPD_NONE) + cp[ncon].HPD = devices[i].hpd; + + cp[ncon].Name = RhdAppendString(cp[ncon].Name, + devices[i].outputName); + devices[i].ot = RHD_OUTPUT_NONE; /* zero the device */ + } + } + } + } + /* Some connector table mark a VGA as DVI-X. This heuristic fixes it */ + if (cp[ncon].Type == RHD_CONNECTOR_DVI) { + if ( ((cp[ncon].Output[0] == RHD_OUTPUT_NONE + && (cp[ncon].Output[1] == RHD_OUTPUT_DACA + || cp[ncon].Output[1] == RHD_OUTPUT_DACB)) + || (cp[ncon].Output[1] == RHD_OUTPUT_NONE + && (cp[ncon].Output[0] == RHD_OUTPUT_DACA + || cp[ncon].Output[0] == RHD_OUTPUT_DACB))) + && cp[ncon].HPD == RHD_HPD_NONE) + cp[ncon].Type = RHD_CONNECTOR_VGA; + } + + if ((++ncon) == RHD_CONNECTORS_MAX) + break; + } + *ptr = cp; + + RhdPrintConnectorInfo(handle->rhdPtr, cp); + + return ATOM_SUCCESS; +} + +/* + * + */ +static AtomBiosResult +rhdAtomConnectorInfo(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data) +{ + int chipset = data->chipset; + + RHDFUNC(handle); + + if (rhdAtomConnectorInfoFromObjectHeader(handle,&data->ConnectorInfo) + == ATOM_SUCCESS) + return ATOM_SUCCESS; + else { + Bool igp = RHDIsIGP(chipset); + return rhdAtomConnectorInfoFromSupportedDevices(handle, igp, + &data->ConnectorInfo); + } +} + +/* + * + */ +static AtomBiosResult +rhdAtomOutputDeviceList(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data) +{ + int chipset = data->chipset; + + RHDFUNC(handle); + + if (rhdAtomOutputDeviceListFromObjectHeader(handle, &data->OutputDeviceList) + == ATOM_SUCCESS) { + return ATOM_SUCCESS; + } else { + Bool igp = RHDIsIGP(chipset); + return rhdAtomOutputDeviceListFromSupportedDevices(handle, igp, &data->OutputDeviceList); + } +} + +/* + * + */ +struct atomCodeDataTableHeader +{ + unsigned char signature; + unsigned short size; +}; + +#define CODE_DATA_TABLE_SIGNATURE 0x7a +#define ATOM_EOT_COMMAND 0x5b + +static AtomBiosResult +rhdAtomGetDataInCodeTable(atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data) +{ + unsigned char *command_table; + unsigned short size; + unsigned short offset; + + int i; + + RHDFUNC(handle); + + if (data->val > sizeof (struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES) / sizeof (USHORT)) + return ATOM_FAILED; + + if ((offset = ((USHORT *)&(((ATOM_MASTER_COMMAND_TABLE *)handle->codeTable) + ->ListOfCommandTables))[data->val])) + command_table = handle->BIOSBase + offset; + else + return ATOM_FAILED; + + if (!rhdAtomGetTableRevisionAndSize(&(((ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *) + command_table)->CommonHeader), + NULL, NULL, &size)) + return ATOM_FAILED; + + for (i = sizeof(ATOM_COMMON_ROM_COMMAND_TABLE_HEADER); i < size - 1; i++) { + + if (command_table[i] == ATOM_EOT_COMMAND + && command_table[i+1] == CODE_DATA_TABLE_SIGNATURE) { + unsigned short *dt_size = (unsigned short*)(command_table + i + 2); + + int diff; + + diff = size - (i + 1) + sizeof(struct atomCodeDataTableHeader) + *dt_size; + + DBG(dbgprintf("Table[0x%2.2x] = 0x%4.4x -> data_size: 0x%x\n",data->val, size, *dt_size)); + + if (diff < 0) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, + "Data table in command table %li extends %i bytes " + "beyond command table size\n", + (unsigned long) data->val, -diff); + + return ATOM_FAILED; + } + data->CommandDataTable.loc = + command_table + i + 2 + sizeof(unsigned short); + + data->CommandDataTable.size = *dt_size; +// DEBUGP(RhdDebugDump(handle->scrnIndex, data->CommandDataTable.loc, *dt_size)); + + return ATOM_SUCCESS; + } + } + + return ATOM_FAILED; +} + +# ifdef ATOM_BIOS_PARSER +static AtomBiosResult +rhdAtomExec (atomBiosHandlePtr handle, + AtomBiosRequestID unused, AtomBiosArgPtr data) +{ + RHDPtr rhdPtr = handle->rhdPtr; + Bool ret = FALSE; + char *msg; + int idx = data->exec.index; + void *pspace = data->exec.pspace; + pointer *dataSpace = data->exec.dataSpace; + + RHDFUNCI(handle->scrnIndex); + + if (dataSpace) { + if (!handle->fbBase && !handle->scratchBase) + return ATOM_FAILED; + if (handle->fbBase) { + if (!rhdPtr->FbBase) { + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: " + "Cannot exec AtomBIOS: framebuffer not mapped\n", + __func__); + return ATOM_FAILED; + } + *dataSpace = (CARD8*)rhdPtr->FbBase + handle->fbBase; + } else + *dataSpace = (CARD8*)handle->scratchBase; + } + ret = ParseTableWrapper(pspace, idx, handle, + handle->BIOSBase, + &msg); + if (!ret) + xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s\n",msg); + else + xf86DrvMsgVerb(handle->scrnIndex, X_INFO, 5, "%s\n",msg); + + return (ret) ? ATOM_SUCCESS : ATOM_FAILED; +} +# endif + +AtomBiosResult +RHDAtomBiosFunc(RHDPtr rhdPtr, atomBiosHandlePtr handle, + AtomBiosRequestID id, AtomBiosArgPtr data) +{ + AtomBiosResult ret = ATOM_FAILED; + int scrnIndex = rhdPtr->scrnIndex; + int i; + char *msg = NULL; + enum msgDataFormat msg_f = MSG_FORMAT_NONE; + AtomBiosRequestFunc req_func = NULL; + + RHDFUNCI(scrnIndex); + + for (i = 0; AtomBiosRequestList[i].id != FUNC_END; i++) { + if (id == AtomBiosRequestList[i].id) { + req_func = AtomBiosRequestList[i].request; + msg = AtomBiosRequestList[i].message; + msg_f = AtomBiosRequestList[i].message_format; + break; + } + } + + if (req_func == NULL) { + xf86DrvMsg(scrnIndex, X_ERROR, "Unknown AtomBIOS request: %i\n",id); + return ATOM_NOT_IMPLEMENTED; + } + /* Hack for now */ + if (id == ATOMBIOS_INIT) + data->val = (CARD32)rhdPtr; + + if (id == ATOMBIOS_INIT || handle) + ret = req_func(handle, id, data); + + if (ret == ATOM_SUCCESS) { + + switch (msg_f) { + case MSG_FORMAT_DEC: + xf86DrvMsg(scrnIndex,X_INFO,"%s: %li\n", msg, + (unsigned long) data->val); + break; + case MSG_FORMAT_HEX: + xf86DrvMsg(scrnIndex,X_INFO,"%s: 0x%lx\n",msg , + (unsigned long) data->val); + break; + case MSG_FORMAT_NONE: + xf86DrvMsgVerb(scrnIndex, 7, X_INFO, + "Call to %s succeeded\n", msg); + break; + } + + } else { + + char *result = (ret == ATOM_FAILED) ? "failed" + : "not implemented"; + switch (msg_f) { + case MSG_FORMAT_DEC: + case MSG_FORMAT_HEX: + xf86DrvMsgVerb(scrnIndex, 1, X_WARNING, + "Call to %s %s\n", msg, result); + break; + case MSG_FORMAT_NONE: + xf86DrvMsg(scrnIndex,X_INFO,"Query for %s: %s\n", msg, result); + break; + } + } + return ret; +} + +/* + * + */ +static void +atomRegisterSaveList(atomBiosHandlePtr handle, struct atomSaveListRecord **SaveList) +{ + struct atomSaveListObject *ListObject = handle->SaveListObjects; + RHDFUNC(handle); + + while (ListObject) { + if (ListObject->SaveList == SaveList) + return; + ListObject = ListObject->next; + } + if (!(ListObject = (struct atomSaveListObject *)xcalloc(1,sizeof (struct atomSaveListObject)))) + return; + ListObject->next = handle->SaveListObjects; + ListObject->SaveList = SaveList; + handle->SaveListObjects = ListObject; +} + +/* + * + */ +static void +atomUnregisterSaveList(atomBiosHandlePtr handle, struct atomSaveListRecord **SaveList) +{ + struct atomSaveListObject **ListObject; + RHDFUNC(handle); + + if (!handle->SaveListObjects) + return; + ListObject = &handle->SaveListObjects; + + while (1) { + if ((*ListObject)->SaveList == SaveList) { + struct atomSaveListObject *tmp = *ListObject; + *ListObject = ((*ListObject)->next); + xfree(tmp); + } + if (!(*ListObject) || !(*ListObject)->next) + return; + ListObject = &((*ListObject)->next); + } +} + +/* + * + */ +static AtomBiosResult +atomSetRegisterListLocation(atomBiosHandlePtr handle, AtomBiosRequestID func, AtomBiosArgPtr data) +{ + RHDFUNC(handle); + + handle->SaveList = (struct atomSaveListRecord **)data->Address; + if (handle->SaveList) + atomRegisterSaveList(handle, handle->SaveList); + + return ATOM_SUCCESS; +} + +/* + * + */ +static AtomBiosResult +atomRestoreRegisters(atomBiosHandlePtr handle, AtomBiosRequestID func, AtomBiosArgPtr data) +{ + struct atomSaveListRecord *List = *(data->Address); + int i; + + RHDFUNC(handle); + + if (!List) + return ATOM_FAILED; + + for (i = 0; i < List->Last; i++) { + switch ( List->RegisterList[i].Type) { + case atomRegisterMMIO: + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: MMIO(0x%4.4x) = 0x%4.4x\n",__func__, List->Last, + List->RegisterList[i].Address, List->RegisterList[i].Value); + RHDRegWrite(handle, List->RegisterList[i].Address, List->RegisterList[i].Value); + break; + case atomRegisterMC: + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: MC(0x%4.4x) = 0x%4.4x\n",__func__, List->Last, + List->RegisterList[i].Address, List->RegisterList[i].Value); + RHDWriteMC(handle, List->RegisterList[i].Address | MC_IND_ALL | MC_IND_WR_EN, + List->RegisterList[i].Value); + break; + case atomRegisterPLL: + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: PLL(0x%4.4x) = 0x%4.4x\n",__func__, List->Last, + List->RegisterList[i].Address, List->RegisterList[i].Value); + _RHDWritePLL(handle->scrnIndex, List->RegisterList[i].Address, List->RegisterList[i].Value); + break; + case atomRegisterPCICFG: + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: PCICFG(0x%4.4x) = 0x%4.4x\n",__func__,List->Last, + List->RegisterList[i].Address, List->RegisterList[i].Value); +#ifdef XSERVER_LIBPCIACCESS + pci_device_cfg_write(RHDPTRI(handle)->PciInfo, + &List->RegisterList[i].Value, + List->RegisterList[i].Address, 4, NULL); +#else + { + PCITAG tag = RHDPTRI(handle)->PciTag; + pciWriteLong(tag, List->RegisterList[i].Address, + List->RegisterList[i].Value); + } +#endif + break; + } + } + + /* deallocate list */ + atomUnregisterSaveList(handle, (struct atomSaveListRecord **)data->Address); + xfree(List); + *(data->Address) = NULL; + + return ATOM_SUCCESS; +} + +# ifdef ATOM_BIOS_PARSER + +#define ALLOC_CNT 25 + +/* + * + */ +static void +atomSaveRegisters(atomBiosHandlePtr handle, enum atomRegisterType Type, CARD32 address) +{ + struct atomSaveListRecord *List; + CARD32 val = 0; + int i; + struct atomSaveListObject *SaveListObj = handle->SaveListObjects; + + RHDFUNC(handle); + + if (!handle->SaveList) + return; + + if (!(*(handle->SaveList))) { + if (!(*handle->SaveList = (struct atomSaveListRecord *)xalloc(sizeof(struct atomSaveListRecord) + + sizeof(struct atomRegisterList) * (ALLOC_CNT - 1)))) + return; + (*(handle->SaveList))->Length = ALLOC_CNT; + (*(handle->SaveList))->Last = 0; + } else if ((*(handle->SaveList))->Length == (*(handle->SaveList))->Last) { + if (!(List = (struct atomSaveListRecord *)xrealloc(*handle->SaveList, + sizeof(struct atomSaveListRecord) + + (sizeof(struct atomRegisterList) + * ((*(handle->SaveList))->Length + ALLOC_CNT - 1))))) + return; + *handle->SaveList = List; + List->Length = (*(handle->SaveList))->Length + ALLOC_CNT; + } + List = *handle->SaveList; + + while (SaveListObj) { + struct atomSaveListRecord *ListFromObj = *(SaveListObj->SaveList); + + if (ListFromObj) { + for (i = 0; i < ListFromObj->Last; i++) + if (ListFromObj->RegisterList[i].Address == address + && ListFromObj->RegisterList[i].Type == Type) + return; + } + SaveListObj = SaveListObj->next; + } + + switch (Type) { + case atomRegisterMMIO: + val = RHDRegRead(handle, address); + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: MMIO(0x%4.4x) = 0x%4.4x\n",__func__,List->Last,address,val); + break; + case atomRegisterMC: + val = RHDReadMC(handle, address | MC_IND_ALL); + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: MC(0x%4.4x) = 0x%4.4x\n",__func__,List->Last,address,val); + break; + case atomRegisterPLL: + val = _RHDReadPLL(handle->scrnIndex, address); + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: PLL(0x%4.4x) = 0x%4.4x\n",__func__,List->Last,address,val); + break; + case atomRegisterPCICFG: +#ifdef XSERVER_LIBPCIACCESS + val = pci_device_cfg_write(RHDPTRI(handle)->PciInfo, + &val, address, 4, NULL); +#else + { + PCITAG tag = RHDPTRI(handle)->PciTag; + val = pciReadLong(tag, address); + } +#endif + RHDDebugVerb(handle->scrnIndex,1, "%s[%i]: PCICFG(0x%4.4x) = 0x%4.4x\n",__func__,List->Last,address,val); + break; + } + List->RegisterList[List->Last].Address = address; + List->RegisterList[List->Last].Value = val; + List->RegisterList[List->Last].Type = Type; + List->Last++; +} + +/* + * + */ +VOID* +CailAllocateMemory(VOID *CAIL,UINT16 size) +{ + CAILFUNC(CAIL); + + return malloc(size); +} + +VOID +CailReleaseMemory(VOID *CAIL, VOID *addr) +{ + CAILFUNC(CAIL); + + free(addr); +} + +VOID +CailDelayMicroSeconds(VOID *CAIL, UINT32 delay) +{ + CAILFUNC(CAIL); + + usleep(delay); + + // DEBUGP(xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_INFO,"Delay %i usec\n",delay)); +} + +UINT32 +CailReadATIRegister(VOID* CAIL, UINT32 idx) +{ + UINT32 ret; + CAILFUNC(CAIL); + + ret = RHDRegRead(((atomBiosHandlePtr)CAIL), idx << 2); +// DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx << 2,ret)); + return ret; +} + +VOID +CailWriteATIRegister(VOID *CAIL, UINT32 idx, UINT32 data) +{ + CAILFUNC(CAIL); + + atomSaveRegisters((atomBiosHandlePtr)CAIL, atomRegisterMMIO, idx << 2); + + RHDRegWrite(((atomBiosHandlePtr)CAIL),idx << 2,data); + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x,%x)\n",__func__,idx << 2,data); +} + +UINT32 +CailReadFBData(VOID* CAIL, UINT32 idx) +{ + UINT32 ret; + + CAILFUNC(CAIL); + + if (((atomBiosHandlePtr)CAIL)->fbBase) { + CARD8 *FBBase = (CARD8*) + RHDPTRI((atomBiosHandlePtr)CAIL)->FbBase; + ret = *((CARD32*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)); + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x) = %x\n",__func__,idx,ret); + } else if (((atomBiosHandlePtr)CAIL)->scratchBase) { + ret = *(CARD32*)((CARD8*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx); + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x) = %x\n",__func__,idx,ret); + } else { + xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR, + "%s: no fbbase set\n",__func__); + return 0; + } + return ret; +} + +VOID +CailWriteFBData(VOID *CAIL, UINT32 idx, UINT32 data) +{ + CAILFUNC(CAIL); + + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x,%x)\n",__func__,idx,data); + if (((atomBiosHandlePtr)CAIL)->fbBase) { + CARD8 *FBBase = (CARD8*) + RHDPTRI((atomBiosHandlePtr)CAIL)->FbBase; + *((CARD32*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)) = data; + } else if (((atomBiosHandlePtr)CAIL)->scratchBase) { + *(CARD32*)((CARD8*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx) = data; + } else + xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR, + "%s: no fbbase set\n",__func__); +} + +ULONG +CailReadMC(VOID *CAIL, ULONG Address) +{ + ULONG ret; + + CAILFUNC(CAIL); + + ret = RHDReadMC(((atomBiosHandlePtr)CAIL)->rhdPtr, Address | MC_IND_ALL); + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x) = %x\n",__func__,Address,ret); + return ret; +} + +VOID +CailWriteMC(VOID *CAIL, ULONG Address, ULONG data) +{ + CAILFUNC(CAIL); + + + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x,%x)\n",__func__,Address,data); + + atomSaveRegisters((atomBiosHandlePtr)CAIL, atomRegisterMC, Address); + + RHDWriteMC(((atomBiosHandlePtr)CAIL)->rhdPtr, Address | MC_IND_ALL | MC_IND_WR_EN, data); +} + +#ifdef XSERVER_LIBPCIACCESS + +VOID +CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size) +{ + pci_device_cfg_read(RHDPTRI((atomBiosHandlePtr)CAIL)->PciInfo, + ret,idx << 2 , size >> 3, NULL); +} + +VOID +CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size) +{ + atomSaveRegisters((atomBiosHandlePtr)CAIL, atomRegisterPCICFG, idx << 2); + pci_device_cfg_write(RHDPTRI((atomBiosHandlePtr)CAIL)->PciInfo, + src, idx << 2, size >> 3, NULL); +} + +#else + +VOID +CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size) +{ u32_t bus, devfn; + PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag; + + CAILFUNC(CAIL); + bus = PCI_BUS_FROM_TAG(tag); + devfn = PCI_DFN_FROM_TAG(tag); + + switch (size) { + case 8: + *(CARD8*)ret = PciRead8(bus,devfn,idx << 2); + break; + case 16: + *(CARD16*)ret = PciRead16(bus,devfn,idx << 2); + break; + case 32: + *(CARD32*)ret = PciRead32(bus,devfn,idx << 2); + break; + default: + xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex, + X_ERROR,"%s: Unsupported size: %i\n", + __func__,(int)size); + return; + break; + } + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x) = %x\n",__func__,idx,*(unsigned int*)ret); + +} + +VOID +CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size) +{ + u32_t bus, devfn; + PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag; + bus = PCI_BUS_FROM_TAG(tag); + devfn = PCI_DFN_FROM_TAG(tag); + + CAILFUNC(CAIL); + + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x,%x)\n",__func__,idx,(*(unsigned int*)src)); + + atomSaveRegisters((atomBiosHandlePtr)CAIL, atomRegisterPCICFG, idx << 2); + switch (size) { + case 8: + PciWrite8(bus,devfn, idx << 2,*(CARD8*)src); + break; + case 16: + PciWrite16(bus,devfn,idx << 2,*(CARD16*)src); + break; + case 32: + PciWrite32(bus,devfn,idx << 2,*(CARD32*)src); + break; + default: + xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR, + "%s: Unsupported size: %i\n",__func__,(int)size); + break; + } +} +#endif + +ULONG +CailReadPLL(VOID *CAIL, ULONG Address) +{ + ULONG ret; + + CAILFUNC(CAIL); + + ret = _RHDReadPLL(((atomBiosHandlePtr)CAIL)->rhdPtr, Address); + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x) = %x\n",__func__,Address,ret); + return ret; +} + +VOID +CailWritePLL(VOID *CAIL, ULONG Address,ULONG Data) +{ + CAILFUNC(CAIL); + + RHDDebugVerb(((atomBiosHandlePtr)CAIL)->scrnIndex,1,"%s(%x,%x)\n",__func__,Address,Data); + atomSaveRegisters((atomBiosHandlePtr)CAIL, atomRegisterPLL, Address); + _RHDWritePLL(((atomBiosHandlePtr)CAIL)->scrnIndex, Address, Data); +} + +# endif + +#endif /* ATOM_BIOS */ diff --git a/programs/system/drivers/rhd/rhd_atombios.h b/programs/system/drivers/rhd/rhd_atombios.h new file mode 100644 index 000000000..af21dc3c8 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atombios.h @@ -0,0 +1,543 @@ +/* + * Copyright 2007, 2008 Egbert Eich + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * 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. + */ + + +#ifndef RHD_ATOMBIOS_H_ +# define RHD_ATOMBIOS_H_ + +# ifdef ATOM_BIOS + +#define RHD_ATOMBIOS_ON 1 +#define RHD_ATOMBIOS_OFF 2 +#define RHD_ATOMBIOS_FORCE 4 +#define RHD_ATOMBIOS_CRTC 0 +#define RHD_ATOMBIOS_PLL 4 +#define RHD_ATOMBIOS_OUTPUT 8 + +typedef enum _AtomBiosRequestID { + ATOMBIOS_INIT, + ATOMBIOS_TEARDOWN, +# ifdef ATOM_BIOS_PARSER + ATOMBIOS_EXEC, +# endif + ATOMBIOS_ALLOCATE_FB_SCRATCH, + ATOMBIOS_GET_CONNECTORS, + ATOMBIOS_GET_OUTPUT_DEVICE_LIST, + ATOMBIOS_GET_PANEL_MODE, + ATOMBIOS_GET_PANEL_EDID, + ATOMBIOS_GET_CODE_DATA_TABLE, + GET_DEFAULT_ENGINE_CLOCK, + GET_DEFAULT_MEMORY_CLOCK, + GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, + GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, + GET_MAX_PIXEL_CLOCK_PLL_INPUT, + GET_MIN_PIXEL_CLOCK_PLL_INPUT, + GET_MAX_PIXEL_CLK, + GET_REF_CLOCK, + GET_FW_FB_START, + GET_FW_FB_SIZE, + ATOM_TMDS_MAX_FREQUENCY, + ATOM_TMDS_PLL_CHARGE_PUMP, + ATOM_TMDS_PLL_DUTY_CYCLE, + ATOM_TMDS_PLL_VCO_GAIN, + ATOM_TMDS_PLL_VOLTAGE_SWING, + ATOM_LVDS_SUPPORTED_REFRESH_RATE, + ATOM_LVDS_OFF_DELAY, + ATOM_LVDS_SEQ_DIG_ONTO_DE, + ATOM_LVDS_SEQ_DE_TO_BL, + ATOM_LVDS_SPATIAL_DITHER, + ATOM_LVDS_TEMPORAL_DITHER, + ATOM_LVDS_DUALLINK, + ATOM_LVDS_24BIT, + ATOM_LVDS_GREYLVL, + ATOM_LVDS_FPDI, + ATOM_GPIO_QUERIES, + ATOM_GPIO_I2C_CLK_MASK, + ATOM_GPIO_I2C_CLK_MASK_SHIFT, + ATOM_GPIO_I2C_DATA_MASK, + ATOM_GPIO_I2C_DATA_MASK_SHIFT, + ATOM_DAC1_BG_ADJ, + ATOM_DAC1_DAC_ADJ, + ATOM_DAC1_FORCE, + ATOM_DAC2_CRTC2_BG_ADJ, + ATOM_DAC2_NTSC_BG_ADJ, + ATOM_DAC2_PAL_BG_ADJ, + ATOM_DAC2_CV_BG_ADJ, + ATOM_DAC2_CRTC2_DAC_ADJ, + ATOM_DAC2_NTSC_DAC_ADJ, + ATOM_DAC2_PAL_DAC_ADJ, + ATOM_DAC2_CV_DAC_ADJ, + ATOM_DAC2_CRTC2_FORCE, + ATOM_DAC2_CRTC2_MUX_REG_IND, + ATOM_DAC2_CRTC2_MUX_REG_INFO, + ATOM_ANALOG_TV_MODE, + ATOM_ANALOG_TV_DEFAULT_MODE, + ATOM_ANALOG_TV_SUPPORTED_MODES, + ATOM_GET_CONDITIONAL_GOLDEN_SETTINGS, + ATOM_GET_PCIENB_CFG_REG7, + ATOM_GET_CAPABILITY_FLAG, + ATOM_GET_PCIE_LANES, + ATOM_SET_REGISTER_LIST_LOCATION, + ATOM_RESTORE_REGISTERS, + FUNC_END +} AtomBiosRequestID; + +typedef enum _AtomBiosResult { + ATOM_SUCCESS, + ATOM_FAILED, + ATOM_NOT_IMPLEMENTED +} AtomBiosResult; + +typedef struct AtomExec { + int index; + pointer pspace; + pointer *dataSpace; +} AtomExecRec, *AtomExecPtr; + +typedef struct AtomFb { + unsigned int start; + unsigned int size; +} AtomFbRec, *AtomFbPtr; + +struct AtomDacCodeTableData +{ + CARD8 DAC1PALWhiteFine; + CARD8 DAC1PALBandGap; + CARD8 DAC1NTSCWhiteFine; + CARD8 DAC1NTSCBandGap; + CARD8 DAC1VGAWhiteFine; + CARD8 DAC1VGABandGap; + CARD8 DAC1CVWhiteFine; + CARD8 DAC1CVBandGap; + CARD8 DAC2PALWhiteFine; + CARD8 DAC2PALBandGap; + CARD8 DAC2NTSCWhiteFine; + CARD8 DAC2NTSCBandGap; + CARD8 DAC2VGAWhiteFine; + CARD8 DAC2VGABandGap; + CARD8 DAC2CVWhiteFine; + CARD8 DAC2CVBandGap; +}; + +typedef enum AtomTVMode { + ATOM_TVMODE_NTSC = 1 << 0, + ATOM_TVMODE_NTSCJ = 1 << 1, + ATOM_TVMODE_PAL = 1 << 2, + ATOM_TVMODE_PALM = 1 << 3, + ATOM_TVMODE_PALCN = 1 << 4, + ATOM_TVMODE_PALN = 1 << 5, + ATOM_TVMODE_PAL60 = 1 << 6, + ATOM_TVMODE_SECAM = 1 << 7, + ATOM_TVMODE_CV = 1 << 8 +} AtomTVMode; + +enum atomPCIELanes { + atomPCIELaneNONE, + atomPCIELane0_3, + atomPCIELane0_7, + atomPCIELane4_7, + atomPCIELane8_11, + atomPCIELane8_15, + atomPCIELane12_15 +}; + +enum atomDevice { + atomNone, /* 0 */ + atomCRT1, /* 1 */ + atomLCD1, /* 2 */ + atomTV1, /* 3 */ + atomDFP1, /* 4 */ + atomCRT2, /* 5 */ + atomLCD2, /* 6 */ + atomTV2, /* 7 */ + atomDFP2, /* 8 */ + atomCV, /* 9 */ + atomDFP3, /* a */ + atomDFP4, /* b */ + atomDFP5 /* c */ +}; + +typedef struct AtomGoldenSettings +{ + unsigned char *BIOSPtr; + unsigned char *End; + unsigned int value; + +} AtomGoldenSettings; + +typedef union AtomBiosArg +{ + CARD32 val; + struct rhdConnectorInfo *ConnectorInfo; + struct rhdAtomOutputDeviceList *OutputDeviceList; + enum RHD_CHIPSETS chipset; + struct AtomGoldenSettings GoldenSettings; + unsigned char* EDIDBlock; + void **Address; + struct { + unsigned char *loc; + unsigned short size; + } CommandDataTable; + struct { + enum atomPCIELanes Chassis; + enum atomPCIELanes Docking; + } pcieLanes; + atomBiosHandlePtr atomhandle; + DisplayModePtr mode; + AtomExecRec exec; + AtomFbRec fb; + enum RHD_TV_MODE tvMode; +} AtomBiosArgRec, *AtomBiosArgPtr; + +enum atomCrtc { + atomCrtc1, + atomCrtc2 +}; + +enum atomCrtcAction { + atomCrtcEnable, + atomCrtcDisable +}; + +enum atomOutputLinks { + atomSingleLink, + atomDualLink +}; + +enum atomTransmitter { + atomTransmitterLVTMA, + atomTransmitterUNIPHY, + atomTransmitterUNIPHY1, + atomTransmitterUNIPHY2, + atomTransmitterPCIEPHY, + atomTransmitterDIG1, + atomTransmitterDIG2 +}; + +enum atomTransmitterAction { + atomTransDisable, + atomTransEnable, + atomTransEnableOutput, + atomTransDisableOutput, + atomTransInit, + atomTransLcdBlOff, + atomTransLcdBlOn, + atomTransLcdBlBrightness, + atomTransSetup +}; + +enum atomEncoder { + atomEncoderNone, + atomEncoderDACA, + atomEncoderDACB, + atomEncoderTV, + atomEncoderTMDS1, /* TMDSA */ + atomEncoderTMDS2, /* LVTMA */ + atomEncoderLVDS, /* LVTMA (Panel) */ + atomEncoderDVO, + atomEncoderDIG1, + atomEncoderDIG2, + atomEncoderExternal +}; + +enum atomEncoderMode { + atomNoEncoder, + atomDVI, + atomDP, + atomLVDS, + atomHDMI, + atomSDVO, + atomTVComposite, + atomTVSVideo, + atomTVComponent, + atomCRT +}; + +enum atomEncoderAction { + atomEncoderOff, + atomEncoderOn +}; + +enum atomOutput { + atomDVOOutput, + atomLCDOutput, + atomCVOutput, + atomTVOutput, + atomLVTMAOutput, + atomTMDSAOutput, + atomDAC1Output, + atomDAC2Output +}; + +enum atomOutputType { + atomOutputNone, + atomOutputDacA, + atomOutputDacB, + atomOutputTmdsa, + atomOutputLvtma, + atomOutputDvo, + atomOutputKldskpLvtma, + atomOutputUniphyA, + atomOutputUniphyB, + atomOutputUniphyC, + atomOutputUniphyD, + atomOutputUniphyE, + atomOutputUniphyF +}; + +enum atomOutputAction { + atomOutputEnable, + atomOutputDisable, + atomOutputLcdOn, + atomOutputLcdOff, + atomOutputLcdBrightnessControl, + atomOutputLcdSelftestStart, + atomOutputLcdSelftestStop, + atomOutputEncoderInit +}; + +enum atomDAC { + atomDACA, + atomDACB, + atomDACExt +}; + +enum atomTransmitterLink { + atomTransLinkA, + atomTransLinkAB, + atomTransLinkB, + atomTransLinkBA +}; + +enum atomDACStandard { + atomDAC_VGA, + atomDAC_CV, + atomDAC_NTSC, + atomDAC_PAL +}; + +enum atomDVORate { + atomDVO_RateSDR, + atomDVO_RateDDR +}; + +enum atomDVOOutput { + atomDVO_OutputLow12Bit, + atomDVO_OutputHigh12Bit, + atomDVO_Output24Bit +}; + +enum atomScaler { + atomScaler1, + atomScaler2 +}; + +enum atomScaleMode { + atomScaleDisable, + atomScaleCenter, + atomScaleExpand, + atomScaleMulttabExpand +}; + +enum atomPxclk { + atomPclk1, + atomPclk2 +}; + +struct atomCodeTableVersion +{ + CARD8 cref; + CARD8 fref; +}; + +enum atomTemporalGreyLevels { + atomTemporalDither0, + atomTemporalDither4, + atomTemporalDither2 +}; + +struct atomTransmitterConfig +{ + int PixelClock; + enum atomEncoder Encoder; + enum atomPCIELanes Lanes; + enum atomEncoderMode Mode; + enum atomTransmitterLink Link; + enum atomOutputLinks LinkCnt; + Bool Coherent; +}; + +struct atomEncoderConfig +{ + int PixelClock; + union { + struct { + enum atomDACStandard DacStandard; + } dac; + struct { + enum RHD_TV_MODE TvStandard; + } tv; + struct { + enum atomOutputLinks LinkCnt; + Bool Is24bit; + } lvds; + struct { + enum atomOutputLinks LinkCnt; + Bool Is24bit; + Bool Coherent; + Bool LinkB; + Bool Hdmi; + Bool SpatialDither; + enum atomTemporalGreyLevels TemporalGrey; + } lvds2; + struct { + enum atomTransmitterLink Link; + enum atomOutputLinks LinkCnt; + enum atomTransmitter Transmitter; + enum atomEncoderMode EncoderMode; + } dig; + struct { + enum atomDevice DvoDeviceType; + int EncoderID; + Bool digital; + union + { + enum RHD_TV_MODE TVMode; + char dummy; /* @@@ placeholder for digital attributes */ + } u; + } dvo; + struct{ + enum atomDVORate Rate; + enum atomDVOOutput DvoOutput; + } dvo3; + } u; +}; + +struct atomCrtcSourceConfig +{ + union { + enum atomDevice Device; + struct { + enum atomEncoder Encoder; + enum atomEncoderMode Mode; + } crtc2; + } u; +}; + +struct atomPixelClockConfig { + Bool Enable; + int PixelClock; + int RefDiv; + int FbDiv; + int PostDiv; + int FracFbDiv; + enum atomCrtc Crtc; + union { + struct { + Bool Force; + enum atomDevice Device; + } v2; + struct { + Bool Force; + enum atomOutputType OutputType; + enum atomEncoderMode EncoderMode; + Bool UsePpll; + } v3; + } u; +}; + +struct atomCrtcOverscan { + unsigned short ovscnLeft; + unsigned short ovscnRight; + unsigned short ovscnTop; + unsigned short ovscnBottom; +}; + +enum atomBlankAction { + atomBlankOn, + atomBlankOff +}; + +struct atomCrtcBlank { + enum atomBlankAction Action; + unsigned short r, g, b; +}; + +extern AtomBiosResult RHDAtomBiosFunc(RHDPtr rhdPtr, atomBiosHandlePtr handle, + AtomBiosRequestID id, AtomBiosArgPtr data); + +# ifdef ATOM_BIOS_PARSER +extern Bool rhdAtomSetTVEncoder(atomBiosHandlePtr handle, Bool enable, int mode); + +# if 0 +extern Bool rhdAtomASICInit(atomBiosHandlePtr handle); +extern struct atomCodeTableVersion rhdAtomASICInitVersion(atomBiosHandlePtr handle); +# endif +extern Bool rhdAtomSetScaler(atomBiosHandlePtr handle, enum atomScaler scaler, + enum atomScaleMode mode); +extern struct atomCodeTableVersion rhdAtomSetScalerVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomDigTransmitterControl(atomBiosHandlePtr handle, enum atomTransmitter id, + enum atomTransmitterAction action, + struct atomTransmitterConfig *config); +extern struct atomCodeTableVersion rhdAtomDigTransmitterControlVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomOutputControl(atomBiosHandlePtr handle, enum atomOutput id, + enum atomOutputAction action); +extern struct atomCodeTableVersion rhdAtomOutputControlVersion(atomBiosHandlePtr handle, + enum atomOutput id); +extern Bool AtomDACLoadDetection(atomBiosHandlePtr handle, enum atomDevice id, enum atomDAC dac); +extern struct atomCodeTableVersion AtomDACLoadDetectionVersion(atomBiosHandlePtr handle, enum atomDevice id); +extern Bool rhdAtomEncoderControl(atomBiosHandlePtr handle, enum atomEncoder id, + enum atomEncoderAction action, struct atomEncoderConfig *config); +struct atomCodeTableVersion rhdAtomEncoderControlVersion(atomBiosHandlePtr handle, +enum atomEncoder id); +extern Bool rhdAtomUpdateCRTC_DoubleBufferRegisters(atomBiosHandlePtr handle, enum atomCrtc id, + enum atomCrtcAction action); +extern struct atomCodeTableVersion rhdAtomUpdateCRTC_DoubleBufferRegistersVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomEnableCrtc(atomBiosHandlePtr handle, enum atomCrtc id, + enum atomCrtcAction action); +extern struct atomCodeTableVersion rhdAtomEnableCrtcVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomEnableCrtcMemReq(atomBiosHandlePtr handle, enum atomCrtc id, + enum atomCrtcAction action); +extern struct atomCodeTableVersion rhdAtomEnableCrtcMemReqVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomSetCRTCTimings(atomBiosHandlePtr handle, enum atomCrtc id, DisplayModePtr mode, + int depth); +extern struct atomCodeTableVersion rhdAtomSetCRTCTimingsVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomSetPixelClock(atomBiosHandlePtr handle, enum atomPxclk id, + struct atomPixelClockConfig *config); +extern struct atomCodeTableVersion rhdAtomSetPixelClockVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomSelectCrtcSource(atomBiosHandlePtr handle, enum atomCrtc id, + struct atomCrtcSourceConfig *config); +extern struct atomCodeTableVersion rhdAtomSelectCrtcSourceVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomSetCRTCOverscan(atomBiosHandlePtr handle, enum atomCrtc id, + struct atomCrtcOverscan *config); +struct atomCodeTableVersion rhdAtomSetCRTCOverscanVersion(atomBiosHandlePtr handle); +extern Bool rhdAtomBlankCRTC(atomBiosHandlePtr handle, enum atomCrtc id, struct atomCrtcBlank *config); +extern struct atomCodeTableVersion rhdAtomBlankCRTCVersion(atomBiosHandlePtr handle); + +# endif /* ATOM_BIOS_PASER */ + +# endif /* ATOM_BIOS */ + +#endif /* RHD_ATOMBIOS_H_ */ diff --git a/programs/system/drivers/rhd/rhd_atomcrtc.c b/programs/system/drivers/rhd/rhd_atomcrtc.c new file mode 100644 index 000000000..3ae1c8772 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atomcrtc.c @@ -0,0 +1,452 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_pll.h" +#include "rhd_lut.h" +#include "rhd_regs.h" +#include "rhd_modes.h" +#include "rhd_mc.h" +#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) +# include "rhd_atombios.h" + +# define D1_REG_OFFSET 0x0000 +# define D2_REG_OFFSET 0x0800 + +struct rhdCrtcScalePrivate { + void *RegList; + CARD32 StoreViewportSize; + CARD32 StoreViewportStart; +}; + +/* + * + */ +static void +rhdAtomCrtcRestore(struct rhdCrtc *Crtc, void *Store) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + union AtomBiosArg data; + + RHDFUNC(rhdPtr); + + data.Address = Store; + RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_RESTORE_REGISTERS, &data); +} + +/* + * + */ +static void +rhdAtomScaleSet(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type, + DisplayModePtr Mode, DisplayModePtr ScaledToMode) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + struct rhdScalerOverscan Overscan; + struct atomCrtcOverscan AtomOverscan; + enum atomCrtc AtomCrtc = RHD_CRTC_1; + enum atomScaler Scaler = 0; + enum atomScaleMode ScaleMode = 0; + union AtomBiosArg data; + CARD32 RegOff = 0; + + RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i\n", __func__, Crtc->Name, + Mode->CrtcHDisplay, Mode->CrtcVDisplay); + + /* D1Mode registers */ + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, + Mode->CrtcVDisplay | (Mode->CrtcHDisplay << 16)); + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, 0); + + Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type); + Type = Overscan.Type; + + ASSERT(Crtc->ScalePriv); + data.Address = &((Crtc->ScalePriv)->RegList); + RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + AtomOverscan.ovscnLeft = Overscan.OverscanLeft; + AtomOverscan.ovscnRight = Overscan.OverscanRight; + AtomOverscan.ovscnTop = Overscan.OverscanTop; + AtomOverscan.ovscnBottom = Overscan.OverscanBottom; + + switch (Crtc->Id) { + case RHD_CRTC_1: + Scaler = atomScaler1; + AtomCrtc = atomCrtc1; + break; + case RHD_CRTC_2: + Scaler = atomScaler2; + AtomCrtc = atomCrtc2; + break; + } + + rhdAtomSetCRTCOverscan(rhdPtr->atomBIOS, AtomCrtc, &AtomOverscan); + + switch (Type) { + case RHD_CRTC_SCALE_TYPE_NONE: + ScaleMode = atomScaleDisable; + break; + case RHD_CRTC_SCALE_TYPE_CENTER: + ScaleMode = atomScaleCenter; + break; + case RHD_CRTC_SCALE_TYPE_SCALE: + case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO: /* scaled to fullscreen */ + ScaleMode = atomScaleExpand; + break; + } + rhdAtomSetScaler(rhdPtr->atomBIOS, Scaler, ScaleMode); + + data.Address = NULL; + RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + RHDTuneMCAccessForDisplay(rhdPtr, Crtc->Id, Mode, + ScaledToMode ? ScaledToMode : Mode); +} + +/* + * + */ +static void +rhdAtomScaleSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcScalePrivate* ScalePriv; + CARD32 RegOff = 0; + + RHDFUNC(Crtc); + + if (!Crtc->ScalePriv) { + if(!(ScalePriv = (struct rhdCrtcScalePrivate*)xnfcalloc(1, sizeof(struct rhdCrtcScalePrivate)))) + return; + Crtc->ScalePriv = ScalePriv; + } else + ScalePriv = Crtc->ScalePriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + ScalePriv->StoreViewportSize = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_SIZE); + ScalePriv->StoreViewportStart = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_START); + ScalePriv->RegList = NULL; +} + +/* + * + */ +static void +rhdAtomCrtcScaleRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcScalePrivate* ScalePriv; + CARD32 RegOff = 0; + + RHDFUNC(Crtc); + + rhdAtomCrtcRestore(Crtc, &(((struct rhdCrtcScalePrivate*)Crtc->ScalePriv)->RegList)); + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + ScalePriv = (struct rhdCrtcScalePrivate*)Crtc->ScalePriv; + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, ScalePriv->StoreViewportSize); + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, ScalePriv->StoreViewportStart); +} + +/* + * + */ +static void +rhdAtomCrtcScaleDestroy(struct rhdCrtc *Crtc) +{ + RHDFUNC(Crtc); + + if (Crtc->ScalePriv) { + xfree(Crtc->ScalePriv->RegList); + xfree(Crtc->ScalePriv); + Crtc->ScalePriv = NULL; + } +} + +/* + * + */ +struct rhdCrtcModePrivate { + void *RegList; + CARD32 StoreModeDataFormat; +}; + +static void +rhdAtomModeSet(struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + union AtomBiosArg data; + CARD32 RegOff = 0; + + RHDFUNC(rhdPtr); + + ASSERT(Crtc->ModePriv); + data.Address = &((Crtc->ModePriv)->RegList); + RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + if (!rhdAtomSetCRTCTimings(rhdPtr->atomBIOS, + Crtc->Id == RHD_CRTC_1 ? atomCrtc1 : atomCrtc2, + Mode, 32)) + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: failed to set mode.\n",__func__); + + /* set interlaced - AtomBIOS never sets the data format - never tested? */ + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + if (Mode->Flags & V_INTERLACE) + RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x1); + else + RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x0); + + data.Address = NULL; + RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); +} + +/* + * + */ +static void +rhdAtomCrtcPower(struct rhdCrtc *Crtc, int Power) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + enum atomCrtc AtomCrtc = atomCrtc1; + union AtomBiosArg data; + + RHDFUNC(Crtc); + + switch (Crtc->Id) { + case RHD_CRTC_1: + AtomCrtc = atomCrtc1; + break; + case RHD_CRTC_2: + AtomCrtc = atomCrtc2; + break; + } + data.Address = &((Crtc->ModePriv)->RegList); + RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + /* + * We call rhdAtomEnableCrtcMemReq blindly as this table seemed to have existed in all + * versions of AtomBIOS on the hardware we support + */ + switch (Power) { + case RHD_POWER_ON: + rhdAtomEnableCrtcMemReq(rhdPtr->atomBIOS, AtomCrtc, atomCrtcEnable); + rhdAtomEnableCrtc(rhdPtr->atomBIOS, AtomCrtc, atomCrtcEnable); + break; + case RHD_POWER_RESET: + case RHD_POWER_SHUTDOWN: + default: + rhdAtomEnableCrtc(rhdPtr->atomBIOS, AtomCrtc, atomCrtcDisable); + rhdAtomEnableCrtcMemReq(rhdPtr->atomBIOS, AtomCrtc, atomCrtcDisable); + break; + } + data.Address = NULL; + RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); +} + +/* + * + */ +static void +rhdAtomCrtcBlank(struct rhdCrtc *Crtc, Bool Blank) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + enum atomCrtc AtomCrtc = atomCrtc1; + struct atomCrtcBlank Config; + union AtomBiosArg data; + + RHDFUNC(Crtc); + + switch (Crtc->Id) { + case RHD_CRTC_1: + AtomCrtc = atomCrtc1; + break; + case RHD_CRTC_2: + AtomCrtc = atomCrtc2; + break; + } + if (Blank) + Config.Action = atomBlankOn; + else + Config.Action = atomBlankOff; + + Config.r = Config.g = Config.b = 0; + + data.Address = &((Crtc->ModePriv)->RegList); + RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + rhdAtomBlankCRTC(rhdPtr->atomBIOS, AtomCrtc , &Config); + + data.Address = NULL; + RHDAtomBiosFunc(Crtc->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); +} + +/* + * + */ +static void +rhdAtomModeSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcModePrivate* ModePriv; + CARD32 RegOff = 0; + + if (!Crtc->ModePriv) { + if(!(ModePriv = (struct rhdCrtcModePrivate*)xnfcalloc(1, sizeof(struct rhdCrtcModePrivate)))) + return; + Crtc->ModePriv = ModePriv; + } else + ModePriv = Crtc->ModePriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + ModePriv->StoreModeDataFormat = RHDRegRead(Crtc, RegOff + D1MODE_DATA_FORMAT); + ModePriv->RegList = NULL; +} + +/* + * + */ +static void +rhdAtomModeRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcModePrivate* ModePriv; + CARD32 RegOff = 0; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + ModePriv = Crtc->ModePriv; + + rhdAtomCrtcRestore(Crtc, &ModePriv->RegList); + + RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, ModePriv->StoreModeDataFormat); +} + +/* + * + */ +static void +rhdAtomModeDestroy(struct rhdCrtc *Crtc) +{ + RHDFUNC(Crtc); + + if (Crtc->ModePriv) { + xfree(Crtc->ModePriv->RegList); + xfree(Crtc->ModePriv); + Crtc->ModePriv = NULL; + } +} + +/* + * + */ +void +RHDAtomCrtcsInit(RHDPtr rhdPtr) +{ + struct rhdCrtc *Crtc; + int i; + + RHDFUNC(rhdPtr); + + if (rhdPtr->Crtc[0] == NULL || rhdPtr->Crtc[1] == NULL) { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: CRTCs not initialized\n",__func__); + return; + } + + for (i = 0; i < 2; i++) { + + Crtc = rhdPtr->Crtc[i]; + + if (i == 0) { + Crtc->Name = "ATOM CRTC 1"; + Crtc->Id = RHD_CRTC_1; + } else { + Crtc->Name = "ATOM CRTC 2"; + Crtc->Id = RHD_CRTC_2; + } + + /* EnableGraphSurfaces is only a BIOS internal table. So use the hardcoded path. + Crtc->FBValid = atomFBValid; + Crtc->FBSet = atomFBSet; + Crtc->FBSave = atomSave; + Crtc->FBRestore = atomRestore; + */ + + /* There is no separate function to set up the LUT thru AtomBIOS */ + + /* Crtc->ScaleValid: From rhd_crtc.c */ + Crtc->ScaleSet = rhdAtomScaleSet; + Crtc->ScaleSave = rhdAtomScaleSave; + Crtc->ScaleRestore = rhdAtomCrtcScaleRestore; + Crtc->ScaleDestroy = rhdAtomCrtcScaleDestroy; + + /* No such AtomBIOS table */ + /* Crtc->FrameSet = atomViewPortStart; */ + + /* Crtc->ModeValid: From rhd_crtc.c */ + Crtc->ModeSet = rhdAtomModeSet; + Crtc->ModeSave = rhdAtomModeSave; + Crtc->ModeRestore = rhdAtomModeRestore; + Crtc->ModeDestroy = rhdAtomModeDestroy; + + Crtc->Power = rhdAtomCrtcPower; + Crtc->Blank = rhdAtomCrtcBlank; + } +} + +#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ diff --git a/programs/system/drivers/rhd/rhd_atomout.c b/programs/system/drivers/rhd/rhd_atomout.c new file mode 100644 index 000000000..110323fbf --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atomout.c @@ -0,0 +1,1208 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +# include +# include +#endif + +#include "rhd.h" +#include "edid.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_crtc.h" +#include "rhd_atombios.h" +#include "rhd_atomout.h" +#include "rhd_biosscratch.h" +#include "rhd_hdmi.h" + +#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) +struct rhdAtomOutputPrivate { + Bool Stored; + + struct atomCodeTableVersion EncoderVersion; + struct atomCodeTableVersion CrtcSourceVersion; + struct atomEncoderConfig EncoderConfig; + enum atomEncoder EncoderId; + + struct atomTransmitterConfig TransmitterConfig; + enum atomTransmitter TransmitterId; + + enum atomOutput OutputControlId; + + Bool RunDualLink; + int PixelClock; + + void *Save; + + CARD16 PowerDigToDE; + CARD16 PowerDEToBL; + CARD16 OffDelay; + Bool TemporalDither; + Bool SpatialDither; + int GreyLevel; + Bool DualLink; + Bool LVDS24Bit; + Bool FPDI; + + Bool Coherent; + DisplayModePtr Mode; + struct rhdHdmi *Hdmi; + + int BlLevel; +}; + +#define ERROR_MSG(x) xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: %s failed.\n", __func__, x) + +/* + * + */ +static inline void +rhdSetEncoderTransmitterConfig(struct rhdOutput *Output, int PixelClock) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + struct atomEncoderConfig *EncoderConfig = &Private->EncoderConfig; + struct atomTransmitterConfig *TransmitterConfig = &Private->TransmitterConfig; + + RHDFUNC(Output); + + EncoderConfig->PixelClock = TransmitterConfig->PixelClock = PixelClock; + + switch (Output->Id) { + case RHD_OUTPUT_NONE: + break; + case RHD_OUTPUT_DVO: + + EncoderConfig->u.dvo.DvoDeviceType = Output->OutputDriverPrivate->Device; + switch (EncoderConfig->u.dvo.DvoDeviceType) { + case atomCRT1: + case atomCRT2: + EncoderConfig->u.dvo.digital = FALSE; + break; + case atomTV1: + case atomTV2: + case atomCV: + EncoderConfig->u.dvo.digital = FALSE; + EncoderConfig->u.dvo.u.TVMode = rhdPtr->tvMode; + break; + case atomLCD1: + case atomDFP1: + case atomDFP2: + case atomLCD2: + case atomDFP3: + case atomDFP4: + case atomDFP5: + EncoderConfig->u.dvo.digital = TRUE; + /* @@@ no digital attributes, yet */ + break; + case atomNone: + break; + } + break; + case RHD_OUTPUT_DACA: + case RHD_OUTPUT_DACB: + switch (Output->SensedType) { + case RHD_SENSED_VGA: + EncoderConfig->u.dac.DacStandard = atomDAC_VGA; + break; + case RHD_SENSED_TV_COMPONENT: + EncoderConfig->u.dac.DacStandard = atomDAC_CV; + break; + case RHD_SENSED_TV_SVIDEO: + case RHD_SENSED_TV_COMPOSITE: + switch (rhdPtr->tvMode) { + case RHD_TV_NTSC: + case RHD_TV_NTSCJ: + EncoderConfig->u.dac.DacStandard = atomDAC_NTSC; + /* NTSC */ + break; + case RHD_TV_PAL: + case RHD_TV_PALN: + case RHD_TV_PALCN: + case RHD_TV_PAL60: + default: + EncoderConfig->u.dac.DacStandard = atomDAC_PAL; + /* PAL */ + break; + } + break; + case RHD_SENSED_NONE: + EncoderConfig->u.dac.DacStandard = atomDAC_VGA; + break; + default: + xf86DrvMsg(Output->scrnIndex, X_ERROR, "Sensed incompatible output for DAC\n"); + EncoderConfig->u.dac.DacStandard = atomDAC_VGA; + break; + } + break; + + case RHD_OUTPUT_TMDSA: + case RHD_OUTPUT_LVTMA: + if (Output->Connector && PixelClock > 0) { + if (Output->Connector->Type == RHD_CONNECTOR_DVI +#if 0 + || Output->Connector->Type == RHD_CONNECTOR_HDMI_B +#endif + ) + Private->RunDualLink = (PixelClock > 165000) ? TRUE : FALSE; + else + Private->RunDualLink = FALSE; + } else + /* only get here for power down: thus power down both channels to be save */ + Private->RunDualLink = TRUE; + + switch (Private->EncoderVersion.cref) { + case 1: + if (Private->RunDualLink) + EncoderConfig->u.lvds.LinkCnt = atomDualLink; + else + EncoderConfig->u.lvds.LinkCnt = atomSingleLink; + break; + case 2: + case 3: + if (Private->RunDualLink) + EncoderConfig->u.lvds2.LinkCnt = atomDualLink; + else + EncoderConfig->u.lvds2.LinkCnt = atomSingleLink; + if (Private->Coherent) + EncoderConfig->u.lvds2.Coherent = TRUE; + else + EncoderConfig->u.lvds2.Coherent = FALSE; + break; + } + break; + + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + if (Output->Connector && PixelClock > 0) { + if (Output->Connector->Type == RHD_CONNECTOR_DVI +#if 0 + || Output->Connector->Type == RHD_CONNECTOR_DP_DUAL + || Output->Connector->Type == RHD_CONNECTOR_HDMI_B +#endif + ) + Private->RunDualLink = (PixelClock > 165000) ? TRUE : FALSE; + else + Private->RunDualLink = FALSE; + } else + /* only get here for power down: thus power down both channels to be save */ + Private->RunDualLink = TRUE; + + if (Private->RunDualLink) { + TransmitterConfig->LinkCnt = EncoderConfig->u.dig.LinkCnt = atomDualLink; + if (TransmitterConfig->Link == atomTransLinkA) + TransmitterConfig->Link = atomTransLinkAB; + else if (TransmitterConfig->Link == atomTransLinkB) + TransmitterConfig->Link = atomTransLinkBA; + } else { + TransmitterConfig->LinkCnt = EncoderConfig->u.dig.LinkCnt = atomSingleLink; + if (TransmitterConfig->Link == atomTransLinkAB) + TransmitterConfig->Link = atomTransLinkA; + else if (TransmitterConfig->Link == atomTransLinkBA) + TransmitterConfig->Link = atomTransLinkB; + } + TransmitterConfig->Coherent = Private->Coherent; + break; + } +} + +/* + * + */ +static void +atomSetBacklightFromBIOSScratch(struct rhdOutput *Output) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + + RHDFUNC(Output); + + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + rhdSetEncoderTransmitterConfig(Output, Private->PixelClock); + if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, + atomTransLcdBlBrightness, &Private->TransmitterConfig)) + ERROR_MSG("rhdAtomDigTransmitterControl(atomTransEnable)"); + break; + default: + if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputLcdBrightnessControl)) + ERROR_MSG("rhdAtomOutputControl(atomOutputLcdBrightnessControl)"); + break; + } +} + +/* + * + */ +static void +atomSetBacklight(struct rhdOutput *Output, int value) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + RHDAtomBIOSScratchBlLevel(rhdPtr, rhdBIOSScratchBlSet, &value); + + atomSetBacklightFromBIOSScratch(Output); +} + +/* + * + */ +static inline void +rhdAtomOutputSet(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + struct atomEncoderConfig *EncoderConfig = &Private->EncoderConfig; + struct atomCrtcSourceConfig CrtcSourceConfig; + union AtomBiosArg data; + + RHDFUNC(Output); + + Private->Mode = Mode; + + data.Address = &Private->Save; + RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + Private->PixelClock = Mode->SynthClock; + rhdSetEncoderTransmitterConfig(Output, Private->PixelClock); + + switch ( Private->CrtcSourceVersion.cref){ + case 1: + CrtcSourceConfig.u.Device = Output->OutputDriverPrivate->Device; + break; + case 2: + CrtcSourceConfig.u.crtc2.Encoder = Private->EncoderId; + CrtcSourceConfig.u.crtc2.Mode = EncoderConfig->u.dig.EncoderMode; + break; + default: + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "Unknown version of SelectCrtcSource code table: %i\n",Private->CrtcSourceVersion.cref); + return; + } + switch (Output->Id) { + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: +#if 1 + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, atomTransInit, + &Private->TransmitterConfig); +#endif + case RHD_OUTPUT_KLDSKP_LVTMA: + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, atomTransSetup, + &Private->TransmitterConfig); + break; + default: + break; + } + + rhdAtomSelectCrtcSource(rhdPtr->atomBIOS, Output->Crtc->Id ? atomCrtc2 : atomCrtc1, &CrtcSourceConfig); + data.Address = NULL; + RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + RHDHdmiSetMode(Private->Hdmi, Mode); +} + +/* + * + */ +static inline void +rhdAtomOutputPower(struct rhdOutput *Output, int Power) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + struct atomEncoderConfig *EncoderConfig = &Private->EncoderConfig; + union AtomBiosArg data; + Bool enableHDMI = FALSE; + + RHDFUNC(Output); + + if(Output->Connector != NULL) { + enableHDMI = RHDConnectorEnableHDMI(Output->Connector); + switch(Output->Id) { + case RHD_OUTPUT_TMDSA: + case RHD_OUTPUT_LVTMA: + if(enableHDMI && !Private->EncoderConfig.u.lvds2.Hdmi) + Private->EncoderConfig.u.lvds2.Hdmi = TRUE; + else if(!enableHDMI && Private->EncoderConfig.u.lvds2.Hdmi) + Private->EncoderConfig.u.lvds2.Hdmi = FALSE; + break; + + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_KLDSKP_LVTMA: + if(enableHDMI && Private->TransmitterConfig.Mode == atomDVI) { + Private->TransmitterConfig.Mode = atomHDMI; + Private->EncoderConfig.u.dig.EncoderMode = atomHDMI; + + } else if(!enableHDMI && Private->TransmitterConfig.Mode == atomHDMI) { + Private->TransmitterConfig.Mode = atomDVI; + Private->EncoderConfig.u.dig.EncoderMode = atomDVI; + } + break; + + default: + break; + } + } + + data.Address = &Private->Save; + RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); + + rhdSetEncoderTransmitterConfig(Output, Private->PixelClock); + + switch (Power) { + case RHD_POWER_ON: + RHDDebug(Output->scrnIndex, "RHD_POWER_ON\n"); + rhdAtomEncoderControl(rhdPtr->atomBIOS, Private->EncoderId, atomEncoderOn, EncoderConfig); + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, + atomTransEnable, &Private->TransmitterConfig)) { + ERROR_MSG("rhdAtomDigTransmitterControl(atomTransEnable)"); + break; + } + if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, + atomTransEnableOutput, &Private->TransmitterConfig)) + ERROR_MSG("rhdAtomDigTransmitterControl(atomTransEnableOutput)"); + break; + default: + if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputEnable)) + ERROR_MSG("rhdAtomOutputControl(atomOutputEnable)"); + break; + } + RHDHdmiEnable(Private->Hdmi, enableHDMI); + break; + case RHD_POWER_RESET: + RHDDebug(Output->scrnIndex, "RHD_POWER_RESET\n"); + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, + atomTransDisableOutput, &Private->TransmitterConfig)) + ERROR_MSG("rhdAtomDigTransmitterControl(atomTransDisableOutput)"); + break; + default: + if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputDisable)) + ERROR_MSG("rhdAtomOutputControl(atomOutputDisable)"); + break; + } + break; + case RHD_POWER_SHUTDOWN: + RHDDebug(Output->scrnIndex, "RHD_POWER_SHUTDOWN\n"); + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + if (Private->EncoderId == atomEncoderNone) + break; + if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, + atomTransDisableOutput, &Private->TransmitterConfig)) { + ERROR_MSG("rhdAtomDigTransmitterControl(atomTransDisableOutput)"); + break; + } + if (!rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, Private->TransmitterId, + atomTransDisable, &Private->TransmitterConfig)) + ERROR_MSG("rhdAtomDigTransmitterControl(atomTransDisable)"); + break; + default: + if (!rhdAtomOutputControl(rhdPtr->atomBIOS, Private->OutputControlId, atomOutputDisable)) + ERROR_MSG("rhdAtomOutputControl(atomOutputDisable)"); + break; + } + if (Private->EncoderId != atomEncoderNone) + if (!rhdAtomEncoderControl(rhdPtr->atomBIOS, Private->EncoderId, atomEncoderOff, &Private->EncoderConfig)) + ERROR_MSG("rhdAtomEncoderControl(atomEncoderOff)"); + RHDHdmiEnable(Private->Hdmi, FALSE); + break; + } + + data.Address = NULL; + RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_SET_REGISTER_LIST_LOCATION, &data); +} + +/* + * + */ +static inline void +rhdAtomOutputSave(struct rhdOutput *Output) +{ + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + RHDHdmiSave(Private->Hdmi); +} + +/* + * + */ +static void +rhdAtomOutputRestore(struct rhdOutput *Output) +{ + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + union AtomBiosArg data; + + data.Address = &Private->Save; + RHDAtomBiosFunc(Output->scrnIndex, rhdPtr->atomBIOS, ATOM_RESTORE_REGISTERS, &data); + if (Output->Connector && Output->Connector->Type == RHD_CONNECTOR_PANEL) + atomSetBacklightFromBIOSScratch(Output); + RHDHdmiRestore(Private->Hdmi); +} + +/* + * + */ +static ModeStatus +rhdAtomOutputModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + if (Mode->Clock < 25000) + return MODE_CLOCK_LOW; + + + if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE +#if 0 + || Output->Connector->Type == RHD_CONNECTOR_DP_DUAL + || Output->Connector->Type == RHD_CONNECTOR_HDMI_B +#endif + ) { + if (Mode->Clock > 165000) + return MODE_CLOCK_HIGH; + } + else if (Output->Connector->Type == RHD_CONNECTOR_DVI) { + if (Mode->Clock > 330000) /* could go higher still */ + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + + +/* + * + */ +static Bool +LVDSInfoRetrieve(RHDPtr rhdPtr, struct rhdAtomOutputPrivate *Private) +{ + AtomBiosArgRec data; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) != ATOM_SUCCESS) + return FALSE; + Private->PowerDigToDE = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_SEQ_DE_TO_BL, &data) != ATOM_SUCCESS) + return FALSE; + Private->PowerDEToBL = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_OFF_DELAY, &data) != ATOM_SUCCESS) + return FALSE; + Private->OffDelay = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_DUALLINK, &data) != ATOM_SUCCESS) + return FALSE; + Private->DualLink = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_24BIT, &data) != ATOM_SUCCESS) + return FALSE; + Private->LVDS24Bit = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_FPDI, &data) != ATOM_SUCCESS) + return FALSE; + Private->FPDI = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_TEMPORAL_DITHER, &data) != ATOM_SUCCESS) + return FALSE; + Private->TemporalDither = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_SPATIAL_DITHER, &data) != ATOM_SUCCESS) + return FALSE; + Private->SpatialDither = data.val; + + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOM_LVDS_GREYLVL, &data) != ATOM_SUCCESS) + return FALSE; + { + Private->GreyLevel = data.val; + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "AtomBIOS returned %i Grey Levels\n", + Private->GreyLevel); + } + Private->Coherent = FALSE; + + RHDAtomBIOSScratchBlLevel(rhdPtr, rhdBIOSScratchBlGet, &Private->BlLevel); + + return TRUE; +} + +/* + * TMDSInfoRetrieve() - interface to set TMDS (DVI) parameters. + */ +static Bool +TMDSInfoRetrieve(RHDPtr rhdPtr, struct rhdAtomOutputPrivate *Private) +{ + Private->FPDI = FALSE; + Private->TemporalDither = FALSE; + Private->SpatialDither = FALSE; + Private->GreyLevel = 0; + Private->BlLevel = -1; + + return TRUE; +} + +/* + * + */ +static Bool +atomLVDSPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + + RHDFUNC(Output); + switch (Action) { + case rhdPropertyCheck: + if (Private->BlLevel < 0) + return FALSE; + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + if (Private->BlLevel < 0) + return FALSE; + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + val->integer = Private->BlLevel; + return TRUE; + default: + return FALSE; + } + break; + case rhdPropertySet: + if (Private->BlLevel < 0) + return FALSE; + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + atomSetBacklight(Output, val->integer); + return TRUE; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static Bool +atomTMDSPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + + RHDFUNC(Output); + switch (Action) { + case rhdPropertyCheck: + switch (Property) { + case RHD_OUTPUT_COHERENT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + val->Bool = Private->Coherent; + return TRUE; + default: + return FALSE; + } + break; + case rhdPropertySet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + Private->Coherent = val->Bool; + Output->Mode(Output, Private->Mode); + Output->Power(Output, RHD_POWER_ON); + break; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static void +rhdAtomOutputDestroy(struct rhdOutput *Output) +{ + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + RHDFUNC(Output); + if (Private->Save) + xfree(Private->Save); + RHDHdmiDestroy(Private->Hdmi); + + if (Private) + xfree(Private); + Output->Private = NULL; + xfree(Output->Name); +} + +/* + * + */ +static Bool +RHDAtomOutputAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc) +{ + struct rhdAtomOutputPrivate *Private = (struct rhdAtomOutputPrivate *) Output->Private; + struct atomTransmitterConfig *TransmitterConfig = &Private->TransmitterConfig; + RHDPtr rhdPtr = RHDPTRI(Output); + char *TransmitterName; + + RHDFUNC(rhdPtr); + + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + TransmitterName = "KLDSKP_LVTMA"; + break; + case RHD_OUTPUT_UNIPHYA: + TransmitterName = "KLDSKP_UNIPHYA"; + break; + case RHD_OUTPUT_UNIPHYB: + TransmitterName = "KLDSKP_UNIPHYB"; + break; + case RHD_OUTPUT_UNIPHYC: + TransmitterName = "KLDSKP_UNIPHYC"; + break; + case RHD_OUTPUT_UNIPHYD: + TransmitterName = "KLDSKP_UNIPHYD"; + break; + case RHD_OUTPUT_UNIPHYE: + TransmitterName = "KLDSKP_UNIPHYE"; + break; + case RHD_OUTPUT_UNIPHYF: + TransmitterName = "KLDSKP_UNIPHYF"; + break; + default: + return TRUE; + } + + switch (Alloc) { + case RHD_OUTPUT_ALLOC: + /* + * LVTMA can only use DIG2. Thus exclude + * DIG1 for LVTMA and prefer it for the + * UNIPHYs. + */ + if (Private->EncoderId != atomEncoderNone) + return TRUE; + if (Output->Id != RHD_OUTPUT_KLDSKP_LVTMA + && !rhdPtr->DigEncoderOutput[0]) { + rhdPtr->DigEncoderOutput[0] = Output; + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG1; + xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG1 encoder to %s\n",TransmitterName); + return TRUE; + } else if (!rhdPtr->DigEncoderOutput[1]) { + rhdPtr->DigEncoderOutput[1] = Output; + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG2; + xf86DrvMsg(Output->scrnIndex, X_INFO, "Mapping DIG2 encoder to %s\n",TransmitterName); + return TRUE; + } else + return FALSE; + case RHD_OUTPUT_FREE: + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone; + if (rhdPtr->DigEncoderOutput[0] == Output) { + rhdPtr->DigEncoderOutput[0] = NULL; + return TRUE; + } else if (rhdPtr->DigEncoderOutput[1] == Output) { + rhdPtr->DigEncoderOutput[1] = NULL; + return TRUE; + } else + return FALSE; + break; + default: + return FALSE; + } +} + +/* + * + */ +struct rhdOutput * +RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType, + rhdOutputType OutputType) +{ + struct rhdOutput *Output; + struct rhdAtomOutputPrivate *Private; + struct atomEncoderConfig *EncoderConfig; + struct atomTransmitterConfig *TransmitterConfig; + char *OutputName = NULL; + + RHDFUNC(rhdPtr); + + switch (OutputType) { + case RHD_OUTPUT_NONE: + return NULL; + case RHD_OUTPUT_DACA: + OutputName = "DACA"; + break; + case RHD_OUTPUT_DACB: + OutputName = "DACB"; + break; + case RHD_OUTPUT_TMDSA: + OutputName = "TMDSA"; + break; + case RHD_OUTPUT_LVTMA: + OutputName = "LVTMA"; + break; + case RHD_OUTPUT_DVO: + OutputName = "DVO"; + break; + case RHD_OUTPUT_KLDSKP_LVTMA: + OutputName = "KldskpLvtma"; + break; + case RHD_OUTPUT_UNIPHYA: + OutputName = "UniphyA"; + break; + case RHD_OUTPUT_UNIPHYB: + OutputName = "UniphyB"; + break; + case RHD_OUTPUT_UNIPHYC: + OutputName = "UniphyC"; + break; + case RHD_OUTPUT_UNIPHYD: + OutputName = "UniphyD"; + break; + case RHD_OUTPUT_UNIPHYE: + OutputName = "UniphyE"; + break; + case RHD_OUTPUT_UNIPHYF: + OutputName = "UniphyF"; + break; + } + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + Output->scrnIndex = rhdPtr->scrnIndex; + + Output->Name = RhdAppendString(NULL, "AtomOutput"); + Output->Name = RhdAppendString(Output->Name, OutputName); + + Output->Id = OutputType; + Output->Sense = NULL; + Private = xnfcalloc(sizeof(struct rhdAtomOutputPrivate), 1); + Output->Private = Private; + Output->OutputDriverPrivate = NULL; + + EncoderConfig = &Private->EncoderConfig; + Private->PixelClock = 0; + + switch (OutputType) { + case RHD_OUTPUT_NONE: + xfree(Output); + xfree(Private); + return NULL; + case RHD_OUTPUT_DACA: + Output->Sense = RHDBIOSScratchDACSense; + Private->EncoderId = atomEncoderDACA; + Private->OutputControlId = atomDAC1Output; + Private->Hdmi = NULL; + break; + case RHD_OUTPUT_DACB: + Output->Sense = RHDBIOSScratchDACSense; + Private->EncoderId = atomEncoderDACB; + Private->OutputControlId = atomDAC2Output; + Private->Hdmi = NULL; + break; + case RHD_OUTPUT_TMDSA: + case RHD_OUTPUT_LVTMA: + if (OutputType == RHD_OUTPUT_LVTMA) { + if (ConnectorType == RHD_CONNECTOR_PANEL) { + Private->OutputControlId = atomLCDOutput; + LVDSInfoRetrieve(rhdPtr, Private); + Private->RunDualLink = Private->DualLink; + Private->EncoderId = atomEncoderLVDS; + } else { + TMDSInfoRetrieve(rhdPtr, Private); + Private->OutputControlId = atomLVTMAOutput; + Private->EncoderId = atomEncoderTMDS2; + } + } else { + TMDSInfoRetrieve(rhdPtr, Private); + Private->OutputControlId = atomTMDSAOutput; + Private->EncoderId = atomEncoderTMDS1; + } + + if (OutputType == RHD_CONNECTOR_DVI) + Private->DualLink = TRUE; + else + Private->DualLink = FALSE; + + if (ConnectorType != RHD_CONNECTOR_PANEL) + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + else + Private->Hdmi = NULL; + + Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS, Private->EncoderId); + switch (Private->EncoderVersion.cref) { + case 1: + EncoderConfig->u.lvds.Is24bit = Private->LVDS24Bit; + break; + case 2: + case 3: + EncoderConfig->u.lvds2.Is24bit = Private->LVDS24Bit; + EncoderConfig->u.lvds2.SpatialDither = Private->SpatialDither; + EncoderConfig->u.lvds2.LinkB = 0; /* @@@ */ + EncoderConfig->u.lvds2.Hdmi = FALSE; +#if 0 + if (ConnectorType == RHD_CONNECTOR_HDMI_B + || ConnectorType == RHD_CONNECTOR_HDMI_A) + EncoderConfig->u.lvds2.hdmi = TRUE; +#endif + switch (Private->GreyLevel) { + case 2: + EncoderConfig->u.lvds2.TemporalGrey = atomTemporalDither2; + break; + case 4: + EncoderConfig->u.lvds2.TemporalGrey = atomTemporalDither4; + break; + case 0: + default: + EncoderConfig->u.lvds2.TemporalGrey = atomTemporalDither0; + } + if (Private->SpatialDither) + EncoderConfig->u.lvds2.SpatialDither = TRUE; + else + EncoderConfig->u.lvds2.SpatialDither = FALSE; + EncoderConfig->u.lvds2.Coherent = Private->Coherent; + break; + } + break; + case RHD_OUTPUT_DVO: + Private->EncoderId = atomEncoderDVO; + Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS, + Private->EncoderId); + switch (Private->EncoderVersion.cref) { + case 1: + case 2: + /* Output->OutputDriverPrivate->Device not set yet. */ + break; + case 3: /* @@@ still to be handled */ + xfree(Output); + xfree(Private); + return NULL; + } + { + struct atomCodeTableVersion version = rhdAtomOutputControlVersion(rhdPtr->atomBIOS, atomDVOOutput); + switch (version.cref) { + case 1: + case 2: + Private->OutputControlId = atomDVOOutput; + break; + case 3: +#if 0 + Private->TransmitterId = atomTransmitterDVO; /* @@@ check how to handle this one */ + break; +#else + xfree(Output); + xfree(Private); + return NULL; +#endif + } + } + break; + case RHD_OUTPUT_KLDSKP_LVTMA: + Private->EncoderVersion = rhdAtomEncoderControlVersion(rhdPtr->atomBIOS, + Private->EncoderId); + Output->AllocFree = RHDAtomOutputAllocFree; + EncoderConfig->u.dig.Link = atomTransLinkA; + EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterLVTMA; + + TransmitterConfig = &Private->TransmitterConfig; + TransmitterConfig->Link = atomTransLinkA; + TransmitterConfig->Encoder = Private->TransmitterId; + + if (ConnectorType == RHD_CONNECTOR_PANEL) { + TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomLVDS; + LVDSInfoRetrieve(rhdPtr, Private); + Private->Hdmi = NULL; + } else { + TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDVI; + TMDSInfoRetrieve(rhdPtr, Private); + Private->Coherent = FALSE; + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + } + break; + + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + Output->AllocFree = RHDAtomOutputAllocFree; + if (RHDIsIGP(rhdPtr->ChipSet)) + EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterPCIEPHY; + else { + switch (OutputType) { + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterUNIPHY; + break; + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYD: + EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterUNIPHY1; + break; + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + EncoderConfig->u.dig.Transmitter = Private->TransmitterId = atomTransmitterUNIPHY2; + break; + default: + xfree(Private); + xfree(Output); + return NULL; + } + } + + TransmitterConfig = &Private->TransmitterConfig; + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone; + switch (OutputType) { + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYC: + case RHD_OUTPUT_UNIPHYE: + TransmitterConfig->Link = EncoderConfig->u.dig.Link = atomTransLinkA; + break; + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_UNIPHYD: + case RHD_OUTPUT_UNIPHYF: + TransmitterConfig->Link = EncoderConfig->u.dig.Link = atomTransLinkB; + break; + default: + xfree(Private); + xfree(Output); + return NULL; + } + + if (RHDIsIGP(rhdPtr->ChipSet)) { + AtomBiosArgRec data; + data.val = 1; + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_PCIE_LANES, + &data) == ATOM_SUCCESS) + TransmitterConfig->Lanes = data.pcieLanes.Chassis; + /* only do 'chassis' for now */ + else { + xfree(Private); + xfree(Output); + return NULL; + } + } + + if (ConnectorType == RHD_CONNECTOR_PANEL) + LVDSInfoRetrieve(rhdPtr, Private); + else + TMDSInfoRetrieve(rhdPtr, Private); + + switch (ConnectorType) { + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDVI; + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + break; + case RHD_CONNECTOR_PANEL: + TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomLVDS; + break; +#if 0 + case RHD_CONNECTOR_DP: + case RHD_CONNECTOR_DP_DUAL: + TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomDP; + break; + case RHD_CONNECTOR_HDMI_A: + case RHD_CONNECTOR_HDMI_B: + TransmitterConfig->Mode = EncoderConfig->u.dig.EncoderMode = atomHDMI; + break; +#endif + default: + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unknown connector type\n",__func__); + xfree(Output); + xfree(Private); + return NULL; + } + break; + default: + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unknown output type\n"); + xfree(Output); + xfree(Private); + return NULL; + } + if (ConnectorType == RHD_CONNECTOR_PANEL) { + Output->Property = atomLVDSPropertyControl; + LVDSInfoRetrieve(rhdPtr, Private); + } else { + Output->Property = atomTMDSPropertyControl; + TMDSInfoRetrieve(rhdPtr, Private); + } + + + Output->Mode = rhdAtomOutputSet; + Output->Power = rhdAtomOutputPower; + Output->Save = rhdAtomOutputSave; + Output->Restore = rhdAtomOutputRestore; + Output->ModeValid = rhdAtomOutputModeValid; + Output->Destroy = rhdAtomOutputDestroy; + Private->CrtcSourceVersion = rhdAtomSelectCrtcSourceVersion(rhdPtr->atomBIOS); + + return Output; +} + +/* + * This sets up AtomBIOS based BL control if we need to use a non-standard method to control BL. + */ +int +RhdAtomSetupBacklightControlProperty(struct rhdOutput *Output, + Bool (**PropertyFunc)(struct rhdOutput *Output, + enum rhdPropertyAction Action, + enum rhdOutputProperty Property, + union rhdPropertyData *val), void **PrivatePtr) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + int BlLevel; + struct rhdAtomOutputPrivate *Private; + struct atomTransmitterConfig *TransmitterConfig; + + RHDFUNC(Output); + + Private = xnfcalloc(sizeof(struct rhdAtomOutputPrivate), 1); + + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYE: + case RHD_OUTPUT_UNIPHYF: + /* We set up a those parameters although they may never be needed for BL control */ + TransmitterConfig = &Private->TransmitterConfig; + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + Private->TransmitterId = atomTransmitterLVTMA; + break; + case RHD_OUTPUT_UNIPHYE: + Private->TransmitterId = atomTransmitterUNIPHY2; + TransmitterConfig->Link = atomTransLinkA; + break; + case RHD_OUTPUT_UNIPHYF: + Private->TransmitterId = atomTransmitterUNIPHY2; + TransmitterConfig->Link = atomTransLinkB; + break; + default: + return 0; /* never get here */ + } + TransmitterConfig = &Private->TransmitterConfig; + TransmitterConfig->Mode = atomLVDS; + if (rhdPtr->DigEncoderOutput[0] == Output) + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG1; + else if (rhdPtr->DigEncoderOutput[1] == Output) + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderDIG2; + else + TransmitterConfig->Encoder = Private->EncoderId = atomEncoderNone; + LVDSInfoRetrieve(rhdPtr, Private); + Private->PixelClock = 0; + Private->Hdmi = NULL; + break; + case RHD_OUTPUT_LVTMA: + Private->OutputControlId = atomLCDOutput; + break; + default: + xfree(Private); + return 0; + } + *PropertyFunc = atomLVDSPropertyControl; + *PrivatePtr = Private; + RHDAtomBIOSScratchBlLevel(rhdPtr, rhdBIOSScratchBlGet, &BlLevel); + + return BlLevel; +} + +void +RhdAtomDestroyBacklightControlProperty(struct rhdOutput *Output, void *PrivatePtr) +{ + if (PrivatePtr) + xfree(PrivatePtr); +} + +#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ diff --git a/programs/system/drivers/rhd/rhd_atomout.h b/programs/system/drivers/rhd/rhd_atomout.h new file mode 100644 index 000000000..fba10402b --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atomout.h @@ -0,0 +1,37 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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. + */ + +#ifndef _RHD_ATOMOUT_H +# define _RHD_ATOMOUT_H + +extern int RhdAtomSetupBacklightControlProperty(struct rhdOutput *Output, + Bool (**PropertyFunc)(struct rhdOutput *Output, + enum rhdPropertyAction Action, + enum rhdOutputProperty Property, + union rhdPropertyData *val), + void **PrivatePtr); +extern void RhdAtomDestroyBacklightControlProperty(struct rhdOutput *Output, void *PrivatePtr); + +#endif diff --git a/programs/system/drivers/rhd/rhd_atompll.c b/programs/system/drivers/rhd/rhd_atompll.c new file mode 100644 index 000000000..1d459848b --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atompll.c @@ -0,0 +1,436 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_pll.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_crtc.h" +#include "rhd_regs.h" +#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) +# include "rhd_atombios.h" +# include "rhd_biosscratch.h" + +struct atomPLLPrivate { + enum atomPxclk Pxclk; + struct atomPixelClockConfig Config; + struct atomCodeTableVersion Version; + + CARD32 StoreFBDivFrac; + enum atomDevice StoreDevice; + enum rhdConnectorType StoreConnectorType; + enum rhdOutputType StoreOutputType; + int StoreCrtc; +}; + +/* + * + */ +static void +getSetPixelClockParameters(struct rhdPLL *PLL, struct atomPixelClockConfig *Config, + enum rhdConnectorType ct, enum rhdOutputType ot, enum atomDevice device) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + + switch (Private->Version.cref) { + case 1: + break; + case 2: + Config->u.v2.Device = device; + Config->u.v2.Force = TRUE; + break; + case 3: + switch (ct) { + case RHD_CONNECTOR_VGA: + Config->u.v3.EncoderMode = atomNoEncoder; + break; + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + Config->u.v3.EncoderMode = atomDVI; + break; + case RHD_CONNECTOR_PANEL: + Config->u.v3.EncoderMode = atomLVDS; + break; +#if 0 + case RHD_CONNECTOR_DP: + case RHD_CONNECTOR_DP_DUAL: + Config->u.v3.EncoderMode = atomDP; + break; + case RHD_CONNECTOR_HDMI_A: + case RHD_CONNECTOR_HDMI_B: + Config->u.v3.EncoderMode = atomHDMI; + break; +#endif + default: + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unknown connector type: 0x%x\n",__func__,ct); + } + switch (ot) { + case RHD_OUTPUT_DACA: + Config->u.v3.OutputType = atomOutputDacA; + break; + case RHD_OUTPUT_DACB: + Config->u.v3.OutputType = atomOutputDacB; + break; + case RHD_OUTPUT_KLDSKP_LVTMA: + Config->u.v3.OutputType = atomOutputKldskpLvtma; + break; + case RHD_OUTPUT_UNIPHYA: + Config->u.v3.OutputType = atomOutputUniphyA; + break; + case RHD_OUTPUT_UNIPHYB: + Config->u.v3.OutputType = atomOutputUniphyB; + break; + case RHD_OUTPUT_UNIPHYC: + Config->u.v3.OutputType = atomOutputUniphyC; + break; + case RHD_OUTPUT_UNIPHYD: + Config->u.v3.OutputType = atomOutputUniphyD; + break; + case RHD_OUTPUT_UNIPHYE: + Config->u.v3.OutputType = atomOutputUniphyE; + break; + case RHD_OUTPUT_UNIPHYF: + Config->u.v3.OutputType = atomOutputUniphyF; + break; + case RHD_OUTPUT_DVO: + Config->u.v3.OutputType = atomOutputDvo; + break; + default: + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Unhandled ouptut type\n",__func__); + break; + } + Config->u.v3.Force = TRUE; + Config->u.v3.UsePpll = FALSE; + break; + default: + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unsupported SelectPixelClock version: %i\n",Private->Version.cref); + break; + } +} + +/* + * + */ +static void +rhdAtomPLLSave(struct rhdPLL *PLL, CARD32 PllCntl, CARD32 OwnerVal) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + CARD32 Crtc1Cntl, Crtc2Cntl; + enum atomCrtc owner; + + RHDFUNC(PLL); + + Crtc1Cntl = RHDRegRead(PLL, PCLK_CRTC1_CNTL); + Crtc2Cntl = RHDRegRead(PLL, PCLK_CRTC2_CNTL); + + if (PllCntl & 0x2) + PLL->StoreActive = FALSE; + else + PLL->StoreActive = TRUE; + + if ((Crtc1Cntl & 0x00010000) == OwnerVal) + owner = atomCrtc1; + else if ((Crtc2Cntl & 0x00010000) == OwnerVal) + owner = atomCrtc2; + else { + owner = atomCrtc1; /* whatever... */ + PLL->StoreActive = FALSE; + } + + Private->StoreCrtc = owner; + Private->StoreDevice = RHDGetDeviceOnCrtc(rhdPtr, owner); + + if (Private->StoreDevice != atomNone) + RHDFindConnectorAndOutputTypesForDevice(rhdPtr, Private->StoreDevice, + &Private->StoreOutputType, &Private->StoreConnectorType); + else + PLL->StoreActive = FALSE; + + RHDDebug(PLL->scrnIndex, "Saving PLL %i on CRTC: %i %s active - device: 0x%x\n", + (PLL->Id == PLL_ID_PLL1) ? 1 : 2, + (owner == atomCrtc1) ? 1 : 2, + (PLL->StoreActive) ? "" : "not", + Private->StoreDevice); + + PLL->Stored = TRUE; + + /* Set parameters found at startup for shutdownInactive(). This is somewhat ugly... */ + Private->Config.Crtc = Private->StoreCrtc; + Private->Config.Enable = PLL->StoreActive; + if (Private->StoreDevice != atomNone) + getSetPixelClockParameters(PLL, &Private->Config, Private->StoreConnectorType, + Private->StoreOutputType, Private->StoreDevice); +} + +/* + * + */ +static void +rhdAtomPLL1Save(struct rhdPLL *PLL) +{ + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + CARD32 PllCntl; + + RHDFUNC(PLL); + + PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL); + PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV) & 0x1FF; + PLL->StoreFBDiv = (RHDRegRead(PLL, EXT1_PPLL_FB_DIV) >> 16) & 0x7FF; + Private->StoreFBDivFrac = RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & 0x7; + PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & 0x3F; + PllCntl = RHDRegRead(PLL, P1PLL_CNTL); + RHDDebug(PLL->scrnIndex, "Saving %i kHz clock on PLL1\n", + ((PLL->StoreFBDiv * PLL->RefClock * 10) + / (PLL->StorePostDiv * PLL->StoreRefDiv))); + + rhdAtomPLLSave(PLL, PllCntl, 0x00000000); +} + + +/* + * + */ +static void +rhdAtomPLL2Save(struct rhdPLL *PLL) +{ + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + CARD32 PllCntl; + + RHDFUNC(PLL); + + PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL); + PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV) & 0x1FF; + PLL->StoreFBDiv = (RHDRegRead(PLL, EXT2_PPLL_FB_DIV) >> 16) & 0x7FF; + Private->StoreFBDivFrac = RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & 0x7; + PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & 0x3F; + PllCntl = RHDRegRead(PLL, P2PLL_CNTL); + RHDDebug(PLL->scrnIndex, "Saving %i kHz clock on PLL2\n", + ((PLL->StoreFBDiv * PLL->RefClock * 10) + / (PLL->StorePostDiv * PLL->StoreRefDiv))); + + rhdAtomPLLSave(PLL, PllCntl, 0x00010000); +} + +/* + * + */ +static void +rhdAtomPLLRestore(struct rhdPLL *PLL) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + struct atomPixelClockConfig Config; + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + + RHDFUNC(PLL); + + if (!PLL->Stored) { + xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore " + "uninitialized values.\n", __func__, PLL->Name); + return; + } + Config.PixelClock = PLL->StoreActive + ? ((PLL->StoreFBDiv * PLL->RefClock * 10) / (PLL->StorePostDiv * PLL->StoreRefDiv)) + : 0; + + Config.Enable = PLL->StoreActive; + Config.RefDiv = PLL->StoreRefDiv; + Config.FbDiv = PLL->StoreFBDiv; + Config.PostDiv = PLL->StorePostDiv; + Config.FracFbDiv = Private->StoreFBDivFrac; + Config.Crtc = Private->StoreCrtc; + + if (Private->StoreDevice != atomNone) + getSetPixelClockParameters(PLL, &Config, Private->StoreConnectorType, + Private->StoreOutputType, Private->StoreDevice); + RHDDebug(PLL->scrnIndex, "Restoring PixelClock %i with %i kHz, (%i * %i) / ( %i * %i )" + " on CRTC %i device: %x\n", + Private->Pxclk, Config.PixelClock, PLL->RefClock, PLL->StoreFBDiv, PLL->StorePostDiv, + PLL->StoreRefDiv, (Config.Crtc == atomCrtc1) ? 1 : 2, Config.u.v2.Device); + + /* Restore spread spectrum: AtomBIOS doesn't handle this for us */ + RHDRegWrite(PLL, (PLL->Id == PLL_ID_PLL1) ? P1PLL_INT_SS_CNTL : P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum); + + rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, &Config); +} + +/* + * + */ +static void +rhdAtomPLLPower(struct rhdPLL *PLL, int Power) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + struct atomPixelClockConfig *config = &Private->Config; + + RHDFUNC(PLL); + + switch (Power) { + case RHD_POWER_ON: + if (config->PixelClock > 0) + config->Enable = TRUE; + else { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "%s: cannot enable pixel clock without frequency set\n",__func__); + config->Enable = FALSE; + } + break; + case RHD_POWER_RESET: + case RHD_POWER_SHUTDOWN: + return; + config->Enable = FALSE; + default: + break; + } + rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, config); +} + +/* + * + */ +static void +rhdAtomPLLSet(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, + CARD16 FeedbackDivider, CARD8 PostDivider) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + struct atomPLLPrivate *Private = (struct atomPLLPrivate *)PLL->Private; + struct rhdCrtc *Crtc = NULL; + + RHDFUNC(PLL); + RHDDebug(rhdPtr->scrnIndex, "%s: %i kHz RefDiv: %x FeedbackDiv: %x PostDiv: %x\n", + __func__, PixelClock, ReferenceDivider, FeedbackDivider, PostDivider); + + Private->Config.PixelClock = PixelClock; + Private->Config.RefDiv = ReferenceDivider; + Private->Config.FbDiv = FeedbackDivider; + Private->Config.PostDiv = PostDivider; + Private->Config.FracFbDiv = 0; + if (rhdPtr->Crtc[0]->PLL == PLL) { + Private->Config.Crtc = atomCrtc1; + Crtc = rhdPtr->Crtc[0]; + } else if (rhdPtr->Crtc[1]->PLL == PLL) { + Private->Config.Crtc = atomCrtc2; + Crtc = rhdPtr->Crtc[1]; + } else + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Trying to set an unassigned PLL\n"); + + if (Crtc && Private->Version.cref > 1) { + struct rhdOutput *Output; + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) { + if (Output->Crtc == Crtc) + break; + } + if (Output) + getSetPixelClockParameters(PLL, &Private->Config, + Output->Connector->Type, Output->Id, + Output->OutputDriverPrivate->Device); + } + + /* Disable spread spectrum. AtomBIOS doesn't do this for us */ + RHDRegMask(PLL, (PLL->Id == PLL_ID_PLL1) ? P1PLL_INT_SS_CNTL : P2PLL_INT_SS_CNTL, 0, 0x00000001); + + Private->Config.Enable = TRUE; + rhdAtomSetPixelClock(rhdPtr->atomBIOS, Private->Pxclk, &Private->Config); +} + +/* + * + */ +Bool +RHDAtomPLLsInit(RHDPtr rhdPtr) +{ + struct rhdPLL *PLL; + struct atomPLLPrivate *Private; + CARD32 RefClock, IntMin, IntMax, PixMin, PixMax; + int i; + + RHDFUNC(rhdPtr); + + RHDSetupLimits(rhdPtr, &RefClock, &IntMin, &IntMax, &PixMin, &PixMax); + + for (i = 0; i < 2; i++) { + + PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1); + Private = (struct atomPLLPrivate *) xnfcalloc(sizeof(struct atomPLLPrivate),1); + PLL->Private = Private; + + Private->Version = rhdAtomSetPixelClockVersion(rhdPtr->atomBIOS); + if (Private->Version.cref > 3) { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Unsupported SelectPixelClock version; %i\n", + Private->Version.cref); + xfree(PLL->Private); + xfree(PLL); + return FALSE; + } + + PLL->scrnIndex = rhdPtr->scrnIndex; + if (i == 0) { + PLL->Name = PLL_NAME_PLL1; + PLL->Id = PLL_ID_PLL1; + PLL->Save = rhdAtomPLL1Save; + Private->Pxclk = atomPclk1; + } else { + PLL->Name = PLL_NAME_PLL2; + PLL->Id = PLL_ID_PLL2; + PLL->Save = rhdAtomPLL2Save; + Private->Pxclk = atomPclk2; + } + + PLL->RefClock = RefClock; + PLL->IntMin = IntMin; + PLL->IntMax = IntMax; + PLL->PixMin = PixMin; + PLL->PixMax = PixMax; + + PLL->Valid = NULL; + + PLL->Set = rhdAtomPLLSet; + PLL->Power = rhdAtomPLLPower; + PLL->Restore = rhdAtomPLLRestore; + + rhdPtr->PLLs[i] = PLL; + } + + + return TRUE; +} + +#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ diff --git a/programs/system/drivers/rhd/rhd_atomwrapper.c b/programs/system/drivers/rhd/rhd_atomwrapper.c new file mode 100644 index 000000000..be26375ef --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atomwrapper.c @@ -0,0 +1,101 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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 + +#include "rhd_atomwrapper.h" + +#define INT32 INT32 +#include "CD_Common_Types.h" +#include "CD_Definitions.h" + + +int +ParseTableWrapper(void *pspace, int index, void *handle, void *BIOSBase, + char **msg_return) +{ + DEVICE_DATA deviceData; + int ret = 0; + + /* FILL OUT PARAMETER SPACE */ + deviceData.pParameterSpace = (UINT32*) pspace; + deviceData.CAIL = handle; + deviceData.pBIOS_Image = BIOSBase; + deviceData.format = TABLE_FORMAT_BIOS; + + switch (ParseTable(&deviceData, index)) { /* IndexInMasterTable */ + case CD_SUCCESS: + ret = 1; + *msg_return = "ParseTable said: CD_SUCCESS"; + break; + case CD_CALL_TABLE: + ret = 1; + *msg_return = "ParseTable said: CD_CALL_TABLE"; + break; + case CD_COMPLETED: + ret = 1; + *msg_return = "ParseTable said: CD_COMPLETED"; + break; + case CD_GENERAL_ERROR: + ret = 0; + *msg_return = " ParseTable said: CD_GENERAL_ERROR"; + break; + case CD_INVALID_OPCODE: + ret = 0; + *msg_return = " ParseTable said: CD_INVALID_OPCODE"; + break; + case CD_NOT_IMPLEMENTED: + ret = 0; + *msg_return = " ParseTable said: CD_NOT_IMPLEMENTED"; + break; + case CD_EXEC_TABLE_NOT_FOUND: + ret = 0; + *msg_return = " ParseTable said: CD_EXEC_TABLE_NOT_FOUND"; + break; + case CD_EXEC_PARAMETER_ERROR: + ret = 0; + *msg_return = " ParseTable said: CD_EXEC_PARAMETER_ERROR"; + break; + case CD_EXEC_PARSER_ERROR: + ret = 0; + *msg_return = " ParseTable said: CD_EXEC_PARSER_ERROR"; + break; + case CD_INVALID_DESTINATION_TYPE: + ret = 0; + *msg_return = " ParseTable said: CD_INVALID_DESTINATION_TYPE"; + break; + case CD_UNEXPECTED_BEHAVIOR: + ret = 0; + *msg_return = " ParseTable said: CD_UNEXPECTED_BEHAVIOR"; + break; + case CD_INVALID_SWITCH_OPERAND_SIZE: + ret = 0; + *msg_return = " ParseTable said: CD_INVALID_SWITCH_OPERAND_SIZE\n"; + break; + } + return ret; +} diff --git a/programs/system/drivers/rhd/rhd_atomwrapper.h b/programs/system/drivers/rhd/rhd_atomwrapper.h new file mode 100644 index 000000000..1e7cc773f --- /dev/null +++ b/programs/system/drivers/rhd/rhd_atomwrapper.h @@ -0,0 +1,31 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ +#ifndef RHD_ATOMWRAPPER_H_ +# define RHD_ATOMWRAPPER_H_ + +extern int ParseTableWrapper(void *pspace, int index, void *CAIL, + void *BIOSBase, char **msg_return); + +#endif /* RHD_ATOMWRAPPER_H_ */ diff --git a/programs/system/drivers/rhd/rhd_audio.h b/programs/system/drivers/rhd/rhd_audio.h new file mode 100644 index 000000000..86b104a4c --- /dev/null +++ b/programs/system/drivers/rhd/rhd_audio.h @@ -0,0 +1,119 @@ +/* + * Copyright 2008 Christian König + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_AUDIO_H +#define _RHD_AUDIO_H + +struct rhdAudio { + + int scrnIndex; + + struct rhdHdmi* Registered; + int Timer; + + Bool SavedPlaying; + int SavedChannels; + int SavedRate; + int SavedBitsPerSample; + CARD8 SavedStatusBits; + CARD8 SavedCategoryCode; + + Bool Stored; + + CARD32 StoreEnabled; + CARD32 StoreTiming; + CARD32 StoreSupportedSizeRate; + CARD32 StoreSupportedCodec; + + CARD32 StorePll1Mul; + CARD32 StorePll1Div; + CARD32 StorePll2Mul; + CARD32 StorePll2Div; + CARD32 StoreClockSrcSel; +}; + +/* + * used for config value of RHDAudioSetSupported + */ +enum { + AUDIO_RATE_8000_HZ = 0x00000001, + AUDIO_RATE_11025_HZ = 0x00000002, + AUDIO_RATE_16000_HZ = 0x00000004, + AUDIO_RATE_22050_HZ = 0x00000008, + AUDIO_RATE_32000_HZ = 0x00000010, + AUDIO_RATE_44100_HZ = 0x00000020, + AUDIO_RATE_48000_HZ = 0x00000040, + AUDIO_RATE_88200_HZ = 0x00000080, + AUDIO_RATE_96000_HZ = 0x00000100, + AUDIO_RATE_176400_HZ = 0x00000200, + AUDIO_RATE_192000_HZ = 0x00000400, + AUDIO_RATE_384000_HZ = 0x00000800, + + AUDIO_BPS_8 = 0x00010000, + AUDIO_BPS_16 = 0x00020000, + AUDIO_BPS_20 = 0x00040000, + AUDIO_BPS_24 = 0x00080000, + AUDIO_BPS_32 = 0x00100000 +}; + +/* + * used for codec value of RHDAudioSetSupported + */ +enum { + AUDIO_CODEC_PCM = 0x00000001, + AUDIO_CODEC_FLOAT32 = 0x00000002, + AUDIO_CODEC_AC3 = 0x00000004 +}; + +/* + * used for status bist value in RHDAudioUpdateHdmi + */ +enum { + AUDIO_STATUS_DIG_ENABLE = 0x01, + AUDIO_STATUS_V = 0x02, + AUDIO_STATUS_VCFG = 0x04, + AUDIO_STATUS_EMPHASIS = 0x08, + AUDIO_STATUS_COPYRIGHT = 0x10, + AUDIO_STATUS_NONAUDIO = 0x20, + AUDIO_STATUS_PROFESSIONAL = 0x40, + AUDIO_STATUS_LEVEL = 0x80 +}; + +void RHDAudioInit(RHDPtr rhdPtr); + +void RHDAudioSetSupported(RHDPtr rhdPtr, Bool clear, CARD32 config, CARD32 codec); +void RHDAudioSetEnable(RHDPtr rhdPtr, Bool Enable); +void RHDAudioSetClock(RHDPtr rhdPtr, struct rhdOutput* Output, CARD32 Clock); + +void RHDAudioRegisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi); +void RHDAudioUnregisterHdmi(RHDPtr rhdPtr, struct rhdHdmi* rhdHdmi); + +void RHDAudioSave(RHDPtr rhdPtr); +void RHDAudioRestore(RHDPtr rhdPtr); + +void RHDAudioDestroy(RHDPtr rhdPtr); + +#endif /* _RHD_AUDIO_H */ diff --git a/programs/system/drivers/rhd/rhd_biosscratch.c b/programs/system/drivers/rhd/rhd_biosscratch.c new file mode 100644 index 000000000..9e534648a --- /dev/null +++ b/programs/system/drivers/rhd/rhd_biosscratch.c @@ -0,0 +1,960 @@ +/* + * Copyright 2007, 2008 Egbert Eich + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * 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 +# include +# include +# 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 */ + diff --git a/programs/system/drivers/rhd/rhd_biosscratch.h b/programs/system/drivers/rhd/rhd_biosscratch.h new file mode 100644 index 000000000..f506e3dd6 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_biosscratch.h @@ -0,0 +1,73 @@ +/* + * Copyright 2007, 2008 Egbert Eich + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * 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. + */ + +#ifndef RHD_BIOSSCRATCH_H_ +# define RHD_BIOSSCRATCH_H_ + +# ifdef ATOM_BIOS + +struct BIOSScratchOutputPrivate { + void (*Mode) (struct rhdOutput *Output, DisplayModePtr Mode); + void (*Power) (struct rhdOutput *Output, int Power); + void (*Destroy) (struct rhdOutput *Output); + struct rhdOutputDevices *OutputDevices; + enum atomDevice Device; +}; + +struct rhdAtomOutputDeviceList { + enum atomDevice DeviceId; + enum rhdOutputType OutputType; + enum rhdConnectorType ConnectorType; +}; + +enum rhdBIOSScratchBlAction { + rhdBIOSScratchBlGet, + rhdBIOSScratchBlSet +}; + + +extern struct rhdBiosScratchRegisters *RHDSaveBiosScratchRegisters(RHDPtr rhdPtr); +extern void RHDRestoreBiosScratchRegisters(RHDPtr rhdPtr, + struct rhdBiosScratchRegisters * regs); + +# if defined (ATOM_BIOS_PARSER) +extern enum rhdSensedOutput RHDBIOSScratchDACSense(struct rhdOutput *Output, + struct rhdConnector *Connector); +# endif +extern Bool RHDAtomSetupOutputDriverPrivate(struct rhdAtomOutputDeviceList *Devices, + struct rhdOutput *Output); +extern Bool RHDFindConnectorAndOutputTypesForDevice(RHDPtr rhdPtr, enum atomDevice Device, + enum rhdOutputType *ot, + enum rhdConnectorType *ct); +extern enum atomDevice RHDGetDeviceOnCrtc(RHDPtr rhdPtr, enum atomCrtc Crtc); + +extern void RHDAtomBIOSScratchBlLevel(RHDPtr rhdPtr, enum rhdBIOSScratchBlAction action, + int *val); + +extern void RHDAtomBIOSScratchSetAccelratorMode(RHDPtr rhdPtr, Bool on); +extern void RHDAtomBIOSScratchPMState(RHDPtr rhdPtr, struct rhdOutput *Output, + int PowerManagementMode); +# endif /* ATOM_BIOS */ +#endif /* RHD_BIOSSCRATCH_H_ */ diff --git a/programs/system/drivers/rhd/rhd_card.h b/programs/system/drivers/rhd/rhd_card.h new file mode 100644 index 000000000..c5d784e5a --- /dev/null +++ b/programs/system/drivers/rhd/rhd_card.h @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_CARD_H +#define _RHD_CARD_H + +/* Four bytes in TYPE/DDC layout: see rhd_connector.h */ +struct rhdConnectorInfo { + rhdConnectorType Type; + char *Name; + rhdDDC DDC; + rhdHPD HPD; + rhdOutputType Output[MAX_OUTPUTS_PER_CONNECTOR]; +}; + +/* Some card specific flags, where and when needed */ +enum rhdCardFlag { + RHD_CARD_FLAG_NONE = 0, + RHD_CARD_FLAG_DMS59 = 1, /* DMS59 connector is only reported as two DVI-I */ + RHD_CARD_FLAG_HPDSWAP = 2, /* some cards have broken connector tables */ + RHD_CARD_FLAG_HPDOFF = 4 /* some have *very* broken connector tables */ +}; + +struct rhdCard { + CARD16 device; + CARD16 card_vendor; + CARD16 card_device; + char *name; + enum rhdCardFlag flags; + + struct rhdConnectorInfo ConnectorInfo[RHD_CONNECTORS_MAX]; +#ifdef ATOM_BIOS + enum atomDevice DeviceInfo[RHD_CONNECTORS_MAX][MAX_OUTPUTS_PER_CONNECTOR]; +#endif +}; + +void RhdPrintConnectorInfo(RHDPtr rhdPtr, struct rhdConnectorInfo *cp); + +#endif /* _RHD_CARD_H */ diff --git a/programs/system/drivers/rhd/rhd_connector.c b/programs/system/drivers/rhd/rhd_connector.c new file mode 100644 index 000000000..5e8e92a63 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_connector.c @@ -0,0 +1,516 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +# include +# include +#endif + +#include "rhd.h" +#include "edid.h" + +#ifdef ATOM_BIOS +# include "rhd_atombios.h" +#endif + +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_regs.h" +#include "rhd_monitor.h" +#include "rhd_card.h" + +#include "xf86i2c.h" +#include "rhd_i2c.h" + + + +/* + * + */ +struct rhdHPD { + Bool Stored; + CARD32 StoreMask; + CARD32 StoreEnable; +}; + +/* + * + */ +void +RHDHPDSave(RHDPtr rhdPtr) +{ + struct rhdHPD *hpd = rhdPtr->HPD; + + RHDFUNC(rhdPtr); + + hpd->StoreMask = RHDRegRead(rhdPtr, DC_GPIO_HPD_MASK); + hpd->StoreEnable = RHDRegRead(rhdPtr, DC_GPIO_HPD_EN); + + hpd->Stored = TRUE; +} + +/* + * + */ +void +RHDHPDRestore(RHDPtr rhdPtr) +{ + struct rhdHPD *hpd = rhdPtr->HPD; + + RHDFUNC(rhdPtr); + + if (hpd->Stored) { + RHDRegWrite(rhdPtr, DC_GPIO_HPD_MASK, hpd->StoreMask); + RHDRegWrite(rhdPtr, DC_GPIO_HPD_EN, hpd->StoreEnable); + } else + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "%s: no registers stored.\n", __func__); +} + +/* + * + */ +static void +RHDHPDSet(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + /* give the hw full control */ + RHDRegWrite(rhdPtr, DC_GPIO_HPD_MASK, 0); + RHDRegWrite(rhdPtr, DC_GPIO_HPD_EN, 0); + + usleep(1); +} + +/* + * + */ +static Bool +RHDHPDCheck(struct rhdConnector *Connector) +{ + Bool ret; + + RHDFUNC(Connector); + + ret = RHDRegRead(Connector, DC_GPIO_HPD_Y); + RHDDebug(Connector->scrnIndex, "%s returned: %x mask: %x\n", + __func__,ret, Connector->HPDMask); + + return (ret & Connector->HPDMask); +} + +struct rhdCsState { + int vga_cnt; + int dvi_cnt; +}; + +/* + * + */ +static char * +rhdConnectorSynthName(struct rhdConnectorInfo *ConnectorInfo, + struct rhdCsState **state) +{ + char *str = NULL; + char *TypeName; + char *str1, *str2; + int cnt; + + ASSERT(state != NULL); + + if (!*state) { + if (!(*state = xcalloc(sizeof(struct rhdCsState), 1))) + return NULL; + } + switch (ConnectorInfo->Type) { + case RHD_CONNECTOR_NONE: + return NULL; + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + if (ConnectorInfo->Output[0] && ConnectorInfo->Output[1]) { + TypeName = "DVI-I"; + cnt = ++(*state)->dvi_cnt; + } else if (ConnectorInfo->Output[0] == RHD_OUTPUT_DACA + || ConnectorInfo->Output[0] == RHD_OUTPUT_DACB + || ConnectorInfo->Output[1] == RHD_OUTPUT_DACA + || ConnectorInfo->Output[1] == RHD_OUTPUT_DACB + ) { + if (ConnectorInfo->HPD == RHD_HPD_NONE) { + TypeName = "VGA"; + cnt = ++(*state)->vga_cnt; + } else { + TypeName = "DVI-A"; + cnt = ++(*state)->dvi_cnt; + } + } else { + TypeName = "DVI-D"; + cnt = ++(*state)->dvi_cnt; + } + str = xalloc(12); + snprintf(str, 11, "%s %i",TypeName, cnt); + return str; + + case RHD_CONNECTOR_VGA: + str = xalloc(10); + snprintf(str, 9, "VGA %i",++(*state)->vga_cnt); + return str; + + case RHD_CONNECTOR_PANEL: + str = xalloc(10); + snprintf(str, 9, "PANEL"); + return str; + + case RHD_CONNECTOR_TV: + str1 = xstrdup(ConnectorInfo->Name); + str = xalloc(20); + str2 = strchr(str1, ' '); + if (str2) *(str2) = '\0'; + snprintf(str, 20, "TV %s",str1); + xfree(str1); + return str; + + case RHD_CONNECTOR_PCIE: /* should never get here */ + return NULL; + } + return NULL; +} + +/* + * + */ +Bool +RHDConnectorsInit(RHDPtr rhdPtr, struct rhdCard *Card) +{ + struct rhdConnectorInfo *ConnectorInfo; + struct rhdConnector *Connector; + struct rhdOutput *Output; + struct rhdCsState *csstate = NULL; + int i, j, k, l, hpd; + Bool InfoAllocated = FALSE; + + RHDFUNC(rhdPtr); + + /* Card->ConnectorInfo is there to work around quirks, so check it first */ + if (Card && (Card->ConnectorInfo[0].Type != RHD_CONNECTOR_NONE)) { + ConnectorInfo = Card->ConnectorInfo; + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, + "ConnectorInfo from quirk table:\n"); + RhdPrintConnectorInfo (rhdPtr, ConnectorInfo); + } else { +#ifdef ATOM_BIOS + /* common case */ + AtomBiosArgRec data; + AtomBiosResult result; + + data.chipset = rhdPtr->ChipSet; + result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOMBIOS_GET_CONNECTORS, &data); + if (result == ATOM_SUCCESS) { + ConnectorInfo = data.ConnectorInfo; + InfoAllocated = TRUE; + } else +#endif + { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: Failed to retrieve " + "Connector information.\n", __func__); + return FALSE; + } + } + + /* Init HPD */ + rhdPtr->HPD = xnfcalloc(sizeof(struct rhdHPD), 1); + RHDHPDSave(rhdPtr); + RHDHPDSet(rhdPtr); + + for (i = 0, j = 0; i < RHD_CONNECTORS_MAX; i++) { + if (ConnectorInfo[i].Type == RHD_CONNECTOR_NONE) + continue; + + RHDDebug(rhdPtr->scrnIndex, "%s: %d (%s) type %d, ddc %d, hpd %d\n", + __func__, i, ConnectorInfo[i].Name, ConnectorInfo[i].Type, + ConnectorInfo[i].DDC, ConnectorInfo[i].HPD); + + Connector = xnfcalloc(sizeof(struct rhdConnector), 1); + Connector->scrnIndex = rhdPtr->scrnIndex; + Connector->Type = ConnectorInfo[i].Type; + Connector->Name = rhdConnectorSynthName(&ConnectorInfo[i], &csstate); + + /* Get the DDC bus of this connector */ + if (ConnectorInfo[i].DDC != RHD_DDC_NONE) { + RHDI2CDataArg data; + int ret; + + data.i = ConnectorInfo[i].DDC; + ret = RHDI2CFunc(rhdPtr->scrnIndex, + rhdPtr->I2C, RHD_I2C_GETBUS, &data); + if (ret == RHD_I2C_SUCCESS) + Connector->DDC = data.i2cBusPtr; + } + + /* attach HPD */ + hpd = ConnectorInfo[i].HPD; + switch (rhdPtr->hpdUsage) { + case RHD_HPD_USAGE_OFF: + case RHD_HPD_USAGE_AUTO_OFF: + hpd = RHD_HPD_NONE; + break; + case RHD_HPD_USAGE_SWAP: + case RHD_HPD_USAGE_AUTO_SWAP: + switch (hpd) { + case RHD_HPD_0: + hpd = RHD_HPD_1; + break; + case RHD_HPD_1: + hpd = RHD_HPD_0; + break; + } + break; + default: + break; + } + switch(hpd) { + case RHD_HPD_0: + Connector->HPDMask = 0x00000001; + Connector->HPDCheck = RHDHPDCheck; + break; + case RHD_HPD_1: + Connector->HPDMask = 0x00000100; + Connector->HPDCheck = RHDHPDCheck; + break; + case RHD_HPD_2: + Connector->HPDMask = 0x00010000; + Connector->HPDCheck = RHDHPDCheck; + break; + case RHD_HPD_3: + Connector->HPDMask = 0x01000000; + Connector->HPDCheck = RHDHPDCheck; + break; + default: + Connector->HPDCheck = NULL; + break; + } + + /* create Outputs */ + for (k = 0; k < 2; k++) { + if (ConnectorInfo[i].Output[k] == RHD_OUTPUT_NONE) + continue; + + /* Check whether the output exists already */ + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + if (Output->Id == ConnectorInfo[i].Output[k]) + break; + + if (!Output) { + if (!RHDUseAtom(rhdPtr, NULL, atomUsageOutput)) { + switch (ConnectorInfo[i].Output[k]) { + case RHD_OUTPUT_DACA: + Output = RHDDACAInit(rhdPtr); + RHDOutputAdd(rhdPtr, Output); + break; + case RHD_OUTPUT_DACB: + Output = RHDDACBInit(rhdPtr); + RHDOutputAdd(rhdPtr, Output); + break; + case RHD_OUTPUT_TMDSA: + Output = RHDTMDSAInit(rhdPtr); + RHDOutputAdd(rhdPtr, Output); + break; + case RHD_OUTPUT_LVTMA: + Output = RHDLVTMAInit(rhdPtr, ConnectorInfo[i].Type); + RHDOutputAdd(rhdPtr, Output); + break; + case RHD_OUTPUT_DVO: + Output = RHDDDIAInit(rhdPtr); + if (Output) + RHDOutputAdd(rhdPtr, Output); + break; + case RHD_OUTPUT_KLDSKP_LVTMA: + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + Output = RHDDIGInit(rhdPtr, ConnectorInfo[i].Output[k], ConnectorInfo[i].Type); + RHDOutputAdd(rhdPtr, Output); + break; + default: + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "%s: unhandled output id: %d. Trying fallback to AtomBIOS\n", __func__, + ConnectorInfo[i].Output[k]); + break; + } + } +#ifdef ATOM_BIOS + if (!Output) { + Output = RHDAtomOutputInit(rhdPtr, ConnectorInfo[i].Type, + ConnectorInfo[i].Output[k]); + if (Output) + RHDOutputAdd(rhdPtr, Output); + } +#endif + } + + if (Output) { + xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED, + "Attaching Output %s to Connector %s\n", + Output->Name, Connector->Name); + for (l = 0; l < 2; l++) + if (!Connector->Output[l]) { + Connector->Output[l] = Output; + break; + } + } + } + + rhdPtr->Connector[j] = Connector; + j++; + } + if (csstate) + xfree(csstate); + + /* Deallocate what atombios code allocated */ + if (ConnectorInfo && InfoAllocated) { + for (i = 0; i < RHD_CONNECTORS_MAX; i++) + if (ConnectorInfo[i].Type != RHD_CONNECTOR_NONE) + xfree(ConnectorInfo[i].Name); + /* Don't free the Privates as they are hooked into the rhdConnector structures !!! */ + xfree(ConnectorInfo); + } + + RHDHPDRestore(rhdPtr); + + return (j && 1); +} + +/* + * + */ +void +RHDConnectorsDestroy(RHDPtr rhdPtr) +{ + struct rhdConnector *Connector; + int i; + + RHDFUNC(rhdPtr); + + for (i = 0; i < RHD_CONNECTORS_MAX; i++) { + Connector = rhdPtr->Connector[i]; + if (Connector) { + if (Connector->Monitor) + RHDMonitorDestroy(Connector->Monitor); + xfree(Connector->Name); + xfree(Connector); + } + } +} + +/* + * + */ +void +RhdPrintConnectorInfo(RHDPtr rhdPtr, struct rhdConnectorInfo *cp) +{ + int n; + int scrnIndex=0; + + const char *c_name[] = + { "RHD_CONNECTOR_NONE", "RHD_CONNECTOR_VGA", "RHD_CONNECTOR_DVI", + "RHD_CONNECTOR_DVI_SINGLE", "RHD_CONNECTOR_PANEL", + "RHD_CONNECTOR_TV", "RHD_CONNECTOR_PCIE" }; + + const char *ddc_name[] = + { "RHD_DDC_0", "RHD_DDC_1", "RHD_DDC_2", "RHD_DDC_3", "RHD_DDC_4" }; + + const char *hpd_name_normal[] = + { "RHD_HPD_NONE", "RHD_HPD_0", "RHD_HPD_1", "RHD_HPD_2", "RHD_HPD_3" }; + const char *hpd_name_off[] = + { "RHD_HPD_NONE", "RHD_HPD_NONE /*0*/", "RHD_HPD_NONE /*1*/", "RHD_HPD_NONE /*2*/", "RHD_HPD_NONE /*3*/" }; + const char *hpd_name_swapped[] = + { "RHD_HPD_NONE", "RHD_HPD_1 /*swapped*/", "RHD_HPD_0 /*swapped*/", "RHD_HPD_2", "RHD_HPD_3" }; + + const char *output_name[] = + { "RHD_OUTPUT_NONE", "RHD_OUTPUT_DACA", "RHD_OUTPUT_DACB", "RHD_OUTPUT_TMDSA", + "RHD_OUTPUT_LVTMA", "RHD_OUTPUT_DVO", "RHD_OUTPUT_KLDSKP_LVTMA", + "RHD_OUTPUT_UNIPHYA", "RHD_OUTPUT_UNIPHYB", "RHD_OUTPUT_UNIPHYC", "RHD_OUTPUT_UNIPHYD", + "RHD_OUTPUT_UNIPHYE", "RHD_OUTPUT_UNIPHYF" }; + const char **hpd_name; + + switch (rhdPtr->hpdUsage) { + case RHD_HPD_USAGE_OFF: + case RHD_HPD_USAGE_AUTO_OFF: + hpd_name = hpd_name_off; + break; + case RHD_HPD_USAGE_SWAP: + case RHD_HPD_USAGE_AUTO_SWAP: + hpd_name = hpd_name_swapped; + break; + default: + hpd_name = hpd_name_normal; + break; + } + + for (n = 0; n < RHD_CONNECTORS_MAX; n++) { + if (cp[n].Type == RHD_CONNECTOR_NONE) + break; + xf86DrvMsg(scrnIndex, X_INFO, "Connector[%i] {%s, \"%s\", %s, %s, { %s, %s } }\n", + n, c_name[cp[n].Type], cp[n].Name, + cp[n].DDC == RHD_DDC_NONE ? "RHD_DDC_NONE" : ddc_name[cp[n].DDC], + hpd_name[cp[n].HPD], output_name[cp[n].Output[0]], + output_name[cp[n].Output[1]]); + } +} + +/* + * Should we enable HDMI on this connector? + */ +Bool RHDConnectorEnableHDMI(struct rhdConnector *Connector) +{ + RHDPtr rhdPtr = RHDPTRI(Connector); + RHDFUNC(rhdPtr); + + /* check if user forced HDMI on this connector */ +// switch(RhdParseBooleanOption(&rhdPtr->hdmi, Connector->Name)) { +// case RHD_OPTION_ON: +// case RHD_OPTION_DEFAULT: +// xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Enabling HDMI on %s because of config option\n", Connector->Name); +// return TRUE; +// case RHD_OPTION_OFF: +// xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Disabling HDMI on %s because of config option\n", Connector->Name); +// return FALSE; +// case RHD_OPTION_NOT_SET: +// /* ask connected monitor if it supports HDMI */ +// /* TODO: Not implemented yet! */ +// return FALSE; +// } + + return FALSE; +} diff --git a/programs/system/drivers/rhd/rhd_connector.h b/programs/system/drivers/rhd/rhd_connector.h new file mode 100644 index 000000000..23967bac7 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_connector.h @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_CONNECTOR_H +#define _RHD_CONNECTOR_H + +/* so that we can map which is which */ +typedef enum rhdConnectorType { + RHD_CONNECTOR_NONE = 0, + RHD_CONNECTOR_VGA, + RHD_CONNECTOR_DVI, + RHD_CONNECTOR_DVI_SINGLE, + RHD_CONNECTOR_PANEL, + RHD_CONNECTOR_TV, + RHD_CONNECTOR_PCIE +} rhdConnectorType; +/* add whatever */ + +/* map which DDC bus is where */ +typedef enum _rhdDDC { + RHD_DDC_0 = 0, + RHD_DDC_1, + RHD_DDC_2, + RHD_DDC_3, + RHD_DDC_4, + RHD_DDC_MAX, + RHD_DDC_NONE = 0xFF, + RHD_DDC_GPIO = RHD_DDC_NONE +} rhdDDC; + +/* map which HPD plug is used where */ +typedef enum _rhdHPD { + RHD_HPD_NONE = 0, + RHD_HPD_0, + RHD_HPD_1, + RHD_HPD_2, + RHD_HPD_3 +} rhdHPD; + +#define MAX_OUTPUTS_PER_CONNECTOR 2 + +struct rhdConnector { + int scrnIndex; + + CARD8 Type; + char *Name; + + struct _I2CBusRec *DDC; + + /* HPD handling here */ + int HPDMask; + Bool HPDAttached; + Bool (*HPDCheck) (struct rhdConnector *Connector); + + /* Add rhdMonitor pointer here. */ + /* This is created either from default, config or from EDID */ + struct rhdMonitor *Monitor; + + /* Point back to our Outputs, so we can handle sensing better */ + struct rhdOutput *Output[MAX_OUTPUTS_PER_CONNECTOR]; +}; + +Bool RHDConnectorsInit(RHDPtr rhdPtr, struct rhdCard *Card); +void RHDHPDSave(RHDPtr rhdPtr); +void RHDHPDRestore(RHDPtr rhdPtr); +void RHDConnectorsDestroy(RHDPtr rhdPtr); +Bool RHDConnectorEnableHDMI(struct rhdConnector *Connector); + +#endif /* _RHD_CONNECTOR_H */ diff --git a/programs/system/drivers/rhd/rhd_crtc.c b/programs/system/drivers/rhd/rhd_crtc.c new file mode 100644 index 000000000..5325ca444 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_crtc.c @@ -0,0 +1,1496 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_pll.h" +#include "rhd_lut.h" +#include "rhd_regs.h" +#include "rhd_modes.h" +#include "rhd_mc.h" +#ifdef ATOM_BIOS +# include "rhd_atombios.h" +#endif + +#define D1_REG_OFFSET 0x0000 +#define D2_REG_OFFSET 0x0800 +#define FMT1_REG_OFFSET 0x0000 +#define FMT2_REG_OFFSET 0x800 + +struct rhdCrtcFMTPrivate { + CARD32 StoreControl; + CARD32 StoreBitDepthControl; + CARD32 StoreClampCntl; +}; + +struct rhdCrtcFBPrivate { + CARD32 StoreGrphEnable; + CARD32 StoreGrphControl; + CARD32 StoreGrphXStart; + CARD32 StoreGrphYStart; + CARD32 StoreGrphXEnd; + CARD32 StoreGrphYEnd; + CARD32 StoreGrphSwap; + CARD32 StoreGrphPrimarySurfaceAddress; + CARD32 StoreGrphSurfaceOffsetX; + CARD32 StoreGrphSurfaceOffsetY; + CARD32 StoreGrphPitch; + CARD32 StoreModeDesktopHeight; +}; + +struct rhdCrtcLUTPrivate { + CARD32 StoreGrphLutSel; +}; + +struct rhdCrtcScalePrivate { + CARD32 StoreModeViewPortSize; + + CARD32 StoreModeOverScanH; + CARD32 StoreModeOverScanV; + + CARD32 StoreModeViewPortStart; + CARD32 StoreScaleEnable; + CARD32 StoreScaleTapControl; + CARD32 StoreModeCenter; + CARD32 StoreScaleHV; + CARD32 StoreScaleHFilter; + CARD32 StoreScaleVFilter; + CARD32 StoreScaleDither; +}; + +struct rhdCrtcModePrivate { + CARD32 StoreCrtcControl; + + CARD32 StoreCrtcHTotal; + CARD32 StoreCrtcHBlankStartEnd; + CARD32 StoreCrtcHSyncA; + CARD32 StoreCrtcHSyncACntl; + CARD32 StoreCrtcHSyncB; + CARD32 StoreCrtcHSyncBCntl; + + CARD32 StoreCrtcVTotal; + CARD32 StoreCrtcVBlankStartEnd; + CARD32 StoreCrtcVSyncA; + CARD32 StoreCrtcVSyncACntl; + CARD32 StoreCrtcVSyncB; + CARD32 StoreCrtcVSyncBCntl; + CARD32 StoreCrtcCountControl; + + CARD32 StoreModeDataFormat; + CARD32 StoreCrtcInterlaceControl; + + CARD32 StoreCrtcBlackColor; + CARD32 StoreCrtcBlankControl; +}; + +/* + * Checks whether Width, Height are within boundaries. + * If MODE_OK is returned and pPitch is not NULL, it is set. + */ +static ModeStatus +DxFBValid(struct rhdCrtc *Crtc, CARD16 Width, CARD16 Height, int bpp, + CARD32 Offset, CARD32 Size, CARD32 *pPitch) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + ScrnInfoPtr pScrn = rhdPtr->pScrn; + + CARD16 Pitch; + unsigned int BytesPerPixel; + CARD8 PitchMask = 0xFF; + + RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s\n", __func__, Crtc->Name); + + /* If we hit this, then the memory claimed so far is not properly aligned */ + if (Offset & 0xFFF) { + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: Offset (0x%08X) is invalid!\n", + __func__, (int) Offset); + return MODE_ERROR; + } + + switch (pScrn->bitsPerPixel) { + case 8: + BytesPerPixel = 1; + break; + case 15: + case 16: + BytesPerPixel = 2; + PitchMask /= BytesPerPixel; + break; + case 24: + case 32: + BytesPerPixel = 4; + PitchMask /= BytesPerPixel; + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s: %dbpp is not implemented!\n", + __func__, pScrn->bitsPerPixel); + return MODE_BAD; + } + + if((Width==720)&&(Height==400)) //skip textmode + return MODE_BAD; + + /* Be reasonable */ + if (Width < 640) + return MODE_H_ILLEGAL; + if (Height < 480) + return MODE_V_ILLEGAL; + + /* D1GRPH_X_START is 14bits while D1_MODE_VIEWPORT_X_START is only 13 bits. + * Since it is reasonable to assume that modes will be at least 1x1 + * limit at 13bits + 1 */ + if (Width > 0x2000) + return MODE_VIRTUAL_X; + + /* D1GRPH_Y_START is 14bits while D1_MODE_VIEWPORT_Y_START is only 13 bits. + * Since it is reasonable to assume that modes will be at least 1x1 + * limit at 13bits + 1 */ + if (Height > 0x2000) + return MODE_VIRTUAL_Y; + + Pitch = (Width + PitchMask) & ~PitchMask; + /* D1_PITCH limit: should never happen after clamping Width to 0x2000 */ + if (Pitch >= 0x4000) + return MODE_VIRTUAL_X; + + if ((Pitch * BytesPerPixel * Height) > Size) + return MODE_MEM_VIRT; + + if (pPitch) + *pPitch = Pitch; + return MODE_OK; +} + +/* + * + */ +static void +DxFBSet(struct rhdCrtc *Crtc, CARD16 Pitch, CARD16 Width, CARD16 Height, + int bpp, CARD32 Offset) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + CARD16 RegOff; + + RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s (%i[%i]x%i@%ibpp) +0x%x )\n", + __func__, Crtc->Name, Width, Pitch, Height, bpp, Offset); + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + RHDRegMask(Crtc, RegOff + D1GRPH_ENABLE, 1, 0x00000001); + + /* disable R/B swap, disable tiling, disable 16bit alpha, etc. */ + RHDRegWrite(Crtc, RegOff + D1GRPH_CONTROL, 0); + + switch (bpp) { + case 8: + RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0, 0x00000703); + break; + case 15: + RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000001, 0x00000703); + break; + case 16: + RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000101, 0x00000703); + break; + case 24: + case 32: + default: + RHDRegMask(Crtc, RegOff + D1GRPH_CONTROL, 0x000002, 0x00000703); + break; + /* TODO: 64bpp ;p */ + } + + /* Make sure that we are not swapping colours around */ + if (rhdPtr->ChipSet > RHD_R600) + RHDRegWrite(Crtc, RegOff + D1GRPH_SWAP_CNTL, 0); + /* R5xx - RS690 case is GRPH_CONTROL bit 16 */ + + RHDRegWrite(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS, + rhdPtr->FbIntAddress + Offset); + RHDRegWrite(Crtc, RegOff + D1GRPH_PITCH, Pitch); + RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X, 0); + RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y, 0); + RHDRegWrite(Crtc, RegOff + D1GRPH_X_START, 0); + RHDRegWrite(Crtc, RegOff + D1GRPH_Y_START, 0); + RHDRegWrite(Crtc, RegOff + D1GRPH_X_END, Width); + RHDRegWrite(Crtc, RegOff + D1GRPH_Y_END, Height); + + /* D1Mode registers */ + RHDRegWrite(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT, Height); + + Crtc->Pitch = Pitch; + Crtc->Width = Width; + Crtc->Height = Height; + Crtc->bpp = bpp; + Crtc->Offset = Offset; +} + +/* + * + */ +static void +DxFBSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcFBPrivate *FBPriv; + CARD32 RegOff; + + if (!Crtc->FBPriv) + FBPriv = xnfcalloc(1, sizeof(struct rhdCrtcFBPrivate)); + else + FBPriv = Crtc->FBPriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + FBPriv->StoreGrphEnable = RHDRegRead(Crtc, RegOff + D1GRPH_ENABLE); + FBPriv->StoreGrphControl = RHDRegRead(Crtc, RegOff + D1GRPH_CONTROL); + FBPriv->StoreGrphXStart = RHDRegRead(Crtc, RegOff + D1GRPH_X_START); + FBPriv->StoreGrphYStart = RHDRegRead(Crtc, RegOff + D1GRPH_Y_START); + FBPriv->StoreGrphXEnd = RHDRegRead(Crtc, RegOff + D1GRPH_X_END); + FBPriv->StoreGrphYEnd = RHDRegRead(Crtc, RegOff + D1GRPH_Y_END); + if (RHDPTRI(Crtc)->ChipSet >= RHD_R600) + FBPriv->StoreGrphSwap = RHDRegRead(Crtc, RegOff + D1GRPH_SWAP_CNTL); + FBPriv->StoreGrphPrimarySurfaceAddress = + RHDRegRead(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS); + FBPriv->StoreGrphSurfaceOffsetX = + RHDRegRead(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X); + FBPriv->StoreGrphSurfaceOffsetY = + RHDRegRead(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y); + FBPriv->StoreGrphPitch = RHDRegRead(Crtc, RegOff + D1GRPH_PITCH); + FBPriv->StoreModeDesktopHeight = RHDRegRead(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT); + + Crtc->FBPriv = FBPriv; +} + +/* + * + */ +static void +DxFBRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcFBPrivate *FBPriv = Crtc->FBPriv; + CARD32 RegOff; + + if (!FBPriv) { + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n", + __func__); + return; + } + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + /* FBSet */ + RHDRegWrite(Crtc, RegOff + D1GRPH_CONTROL, FBPriv->StoreGrphControl); + RHDRegWrite(Crtc, RegOff + D1GRPH_X_START, FBPriv->StoreGrphXStart); + RHDRegWrite(Crtc, RegOff + D1GRPH_Y_START, FBPriv->StoreGrphYStart); + RHDRegWrite(Crtc, RegOff + D1GRPH_X_END, FBPriv->StoreGrphXEnd); + RHDRegWrite(Crtc, RegOff + D1GRPH_Y_END, FBPriv->StoreGrphYEnd); + if (RHDPTRI(Crtc)->ChipSet >= RHD_R600) + RHDRegWrite(Crtc, RegOff + D1GRPH_SWAP_CNTL, FBPriv->StoreGrphSwap); + + /* disable read requests */ + RHDRegMask(Crtc, RegOff + D1CRTC_CONTROL, 0x01000000, 0x01000000); + RHDRegMask(Crtc, RegOff + D1GRPH_ENABLE, 0, 0x00000001); + usleep (10); + + RHDRegWrite(Crtc, RegOff + D1GRPH_PRIMARY_SURFACE_ADDRESS, + FBPriv->StoreGrphPrimarySurfaceAddress); + usleep(10); + + RHDRegWrite(Crtc, RegOff + D1GRPH_ENABLE, FBPriv->StoreGrphEnable); + + RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_X, + FBPriv->StoreGrphSurfaceOffsetX); + RHDRegWrite(Crtc, RegOff + D1GRPH_SURFACE_OFFSET_Y, + FBPriv->StoreGrphSurfaceOffsetY); + + RHDRegWrite(Crtc, RegOff + D1GRPH_PITCH, FBPriv->StoreGrphPitch); + RHDRegWrite(Crtc, RegOff + D1MODE_DESKTOP_HEIGHT, FBPriv->StoreModeDesktopHeight); +} + +/* + * + */ +static void +DxFBDestroy(struct rhdCrtc *Crtc) +{ + if (Crtc->FBPriv) + xfree(Crtc->FBPriv); + Crtc->FBPriv = NULL; +} + +/* + * + */ +static ModeStatus +DxModeValid(struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + CARD32 tmp; + + RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name); + + /* Work around HW bug: need at least 2 lines of front porch + for interlaced mode */ + if ((Mode->Flags & V_INTERLACE) + && (Mode->CrtcVSyncStart < (Mode->CrtcVDisplay + 2))) { + Mode->CrtcVSyncStart = Mode->CrtcVDisplay + 2; + Mode->CrtcVAdjusted = TRUE; + } + + /* D1CRTC_H_TOTAL - 1 : 13bits */ + if (Mode->CrtcHTotal > 0x2000) + return MODE_BAD_HVALUE; + + tmp = Mode->CrtcHTotal + Mode->CrtcHBlankStart - Mode->CrtcHSyncStart; + /* D1CRTC_H_BLANK_START: 13bits */ + if (tmp >= 0x2000) + return MODE_BAD_HVALUE; + + tmp = Mode->CrtcHBlankEnd - Mode->CrtcHSyncStart; + /* D1CRTC_H_BLANK_END: 13bits */ + if (tmp >= 0x2000) + return MODE_BAD_HVALUE; + + tmp = Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart; + /* D1CRTC_H_SYNC_A_END: 13bits */ + if (tmp >= 0x2000) + return MODE_HSYNC_WIDE; + + /* D1CRTC_V_TOTAL - 1 : 13bits */ + if (Mode->CrtcVTotal > 0x2000) + return MODE_BAD_VVALUE; + + tmp = Mode->CrtcVTotal + Mode->CrtcVBlankStart - Mode->CrtcVSyncStart; + /* D1CRTC_V_BLANK_START: 13bits */ + if (tmp >= 0x2000) + return MODE_BAD_VVALUE; + + tmp = Mode->CrtcVBlankEnd - Mode->CrtcVSyncStart; + /* D1CRTC_V_BLANK_END: 13bits */ + if (tmp >= 0x2000) + return MODE_BAD_VVALUE; + + tmp = Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart; + /* D1CRTC_V_SYNC_A_END: 13bits */ + if (tmp >= 0x2000) + return MODE_VSYNC_WIDE; + + return MODE_OK; +} + +/* + * + */ +static void +DxModeSet(struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + CARD16 BlankStart, BlankEnd; + CARD16 RegOff; + + RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s\n", __func__, Crtc->Name); + + if (rhdPtr->verbosity > 6) { + xf86DrvMsg(Crtc->scrnIndex, X_INFO, "%s: Setting ",__func__); + RHDPrintModeline(Mode); + } + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + /* enable read requests */ + RHDRegMask(Crtc, RegOff + D1CRTC_CONTROL, 0, 0x01000000); + + /* Horizontal */ + RHDRegWrite(Crtc, RegOff + D1CRTC_H_TOTAL, Mode->CrtcHTotal - 1); + + BlankStart = Mode->CrtcHTotal + Mode->CrtcHBlankStart - Mode->CrtcHSyncStart; + BlankEnd = Mode->CrtcHBlankEnd - Mode->CrtcHSyncStart; + RHDRegWrite(Crtc, RegOff + D1CRTC_H_BLANK_START_END, + BlankStart | (BlankEnd << 16)); + + RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A, + (Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart) << 16); + RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL, Mode->Flags & V_NHSYNC); + + /* Vertical */ + RHDRegWrite(Crtc, RegOff + D1CRTC_V_TOTAL, Mode->CrtcVTotal - 1); + + BlankStart = Mode->CrtcVTotal + Mode->CrtcVBlankStart - Mode->CrtcVSyncStart; + BlankEnd = Mode->CrtcVBlankEnd - Mode->CrtcVSyncStart; + RHDRegWrite(Crtc, RegOff + D1CRTC_V_BLANK_START_END, + BlankStart | (BlankEnd << 16)); + + /* set interlaced */ + if (Mode->Flags & V_INTERLACE) { + RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, 0x1); + RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x1); + } else { + RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, 0x0); + RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, 0x0); + } + + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, + (Mode->CrtcVSyncEnd - Mode->CrtcVSyncStart) << 16); + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL, Mode->Flags & V_NVSYNC); + + /* set D1CRTC_HORZ_COUNT_BY2_EN to 0; should only be set to 1 on 30bpp DVI modes */ + RHDRegMask(Crtc, RegOff + D1CRTC_COUNT_CONTROL, 0x0, 0x1); + + Crtc->CurrentMode = Mode; +} + +/* + * + */ +static void +DxModeSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcModePrivate *ModePriv; + CARD32 RegOff; + + if (!Crtc->ModePriv) + ModePriv = xnfcalloc(1, sizeof(struct rhdCrtcModePrivate)); + else + ModePriv = Crtc->ModePriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + ModePriv->StoreCrtcControl = RHDRegRead(Crtc, RegOff + D1CRTC_CONTROL); + + ModePriv->StoreCrtcHTotal = RHDRegRead(Crtc, RegOff + D1CRTC_H_TOTAL); + ModePriv->StoreCrtcHBlankStartEnd = + RHDRegRead(Crtc, RegOff + D1CRTC_H_BLANK_START_END); + ModePriv->StoreCrtcHSyncA = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_A); + ModePriv->StoreCrtcHSyncACntl = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL); + ModePriv->StoreCrtcHSyncB = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_B); + ModePriv->StoreCrtcHSyncBCntl = RHDRegRead(Crtc, RegOff + D1CRTC_H_SYNC_B_CNTL); + + ModePriv->StoreModeDataFormat = RHDRegRead(Crtc, RegOff + D1MODE_DATA_FORMAT); + ModePriv->StoreCrtcInterlaceControl = RHDRegRead(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL); + + ModePriv->StoreCrtcVTotal = RHDRegRead(Crtc, RegOff + D1CRTC_V_TOTAL); + ModePriv->StoreCrtcVBlankStartEnd = + RHDRegRead(Crtc, RegOff + D1CRTC_V_BLANK_START_END); + ModePriv->StoreCrtcVSyncA = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_A); + ModePriv->StoreCrtcVSyncACntl = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL); + ModePriv->StoreCrtcVSyncB = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_B); + ModePriv->StoreCrtcVSyncBCntl = RHDRegRead(Crtc, RegOff + D1CRTC_V_SYNC_B_CNTL); + + ModePriv->StoreCrtcBlackColor = RHDRegRead(Crtc, RegOff + D1CRTC_BLACK_COLOR); + ModePriv->StoreCrtcBlankControl = RHDRegRead(Crtc, RegOff + D1CRTC_BLANK_CONTROL); + + ModePriv->StoreCrtcCountControl = RHDRegRead(Crtc, RegOff + D1CRTC_COUNT_CONTROL); + RHDDebug(Crtc->scrnIndex, "Saved CrtcCountControl[%i] = 0x%8.8x\n", + Crtc->Id,ModePriv->StoreCrtcCountControl); + + Crtc->ModePriv = ModePriv; +} + +/* + * + */ +static void +DxModeRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcModePrivate *ModePriv = Crtc->ModePriv; + CARD32 RegOff; + + if (!ModePriv) { + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n", + __func__); + return; + } + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + /* ModeSet */ + RHDRegWrite(Crtc, RegOff + D1CRTC_CONTROL, ModePriv->StoreCrtcControl); + + RHDRegWrite(Crtc, RegOff + D1CRTC_H_TOTAL, ModePriv->StoreCrtcHTotal); + RHDRegWrite(Crtc, RegOff + D1CRTC_H_BLANK_START_END, + ModePriv->StoreCrtcHBlankStartEnd); + RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A, ModePriv->StoreCrtcHSyncA); + RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_A_CNTL, ModePriv->StoreCrtcHSyncACntl); + RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_B, ModePriv->StoreCrtcHSyncB); + RHDRegWrite(Crtc, RegOff + D1CRTC_H_SYNC_B_CNTL, ModePriv->StoreCrtcHSyncBCntl); + + RHDRegWrite(Crtc, RegOff + D1MODE_DATA_FORMAT, ModePriv->StoreModeDataFormat); + RHDRegWrite(Crtc, RegOff + D1CRTC_INTERLACE_CONTROL, ModePriv->StoreCrtcInterlaceControl); + + RHDRegWrite(Crtc, RegOff + D1CRTC_V_TOTAL, ModePriv->StoreCrtcVTotal); + RHDRegWrite(Crtc, RegOff + D1CRTC_V_BLANK_START_END, + ModePriv->StoreCrtcVBlankStartEnd); + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, ModePriv->StoreCrtcVSyncA); + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A_CNTL, ModePriv->StoreCrtcVSyncACntl); + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_B, ModePriv->StoreCrtcVSyncB); + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_B_CNTL, ModePriv->StoreCrtcVSyncBCntl); + + RHDRegWrite(Crtc, RegOff + D1CRTC_COUNT_CONTROL, ModePriv->StoreCrtcCountControl); + + /* Blank */ + RHDRegWrite(Crtc, RegOff + D1CRTC_BLACK_COLOR, ModePriv->StoreCrtcBlackColor); + RHDRegWrite(Crtc, RegOff + D1CRTC_BLANK_CONTROL, ModePriv->StoreCrtcBlankControl); + + /* When VGA is enabled, it imposes its timing on us, so our CRTC SYNC + * timing can be set to 0. This doesn't always restore properly... + * Workaround is to set a valid sync length for a bit so VGA can + * latch in. */ + if (!ModePriv->StoreCrtcVSyncA && (ModePriv->StoreCrtcControl & 0x00000001)) { + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, 0x00040000); + usleep(300000); /* seems a reliable timeout here */ + RHDRegWrite(Crtc, RegOff + D1CRTC_V_SYNC_A, ModePriv->StoreCrtcVSyncA); + } +} + +/* + * + */ +static void +DxModeDestroy(struct rhdCrtc *Crtc) +{ + RHDFUNC(Crtc); + + if (Crtc->ModePriv) + xfree(Crtc->ModePriv); + Crtc->ModePriv = NULL; +} + +/* + * + */ +struct rhdScalerOverscan +rhdCalculateOverscan(DisplayModePtr Mode, DisplayModePtr ScaledToMode, enum rhdCrtcScaleType Type) +{ + struct rhdScalerOverscan Overscan; + int tmp; + + Overscan.OverscanTop = Overscan.OverscanBottom = Overscan.OverscanLeft = Overscan.OverscanRight = 0; + Overscan.Type = Type; + + if (ScaledToMode) { + Overscan.OverscanTop = ScaledToMode->CrtcVDisplay - Mode->CrtcVDisplay; + Overscan.OverscanLeft = ScaledToMode->CrtcHDisplay - Mode->CrtcHDisplay; + + if (!Overscan.OverscanTop && !Overscan.OverscanLeft) + Overscan.Type = RHD_CRTC_SCALE_TYPE_NONE; + + /* handle down scaling */ + if (Overscan.OverscanTop < 0) { + Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE; + Overscan.OverscanTop = 0; + } + if (Overscan.OverscanLeft < 0) { + Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE; + Overscan.OverscanLeft = 0; + } + } + + switch (Type) { + case RHD_CRTC_SCALE_TYPE_NONE: + break; + + case RHD_CRTC_SCALE_TYPE_CENTER: + tmp = Overscan.OverscanTop; + Overscan.OverscanTop >>= 1; + Overscan.OverscanBottom = tmp - Overscan.OverscanTop; + tmp = Overscan.OverscanLeft; + Overscan.OverscanLeft >>= 1; + Overscan.OverscanRight = tmp - Overscan.OverscanLeft; + break; + + case RHD_CRTC_SCALE_TYPE_SCALE: + Overscan.OverscanLeft = Overscan.OverscanRight = Overscan.OverscanTop = Overscan.OverscanBottom = 0; + break; + case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO: + { + int p1, p2, tmp; + Overscan.OverscanLeft = Overscan.OverscanRight = Overscan.OverscanTop = Overscan.OverscanBottom = 0; + p1 = Mode->CrtcVDisplay * ScaledToMode->CrtcHDisplay; + p2 = ScaledToMode->CrtcVDisplay * Mode->CrtcHDisplay; + if (p1 == p2) { + Overscan.Type = RHD_CRTC_SCALE_TYPE_SCALE; + } else if (p1 > p2) { + tmp = (p2 / Mode->CrtcVDisplay); + tmp = ScaledToMode->CrtcHDisplay - tmp; + Overscan.OverscanLeft = tmp >> 1; + Overscan.OverscanRight = tmp - Overscan.OverscanLeft; + ErrorF("HScale %i %i\n", Overscan.OverscanLeft, Overscan.OverscanRight); + } else { + tmp = (p1 / Mode->CrtcHDisplay); + tmp = ScaledToMode->CrtcVDisplay - tmp; + Overscan.OverscanTop = tmp >> 1; + Overscan.OverscanBottom = tmp - Overscan.OverscanTop; + ErrorF("VScale %i %i\n", Overscan.OverscanTop, Overscan.OverscanBottom); + } + break; + } + } + + return Overscan; +} + +/* + * + */ +static ModeStatus +DxScaleValid(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type, + DisplayModePtr Mode, DisplayModePtr ScaledToMode) +{ + struct rhdScalerOverscan Overscan; + + /* D1_MODE_VIEWPORT_WIDTH: 14bits */ + if (Mode->CrtcHDisplay >= 0x4000) + return MODE_BAD_HVALUE; + + /* D1_MODE_VIEWPORT_HEIGHT: 14bits */ + if (Mode->CrtcVDisplay >= 0x4000) + return MODE_BAD_VVALUE; + + Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type); + + if (Overscan.OverscanLeft >= 4096 || Overscan.OverscanRight >= 4096) + return MODE_HBLANK_WIDE; + + if (Overscan.OverscanTop >= 4096 || Overscan.OverscanBottom >= 4096) + return MODE_VBLANK_WIDE; + + if ((Type == RHD_CRTC_SCALE_TYPE_SCALE + || Type == RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO) + && (Mode->Flags & V_INTERLACE)) + return MODE_NO_INTERLACE; + + /* should we also fail of Type != Overscan.Type? */ + + return MODE_OK; +} + +/* + * + */ +static void +DxScaleSet(struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type, + DisplayModePtr Mode, DisplayModePtr ScaledToMode) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + CARD16 RegOff; + struct rhdScalerOverscan Overscan; + + RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i\n", __func__, Crtc->Name, + Mode->CrtcHDisplay, Mode->CrtcVDisplay); + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + Overscan = rhdCalculateOverscan(Mode, ScaledToMode, Type); + Type = Overscan.Type; + + RHDDebug(Crtc->scrnIndex, "FUNCTION: %s: %s viewport: %ix%i - OverScan: T: %i B: %i R: %i L: %i\n", + __func__, Crtc->Name, Mode->CrtcHDisplay, Mode->CrtcVDisplay, + Overscan.OverscanTop, Overscan.OverscanBottom, + Overscan.OverscanLeft, Overscan.OverscanRight); + + /* D1Mode registers */ + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, + Mode->CrtcVDisplay | (Mode->CrtcHDisplay << 16)); + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, 0); + + RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT, + (Overscan.OverscanLeft << 16) | Overscan.OverscanRight); + RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM, + (Overscan.OverscanTop << 16) | Overscan.OverscanBottom); + + switch (Type) { + case RHD_CRTC_SCALE_TYPE_NONE: /* No scaling whatsoever */ + ErrorF("None\n"); + RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 0); + RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0); + RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 0); + break; + case RHD_CRTC_SCALE_TYPE_CENTER: /* center of the actual mode */ + ErrorF("Center\n"); + RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 0); + RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0); + RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 1); + break; + case RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO: /* scaled to fullscreen */ + case RHD_CRTC_SCALE_TYPE_SCALE: /* scaled to fullscreen */ + ErrorF("Full\n"); + if (Type == RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO) + RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 1); + else + RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, 0); + + RHDRegWrite(Crtc, RegOff + D1SCL_UPDATE, 0); + RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, 0); + + RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, 1); + RHDRegWrite(Crtc, RegOff + D1SCL_HVSCALE, 0x00010001); /* both h/v */ + + RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, 0x00000101); + + RHDRegWrite(Crtc, RegOff + D1SCL_HFILTER, 0x00030100); + RHDRegWrite(Crtc, RegOff + D1SCL_VFILTER, 0x00030100); + + RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, 0x00001010); + break; + } + RHDTuneMCAccessForDisplay(rhdPtr, Crtc->Id, Mode, + ScaledToMode ? ScaledToMode : Mode); +} + +/* + * + */ +static void +DxScaleSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcScalePrivate *ScalePriv; + CARD32 RegOff; + + if (!Crtc->ScalePriv) + ScalePriv = xnfcalloc(1, sizeof(struct rhdCrtcScalePrivate)); + else + ScalePriv = Crtc->ScalePriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + ScalePriv->StoreModeViewPortSize = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_SIZE); + ScalePriv->StoreModeViewPortStart = RHDRegRead(Crtc, RegOff + D1MODE_VIEWPORT_START); + ScalePriv->StoreModeOverScanH = + RHDRegRead(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT); + ScalePriv->StoreModeOverScanV = + RHDRegRead(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM); + + ScalePriv->StoreScaleEnable = RHDRegRead(Crtc, RegOff + D1SCL_ENABLE); + ScalePriv->StoreScaleTapControl = RHDRegRead(Crtc, RegOff + D1SCL_TAP_CONTROL); + ScalePriv->StoreModeCenter = RHDRegRead(Crtc, RegOff + D1MODE_CENTER); + ScalePriv->StoreScaleHV = RHDRegRead(Crtc, RegOff + D1SCL_HVSCALE); + ScalePriv->StoreScaleHFilter = RHDRegRead(Crtc, RegOff + D1SCL_HFILTER); + ScalePriv->StoreScaleVFilter = RHDRegRead(Crtc, RegOff + D1SCL_VFILTER); + ScalePriv->StoreScaleDither = RHDRegRead(Crtc, RegOff + D1SCL_DITHER); + + Crtc->ScalePriv = ScalePriv; +} + +/* + * + */ +static void +DxScaleRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcScalePrivate *ScalePriv = Crtc->ScalePriv; + CARD32 RegOff; + + if (!ScalePriv) { + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n", + __func__); + return; + } + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + /* ScaleSet */ + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_SIZE, ScalePriv->StoreModeViewPortSize); + + /* ScaleSet/ViewPortStart */ + RHDRegWrite(Crtc, RegOff + D1MODE_VIEWPORT_START, ScalePriv->StoreModeViewPortStart); + + /* ScaleSet */ + RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_LEFT_RIGHT, + ScalePriv->StoreModeOverScanH); + RHDRegWrite(Crtc, RegOff + D1MODE_EXT_OVERSCAN_TOP_BOTTOM, + ScalePriv->StoreModeOverScanV); + + RHDRegWrite(Crtc, RegOff + D1SCL_ENABLE, ScalePriv->StoreScaleEnable); + RHDRegWrite(Crtc, RegOff + D1SCL_TAP_CONTROL, ScalePriv->StoreScaleTapControl); + RHDRegWrite(Crtc, RegOff + D1MODE_CENTER, ScalePriv->StoreModeCenter); + RHDRegWrite(Crtc, RegOff + D1SCL_HVSCALE, ScalePriv->StoreScaleHV); + RHDRegWrite(Crtc, RegOff + D1SCL_HFILTER, ScalePriv->StoreScaleHFilter); + RHDRegWrite(Crtc, RegOff + D1SCL_VFILTER, ScalePriv->StoreScaleVFilter); + RHDRegWrite(Crtc, RegOff + D1SCL_DITHER, ScalePriv->StoreScaleDither); +} + +/* + * + */ +static void +DxScaleDestroy(struct rhdCrtc *Crtc) +{ + RHDFUNC(Crtc); + + if (Crtc->ScalePriv) + xfree(Crtc->ScalePriv); + Crtc->ScalePriv = NULL; +} + +/* + * + */ +static void +D1LUTSelect(struct rhdCrtc *Crtc, struct rhdLUT *LUT) +{ + RHDFUNC(Crtc); + + RHDRegWrite(Crtc, D1GRPH_LUT_SEL, LUT->Id & 1); + Crtc->LUT = LUT; +} + +/* + * + */ +static void +D2LUTSelect(struct rhdCrtc *Crtc, struct rhdLUT *LUT) +{ + RHDFUNC(Crtc); + + RHDRegWrite(Crtc, D2GRPH_LUT_SEL, LUT->Id & 1); + Crtc->LUT = LUT; +} + +/* + * + */ +static void +DxLUTSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcLUTPrivate *LUTPriv; + CARD32 RegOff; + + if (!Crtc->LUTPriv) + LUTPriv = xnfcalloc(1, sizeof(struct rhdCrtcLUTPrivate)); + else + LUTPriv = Crtc->LUTPriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + LUTPriv->StoreGrphLutSel = RHDRegRead(Crtc, RegOff + D1GRPH_LUT_SEL); + + Crtc->LUTPriv = LUTPriv; +} + +/* + * + */ +static void +DxLUTRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcLUTPrivate *LUTPriv = Crtc->LUTPriv; + CARD32 RegOff; + + if (!LUTPriv) { + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: no registers stored!\n", + __func__); + return; + } + + if (Crtc->Id == RHD_CRTC_1) + RegOff = D1_REG_OFFSET; + else + RegOff = D2_REG_OFFSET; + + /* LUTSelect */ + RHDRegWrite(Crtc, RegOff + D1GRPH_LUT_SEL, LUTPriv->StoreGrphLutSel); +} + +/* + * + */ +static void +DxLUTDestroy(struct rhdCrtc *Crtc) +{ + RHDFUNC(Crtc); + + if (Crtc->LUTPriv) + xfree(Crtc->LUTPriv); + Crtc->LUTPriv = NULL; +} + +/* + * + */ +static void +D1ViewPortStart(struct rhdCrtc *Crtc, CARD16 X, CARD16 Y) +{ + RHDFUNC(Crtc); + + /* not as granular as docs make it seem to be. + * if the lower two bits are set the line buffer might screw up, requiring + * a power cycle. */ + X = (X + 0x02) & ~0x03; + Y &= ~0x01; + + RHDRegMask(Crtc, D1SCL_UPDATE, 0x00010000, 0x0001000); + RHDRegWrite(Crtc, D1MODE_VIEWPORT_START, (X << 16) | Y); + RHDRegMask(Crtc, D1SCL_UPDATE, 0, 0x0001000); + + Crtc->X = X; + Crtc->Y = Y; +} + +/* + * + */ +static void +D2ViewPortStart(struct rhdCrtc *Crtc, CARD16 X, CARD16 Y) +{ + RHDFUNC(Crtc); + + /* not as granular as docs make it seem to be. */ + X = (X + 0x02) & ~0x03; + Y &= ~0x01; + + RHDRegMask(Crtc, D2SCL_UPDATE, 0x00010000, 0x0001000); + RHDRegWrite(Crtc, D2MODE_VIEWPORT_START, (X << 16) | Y); + RHDRegMask(Crtc, D2SCL_UPDATE, 0, 0x0001000); + + Crtc->X = X; + Crtc->Y = Y; +} + +#define CRTC_SYNC_WAIT 0x100000 +/* + * + */ +static void +D1CRTCDisable(struct rhdCrtc *Crtc) +{ + if (RHDRegRead(Crtc, D1CRTC_CONTROL) & 0x00000001) { + CARD32 Control = RHDRegRead(Crtc, D1CRTC_CONTROL); + int i; + + RHDRegMask(Crtc, D1CRTC_CONTROL, 0, 0x00000301); + (void)RHDRegRead(Crtc, D1CRTC_CONTROL); + + for (i = 0; i < CRTC_SYNC_WAIT; i++) + if (!(RHDRegRead(Crtc, D1CRTC_CONTROL) & 0x00010000)) { + RHDDebug(Crtc->scrnIndex, "%s: %d loops\n", __func__, i); + RHDRegMask(Crtc, D1CRTC_CONTROL, Control, 0x00000300); + return; + } + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, + "%s: Failed to Unsync %s\n", __func__, Crtc->Name); + RHDRegMask(Crtc, D1CRTC_CONTROL, Control, 0x00000300); + } +} + +/* + * + */ +static void +D2CRTCDisable(struct rhdCrtc *Crtc) +{ + if (RHDRegRead(Crtc, D2CRTC_CONTROL) & 0x00000001) { + CARD32 Control = RHDRegRead(Crtc, D2CRTC_CONTROL); + int i; + + RHDRegMask(Crtc, D2CRTC_CONTROL, 0, 0x00000301); + (void)RHDRegRead(Crtc, D2CRTC_CONTROL); + + for (i = 0; i < CRTC_SYNC_WAIT; i++) + if (!(RHDRegRead(Crtc, D2CRTC_CONTROL) & 0x00010000)) { + RHDDebug(Crtc->scrnIndex, "%s: %d loops\n", __func__, i); + RHDRegMask(Crtc, D2CRTC_CONTROL, Control, 0x00000300); + return; + } + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, + "%s: Failed to Unsync %s\n", __func__, Crtc->Name); + RHDRegMask(Crtc, D2CRTC_CONTROL, Control, 0x00000300); + } +} + +/* + * + */ +static void +D1Power(struct rhdCrtc *Crtc, int Power) +{ + RHDFUNC(Crtc); + + switch (Power) { + case RHD_POWER_ON: + RHDRegMask(Crtc, D1GRPH_ENABLE, 0x00000001, 0x00000001); + usleep(2); + RHDRegMask(Crtc, D1CRTC_CONTROL, 0, 0x01000000); /* enable read requests */ + RHDRegMask(Crtc, D1CRTC_CONTROL, 1, 1); + return; + case RHD_POWER_RESET: + RHDRegMask(Crtc, D1CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */ + D1CRTCDisable(Crtc); + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(Crtc, D1CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */ + D1CRTCDisable(Crtc); + RHDRegMask(Crtc, D1GRPH_ENABLE, 0, 0x00000001); + return; + } +} + +/* + * + */ +static void +D2Power(struct rhdCrtc *Crtc, int Power) +{ + RHDFUNC(Crtc); + + switch (Power) { + case RHD_POWER_ON: + RHDRegMask(Crtc, D2GRPH_ENABLE, 0x00000001, 0x00000001); + usleep(2); + RHDRegMask(Crtc, D2CRTC_CONTROL, 0, 0x01000000); /* enable read requests */ + RHDRegMask(Crtc, D2CRTC_CONTROL, 1, 1); + return; + case RHD_POWER_RESET: + RHDRegMask(Crtc, D2CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */ + D2CRTCDisable(Crtc); + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(Crtc, D2CRTC_CONTROL, 0x01000000, 0x01000000); /* disable read requests */ + D2CRTCDisable(Crtc); + RHDRegMask(Crtc, D2GRPH_ENABLE, 0, 0x00000001); + return; + } +} + +/* + * This is quite different from Power. Power disables and enables things, + * this here makes the hw send out black, and can switch back and forth + * immediately. Useful for covering up a framebuffer that is not filled + * in yet. + */ +static void +D1Blank(struct rhdCrtc *Crtc, Bool Blank) +{ + RHDFUNC(Crtc); + + RHDRegWrite(Crtc, D1CRTC_BLACK_COLOR, 0); + if (Blank) + RHDRegMask(Crtc, D1CRTC_BLANK_CONTROL, 0x00000100, 0x00000100); + else + RHDRegMask(Crtc, D1CRTC_BLANK_CONTROL, 0, 0x00000100); +} + +/* + * + */ +static void +D2Blank(struct rhdCrtc *Crtc, Bool Blank) +{ + RHDFUNC(Crtc); + + RHDRegWrite(Crtc, D2CRTC_BLACK_COLOR, 0); + if (Blank) + RHDRegMask(Crtc, D2CRTC_BLANK_CONTROL, 0x00000100, 0x00000100); + else + RHDRegMask(Crtc, D2CRTC_BLANK_CONTROL, 0, 0x00000100); +} + +/* + * + */ +static void +DxFMTSet(struct rhdCrtc *Crtc, struct rhdFMTDither *FMTDither) +{ + CARD32 RegOff; + CARD32 fmt_cntl = 0; + + RHDFUNC(Crtc); + + if (Crtc->Id == RHD_CRTC_1) + RegOff = FMT1_REG_OFFSET; + else + RegOff = FMT2_REG_OFFSET; + + if (FMTDither) { + + /* set dither depth to 18/24 */ + fmt_cntl = FMTDither->LVDS24Bit + ? (RV62_FMT_SPATIAL_DITHER_DEPTH | RV62_FMT_TEMPORAL_DITHER_DEPTH) + : 0; + RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, fmt_cntl, + RV62_FMT_SPATIAL_DITHER_DEPTH | RV62_FMT_TEMPORAL_DITHER_DEPTH); + + /* set temporal dither */ + if (FMTDither->LVDSTemporalDither) { + fmt_cntl = FMTDither->LVDSGreyLevel ? RV62_FMT_TEMPORAL_LEVEL : 0x0; + /* grey level */ + RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, + fmt_cntl, RV62_FMT_TEMPORAL_LEVEL); + /* turn on temporal dither and reset */ + RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, + RV62_FMT_TEMPORAL_DITHER_EN | RV62_FMT_TEMPORAL_DITHER_RESET, + RV62_FMT_TEMPORAL_DITHER_EN | RV62_FMT_TEMPORAL_DITHER_RESET); + usleep(20); + /* turn off reset */ + RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, 0x0, + RV62_FMT_TEMPORAL_DITHER_RESET); + } + /* spatial dither */ + RHDRegMask(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, + FMTDither->LVDSSpatialDither ? RV62_FMT_SPATIAL_DITHER_EN : 0, + RV62_FMT_SPATIAL_DITHER_EN); + } else + RHDRegWrite(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, 0); + + /* 4:4:4 encoding */ + RHDRegMask(Crtc, RegOff + RV620_FMT1_CONTROL, 0, RV62_FMT_PIXEL_ENCODING); + /* disable color clamping */ + RHDRegWrite(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL, 0); +} + +/* + * + */ +static void +DxFMTSave(struct rhdCrtc *Crtc) +{ + struct rhdCrtcFMTPrivate *FMTPrivate; + CARD32 RegOff; + + RHDFUNC(Crtc); + + if (!Crtc->FMTPriv) + FMTPrivate = xnfcalloc(sizeof (struct rhdCrtcFMTPrivate),1); + else + FMTPrivate = Crtc->FMTPriv; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = FMT1_REG_OFFSET; + else + RegOff = FMT2_REG_OFFSET; + + FMTPrivate->StoreControl = RHDRegRead(Crtc, RegOff + RV620_FMT1_CONTROL); + FMTPrivate->StoreBitDepthControl = RHDRegRead(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL); + FMTPrivate->StoreClampCntl = RHDRegRead(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL); + + Crtc->FMTPriv = FMTPrivate; +} + +/* + * + */ +static void +DxFMTRestore(struct rhdCrtc *Crtc) +{ + struct rhdCrtcFMTPrivate *FMTPrivate = Crtc->FMTPriv; + CARD32 RegOff; + + RHDFUNC(Crtc); + + if (!FMTPrivate) + return; + + if (Crtc->Id == RHD_CRTC_1) + RegOff = FMT1_REG_OFFSET; + else + RegOff = FMT2_REG_OFFSET; + + RHDRegWrite(Crtc, RegOff + RV620_FMT1_CONTROL, FMTPrivate->StoreControl); + RHDRegWrite(Crtc, RegOff + RV620_FMT1_BIT_DEPTH_CONTROL, FMTPrivate->StoreBitDepthControl); + RHDRegWrite(Crtc, RegOff + RV620_FMT1_CLAMP_CNTL, FMTPrivate->StoreClampCntl); +} + +/* + * + */ +static void +DxFMTDestroy(struct rhdCrtc *Crtc) +{ + RHDFUNC(Crtc); + + if (Crtc->FMTPriv) + xfree(Crtc->FMTPriv); + Crtc->FMTPriv = NULL; +} + +/* + * + */ +static enum rhdCrtcScaleType +rhdInitScaleType(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); +/* + if (rhdPtr->scaleTypeOpt.set) { + if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "none")) + return RHD_CRTC_SCALE_TYPE_NONE; + else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "center")) + return RHD_CRTC_SCALE_TYPE_CENTER; + else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "scale")) + return RHD_CRTC_SCALE_TYPE_SCALE; + else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "scale_keep_aspect_ratio")) + return RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO; + else if (!strcasecmp(rhdPtr->scaleTypeOpt.val.string, "default")) + return RHD_CRTC_SCALE_TYPE_DEFAULT; + else { + xf86DrvMsgVerb(rhdPtr->scrnIndex, X_ERROR, 0, + "Unknown scale type: %s\n", rhdPtr->scaleTypeOpt.val.string); + return RHD_CRTC_SCALE_TYPE_DEFAULT; + } + } else */ + return RHD_CRTC_SCALE_TYPE_SCALE; +} + +/* + * + */ +Bool +RHDCrtcsInit(RHDPtr rhdPtr) +{ + struct rhdCrtc *Crtc; + enum rhdCrtcScaleType ScaleType; + Bool useAtom; + + RHDFUNC(rhdPtr); + + useAtom = RHDUseAtom(rhdPtr, NULL, atomUsageCrtc); + + ScaleType = rhdInitScaleType(rhdPtr); + + Crtc = xnfcalloc(sizeof(struct rhdCrtc), 1); + Crtc->scrnIndex = rhdPtr->scrnIndex; + Crtc->Name = "CRTC 1"; + Crtc->Id = RHD_CRTC_1; + + Crtc->ScaleType = ScaleType; + + if (rhdPtr->ChipSet >= RHD_RV620) { + Crtc->FMTDestroy = DxFMTDestroy; + Crtc->FMTSave = DxFMTSave; + Crtc->FMTRestore = DxFMTRestore; + Crtc->FMTModeSet = DxFMTSet; + } + Crtc->FMTPriv = NULL; + + Crtc->FBValid = DxFBValid; + Crtc->FBSet = DxFBSet; + Crtc->FBSave = DxFBSave; + Crtc->FBRestore = DxFBRestore; + Crtc->FBDestroy = DxFBDestroy; + + Crtc->ModeValid = DxModeValid; + Crtc->ModeSet = DxModeSet; + Crtc->ModeSave = DxModeSave; + Crtc->ModeRestore = DxModeRestore; + Crtc->ModeDestroy = DxModeDestroy; + Crtc->ModePriv = NULL; + + Crtc->ScaleValid = DxScaleValid; + Crtc->ScaleSet = DxScaleSet; + Crtc->ScaleSave = DxScaleSave; + Crtc->ScaleRestore = DxScaleRestore; + Crtc->ScaleDestroy = DxScaleDestroy; + Crtc->ScalePriv = NULL; + + Crtc->LUTSelect = D1LUTSelect; + Crtc->LUTSave = DxLUTSave; + Crtc->LUTRestore = DxLUTRestore; + Crtc->LUTDestroy = DxLUTDestroy; + Crtc->LUTPriv = NULL; + + Crtc->FrameSet = D1ViewPortStart; + + Crtc->Power = D1Power; + Crtc->Blank = D1Blank; + + rhdPtr->Crtc[0] = Crtc; + + Crtc = xnfcalloc(sizeof(struct rhdCrtc), 1); + Crtc->scrnIndex = rhdPtr->scrnIndex; + Crtc->Name = "CRTC 2"; + Crtc->Id = RHD_CRTC_2; + + Crtc->ScaleType = ScaleType; + + if (rhdPtr->ChipSet >= RHD_RV620) { + Crtc->FMTDestroy = DxFMTDestroy; + Crtc->FMTSave = DxFMTSave; + Crtc->FMTRestore = DxFMTRestore; + Crtc->FMTModeSet = DxFMTSet; + } + Crtc->FMTPriv = NULL; + + Crtc->FBValid = DxFBValid; + Crtc->FBSet = DxFBSet; + Crtc->FBSave = DxFBSave; + Crtc->FBRestore = DxFBRestore; + Crtc->FBDestroy = DxFBDestroy; + + Crtc->ModeValid = DxModeValid; + Crtc->ModeSet = DxModeSet; + Crtc->ModeSave = DxModeSave; + Crtc->ModeRestore = DxModeRestore; + Crtc->ModeDestroy = DxModeDestroy; + Crtc->ModePriv = NULL; + + Crtc->ScaleValid = DxScaleValid; + Crtc->ScaleSet = DxScaleSet; + Crtc->ScaleSave = DxScaleSave; + Crtc->ScaleRestore = DxScaleRestore; + Crtc->ScaleDestroy = DxScaleDestroy; + Crtc->ScalePriv = NULL; + + Crtc->LUTSelect = D2LUTSelect; + Crtc->LUTSave = DxLUTSave; + Crtc->LUTRestore = DxLUTRestore; + Crtc->LUTDestroy = DxLUTDestroy; + Crtc->LUTPriv = NULL; + + Crtc->FrameSet = D2ViewPortStart; + + Crtc->Power = D2Power; + Crtc->Blank = D2Blank; + + rhdPtr->Crtc[1] = Crtc; + + return !useAtom; +} + +/* + * + */ +void +RHDCrtcsDestroy(RHDPtr rhdPtr) +{ + struct rhdCrtc *Crtc; + int i; + + RHDFUNC(rhdPtr); + + for (i = 0; i < 2; i++) { + Crtc = rhdPtr->Crtc[i]; + if (Crtc) { + if (Crtc->FMTDestroy) + Crtc->FMTDestroy(Crtc); + + if (Crtc->LUTDestroy) + Crtc->LUTDestroy(Crtc); + + if (Crtc->FBDestroy) + Crtc->FBDestroy(Crtc); + + if (Crtc->ScaleDestroy) + Crtc->ScaleDestroy(Crtc); + + if (Crtc->ModeDestroy) + Crtc->ModeDestroy(Crtc); + + xfree(Crtc); + rhdPtr->Crtc[i] = NULL; + } + } +} + + +/* + * + */ +void +RHDCrtcSave(struct rhdCrtc *Crtc) +{ + RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name); + + if (Crtc->FMTSave) + Crtc->FMTSave(Crtc); + + if (Crtc->FBSave) + Crtc->FBSave(Crtc); + + if (Crtc->LUTSave) + Crtc->LUTSave(Crtc); + + if (Crtc->ScaleSave) + Crtc->ScaleSave(Crtc); + + if (Crtc->ModeSave) + Crtc->ModeSave(Crtc); +} + +/* + * + */ +void +RHDCrtcRestore(struct rhdCrtc *Crtc) +{ + + RHDDebug(Crtc->scrnIndex, "%s: %s\n", __func__, Crtc->Name); + + if (Crtc->FMTRestore) + Crtc->FMTRestore(Crtc); + + if (Crtc->FBRestore) + Crtc->FBRestore(Crtc); + + if (Crtc->LUTRestore) + Crtc->LUTRestore(Crtc); + + if (Crtc->ScaleRestore) + Crtc->ScaleRestore(Crtc); + + if (Crtc->ModeRestore) + Crtc->ModeRestore(Crtc); +} diff --git a/programs/system/drivers/rhd/rhd_crtc.h b/programs/system/drivers/rhd/rhd_crtc.h new file mode 100644 index 000000000..8f58c13a8 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_crtc.h @@ -0,0 +1,139 @@ +/* + * Copyright 2004-2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * + * 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. + */ + +#ifndef _RHD_CRTC_H +# define _RHD_CRTC_H + +struct rhdFMTDither { + Bool LVDS24Bit; + Bool LVDSSpatialDither; + Bool LVDSTemporalDither; + int LVDSGreyLevel; +}; + +enum rhdCrtcScaleType { + RHD_CRTC_SCALE_TYPE_NONE, /* top left */ + RHD_CRTC_SCALE_TYPE_CENTER, /* center of the actual mode */ + RHD_CRTC_SCALE_TYPE_SCALE, /* scaled to fullscreen */ + RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO /* scaled to fullscreen */ +}; + +#define RHD_CRTC_SCALE_TYPE_DEFAULT RHD_CRTC_SCALE_TYPE_SCALE_KEEP_ASPECT_RATIO + + +struct rhdCrtc { + int scrnIndex; + + char *Name; +#define RHD_CRTC_1 0 +#define RHD_CRTC_2 1 + int Id; /* for others to hook onto */ + + Bool Active; + + int Offset; /* Current offset */ + int bpp; + int Pitch; + int Width; + int Height; + int X, Y; /* Current frame */ + int MinX, MinY, MaxX, MaxY; /* Panning Area: Max != 0 if used */ + enum rhdCrtcScaleType ScaleType; + struct rhdPLL *PLL; /* Currently attached PLL: move to private */ + struct rhdLUT *LUT; /* Currently attached LUT: move to private */ + struct rhdCursor *Cursor; /* Fixed to the MODE engine */ + + DisplayModePtr CurrentMode; + DisplayModePtr Modes; /* Validated ones: Cycle through these */ + + DisplayModePtr ScaledToMode; /* usually a fixed mode from one of the monitors */ + + struct rhdCrtcFMTPrivate *FMTPriv; /* each CRTC subsystem may define this independently */ + void (*FMTModeSet)(struct rhdCrtc *Crtc, struct rhdFMTDither *FMTDither); + void (*FMTSave)(struct rhdCrtc *Crtc); + void (*FMTRestore)(struct rhdCrtc *Crtc); + void (*FMTDestroy) (struct rhdCrtc *Crtc); + + struct rhdCrtcFBPrivate *FBPriv; /* each CRTC subsystem may define this independently */ + ModeStatus (*FBValid) (struct rhdCrtc *Crtc, CARD16 Width, CARD16 Height, + int bpp, CARD32 Offset, CARD32 Size, CARD32 *pPitch); + void (*FBSet) (struct rhdCrtc *Crtc, CARD16 Pitch, CARD16 Width, + CARD16 Height, int bpp, CARD32 Offset); + void (*FBSave) (struct rhdCrtc *Crtc); + void (*FBRestore) (struct rhdCrtc *Crtc); + void (*FBDestroy) (struct rhdCrtc *Crtc); + + struct rhdCrtcModePrivate *ModePriv; /* each CRTC subsystem may define this independently */ + ModeStatus (*ModeValid) (struct rhdCrtc *Crtc, DisplayModePtr Mode); + void (*ModeSet) (struct rhdCrtc *Crtc, DisplayModePtr Mode); + void (*ModeSave) (struct rhdCrtc *Crtc); + void (*ModeRestore) (struct rhdCrtc *Crtc); + void (*ModeDestroy) (struct rhdCrtc *Crtc); + + struct rhdCrtcScalePrivate *ScalePriv; /* each CRTC subsystem may define this independently */ + ModeStatus (*ScaleValid) (struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type, DisplayModePtr Mode, DisplayModePtr ScaledToMode); + void (*ScaleSet) (struct rhdCrtc *Crtc, enum rhdCrtcScaleType Type, DisplayModePtr Mode, DisplayModePtr ScaledToMode); + void (*ScaleSave) (struct rhdCrtc *Crtc); + void (*ScaleRestore) (struct rhdCrtc *Crtc); + void (*ScaleDestroy) (struct rhdCrtc *Crtc); + + void (*FrameSet) (struct rhdCrtc *Crtc, CARD16 X, CARD16 Y); + + /* callback for pll setting lives here */ + /* callback for lut setting lives here */ + struct rhdCrtcLUTPrivate *LUTPriv; /* each CRTC subsystem may define this independently */ + void (*LUTSelect) (struct rhdCrtc *Crtc, struct rhdLUT *LUT); + void (*LUTSave) (struct rhdCrtc *Crtc); + void (*LUTRestore) (struct rhdCrtc *Crtc); + void (*LUTDestroy) (struct rhdCrtc *Crtc); + + void (*Power) (struct rhdCrtc *Crtc, int Power); + void (*Blank) (struct rhdCrtc *Crtc, Bool Blank); +}; + +Bool RHDCrtcsInit(RHDPtr rhdPtr); +void RHDAtomCrtcsInit(RHDPtr rhdPtr); +void RHDCrtcsDestroy(RHDPtr rhdPtr); +void RHDCrtcSave(struct rhdCrtc *Crtc); +void RHDCrtcRestore(struct rhdCrtc *Crtc); + +/* + * Calculate overscan values for scaler. + */ +struct rhdScalerOverscan +{ + int OverscanTop; + int OverscanBottom; + int OverscanLeft; + int OverscanRight; + enum rhdCrtcScaleType Type; +}; + +extern struct rhdScalerOverscan +rhdCalculateOverscan(DisplayModePtr Mode, + DisplayModePtr ScaledToMode, + enum rhdCrtcScaleType Type); + + +#endif /* _RHD_CRTC_H */ diff --git a/programs/system/drivers/rhd/rhd_dac.c b/programs/system/drivers/rhd/rhd_dac.c new file mode 100644 index 000000000..d1a4aabcb --- /dev/null +++ b/programs/system/drivers/rhd/rhd_dac.c @@ -0,0 +1,1099 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +# include +# include +#endif + +#include "rhd.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_crtc.h" +#include "rhd_regs.h" +#ifdef ATOM_BIOS +# include "rhd_atombios.h" +#endif + +#define REG_DACA_OFFSET 0 +#define RV620_REG_DACA_OFFSET 0 +#define REG_DACB_OFFSET 0x200 +#define RV620_REG_DACB_OFFSET 0x100 + +struct rhdDACPrivate { + Bool Stored; + + CARD32 Store_Powerdown; + CARD32 Store_Force_Output_Control; + CARD32 Store_Force_Data; + CARD32 Store_Source_Select; + CARD32 Store_Sync_Select; + CARD32 Store_Enable; + CARD32 Store_Control1; + CARD32 Store_Control2; + CARD32 Store_Tristate_Control; + CARD32 Store_Auto_Calib_Control; + CARD32 Store_Dac_Bgadj_Src; +}; + +/* ----------------------------------------------------------- */ + +/* + * + */ +static unsigned char +DACSense(struct rhdOutput *Output, CARD32 offset, Bool TV) +{ + CARD32 CompEnable, Control1, Control2, DetectControl, Enable; + CARD8 ret; + + CompEnable = RHDRegRead(Output, offset + DACA_COMPARATOR_ENABLE); + Control1 = RHDRegRead(Output, offset + DACA_CONTROL1); + Control2 = RHDRegRead(Output, offset + DACA_CONTROL2); + DetectControl = RHDRegRead(Output, offset + DACA_AUTODETECT_CONTROL); + Enable = RHDRegRead(Output, offset + DACA_ENABLE); + + RHDRegWrite(Output, offset + DACA_ENABLE, 1); + /* ack autodetect */ + RHDRegMask(Output, offset + DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01); + RHDRegMask(Output, offset + DACA_AUTODETECT_CONTROL, 0, 0x00000003); + RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x00000001); + RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x00ff0000); + + if (offset) { /* We can do TV on DACA but only DACB has mux for separate connector */ + if (TV) + RHDRegMask(Output, offset + DACA_CONTROL2, 0x00000100, 0x00000100); + else + RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x00000100); + } + RHDRegWrite(Output, offset + DACA_FORCE_DATA, 0); + RHDRegMask(Output, offset + DACA_CONTROL2, 0x00000001, 0x0000001); + + RHDRegMask(Output, offset + DACA_COMPARATOR_ENABLE, 0x00070000, 0x00070101); + RHDRegWrite(Output, offset + DACA_CONTROL1, 0x00050802); + RHDRegMask(Output, offset + DACA_POWERDOWN, 0, 0x00000001); /* Shut down Bandgap Voltage Reference Power */ + usleep(5); + + RHDRegMask(Output, offset + DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */ + + RHDRegWrite(Output, offset + DACA_FORCE_DATA, 0x1e6); /* 486 out of 1024 */ + usleep(200); + + RHDRegMask(Output, offset + DACA_POWERDOWN, 0x01010100, 0x01010100); /* Enable RGB */ + usleep(88); + + RHDRegMask(Output, offset + DACA_POWERDOWN, 0, 0x01010100); /* Shut down RGB */ + + RHDRegMask(Output, offset + DACA_COMPARATOR_ENABLE, 0x00000100, 0x00000100); + usleep(100); + + /* Get RGB detect values + * If only G is detected, we could have a monochrome monitor, + * but we don't bother with this at the moment. + */ + ret = (RHDRegRead(Output, offset + DACA_COMPARATOR_OUTPUT) & 0x0E) >> 1; + + RHDRegMask(Output, offset + DACA_COMPARATOR_ENABLE, CompEnable, 0x00FFFFFF); + RHDRegWrite(Output, offset + DACA_CONTROL1, Control1); + RHDRegMask(Output, offset + DACA_CONTROL2, Control2, 0x000001FF); + RHDRegMask(Output, offset + DACA_AUTODETECT_CONTROL, DetectControl, 0x000000FF); + RHDRegMask(Output, offset + DACA_ENABLE, Enable, 0x000000FF); + + RHDDebug(Output->scrnIndex, "%s: DAC: 0x0%1X\n", __func__, ret); + + return ret; +} + +/* + * + */ +static enum rhdSensedOutput +DACASense(struct rhdOutput *Output, struct rhdConnector *Connector) +{ + enum rhdConnectorType Type = Connector->Type; + RHDFUNC(Output); + + switch (Type) { + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + case RHD_CONNECTOR_VGA: + return (DACSense(Output, REG_DACA_OFFSET, FALSE) == 0x7) + ? RHD_SENSED_VGA + : RHD_SENSED_NONE; + default: + xf86DrvMsg(Output->scrnIndex, X_WARNING, + "%s: connector type %d is not supported on DACA.\n", + __func__, Type); + return RHD_SENSED_NONE; + } +} + +/* + * + */ +static enum rhdSensedOutput +DACBSense(struct rhdOutput *Output, struct rhdConnector *Connector) +{ + enum rhdConnectorType Type = Connector->Type; + RHDFUNC(Output); + + switch (Type) { + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + case RHD_CONNECTOR_VGA: + return (DACSense(Output, REG_DACB_OFFSET, FALSE) == 0x7) + ? RHD_SENSED_VGA + : RHD_SENSED_NONE; + case RHD_CONNECTOR_TV: + switch (DACSense(Output, REG_DACB_OFFSET, TRUE) & 0x7) { + case 0x7: + return RHD_SENSED_TV_COMPONENT; + case 0x6: + return RHD_SENSED_TV_SVIDEO; + case 0x1: + return RHD_SENSED_TV_COMPOSITE; + default: + return RHD_SENSED_NONE; + } + default: + xf86DrvMsg(Output->scrnIndex, X_WARNING, + "%s: connector type %d is not supported on DACB.\n", + __func__, Type); + return RHD_SENSED_NONE; + } +} + +enum outputType { + TvPAL = 0, + TvNTSC, + VGA, + TvCV, + typeLast = VGA +}; + +/* + * + */ +static void +DACGetElectrical(RHDPtr rhdPtr, enum outputType type, int dac, CARD8 *bandgap, CARD8 *whitefine) +{ +#ifdef ATOM_BIOS + enum _AtomBiosRequestID bg = 0, wf = 0; + AtomBiosArgRec atomBiosArg; +#endif + struct + { + CARD16 pciIdMin; + CARD16 pciIdMax; + CARD8 bandgap[2][4]; + CARD8 whitefine[2][4]; + } list[] = { + { 0x791E, 0x791F, + { { 0x07, 0x07, 0x07, 0x07 }, + { 0x07, 0x07, 0x07, 0x07 } }, + { { 0x09, 0x09, 0x04, 0x09 }, + { 0x09, 0x09, 0x04, 0x09 } }, + }, + { 0x793F, 0x7942, + { { 0x09, 0x09, 0x09, 0x09 }, + { 0x09, 0x09, 0x09, 0x09 } }, + { { 0x0a, 0x0a, 0x08, 0x0a }, + { 0x0a, 0x0a, 0x08, 0x0a } }, + }, + { 0x9500, 0x9519, + { { 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x20, 0x00 }, + { 0x25, 0x25, 0x26, 0x26 } }, + }, + { 0, 0, + { { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } }, + { { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } } + } + }; + + *bandgap = *whitefine = 0; + +#ifdef ATOM_BIOS + switch (type) { + case TvPAL: + bg = ATOM_DAC2_PAL_BG_ADJ; + wf = ATOM_DAC2_PAL_DAC_ADJ; + break; + case TvNTSC: + bg = ATOM_DAC2_NTSC_BG_ADJ; + wf = ATOM_DAC2_NTSC_DAC_ADJ; + break; + case TvCV: + bg = ATOM_DAC2_CV_BG_ADJ; + wf = ATOM_DAC2_CV_DAC_ADJ; + break; + case VGA: + switch (dac) { + case 0: + bg = ATOM_DAC1_BG_ADJ; + wf = ATOM_DAC1_DAC_ADJ; + break; + default: + bg = ATOM_DAC2_CRTC2_BG_ADJ; + wf = ATOM_DAC2_CRTC2_DAC_ADJ; + break; + } + break; + } + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, bg, &atomBiosArg) + == ATOM_SUCCESS) { + *bandgap = atomBiosArg.val; + RHDDebug(rhdPtr->scrnIndex, "%s: BandGap found in CompassionateData.\n",__func__); + } + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, wf, &atomBiosArg) + == ATOM_SUCCESS) { + *whitefine = atomBiosArg.val; + RHDDebug(rhdPtr->scrnIndex, "%s: WhiteFine found in CompassionateData.\n",__func__); + } + if (*whitefine == 0) { + CARD8 w_f = 0, b_g = 0; + + if (atomBiosArg.val = 0x18, + RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + ATOMBIOS_GET_CODE_DATA_TABLE, + &atomBiosArg) == ATOM_SUCCESS) { + struct AtomDacCodeTableData *data + = (struct AtomDacCodeTableData *)atomBiosArg.CommandDataTable.loc; + if (atomBiosArg.CommandDataTable.size + < (sizeof (struct AtomDacCodeTableData) >> (dac ? 0 : 1))) { /* IGPs only have 1 DAC -> table_size / 2 */ + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "Code table data size: %i doesn't match expected size: %u\n", + atomBiosArg.CommandDataTable.size, + (unsigned int) sizeof (struct AtomDacCodeTableData)); + return; + } + RHDDebug(rhdPtr->scrnIndex, "%s: WhiteFine found in Code Table.\n",__func__); + switch (type) { + case TvPAL: + w_f = dac ? data->DAC2PALWhiteFine : data->DAC1PALWhiteFine; + b_g = dac ? data->DAC2PALBandGap : data->DAC1PALBandGap; + break; + case TvNTSC: + w_f = dac ? data->DAC2NTSCWhiteFine : data->DAC1NTSCWhiteFine; + b_g = dac ? data->DAC2NTSCBandGap : data->DAC1NTSCBandGap; + break; + case TvCV: + w_f = dac ? data->DAC2CVWhiteFine : data->DAC1CVWhiteFine; + b_g = dac ? data->DAC2CVBandGap : data->DAC1CVBandGap; + break; + case VGA: + w_f = dac ? data->DAC2VGAWhiteFine : data->DAC1VGAWhiteFine; + b_g = dac ? data->DAC2VGABandGap : data->DAC1VGABandGap; + break; + } + *whitefine = w_f; + if (rhdPtr->ChipSet >= RHD_RV770) /* Dunno why this is broken on older ASICs */ + *bandgap = b_g; + } + } +#endif + if (*bandgap == 0 || *whitefine == 0) { + int i = 0; + while (list[i].pciIdMin != 0) { + if (list[i].pciIdMin <= rhdPtr->PciDeviceID + && list[i].pciIdMax >= rhdPtr->PciDeviceID) { +#if 0 + ErrorF(">> %x %x %x -- %x %x\n",list[i].pciIdMin, + rhdPtr->PciDeviceID,list[i].pciIdMax, + list[i].bandgap[dac][type],list[i].whitefine[dac][type]); + ErrorF(">> %i %i\n",dac,type); +#endif + if (*bandgap == 0) *bandgap = list[i].bandgap[dac][type]; + if (*whitefine == 0) *whitefine = list[i].whitefine[dac][type]; + break; + } + i++; + } + if (list[i].pciIdMin != 0) + RHDDebug(rhdPtr->scrnIndex, "%s: BandGap and WhiteFine found in Table.\n",__func__); + } + RHDDebug(rhdPtr->scrnIndex, "%s: DAC[%i] BandGap: 0x%2.2x WhiteFine: 0x%2.2x\n", + __func__, dac, *bandgap, *whitefine); +} + +/* + * + */ +static inline void +DACSet(struct rhdOutput *Output, CARD16 offset) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + CARD8 Standard, WhiteFine, Bandgap; + Bool TV; + CARD32 Mask = 0; + + switch (Output->SensedType) { + case RHD_SENSED_TV_SVIDEO: + case RHD_SENSED_TV_COMPOSITE: + /* might want to selectively enable lines based on type */ + TV = TRUE; + + switch (rhdPtr->tvMode) { + case RHD_TV_NTSC: + case RHD_TV_NTSCJ: + DACGetElectrical(rhdPtr, TvNTSC, offset ? 1 : 0, &Bandgap, &WhiteFine); + Standard = 1; /* NTSC */ + break; + case RHD_TV_PAL: + case RHD_TV_PALN: + case RHD_TV_PALCN: + case RHD_TV_PAL60: + default: + DACGetElectrical(rhdPtr, TvPAL, offset ? 1 : 0, &Bandgap, &WhiteFine); + Standard = 0; /* PAL */ + break; + } + break; + + case RHD_SENSED_TV_COMPONENT: + TV = TRUE; + DACGetElectrical(rhdPtr, TvCV, offset ? 1 : 0, &Bandgap, &WhiteFine); + Standard = 3; /* HDTV */ + break; + + case RHD_SENSED_VGA: + default: + TV = FALSE; + DACGetElectrical(rhdPtr, VGA, offset ? 1 : 0, &Bandgap, &WhiteFine); + Standard = 2; /* VGA */ + break; + } + if (Bandgap) Mask |= 0xFF << 16; + if (WhiteFine) Mask |= 0xFF << 8; + + RHDRegMask(Output, offset + DACA_CONTROL1, Standard, 0x000000FF); + /* white level fine adjust */ + RHDRegMask(Output, offset + DACA_CONTROL1, (Bandgap << 16) | (WhiteFine << 8), Mask); + + if (TV) { + /* tv enable */ + if (offset) /* TV mux only available on DACB */ + RHDRegMask(Output, offset + DACA_CONTROL2, 0x00000100, 0x0000FF00); + /* select tv encoder */ + RHDRegMask(Output, offset + DACA_SOURCE_SELECT, 0x00000002, 0x00000003); + } else { + if (offset) /* TV mux only available on DACB */ + RHDRegMask(Output, offset + DACA_CONTROL2, 0, 0x0000FF00); + /* select a crtc */ + RHDRegMask(Output, offset + DACA_SOURCE_SELECT, Output->Crtc->Id & 0x01, 0x00000003); + } + + RHDRegMask(Output, offset + DACA_FORCE_OUTPUT_CNTL, 0x00000701, 0x00000701); + RHDRegMask(Output, offset + DACA_FORCE_DATA, 0, 0x0000FFFF); +} + +/* + * + */ +static void +DACASet(struct rhdOutput *Output, DisplayModePtr unused) +{ + RHDFUNC(Output); + + DACSet(Output, REG_DACA_OFFSET); +} + +/* + * + */ +static void +DACBSet(struct rhdOutput *Output, DisplayModePtr unused) +{ + RHDFUNC(Output); + + DACSet(Output, REG_DACB_OFFSET); +} + +/* + * + */ +static inline void +DACPower(struct rhdOutput *Output, CARD16 offset, int Power) +{ + CARD32 powerdown; + + RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, + rhdPowerString[Power]); + + switch (Power) { + case RHD_POWER_ON: + switch (Output->SensedType) { + case RHD_SENSED_TV_SVIDEO: + powerdown = 0 /* 0x100 */; + break; + case RHD_SENSED_TV_COMPOSITE: + powerdown = 0 /* 0x1010000 */; + break; + case RHD_SENSED_TV_COMPONENT: + powerdown = 0; + break; + case RHD_SENSED_VGA: + default: + powerdown = 0; + break; + } + RHDRegWrite(Output, offset + DACA_ENABLE, 1); + RHDRegWrite(Output, offset + DACA_POWERDOWN, 0); + usleep (14); + RHDRegMask(Output, offset + DACA_POWERDOWN, powerdown, 0xFFFFFF00); + usleep(2); + RHDRegWrite(Output, offset + DACA_FORCE_OUTPUT_CNTL, 0); + RHDRegMask(Output, offset + DACA_SYNC_SELECT, 0, 0x00000101); + RHDRegWrite(Output, offset + DACA_SYNC_TRISTATE_CONTROL, 0); + return; + case RHD_POWER_RESET: /* don't bother */ + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(Output, offset + DACA_FORCE_DATA, 0, 0x0000FFFF); + RHDRegMask(Output, offset + DACA_FORCE_OUTPUT_CNTL, 0x0000701, 0x0000701); + RHDRegWrite(Output, offset + DACA_POWERDOWN, 0x01010100); + RHDRegWrite(Output, offset + DACA_POWERDOWN, 0x01010101); + RHDRegWrite(Output, offset + DACA_ENABLE, 0); + RHDRegWrite(Output, offset + DACA_ENABLE, 0); + return; + } +} + +/* + * + */ +static void +DACAPower(struct rhdOutput *Output, int Power) +{ + RHDFUNC(Output); + + DACPower(Output, REG_DACA_OFFSET, Power); +} + +/* + * + */ +static void +DACBPower(struct rhdOutput *Output, int Power) +{ + RHDFUNC(Output); + + DACPower(Output, REG_DACB_OFFSET, Power); +} + +/* + * + */ +static inline void +DACSave(struct rhdOutput *Output, CARD16 offset) +{ + struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private; + + Private->Store_Powerdown = RHDRegRead(Output, offset + DACA_POWERDOWN); + Private->Store_Force_Output_Control = RHDRegRead(Output, offset + DACA_FORCE_OUTPUT_CNTL); + Private->Store_Force_Data = RHDRegRead(Output, offset + DACA_FORCE_DATA); + Private->Store_Source_Select = RHDRegRead(Output, offset + DACA_SOURCE_SELECT); + Private->Store_Sync_Select = RHDRegRead(Output, offset + DACA_SYNC_SELECT); + Private->Store_Enable = RHDRegRead(Output, offset + DACA_ENABLE); + Private->Store_Control1 = RHDRegRead(Output, offset + DACA_CONTROL1); + Private->Store_Control2 = RHDRegRead(Output, offset + DACA_CONTROL2); + Private->Store_Tristate_Control = RHDRegRead(Output, offset + DACA_SYNC_TRISTATE_CONTROL); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +DACASave(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + DACSave(Output, REG_DACA_OFFSET); +} + +/* + * + */ +static void +DACBSave(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + DACSave(Output, REG_DACB_OFFSET); +} + +/* + * + */ +static inline void +DACRestore(struct rhdOutput *Output, CARD16 offset) +{ + struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private; + + RHDRegWrite(Output, offset + DACA_POWERDOWN, Private->Store_Powerdown); + RHDRegWrite(Output, offset + DACA_FORCE_OUTPUT_CNTL, Private->Store_Force_Output_Control); + RHDRegWrite(Output, offset + DACA_FORCE_DATA, Private->Store_Force_Data); + RHDRegWrite(Output, offset + DACA_SOURCE_SELECT, Private->Store_Source_Select); + RHDRegWrite(Output, offset + DACA_SYNC_SELECT, Private->Store_Sync_Select); + RHDRegWrite(Output, offset + DACA_ENABLE, Private->Store_Enable); + RHDRegWrite(Output, offset + DACA_CONTROL1, Private->Store_Control1); + RHDRegWrite(Output, offset + DACA_CONTROL2, Private->Store_Control2); + RHDRegWrite(Output, offset + DACA_SYNC_TRISTATE_CONTROL, Private->Store_Tristate_Control); +} + +/* + * + */ +static void +DACARestore(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + if (!((struct rhdDACPrivate *) Output->Private)->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + DACRestore(Output, REG_DACA_OFFSET); +} + +/* + * + */ +static void +DACBRestore(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + if (!((struct rhdDACPrivate *) Output->Private)->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + DACRestore(Output, REG_DACB_OFFSET); +} + +/* ----------------------------------------------------------- */ + +/* + * + */ +static CARD32 +DACSenseRV620(struct rhdOutput *Output, CARD32 offset, Bool TV) +{ + CARD32 ret; + CARD32 DetectControl, AutodetectIntCtl, ForceData, + Control1, Control2, CompEnable; + + RHDFUNC(Output); + + Control1 = RHDRegRead(Output, offset + RV620_DACA_MACRO_CNTL); /* 7ef4 */ + Control2 = RHDRegRead(Output, offset + RV620_DACA_CONTROL2); /* 7058 */ + ForceData = RHDRegRead(Output, offset + RV620_DACA_FORCE_DATA); + AutodetectIntCtl = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL); + DetectControl = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_CONTROL); + CompEnable = RHDRegRead(Output, offset + RV620_DACA_COMPARATOR_ENABLE); + + if (offset) { /* We can do TV on DACA but only DACB has mux for separate connector */ + if (TV) + RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0x100, 0xff00); + else + RHDRegMask(Output, offset + RV620_DACA_CONTROL2, 0x00, 0xff00); + } + RHDRegMask(Output, offset + RV620_DACA_FORCE_DATA, 0x18, 0xffff); + RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL, 0x01, 0x01); + RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_CONTROL, 0x00, 0xff); + RHDRegMask(Output, offset + RV620_DACA_MACRO_CNTL, + (offset > 0) ? 0x2502 : 0x2002, 0xffff); + /* enable comparators for R/G/B, disable DDET and SDET reference */ + RHDRegMask(Output, offset + RV620_DACA_COMPARATOR_ENABLE, 0x70000, 0x070101); + RHDRegMask(Output, offset + RV620_DACA_AUTODETECT_CONTROL, 0x01, 0xff); + usleep(32); + ret = RHDRegRead(Output, offset + RV620_DACA_AUTODETECT_STATUS); + RHDRegWrite(Output, offset + RV620_DACA_AUTODETECT_CONTROL, DetectControl); + RHDRegWrite(Output, offset + RV620_DACA_MACRO_CNTL, Control1); + RHDRegWrite(Output, offset + RV620_DACA_CONTROL2, Control2); + RHDRegWrite(Output, offset + RV620_DACA_FORCE_DATA, ForceData); + RHDRegWrite(Output, offset + RV620_DACA_AUTODETECT_INT_CONTROL, AutodetectIntCtl); +#ifdef DEBUG + RHDDebug(Output->scrnIndex, "DAC%i: ret = 0x%x %s\n",offset ? "A" : "B", + ret,TV ? "TV" : ""); +#endif + return ret; +} + +/* + * + */ +static enum rhdSensedOutput +DACASenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector) +{ + enum rhdConnectorType Type = Connector->Type; + RHDFUNC(Output); + + switch (Type) { + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + case RHD_CONNECTOR_VGA: + return (DACSenseRV620(Output, RV620_REG_DACA_OFFSET, FALSE) + & 0x1010100) ? RHD_SENSED_VGA : RHD_SENSED_NONE; + case RHD_CONNECTOR_TV: + switch (DACSenseRV620(Output, RV620_REG_DACA_OFFSET, TRUE) + & 0x1010100) { + case 0x1010100: + return RHD_SENSED_NONE; /* on DAC A we cannot distinguish VGA and CV */ + case 0x10100: + return RHD_SENSED_TV_SVIDEO; + case 0x1000000: + return RHD_SENSED_TV_COMPOSITE; + default: + return RHD_SENSED_NONE; + } + default: + xf86DrvMsg(Output->scrnIndex, X_WARNING, + "%s: connector type %d is not supported.\n", + __func__, Type); + return RHD_SENSED_NONE; + } +} + +/* + * + */ +static enum rhdSensedOutput +DACBSenseRV620(struct rhdOutput *Output, struct rhdConnector *Connector) +{ + enum rhdConnectorType Type = Connector->Type; + RHDFUNC(Output); + + switch (Type) { + case RHD_CONNECTOR_DVI: + case RHD_CONNECTOR_DVI_SINGLE: + case RHD_CONNECTOR_VGA: + return (DACSenseRV620(Output, RV620_REG_DACB_OFFSET, FALSE) + & 0x1010100) ? RHD_SENSED_VGA : RHD_SENSED_NONE; + case RHD_CONNECTOR_TV: + switch (DACSenseRV620(Output, RV620_REG_DACB_OFFSET, TRUE) + & 0x1010100) { + case 0x1000000: + return RHD_SENSED_TV_COMPONENT; + case 0x1010100: + return RHD_SENSED_TV_SVIDEO; + case 0x10100: + return RHD_SENSED_TV_COMPOSITE; + default: + return RHD_SENSED_NONE; + } + default: + xf86DrvMsg(Output->scrnIndex, X_WARNING, + "%s: connector type %d is not supported.\n", + __func__, Type); + return RHD_SENSED_NONE; + } +} + +/* + * + */ +static inline void +DACSetRV620(struct rhdOutput *Output, CARD16 offset) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + CARD32 Source; + CARD32 Mode; + CARD32 TV; + CARD8 WhiteFine, Bandgap; + CARD32 Mask = 0; + + switch (Output->SensedType) { + case RHD_SENSED_TV_SVIDEO: + case RHD_SENSED_TV_COMPOSITE: + TV = 0x1; + Source = 0x2; /* tv encoder */ + switch (rhdPtr->tvMode) { + case RHD_TV_NTSC: + case RHD_TV_NTSCJ: + DACGetElectrical(rhdPtr, TvNTSC, offset ? 1 : 0, &Bandgap, &WhiteFine); + Mode = 1; + break; + case RHD_TV_PAL: + case RHD_TV_PALN: + case RHD_TV_PALCN: + case RHD_TV_PAL60: + default: + DACGetElectrical(rhdPtr, TvPAL, offset ? 1 : 0, &Bandgap, &WhiteFine); + Mode = 0; + break; + } + break; + case RHD_SENSED_TV_COMPONENT: + DACGetElectrical(rhdPtr, TvCV, offset ? 1 : 0, &Bandgap, &WhiteFine); + Mode = 3; /* HDTV */ + TV = 0x1; /* tv on?? */ + Source = 0x2; /* tv encoder ?? */ + break; + case RHD_SENSED_VGA: + default: + DACGetElectrical(rhdPtr, VGA, offset ? 1 : 0, &Bandgap, &WhiteFine); + Mode = 2; + TV = 0; + Source = Output->Crtc->Id; + break; + } + if (Bandgap) Mask |= 0xFF << 16; + if (WhiteFine) Mask |= 0xFF << 8; + + RHDRegMask(Output, offset + RV620_DACA_MACRO_CNTL, Mode, 0xFF); /* no fine control yet */ + RHDRegMask(Output, offset + RV620_DACA_SOURCE_SELECT, Source, 0x00000003); + if (offset) /* TV mux only present on DACB */ + RHDRegMask(Output, offset + RV620_DACA_CONTROL2, TV << 8, 0x0100); /* tv enable/disable */ + /* use fine control from white_fine control register */ + RHDRegMask(Output, offset + RV620_DACA_AUTO_CALIB_CONTROL, 0x0, 0x4); + RHDRegMask(Output, offset + RV620_DACA_BGADJ_SRC, 0x0, 0x30); + RHDRegMask(Output, offset + RV620_DACA_MACRO_CNTL, (Bandgap << 16) | (WhiteFine << 8), Mask); + /* Reset the FMT register on CRTC leading to this output */ + Output->Crtc->FMTModeSet(Output->Crtc, NULL); +} + +/* + * + */ +static void +DACASetRV620(struct rhdOutput *Output, DisplayModePtr unused) +{ + RHDFUNC(Output); + + DACSetRV620(Output, RV620_REG_DACA_OFFSET); +} + +/* + * + */ +static void +DACBSetRV620(struct rhdOutput *Output, DisplayModePtr unused) +{ + RHDFUNC(Output); + + DACSetRV620(Output, RV620_REG_DACB_OFFSET); +} + +/* + * + */ +static inline void +DACPowerRV620(struct rhdOutput *Output, CARD16 offset, int Power) +{ + CARD32 powerdown; + + switch (Power) { + case RHD_POWER_ON: + switch (Output->SensedType) { + case RHD_SENSED_TV_SVIDEO: + powerdown = 0 /* 0x100 */; + break; + case RHD_SENSED_TV_COMPOSITE: + powerdown = 0 /* 0x1010000 */; + break; + case RHD_SENSED_TV_COMPONENT: + powerdown = 0; + break; + case RHD_SENSED_VGA: + default: + powerdown = 0; + break; + } + + if (!(RHDRegRead(Output, offset + RV620_DACA_ENABLE) & 0x01)) + RHDRegMask(Output, offset + RV620_DACA_ENABLE, 0x1, 0xff); + RHDRegMask(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, 0x01, 0x01); + RHDRegMask(Output, offset + RV620_DACA_POWERDOWN, 0x0, 0xff); + usleep (0x14); + RHDRegMask(Output, offset + RV620_DACA_POWERDOWN, powerdown, 0xffffff00); + usleep(2); + RHDRegMask(Output, offset + RV620_DACA_FORCE_DATA, 0, 0x0000ffff); + RHDRegWrite(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, 0x0); + RHDRegWrite(Output, offset + RV620_DACA_SYNC_TRISTATE_CONTROL, 0); + return; + case RHD_POWER_RESET: /* don't bother */ + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegWrite(Output, offset + RV620_DACA_POWERDOWN, 0x01010100); + RHDRegWrite(Output, offset + RV620_DACA_POWERDOWN, 0x01010101); + RHDRegWrite(Output, offset + RV620_DACA_ENABLE, 0); + RHDRegMask(Output, offset + RV620_DACA_FORCE_DATA, 0, 0xffff); + RHDRegMask(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, 0x701, 0x701); + return; + } +} + +/* + * + */ +static void +DACAPowerRV620(struct rhdOutput *Output, int Power) +{ + RHDFUNC(Output); + + DACPowerRV620(Output, RV620_REG_DACA_OFFSET, Power); +} + +/* + * + */ +static void +DACBPowerRV620(struct rhdOutput *Output, int Power) +{ + RHDFUNC(Output); + + DACPowerRV620(Output, RV620_REG_DACB_OFFSET, Power); +} + +/* + * + */ +static inline void +DACSaveRV620(struct rhdOutput *Output, CARD16 offset) +{ + struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private; + + Private->Store_Powerdown = RHDRegRead(Output, offset + RV620_DACA_POWERDOWN); + Private->Store_Force_Output_Control = RHDRegRead(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL); + Private->Store_Force_Data = RHDRegRead(Output, offset + RV620_DACA_FORCE_DATA); + Private->Store_Source_Select = RHDRegRead(Output, offset + RV620_DACA_SOURCE_SELECT); + Private->Store_Enable = RHDRegRead(Output, offset + RV620_DACA_ENABLE); + Private->Store_Control1 = RHDRegRead(Output, offset + RV620_DACA_MACRO_CNTL); + Private->Store_Control2 = RHDRegRead(Output, offset + RV620_DACA_CONTROL2); + Private->Store_Tristate_Control = RHDRegRead(Output, offset + RV620_DACA_SYNC_TRISTATE_CONTROL); + Private->Store_Auto_Calib_Control = RHDRegRead(Output, offset + RV620_DACA_AUTO_CALIB_CONTROL); + Private->Store_Dac_Bgadj_Src = RHDRegRead(Output, offset + RV620_DACA_BGADJ_SRC); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +DACASaveRV620(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + DACSaveRV620(Output, RV620_REG_DACA_OFFSET); +} + +/* + * + */ +static void +DACBSaveRV620(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + DACSaveRV620(Output, RV620_REG_DACB_OFFSET); +} + +/* + * + */ +static inline void +DACRestoreRV620(struct rhdOutput *Output, CARD16 offset) +{ + struct rhdDACPrivate *Private = (struct rhdDACPrivate *) Output->Private; + + RHDRegWrite(Output, offset + RV620_DACA_BGADJ_SRC, Private->Store_Dac_Bgadj_Src); + RHDRegWrite(Output, offset + RV620_DACA_AUTO_CALIB_CONTROL, Private->Store_Auto_Calib_Control); + RHDRegWrite(Output, offset + RV620_DACA_POWERDOWN, Private->Store_Powerdown); + RHDRegWrite(Output, offset + RV620_DACA_FORCE_OUTPUT_CNTL, Private->Store_Force_Output_Control); + RHDRegWrite(Output, offset + RV620_DACA_FORCE_DATA, Private->Store_Force_Data); + RHDRegWrite(Output, offset + RV620_DACA_SOURCE_SELECT, Private->Store_Source_Select); + RHDRegWrite(Output, offset + RV620_DACA_ENABLE, Private->Store_Enable); + RHDRegWrite(Output, offset + RV620_DACA_MACRO_CNTL, Private->Store_Control1); + RHDRegWrite(Output, offset + RV620_DACA_CONTROL2, Private->Store_Control2); + RHDRegWrite(Output, offset + RV620_DACA_SYNC_TRISTATE_CONTROL, Private->Store_Tristate_Control); + +} + +/* + * + */ +static void +DACARestoreRV620(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + if (!((struct rhdDACPrivate *) Output->Private)->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + DACRestoreRV620(Output, RV620_REG_DACA_OFFSET); +} + +/* + * + */ +static void +DACBRestoreRV620(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + if (!((struct rhdDACPrivate *) Output->Private)->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + DACRestoreRV620(Output, RV620_REG_DACB_OFFSET); +} + +/* ----------------------------------------------------------- */ + +/* + * + */ +static ModeStatus +DACModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Clock < 20000) + return MODE_CLOCK_LOW; + + if (Mode->Clock > 400000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/* + * + */ +static void +DACDestroy(struct rhdOutput *Output) +{ + RHDFUNC(Output); + + if (!Output->Private) + return; + + xfree(Output->Private); + Output->Private = NULL; +} + +/* + * + */ +struct rhdOutput * +RHDDACAInit(RHDPtr rhdPtr) +{ + struct rhdOutput *Output; + struct rhdDACPrivate *Private; + + RHDFUNC(rhdPtr); + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + + Output->scrnIndex = rhdPtr->scrnIndex; + Output->Name = "DAC A"; + Output->Id = RHD_OUTPUT_DACA; + + if (rhdPtr->ChipSet < RHD_RV620) { + Output->Sense = DACASense; + Output->Mode = DACASet; + Output->Power = DACAPower; + Output->Save = DACASave; + Output->Restore = DACARestore; + } else { + Output->Sense = DACASenseRV620; + Output->Mode = DACASetRV620; + Output->Power = DACAPowerRV620; + Output->Save = DACASaveRV620; + Output->Restore = DACARestoreRV620; + } + Output->ModeValid = DACModeValid; + Output->Destroy = DACDestroy; + Private = xnfcalloc(sizeof(struct rhdDACPrivate), 1); + Output->Private = Private; + + return Output; +} + +/* + * + */ +struct rhdOutput * +RHDDACBInit(RHDPtr rhdPtr) +{ + struct rhdOutput *Output; + struct rhdDACPrivate *Private; + + RHDFUNC(rhdPtr); + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + + Output->scrnIndex = rhdPtr->scrnIndex; + Output->Name = "DAC B"; + Output->Id = RHD_OUTPUT_DACB; + + if (rhdPtr->ChipSet < RHD_RV620) { + Output->Sense = DACBSense; + Output->Mode = DACBSet; + Output->Power = DACBPower; + Output->Save = DACBSave; + Output->Restore = DACBRestore; + } else { + Output->Sense = DACBSenseRV620; + Output->Mode = DACBSetRV620; + Output->Power = DACBPowerRV620; + Output->Save = DACBSaveRV620; + Output->Restore = DACBRestoreRV620; + } + Output->ModeValid = DACModeValid; + Output->Destroy = DACDestroy; + + Private = xnfcalloc(sizeof(struct rhdDACPrivate), 1); + Output->Private = Private; + + return Output; +} diff --git a/programs/system/drivers/rhd/rhd_ddia.c b/programs/system/drivers/rhd/rhd_ddia.c new file mode 100644 index 000000000..250c75618 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_ddia.c @@ -0,0 +1,389 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_regs.h" +#ifdef ATOM_BIOS +#include "rhd_atombios.h" +#endif + +struct DDIAPrivate +{ + Bool RunDualLink; + CARD32 PcieCfgReg7; + CARD32 CapabilityFlag; + + Bool Stored; + + CARD32 DdiaPathControl; + CARD32 DdiaCntl; + CARD32 DdiaDcbalancerControl; + CARD32 DdiaPcieLinkControl2; + CARD32 DdiaBitDepthControl; +}; + +/* + * + */ +static ModeStatus +DDIAModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + if (Mode->Clock < 25000) + return MODE_CLOCK_LOW; + + if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) { + if (Mode->Clock > 165000) + return MODE_CLOCK_HIGH; + } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) { + if (Mode->Clock > 330000) /* could go higher still */ + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + +/* + * + */ +static void +DDIAMode(struct rhdOutput *Output, DisplayModePtr Mode) +{ + struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private; + CARD32 mux0, mux1, mux2, mux3; + Bool LaneReversal; + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + if (Mode->SynthClock >= 165000) + Private->RunDualLink = TRUE; + else + Private->RunDualLink = FALSE; + + /* reset on - will be enabled at POWER_ON */ + RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, RS69_DDIA_PIXVLD_RESET); + /* RGB 4:4:4 */ + RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_PIXEL_ENCODING); + /* TMDS_AC */ + RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, + 2 << RS69_DDIA_PATH_SELECT_SHIFT, + 0x3 << RS69_DDIA_PATH_SELECT_SHIFT); + /* dual link */ + RHDRegMask(Output, RS69_DDIA_CNTL, Private->RunDualLink ? + RS69_DDIA_DUAL_LINK_ENABLE : 0, RS69_DDIA_DUAL_LINK_ENABLE); + RHDRegMask(Output, RS69_DDIA_DCBALANCER_CONTROL, + RS69_DDIA_DCBALANCER_EN, + RS69_DDIA_SYNC_DCBAL_EN_MASK | RS69_DDIA_DCBALANCER_EN); + + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x80); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x100); + + mux0 = Private->PcieCfgReg7 & 0x3; + mux1 = (Private->PcieCfgReg7 >> 2) & 0x3; + mux2 = (Private->PcieCfgReg7 >> 4) & 0x3; + mux3 = (Private->PcieCfgReg7 >> 6) & 0x3; + + RHDRegMask(Output, RS69_DDIA_PCIE_LINK_CONTROL2, + (mux0 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL0) + | (mux1 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL1) + | (mux2 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL2) + | (mux3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL3), + (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL0) + | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL1) + | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL2) + | (3 << RS69_DDIA_PCIE_OUTPUT_MUX_SEL3) + ); + LaneReversal = Private->PcieCfgReg7 & (0x1 << 10); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x3); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x2, 0x2); + + RHDRegMask(Output, RS69_DDIA_PCIE_LINK_CONTROL3, + LaneReversal ? RS69_DDIA_PCIE_MIRROR_EN : 0, + RS69_DDIA_PCIE_MIRROR_EN); + + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x70, 0x70); + + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x10); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x60); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0, 0x4000000); + + switch (rhdPtr->PciDeviceID) { + case 0x791E: + if (Mode->SynthClock <= 25000) { + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x2780, 0x3f80); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x039f0000, 0x03000000 | 0x039f0000); + } else if (Mode->SynthClock <= 60000) { + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x2780, 0x3f80); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x024f0000, 0x03000000 | 0x024f0000); + } else { + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0980, 0x3f80); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x01270000, 0x03000000 | 0x01270000); + } + break; + case 0x791F: + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0980, 0x3f80); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x4000, 0xc000); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x00ac0000, 0x03000000 | 0x00ac0000); + if (Private->CapabilityFlag & 0x10) { + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xc000); + if (Mode->SynthClock <= 6500) + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x01ac0000, 0x03ff0000); + else + RHDRegMaskD(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x01110000, 0x03ff0000); + } + break; + } + usleep (1); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x04000000, 0x04000000); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x60, 0x60); + usleep(30); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x01, 0x01); + usleep(1); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x02, 0x02); + usleep(1); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x04, 0x04); + usleep(1); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x08, 0x08); + usleep(1); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x10, 0x10); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL1, 0x0, 0xf); + + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0180, 0x0180); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x600, 0x600); + usleep(5); + RHDRegMask(Output, RS69_DDIA_PCIE_PHY_CONTROL2, 0x0, 0x600); + + /* hw reset will be turned off at POWER_ON */ + + /* select crtc source, sync_a, no stereosync */ + RHDRegMask(Output, RS69_DDIA_SOURCE_SELECT, Output->Crtc->Id, + RS69_DDIA_SOURCE_SELECT_BIT + | RS69_DDIA_SYNC_SELECT + | RS69_DDIA_STEREOSYNC_SELECT); +} + +/* + * + */ +static void +DDIAPower(struct rhdOutput *Output, int Power) +{ + RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, + rhdPowerString[Power]); + + switch (Power) { + case RHD_POWER_ON: + RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, + RS69_DDIA_PIXVLD_RESET); + RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, 0); + RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL, + RS69_DDIA_TEMPORAL_DITHER_RESET, RS69_DDIA_TEMPORAL_DITHER_RESET); + RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL, + 0, RS69_DDIA_TEMPORAL_DITHER_RESET); + RHDRegMask(Output, RS69_DDIA_CNTL, RS69_DDIA_ENABLE, RS69_DDIA_ENABLE); + RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, 0, RS69_DDIA_PIXVLD_RESET); + return; + case RHD_POWER_RESET: + RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE); + return; + case RHD_POWER_SHUTDOWN: + RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL, + RS69_DDIA_TEMPORAL_DITHER_RESET, RS69_DDIA_TEMPORAL_DITHER_RESET); + RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL, + 0, RS69_DDIA_TEMPORAL_DITHER_RESET); + RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL, + 0, + RS69_DDIA_TRUNCATE_EN + | RS69_DDIA_TRUNCATE_DEPTH + | RS69_DDIA_SPATIAL_DITHER_EN + | RS69_DDIA_SPATIAL_DITHER_DEPTH); + RHDRegMask(Output, RS69_DDIA_BIT_DEPTH_CONTROL, + 0, + RS69_DDIA_TEMPORAL_DITHER_EN + | RS69_DDIA_TEMPORAL_DITHER_EN + | RS69_DDIA_TEMPORAL_DITHER_DEPTH + | RS69_DDIA_TEMPORAL_LEVEL); + RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE); + return; + default: + return; + } +} + +/* + * + */ +static void +DDIASave(struct rhdOutput *Output) +{ + struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private; + + RHDFUNC(Output); + + Private->DdiaPathControl = RHDRegRead(Output, RS69_DDIA_PATH_CONTROL); + Private->DdiaCntl = RHDRegRead(Output, RS69_DDIA_CNTL); + Private->DdiaDcbalancerControl = RHDRegRead(Output, RS69_DDIA_DCBALANCER_CONTROL); + Private->DdiaPcieLinkControl2 = RHDRegRead(Output, RS69_DDIA_PCIE_LINK_CONTROL2); + Private->DdiaBitDepthControl = RHDRegRead(Output, RS69_DDIA_BIT_DEPTH_CONTROL); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +DDIARestore(struct rhdOutput *Output) +{ + struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private; + RHDFUNC(Output); + + if (!Private->Stored) + return; + + /* disalbe */ + RHDRegMask(Output, RS69_DDIA_CNTL, 0, RS69_DDIA_ENABLE); + /* reset on */ + RHDRegMask(Output, RS69_DDIA_PATH_CONTROL, RS69_DDIA_PIXVLD_RESET, RS69_DDIA_PIXVLD_RESET); + RHDRegWrite(Output, RS69_DDIA_PATH_CONTROL, Private->DdiaPathControl | RS69_DDIA_PIXVLD_RESET); + + RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl); + /* temporal dither reset on */ + RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl + | RS69_DDIA_TEMPORAL_DITHER_RESET); + /* temporal dither reset off */ + RHDRegWrite(Output, RS69_DDIA_BIT_DEPTH_CONTROL, Private->DdiaBitDepthControl); + + RHDRegWrite(Output, RS69_DDIA_DCBALANCER_CONTROL, Private->DdiaDcbalancerControl); + RHDRegWrite(Output, RS69_DDIA_PCIE_LINK_CONTROL2, Private->DdiaPcieLinkControl2); + /* enable if enabled at startup */ + RHDRegWrite(Output, RS69_DDIA_CNTL, Private->DdiaCntl); + /* reset off */ + RHDRegWrite(Output, RS69_DDIA_PATH_CONTROL, Private->DdiaPathControl); +} + +/* + * + */ +static void +DDIADestroy(struct rhdOutput *Output) +{ + struct DDIAPrivate *Private = (struct DDIAPrivate *)Output->Private; + + RHDFUNC(Output); + + xfree(Private); + Output->Private = NULL; +} + +/* + * + */ +struct rhdOutput * +RHDDDIAInit(RHDPtr rhdPtr) +{ +#ifdef ATOM_BIOS + struct rhdOutput *Output; + struct DDIAPrivate *Private; + AtomBiosArgRec data; + + RHDFUNC(rhdPtr); + + /* + * This needs to be handled separately + * for now we only deal with it here. + */ + if (rhdPtr->ChipSet < RHD_RS600 || rhdPtr->ChipSet >= RHD_RS740) + return FALSE; + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + + Output->Name = "DDIA"; + + Output->scrnIndex = rhdPtr->scrnIndex; + Output->Id = RHD_OUTPUT_DVO; + + Output->Sense = NULL; + Output->ModeValid = DDIAModeValid; + Output->Mode = DDIAMode; + Output->Power = DDIAPower; + Output->Save = DDIASave; + Output->Restore = DDIARestore; + Output->Destroy = DDIADestroy; + + Private = xnfcalloc(1, sizeof(struct DDIAPrivate)); + Output->Private = Private; + Private->Stored = FALSE; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GET_PCIENB_CFG_REG7, &data) == ATOM_SUCCESS) { + Private->PcieCfgReg7 = data.val; + } else { + xf86DrvMsg(Output->scrnIndex, X_ERROR, "Retrieval of PCIE MUX values failed. " + "no DDIA block support available\n"); + goto error; + } + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GET_CAPABILITY_FLAG, &data) == ATOM_SUCCESS) { + Private->CapabilityFlag = data.val; + } else { + xf86DrvMsg(Output->scrnIndex, X_ERROR, "Retrieval of Capability flag failed. " + "no DDIA block support available\n"); + goto error; + } + + return Output; +error: + xfree(Private); + return NULL; + +#else + return NULL; +#endif +} diff --git a/programs/system/drivers/rhd/rhd_dig.c b/programs/system/drivers/rhd/rhd_dig.c new file mode 100644 index 000000000..4c3d621f3 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_dig.c @@ -0,0 +1,1869 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_regs.h" +#include "rhd_hdmi.h" +#ifdef ATOM_BIOS +#include "rhd_atombios.h" +#include "rhd_atomout.h" +#endif + +#define FMT2_OFFSET 0x800 +#define DIG1_OFFSET 0x000 +#define DIG2_OFFSET 0x400 + +/* + * Transmitter + */ +struct transmitter { + enum rhdSensedOutput (*Sense) (struct rhdOutput *Output, + enum rhdConnectorType Type); + ModeStatus (*ModeValid) (struct rhdOutput *Output, DisplayModePtr Mode); + void (*Mode) (struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode); + void (*Power) (struct rhdOutput *Output, int Power); + void (*Save) (struct rhdOutput *Output); + void (*Restore) (struct rhdOutput *Output); + void (*Destroy) (struct rhdOutput *Output); + Bool (*Property) (struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val); +#ifdef NOT_YET + Bool (*WrappedPropertyCallback) (struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val); + void *PropertyPrivate; +#endif + void *Private; +}; + +/* + * Encoder + */ +struct encoder { + ModeStatus (*ModeValid) (struct rhdOutput *Output, DisplayModePtr Mode); + void (*Mode) (struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode); + void (*Power) (struct rhdOutput *Output, int Power); + void (*Save) (struct rhdOutput *Output); + void (*Restore) (struct rhdOutput *Output); + void (*Destroy) (struct rhdOutput *Output); + void *Private; +}; + +/* + * + */ +enum encoderMode { + DISPLAYPORT = 0, + LVDS = 1, + TMDS_DVI = 2, + TMDS_HDMI = 3, + SDVO = 4 +}; + +enum encoderID { + ENCODER_NONE, + ENCODER_DIG1, + ENCODER_DIG2 +}; + +struct DIGPrivate +{ + struct encoder Encoder; + struct transmitter Transmitter; + enum encoderID EncoderID; + enum encoderMode EncoderMode; + Bool Coherent; + Bool RunDualLink; + DisplayModePtr Mode; + struct rhdHdmi *Hdmi; + + /* LVDS */ + Bool FPDI; + CARD32 PowerSequenceDe2Bl; + CARD32 PowerSequenceDig2De; + CARD32 OffDelay; + struct rhdFMTDither FMTDither; + int BlLevel; +}; + +/* + * LVTMA Transmitter + */ + +struct LVTMATransmitterPrivate +{ + Bool Stored; + + CARD32 StoredTransmitterControl; + CARD32 StoredTransmitterAdjust; + CARD32 StoredPreemphasisControl; + CARD32 StoredMacroControl; + CARD32 StoredLVTMADataSynchronization; + CARD32 StoredTransmiterEnable; + CARD32 StoredPwrSeqCntl; + CARD32 StoredPwrSeqRevDiv; + CARD32 StoredPwrSeqDelay1; + CARD32 StoredPwrSeqDelay2; +}; + +/* + * + */ +static ModeStatus +LVTMATransmitterModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE + && Mode->SynthClock > 165000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void +LVDSSetBacklight(struct rhdOutput *Output, int level) +{ + struct DIGPrivate *Private = (struct DIGPrivate *) Output->Private; + + RHDFUNC(Output); + + Private->BlLevel = level; + + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_REF_DIV, + 0x144 << LVTMA_BL_MOD_REF_DI_SHIFT, + 0x7ff << LVTMA_BL_MOD_REF_DI_SHIFT); + RHDRegWrite(Output, RV620_LVTMA_BL_MOD_CNTL, + 0xff << LVTMA_BL_MOD_RES_SHIFT + | level << LVTMA_BL_MOD_LEVEL_SHIFT + | LVTMA_BL_MOD_EN); +} + +/* + * + */ +static Bool +LVDSTransmitterPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct DIGPrivate *Private = (struct DIGPrivate *) Output->Private; + + RHDFUNC(Output); + switch (Action) { + case rhdPropertyCheck: + if (Private->BlLevel < 0) + return FALSE; + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + if (Private->BlLevel < 0) + return FALSE; + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + val->integer = Private->BlLevel; + return TRUE; + default: + return FALSE; + } + break; + case rhdPropertySet: + if (Private->BlLevel < 0) + return FALSE; + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + LVDSSetBacklight(Output, val->integer); + return TRUE; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static Bool +TMDSTransmitterPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct DIGPrivate *Private = (struct DIGPrivate *) Output->Private; + + RHDFUNC(Output); + switch (Action) { + case rhdPropertyCheck: + switch (Property) { + case RHD_OUTPUT_COHERENT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + val->Bool = Private->Coherent; + return TRUE; + default: + return FALSE; + } + break; + case rhdPropertySet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + Private->Coherent = val->Bool; + Output->Mode(Output, Private->Mode); + Output->Power(Output, RHD_POWER_ON); + break; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static void +LVTMATransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + CARD32 value = 0; +#ifdef ATOM_BIOS + AtomBiosArgRec data; +#endif + RHDPtr rhdPtr = RHDPTRI(Output); + Bool doCoherent = Private->Coherent; + RHDFUNC(Output); + + /* set coherent / not coherent mode; whatever that is */ + if (Output->Connector->Type != RHD_CONNECTOR_PANEL) + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + doCoherent ? 0 : RV62_LVTMA_BYPASS_PLL, RV62_LVTMA_BYPASS_PLL); + + Private->Mode = Mode; +#ifdef ATOM_BIOS + RHDDebug(Output->scrnIndex, "%s: SynthClock: %i Hex: %x EncoderMode: %x\n",__func__, + (Mode->SynthClock),(Mode->SynthClock / 10), Private->EncoderMode); + + /* Set up magic value that's used for list lookup */ + value = ((Mode->SynthClock / 10 / ((Private->RunDualLink) ? 2 : 1)) & 0xffff) + | (Private->EncoderMode << 16) + | ((doCoherent ? 0x2 : 0) << 24); + + RHDDebug(Output->scrnIndex, "%s: GetConditionalGoldenSettings for: %x\n", __func__, value); + + /* Get data from DIG2TransmitterControl table */ + data.val = 0x4d; + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, ATOMBIOS_GET_CODE_DATA_TABLE, + &data) == ATOM_SUCCESS) { + AtomBiosArgRec data1; + CARD32 *d_p = NULL; + + data1.GoldenSettings.BIOSPtr = data.CommandDataTable.loc; + data1.GoldenSettings.End = data1.GoldenSettings.BIOSPtr + data.CommandDataTable.size; + data1.GoldenSettings.value = value; + + /* now find pointer */ + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GET_CONDITIONAL_GOLDEN_SETTINGS, &data1) == ATOM_SUCCESS) { + d_p = (CARD32*)data1.GoldenSettings.BIOSPtr; + } else { + /* nothing found, now try toggling the coherent setting */ + doCoherent = !doCoherent; + value = (value & ~(0x2 << 24)) | ((doCoherent ? 0x2 : 0) << 24); + data1.GoldenSettings.value = value; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GET_CONDITIONAL_GOLDEN_SETTINGS, &data1) == ATOM_SUCCESS) { + d_p = (CARD32*)data1.GoldenSettings.BIOSPtr; + /* set coherent / not coherent mode; whatever that is */ + xf86DrvMsg(Output->scrnIndex, X_INFO, "%s: %soherent Mode not supported, switching to %soherent.\n", + __func__, doCoherent ? "Inc" : "C", doCoherent ? "C" : "Inc"); + if (Output->Connector->Type != RHD_CONNECTOR_PANEL) + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + doCoherent ? 0 : RV62_LVTMA_BYPASS_PLL, RV62_LVTMA_BYPASS_PLL); + } else + doCoherent = Private->Coherent; /* reset old value if nothing found either */ + } + if (d_p) { + RHDDebug(Output->scrnIndex, "TransmitterAdjust: 0x%8.8x\n",d_p[0]); + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, d_p[0]); + + RHDDebug(Output->scrnIndex, "PreemphasisControl: 0x%8.8x\n",d_p[1]); + RHDRegWrite(Output, RV620_LVTMA_PREEMPHASIS_CONTROL, d_p[1]); + + RHDDebug(Output->scrnIndex, "MacroControl: 0x%8.8x\n",d_p[2]); + RHDRegWrite(Output, RV620_LVTMA_MACRO_CONTROL, d_p[2]); + } else + xf86DrvMsg(Output->scrnIndex, X_WARNING, "%s: cannot get golden settings\n",__func__); + } else +#endif + { + xf86DrvMsg(Output->scrnIndex, X_WARNING, "%s: No AtomBIOS supplied " + "electrical parameters available\n", __func__); + } +} + +/* + * + */ +static void +LVTMATransmitterSave(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; + + Private->StoredTransmitterControl = RHDRegRead(Output, RV620_LVTMA_TRANSMITTER_CONTROL); + Private->StoredTransmitterAdjust = RHDRegRead(Output, RV620_LVTMA_TRANSMITTER_ADJUST); + Private->StoredPreemphasisControl = RHDRegRead(Output, RV620_LVTMA_PREEMPHASIS_CONTROL); + Private->StoredMacroControl = RHDRegRead(Output, RV620_LVTMA_MACRO_CONTROL); + Private->StoredLVTMADataSynchronization = RHDRegRead(Output, RV620_LVTMA_DATA_SYNCHRONIZATION); + Private->StoredTransmiterEnable = RHDRegRead(Output, RV620_LVTMA_TRANSMITTER_ENABLE); +} + +/* + * + */ +static void +LVTMATransmitterRestore(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; + + RHDFUNC(Output); + + /* write control values back */ + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_CONTROL,Private->StoredTransmitterControl); + usleep (14); + /* reset PLL */ + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_CONTROL,Private->StoredTransmitterControl + | RV62_LVTMA_PLL_RESET); + usleep (10); + /* unreset PLL */ + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_CONTROL,Private->StoredTransmitterControl); + usleep(1000); + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, Private->StoredTransmitterAdjust); + RHDRegWrite(Output, RV620_LVTMA_PREEMPHASIS_CONTROL, Private->StoredPreemphasisControl); + RHDRegWrite(Output, RV620_LVTMA_MACRO_CONTROL, Private->StoredMacroControl); + /* start data synchronization */ + RHDRegWrite(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, (Private->StoredLVTMADataSynchronization + & ~(CARD32)RV62_LVTMA_DSYNSEL) + | RV62_LVTMA_PFREQCHG); + usleep (1); + RHDRegWrite(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, Private->StoredLVTMADataSynchronization); + usleep(10); + RHDRegWrite(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, Private->StoredLVTMADataSynchronization); + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ENABLE, Private->StoredTransmiterEnable); +} + +/* + * + */ +static void +LVTMA_TMDSTransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + /* TMDS Mode */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_USE_CLK_DATA, RV62_LVTMA_USE_CLK_DATA); + + LVTMATransmitterSet(Output, Crtc, Mode); + + /* use differential post divider input */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_IDSCKSEL, RV62_LVTMA_IDSCKSEL); +} + +/* + * + */ +static void +LVTMA_TMDSTransmitterPower(struct rhdOutput *Output, int Power) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + + RHDFUNC(Output); + + switch (Power) { + case RHD_POWER_ON: + /* enable PLL */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_PLL_ENABLE, RV62_LVTMA_PLL_ENABLE); + usleep(14); + /* PLL reset on */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_PLL_RESET, RV62_LVTMA_PLL_RESET); + usleep(10); + /* PLL reset off */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + 0, RV62_LVTMA_PLL_RESET); + usleep(1000); + /* start data synchronization */ + RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, + RV62_LVTMA_PFREQCHG, RV62_LVTMA_PFREQCHG); + usleep(1); + /* restart write address logic */ + RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, + RV62_LVTMA_DSYNSEL, RV62_LVTMA_DSYNSEL); +#if 1 + /* TMDS Mode ?? */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_MODE, RV62_LVTMA_MODE); +#endif + /* enable lower link */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, + RV62_LVTMA_LNKL, + RV62_LVTMA_LNK_ALL); + if (Private->RunDualLink) { + usleep (28); + /* enable upper link */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, + RV62_LVTMA_LNKU, + RV62_LVTMA_LNKU); + } + return; + case RHD_POWER_RESET: + /* disable all links */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, + 0, RV62_LVTMA_LNK_ALL); + return; + case RHD_POWER_SHUTDOWN: + default: + /* disable transmitter */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, + 0, RV62_LVTMA_LNK_ALL); + /* PLL reset */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_PLL_RESET, RV62_LVTMA_PLL_RESET); + usleep(10); + /* end PLL reset */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + 0, RV62_LVTMA_PLL_RESET); + /* disable data synchronization */ + RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, + 0, RV62_LVTMA_DSYNSEL); + /* reset macro control */ + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, 0); + + return; + } +} + +/* + * + */ +static void +LVTMA_TMDSTransmitterSave(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; + + RHDFUNC(Output); + + LVTMATransmitterSave(Output); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +LVTMA_TMDSTransmitterRestore(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; + + RHDFUNC(Output); + + if (!Private->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + LVTMATransmitterRestore(Output); +} + +/* + * + */ +static void +LVTMA_LVDSTransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + /* LVDS Mode */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + 0, RV62_LVTMA_USE_CLK_DATA); + + LVTMATransmitterSet(Output, Crtc, Mode); + + /* use IDCLK */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, RV62_LVTMA_IDSCKSEL, RV62_LVTMA_IDSCKSEL); + /* enable pwrseq, pwrseq overwrite PPL enable, reset */ + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, + RV62_LVTMA_PWRSEQ_EN + | RV62_LVTMA_PLL_ENABLE_PWRSEQ_MASK + | RV62_LVTMA_PLL_RESET_PWRSEQ_MASK, + RV62_LVTMA_PWRSEQ_EN + | RV62_LVTMA_PLL_ENABLE_PWRSEQ_MASK + | RV62_LVTMA_PLL_RESET_PWRSEQ_MASK + ); + +} + +/* + * + */ +static void +LVTMA_LVDSTransmitterPower(struct rhdOutput *Output, int Power) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + CARD32 tmp, tmp1; + int i; + + RHDFUNC(Output); + + switch (Power) { + case RHD_POWER_ON: + /* enable PLL */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_PLL_ENABLE, RV62_LVTMA_PLL_ENABLE); + usleep(14); + /* PLL reset on */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + RV62_LVTMA_PLL_RESET, RV62_LVTMA_PLL_RESET); + usleep(10); + /* PLL reset off */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + 0, RV62_LVTMA_PLL_RESET); + usleep(1000); + /* start data synchronization */ + RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, + RV62_LVTMA_PFREQCHG, RV62_LVTMA_PFREQCHG); + usleep(1); + /* restart write address logic */ + RHDRegMask(Output, RV620_LVTMA_DATA_SYNCHRONIZATION, + RV62_LVTMA_DSYNSEL, RV62_LVTMA_DSYNSEL); + /* SYNCEN disables pwrseq ?? */ + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, + RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN, + RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN); + /* LVDS Mode ?? */ + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_CONTROL, + 0, RV62_LVTMA_MODE); + /* enable links */ + if (Private->RunDualLink) { + if (Private->FMTDither.LVDS24Bit) + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x3ff, 0x3ff); + else + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x1ef, 0x3ff); + } else { + if (Private->FMTDither.LVDS24Bit) + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x1f, 0x3ff); + else + RHDRegMask(Output, RV620_LVTMA_TRANSMITTER_ENABLE, 0x0f, 0x3ff); + } + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, 0, + RV62_LVTMA_DIGON_OVRD | RV62_LVTMA_BLON_OVRD); + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_REF_DIV, 3999, 0xffff); /* 4000 - 1 */ + tmp = Private->PowerSequenceDe2Bl * 10 / 4; + tmp1 = Private->PowerSequenceDig2De * 10 / 4; + /* power sequencing delay for on / off between DIGON and SYNCEN, and SYNCEN and BLON */ + RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY1, (tmp1 << 24) | tmp1 | (tmp << 8) | (tmp << 16)); + RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY2, Private->OffDelay / 4); + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, 0, RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN); + for (i = 0; i < 500; i++) { + CARD32 tmp; + + usleep(1000); + tmp = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_STATE); + tmp >>= RV62_LVTMA_PWRSEQ_STATE_SHIFT; + tmp &= 0xff; + if (tmp <= RV62_POWERUP_DONE) + break; + if (tmp >= RV62_POWERDOWN_DONE) + break; + } + /* LCD on */ + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, RV62_LVTMA_PWRSEQ_TARGET_STATE, + RV62_LVTMA_PWRSEQ_TARGET_STATE); + return; + + case RHD_POWER_RESET: + /* Disable LCD and BL */ + RHDRegMask(Output, RV620_LVTMA_PWRSEQ_CNTL, 0, + RV62_LVTMA_PWRSEQ_TARGET_STATE + | RV62_LVTMA_DIGON_OVRD + | RV62_LVTMA_BLON_OVRD); + for (i = 0; i < 500; i++) { + CARD32 tmp; + + usleep(1000); + tmp = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_STATE); + tmp >>= RV62_LVTMA_PWRSEQ_STATE_SHIFT; + tmp &= 0xff; + if (tmp >= RV62_POWERDOWN_DONE) + break; + } + return; + case RHD_POWER_SHUTDOWN: + LVTMA_LVDSTransmitterPower(Output, RHD_POWER_RESET); + /* op-amp down, bias current for output driver down, shunt resistor down */ + RHDRegWrite(Output, RV620_LVTMA_TRANSMITTER_ADJUST, 0x00e00000); + /* set macro control */ + RHDRegWrite(Output, RV620_LVTMA_MACRO_CONTROL, 0x07430408); + default: + return; + } +} + +/* + * + */ +static void +LVTMA_LVDSTransmitterSave(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; + + RHDFUNC(Output); + + LVTMATransmitterSave(Output); + + Private->StoredPwrSeqCntl = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_CNTL); + Private->StoredPwrSeqRevDiv = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_REF_DIV); + Private->StoredPwrSeqDelay1 = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_DELAY1); + Private->StoredPwrSeqDelay2 = RHDRegRead(Output, RV620_LVTMA_PWRSEQ_DELAY2); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +LVTMA_LVDSTransmitterRestore(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct LVTMATransmitterPrivate *Private = (struct LVTMATransmitterPrivate*)digPrivate->Transmitter.Private; + + RHDFUNC(Output); + + if (!Private->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + LVTMATransmitterRestore(Output); + + RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_REF_DIV, Private->StoredPwrSeqRevDiv); + RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY1, Private->StoredPwrSeqDelay1); + RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_DELAY2, Private->StoredPwrSeqDelay2); + RHDRegWrite(Output, RV620_LVTMA_PWRSEQ_CNTL, Private->StoredPwrSeqCntl); +} + +/* + * + */ +static void +LVTMATransmitterDestroy(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + + RHDFUNC(Output); + + if (!digPrivate) + return; + + xfree(digPrivate->Transmitter.Private); +} + +#if defined(ATOM_BIOS) && defined(ATOM_BIOS_PARSER) + +struct ATOMTransmitterPrivate +{ + struct atomTransmitterConfig atomTransmitterConfig; + enum atomTransmitter atomTransmitterID; +}; + +/* + * + */ +static ModeStatus +ATOMTransmitterModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + + RHDFUNC(Output); + + if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE + && Mode->SynthClock > 165000) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +/* + * + */ +void +rhdPrintDigDebug(RHDPtr rhdPtr, const char *name) +{ + xf86DrvMsgVerb(rhdPtr->scrnIndex, X_INFO, 7, "%s: DIGn_CNTL: n=1: 0x%x n=2: 0x%x\n", + name, RHDRegRead(rhdPtr, RV620_DIG1_CNTL), + RHDRegRead(rhdPtr, DIG2_OFFSET + RV620_DIG1_CNTL)); +} + +/* + * + */ +static void +ATOMTransmitterSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct ATOMTransmitterPrivate *transPrivate + = (struct ATOMTransmitterPrivate*) Private->Transmitter.Private; + struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; + + RHDFUNC(Output); + + atc->Coherent = Private->Coherent; + atc->PixelClock = Mode->SynthClock; + + rhdPrintDigDebug(rhdPtr,__func__); + + if (Private->RunDualLink) { + atc->Mode = atomDualLink; + + if (atc->Link == atomTransLinkA) + atc->Link = atomTransLinkAB; + else if (atc->Link == atomTransLinkB) + atc->Link = atomTransLinkBA; + + } else { + atc->Mode = atomSingleLink; + + if (atc->Link == atomTransLinkAB) + atc->Link = atomTransLinkA; + else if (atc->Link == atomTransLinkBA) + atc->Link = atomTransLinkB; + + } + + atc->PixelClock = Mode->SynthClock; + + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, + atomTransSetup, atc); + rhdPrintDigDebug(rhdPtr,__func__); +} + +/* + * + */ +static CARD32 +digProbeEncoder(struct rhdOutput *Output) +{ + if (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) { + return ENCODER_DIG2; + } else { + Bool swap = (RHDRegRead(Output, RV620_DCIO_LINK_STEER_CNTL) + & RV62_LINK_STEER_SWAP) == RV62_LINK_STEER_SWAP; + + switch (Output->Id) { + case RHD_OUTPUT_UNIPHYA: + if (swap) { + RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG2 for UNIPHYA\n",__func__); + return ENCODER_DIG2; + } else { + RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG1 for UNIPHYA\n",__func__); + return ENCODER_DIG1; + } + break; + case RHD_OUTPUT_UNIPHYB: + if (swap) { + RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG1 for UNIPHYB\n",__func__); + return ENCODER_DIG1; + } else { + RHDDebug(Output->scrnIndex, "%s: detected ENCODER_DIG2 for UNIPHYB\n",__func__); + return ENCODER_DIG2; + } + break; + default: + return ENCODER_NONE; /* should not get here */ + } + } + return ENCODER_NONE; +} + +/* + * + */ +static void +ATOMTransmitterPower(struct rhdOutput *Output, int Power) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct ATOMTransmitterPrivate *transPrivate + = (struct ATOMTransmitterPrivate*) Private->Transmitter.Private; + struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; + + RHDFUNC(Output); + + rhdPrintDigDebug(rhdPtr,__func__); + + if (Private->RunDualLink) + atc->LinkCnt = atomDualLink; + else + atc->LinkCnt = atomSingleLink; + + atc->Coherent = Private->Coherent; + + if (atc->Encoder == atomEncoderNone) { + switch (digProbeEncoder(Output)) { + case ENCODER_DIG1: + if (rhdPtr->DigEncoderOutput[0]) { + RHDDebug(Output->scrnIndex,"%s: DIG1 for %s already taken\n",__func__,Output->Name); + return; + } + atc->Encoder = atomEncoderDIG1; + break; + case ENCODER_DIG2: + if (rhdPtr->DigEncoderOutput[1]) { + RHDDebug(Output->scrnIndex,"%s: DIG2 for %s already taken\n",__func__,Output->Name); + return; + } + atc->Encoder = atomEncoderDIG2; + break; + default: + return; + } + } + + switch (Power) { + case RHD_POWER_ON: + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, + atomTransEnable, atc); + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, + atomTransEnableOutput, atc); + break; + case RHD_POWER_RESET: + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, + atomTransDisableOutput, atc); + break; + case RHD_POWER_SHUTDOWN: + if (!Output->Connector || Output->Connector->Type == RHD_CONNECTOR_DVI) + atc->Mode = atomDVI; + + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, + atomTransDisableOutput, atc); + rhdAtomDigTransmitterControl(rhdPtr->atomBIOS, transPrivate->atomTransmitterID, + atomTransDisable, atc); + break; + } + rhdPrintDigDebug(rhdPtr,__func__); +} + +/* + * + */ +static void +ATOMTransmitterSave(struct rhdOutput *Output) +{ + RHDFUNC(Output); +} + +/* + * + */ +static void +ATOMTransmitterRestore(struct rhdOutput *Output) +{ + RHDFUNC(Output); +} + +/* + * + */ +static void +ATOMTransmitterDestroy(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + + RHDFUNC(Output); + + if (!digPrivate) + return; + + xfree(digPrivate->Transmitter.Private); +} + +#endif /* ATOM_BIOS && ATOM_BIOS_PASER */ + +/* + * Encoder + */ + +struct DIGEncoder +{ + Bool Stored; + + CARD32 StoredOff; + + CARD32 StoredRegExt1DiffPostDivCntl; + CARD32 StoredRegExt2DiffPostDivCntl; + CARD32 StoredDIGClockPattern; + CARD32 StoredLVDSDataCntl; + CARD32 StoredTMDSPixelEncoding; + CARD32 StoredTMDSCntl; + CARD32 StoredDIGCntl; + CARD32 StoredDIGMisc1; + CARD32 StoredDIGMisc2; + CARD32 StoredDIGMisc3; + CARD32 StoredDCCGPclkDigCntl; + CARD32 StoredDCCGSymclkCntl; + CARD32 StoredDCIOLinkSteerCntl; + CARD32 StoredBlModCntl; +}; + +/* + * + */ +static ModeStatus +EncoderModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + return MODE_OK; +} + +/* + * + */ +static void +LVDSEncoder(struct rhdOutput *Output) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + CARD32 off; + + RHDFUNC(Output); + + + off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; + /* Clock pattern ? */ + RHDRegMask(Output, off + RV620_DIG1_CLOCK_PATTERN, 0x0063, 0xFFFF); + /* set panel type: 18/24 bit mode */ + RHDRegMask(Output, off + RV620_LVDS1_DATA_CNTL, + (Private->FMTDither.LVDS24Bit ? RV62_LVDS_24BIT_ENABLE : 0) + | (Private->FPDI ? RV62_LVDS_24BIT_FORMAT : 0), + RV62_LVDS_24BIT_ENABLE | RV62_LVDS_24BIT_FORMAT); + + Output->Crtc->FMTModeSet(Output->Crtc, &Private->FMTDither); +} + +/* + * + */ +static void +TMDSEncoder(struct rhdOutput *Output) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + CARD32 off; + + RHDFUNC(Output); + + off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; + /* clock pattern ? */ + RHDRegMask(Output, off + RV620_DIG1_CLOCK_PATTERN, 0x001F, 0xFFFF); + /* color format RGB - normal color format 24bpp, Twin-Single 30bpp or Dual 48bpp*/ + RHDRegMask(Output, off + RV620_TMDS1_CNTL, 0x0, + RV62_TMDS_PIXEL_ENCODING | RV62_TMDS_COLOR_FORMAT); + /* no dithering */ + Output->Crtc->FMTModeSet(Output->Crtc, NULL); +} + +/* + * + */ +static void +EncoderSet(struct rhdOutput *Output, struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + CARD32 off; + + RHDFUNC(Output); + + off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; + + rhdPrintDigDebug(rhdPtr,__func__); + + RHDRegMask(Output, off + RV620_DIG1_CNTL, Output->Crtc->Id, + RV62_DIG_SOURCE_SELECT); + + if (Output->Id == RHD_OUTPUT_UNIPHYA) { + /* select LinkA ?? */ + RHDRegMask(Output, RV620_DCIO_LINK_STEER_CNTL, + ((Private->EncoderID == ENCODER_DIG2) + ? RV62_LINK_STEER_SWAP + : 0), RV62_LINK_STEER_SWAP); /* swap if DIG2 */ + if (!Private->RunDualLink) { + RHDRegMask(Output, off + RV620_DIG1_CNTL, + 0, + RV62_DIG_SWAP |RV62_DIG_DUAL_LINK_ENABLE); + } else { + RHDRegMask(Output, off + RV620_DIG1_CNTL, + RV62_DIG_DUAL_LINK_ENABLE, + RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE); + } + } else if (Output->Id == RHD_OUTPUT_UNIPHYB) { + /* select LinkB ?? */ + RHDRegMask(Output, RV620_DCIO_LINK_STEER_CNTL, + ((Private->EncoderID == ENCODER_DIG2) + ? 0 + : RV62_LINK_STEER_SWAP), RV62_LINK_STEER_SWAP); + if (!Private->RunDualLink) + RHDRegMask(Output, off + RV620_DIG1_CNTL, + 0, + RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE); + else + RHDRegMask(Output, off + RV620_DIG1_CNTL, + RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE, + RV62_DIG_SWAP | RV62_DIG_DUAL_LINK_ENABLE); + } else { /* LVTMA */ + RHDRegMask(Output, RV620_EXT2_DIFF_POST_DIV_CNTL, 0, RV62_EXT2_DIFF_DRIVER_ENABLE); + } + + if (Private->EncoderMode == LVDS) + LVDSEncoder(Output); + else if (Private->EncoderMode == DISPLAYPORT) + dbgprintf("No displayport support yet!",__FILE__, __LINE__, __func__); /* bugger ! */ + else + TMDSEncoder(Output); + + /* Start DIG, set links, disable stereo sync, select FMT source */ + RHDRegMask(Output, off + RV620_DIG1_CNTL, + (Private->EncoderMode & 0x7) << 8 + | RV62_DIG_START + | (Private->RunDualLink ? RV62_DIG_DUAL_LINK_ENABLE : 0) + | Output->Crtc->Id, + RV62_DIG_MODE + | RV62_DIG_START + | RV62_DIG_DUAL_LINK_ENABLE + | RV62_DIG_STEREOSYNC_SELECT + | RV62_DIG_SOURCE_SELECT); + rhdPrintDigDebug(rhdPtr,__func__); +} + +/* + * + */ +static void +EncoderPower(struct rhdOutput *Output, int Power) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + CARD32 off; + enum encoderID EncoderID = Private->EncoderID; + RHDPtr rhdPtr = Output->rhdPtr; + + RHDFUNC(Output); + + if (EncoderID == ENCODER_NONE) { + EncoderID = digProbeEncoder(Output); + switch (EncoderID) { + case ENCODER_DIG1: + if (rhdPtr->DigEncoderOutput[0]) { + RHDDebug(Output->scrnIndex,"%s: DIG1 for %s already taken\n",__func__,Output->Name); + return; + } + break; + case ENCODER_DIG2: + if (rhdPtr->DigEncoderOutput[1]) { + RHDDebug(Output->scrnIndex,"%s: DIG2 for %s already taken\n",__func__,Output->Name); + return; + } + break; + default: + return; + } + } + + off = (EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; + + /* clock src is pixel PLL */ + RHDRegMask(Output, RV620_DCCG_SYMCLK_CNTL, 0x0, + 0x3 << ((EncoderID == ENCODER_DIG2) + ? RV62_SYMCLKB_SRC_SHIFT + : RV62_SYMCLKA_SRC_SHIFT)); + + rhdPrintDigDebug(rhdPtr,__func__); + switch (Power) { + case RHD_POWER_ON: + RHDDebug(Output->scrnIndex,"%s(RHD_POWER_ON, %i)\n",__func__, + EncoderID); + /* enable DIG */ + RHDRegMask(Output, off + RV620_DIG1_CNTL, 0x10, 0x10); + RHDRegMask(Output, (EncoderID == ENCODER_DIG2) + ? RV620_DCCG_PCLK_DIGB_CNTL + : RV620_DCCG_PCLK_DIGA_CNTL, + RV62_PCLK_DIGA_ON, RV62_PCLK_DIGA_ON); /* @@@ */ + rhdPrintDigDebug(rhdPtr,__func__); + return; + case RHD_POWER_RESET: + case RHD_POWER_SHUTDOWN: + default: + RHDDebug(Output->scrnIndex,"%s(RHD_POWER_SHUTDOWN, %i)\n",__func__, + EncoderID); + /* disable differential clock driver */ + if (EncoderID == ENCODER_DIG1) + RHDRegMask(Output, RV620_EXT1_DIFF_POST_DIV_CNTL, + 0, + RV62_EXT1_DIFF_DRIVER_ENABLE); + else + RHDRegMask(Output, RV620_EXT2_DIFF_POST_DIV_CNTL, + 0, + RV62_EXT2_DIFF_DRIVER_ENABLE); + /* disable DIG */ + RHDRegMask(Output, off + RV620_DIG1_CNTL, 0x0, 0x10); + RHDRegMask(Output, (EncoderID == ENCODER_DIG2) + ? RV620_DCCG_PCLK_DIGB_CNTL + : RV620_DCCG_PCLK_DIGA_CNTL, + 0, RV62_PCLK_DIGA_ON); /* @@@ */ + rhdPrintDigDebug(rhdPtr,__func__); + return; + } +} + +/* + * + */ +static void +EncoderSave(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct DIGEncoder *Private = (struct DIGEncoder *)(digPrivate->Encoder.Private); + CARD32 off; + enum encoderID EncoderID; + + RHDFUNC(Output); + + EncoderID = digProbeEncoder(Output); + off = (EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; + Private->StoredOff = off; + + Private->StoredRegExt1DiffPostDivCntl = RHDRegRead(Output, off + RV620_EXT1_DIFF_POST_DIV_CNTL); + Private->StoredRegExt2DiffPostDivCntl = RHDRegRead(Output, off + RV620_EXT2_DIFF_POST_DIV_CNTL); + Private->StoredDIGClockPattern = RHDRegRead(Output, off + RV620_DIG1_CLOCK_PATTERN); + Private->StoredLVDSDataCntl = RHDRegRead(Output, off + RV620_LVDS1_DATA_CNTL); + Private->StoredDIGCntl = RHDRegRead(Output, off + RV620_DIG1_CNTL); + Private->StoredTMDSCntl = RHDRegRead(Output, off + RV620_TMDS1_CNTL); + Private->StoredDCIOLinkSteerCntl = RHDRegRead(Output, RV620_DCIO_LINK_STEER_CNTL); + Private->StoredDCCGPclkDigCntl = RHDRegRead(Output, + (off == DIG2_OFFSET) + ? RV620_DCCG_PCLK_DIGB_CNTL + : RV620_DCCG_PCLK_DIGA_CNTL); + Private->StoredDCCGSymclkCntl = RHDRegRead(Output, RV620_DCCG_SYMCLK_CNTL); + Private->StoredBlModCntl = RHDRegRead(Output, RV620_LVTMA_BL_MOD_CNTL); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +EncoderRestore(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + struct DIGEncoder *Private = (struct DIGEncoder *)(digPrivate->Encoder.Private); + CARD32 off; + + RHDFUNC(Output); + + if (!Private->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + off = Private->StoredOff; + + RHDRegWrite(Output, off + RV620_EXT1_DIFF_POST_DIV_CNTL, Private->StoredRegExt1DiffPostDivCntl); + RHDRegWrite(Output, off + RV620_EXT2_DIFF_POST_DIV_CNTL, Private->StoredRegExt2DiffPostDivCntl); + /* reprogram all values but don't start the encoder, yet */ + RHDRegWrite(Output, off + RV620_DIG1_CNTL, Private->StoredDIGCntl & ~(CARD32)RV62_DIG_START); + RHDRegWrite(Output, RV620_DCIO_LINK_STEER_CNTL, Private->StoredDCIOLinkSteerCntl); + RHDRegWrite(Output, off + RV620_DIG1_CLOCK_PATTERN, Private->StoredDIGClockPattern); + RHDRegWrite(Output, off + RV620_LVDS1_DATA_CNTL, Private->StoredLVDSDataCntl); + RHDRegWrite(Output, off + RV620_TMDS1_CNTL, Private->StoredTMDSCntl); + RHDRegWrite(Output, (off == DIG2_OFFSET) + ? RV620_DCCG_PCLK_DIGB_CNTL + : RV620_DCCG_PCLK_DIGA_CNTL, + Private->StoredDCCGPclkDigCntl); + /* now enable the encoder */ + RHDRegWrite(Output, off + RV620_DIG1_CNTL, Private->StoredDIGCntl); + RHDRegWrite(Output, RV620_DCCG_SYMCLK_CNTL, Private->StoredDCCGSymclkCntl); + RHDRegWrite(Output, RV620_LVTMA_BL_MOD_CNTL, Private->StoredBlModCntl); +} + +/* + * + */ +static void +EncoderDestroy(struct rhdOutput *Output) +{ + struct DIGPrivate *digPrivate = (struct DIGPrivate *)Output->Private; + + RHDFUNC(Output); + + if (!digPrivate || !digPrivate->Encoder.Private) + return; + + xfree(digPrivate->Encoder.Private); +} + +/* + * Housekeeping + */ +void +GetLVDSInfo(RHDPtr rhdPtr, struct DIGPrivate *Private) +{ + CARD32 off = (Private->EncoderID == ENCODER_DIG2) ? DIG2_OFFSET : DIG1_OFFSET; + CARD32 tmp; + + RHDFUNC(rhdPtr); + + Private->FPDI = ((RHDRegRead(rhdPtr, off + RV620_LVDS1_DATA_CNTL) + & RV62_LVDS_24BIT_FORMAT) != 0); + Private->RunDualLink = ((RHDRegRead(rhdPtr, off + RV620_DIG1_CNTL) + & RV62_DIG_DUAL_LINK_ENABLE) != 0); + Private->FMTDither.LVDS24Bit = ((RHDRegRead(rhdPtr, off + RV620_LVDS1_DATA_CNTL) + & RV62_LVDS_24BIT_ENABLE) != 0); + + tmp = RHDRegRead(rhdPtr, RV620_LVTMA_BL_MOD_CNTL); + if (tmp & 0x1) + Private->BlLevel = ( tmp >> LVTMA_BL_MOD_LEVEL_SHIFT ) & 0xff; + else + Private->BlLevel = -1; + + tmp = RHDRegRead(rhdPtr, RV620_LVTMA_PWRSEQ_REF_DIV); + tmp &= 0xffff; + tmp += 1; + tmp /= 1000; + Private->PowerSequenceDig2De = Private->PowerSequenceDe2Bl = + RHDRegRead(rhdPtr, RV620_LVTMA_PWRSEQ_REF_DIV); + Private->PowerSequenceDig2De = ((Private->PowerSequenceDig2De & 0xff) * tmp) / 10; + Private->PowerSequenceDe2Bl = (((Private->PowerSequenceDe2Bl >> 8) & 0xff) * tmp) / 10; + Private->OffDelay = RHDRegRead(rhdPtr, RV620_LVTMA_PWRSEQ_DELAY2); + Private->OffDelay *= tmp; + + /* This is really ugly! */ + { + CARD32 fmt_offset; + + tmp = RHDRegRead(rhdPtr, off + RV620_DIG1_CNTL); + fmt_offset = (tmp & RV62_DIG_SOURCE_SELECT) ? FMT2_OFFSET :0; + tmp = RHDRegRead(rhdPtr, fmt_offset + RV620_FMT1_BIT_DEPTH_CONTROL); + Private->FMTDither.LVDSSpatialDither = ((tmp & 0x100) != 0); + Private->FMTDither.LVDSGreyLevel = ((tmp & 0x10000) != 0); + Private->FMTDither.LVDSTemporalDither + = (Private->FMTDither.LVDSGreyLevel > 0) || ((tmp & 0x1000000) != 0); + } + +#ifdef ATOM_BIOS + { + AtomBiosArgRec data; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_FPDI, &data) == ATOM_SUCCESS) + Private->FPDI = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_DUALLINK, &data) == ATOM_SUCCESS) + Private->RunDualLink = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_GREYLVL, &data) == ATOM_SUCCESS) + Private->FMTDither.LVDSGreyLevel = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) == ATOM_SUCCESS) + Private->PowerSequenceDig2De = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_SEQ_DE_TO_BL, &data) == ATOM_SUCCESS) + Private->PowerSequenceDe2Bl = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_OFF_DELAY, &data) == ATOM_SUCCESS) + Private->OffDelay = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_24BIT, &data) == ATOM_SUCCESS) + Private->FMTDither.LVDS24Bit = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_SPATIAL_DITHER, &data) == ATOM_SUCCESS) + Private->FMTDither.LVDSSpatialDither = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_TEMPORAL_DITHER, &data) == ATOM_SUCCESS) + Private->FMTDither.LVDSTemporalDither = data.val; + + Private->PowerSequenceDe2Bl = data.val; + + } +#endif + +} + +/* + * Infrastructure + */ + +static ModeStatus +DigModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct transmitter *Transmitter = &Private->Transmitter; + struct encoder *Encoder = &Private->Encoder; + ModeStatus Status; + + RHDFUNC(Output); + + if ((Status = Transmitter->ModeValid(Output, Mode)) == MODE_OK) + return ((Encoder->ModeValid(Output, Mode))); + else + return Status; +} + +/* + * + */ +static void +DigPower(struct rhdOutput *Output, int Power) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct transmitter *Transmitter = &Private->Transmitter; + struct encoder *Encoder = &Private->Encoder; + Bool enableHDMI; + + RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, + rhdPowerString[Power]); + + if(Output->Connector != NULL) { + /* check if attached monitor supports HDMI */ + enableHDMI = RHDConnectorEnableHDMI(Output->Connector); + if (enableHDMI && Private->EncoderMode == TMDS_DVI) + Private->EncoderMode = TMDS_HDMI; + else if (!enableHDMI && Private->EncoderMode == TMDS_HDMI) + Private->EncoderMode = TMDS_DVI; + } + + switch (Power) { + case RHD_POWER_ON: + Encoder->Power(Output, Power); + Transmitter->Power(Output, Power); + RHDHdmiEnable(Private->Hdmi, Private->EncoderMode == TMDS_HDMI); + return; + case RHD_POWER_RESET: + Transmitter->Power(Output, Power); + Encoder->Power(Output, Power); + return; + case RHD_POWER_SHUTDOWN: + default: + Transmitter->Power(Output, Power); + Encoder->Power(Output, Power); + RHDHdmiEnable(Private->Hdmi, FALSE); + return; + } +} + +/* + * + */ +static Bool +DigPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + + RHDFUNC(Output); + + switch(Property) { + case RHD_OUTPUT_COHERENT: + case RHD_OUTPUT_BACKLIGHT: + { + if (!Private->Transmitter.Property) + return FALSE; + Private->Transmitter.Property(Output, Action, Property, val); + break; + } + default: + return FALSE; + } + return TRUE; +} + + +/* + * + */ +static void +DigMode(struct rhdOutput *Output, DisplayModePtr Mode) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct transmitter *Transmitter = &Private->Transmitter; + struct encoder *Encoder = &Private->Encoder; + struct rhdCrtc *Crtc = Output->Crtc; + + RHDFUNC(Output); + + /* + * For dual link capable DVI we need to decide from the pix clock if we are dual link. + * Do it here as it is convenient. + */ + if (Output->Connector->Type == RHD_CONNECTOR_DVI) + Private->RunDualLink = (Mode->SynthClock > 165000) ? TRUE : FALSE; + + Encoder->Mode(Output, Crtc, Mode); + Transmitter->Mode(Output, Crtc, Mode); + RHDHdmiSetMode(Private->Hdmi, Mode); +} + +/* + * + */ +static void +DigSave(struct rhdOutput *Output) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct transmitter *Transmitter = &Private->Transmitter; + struct encoder *Encoder = &Private->Encoder; + + RHDFUNC(Output); + + Encoder->Save(Output); + Transmitter->Save(Output); + RHDHdmiSave(Private->Hdmi); +} + +/* + * + */ +static void +DigRestore(struct rhdOutput *Output) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct transmitter *Transmitter = &Private->Transmitter; + struct encoder *Encoder = &Private->Encoder; + + RHDFUNC(Output); + + Encoder->Restore(Output); + Transmitter->Restore(Output); + RHDHdmiRestore(Private->Hdmi); +} + +/* + * + */ +static void +DigDestroy(struct rhdOutput *Output) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + struct transmitter *Transmitter = &Private->Transmitter; + struct encoder *Encoder = &Private->Encoder; + + RHDFUNC(Output); + + Encoder->Destroy(Output); + Transmitter->Destroy(Output); + RHDHdmiDestroy(Private->Hdmi); +#ifdef NOT_YET + if (Transmitter->PropertyPrivate) + RhdAtomDestroyBacklightControlProperty(Output, Transmitter->PropertyPrivate); +#endif + xfree(Private); + Output->Private = NULL; +} + +/* + * + */ +static Bool +DigAllocFree(struct rhdOutput *Output, enum rhdOutputAllocation Alloc) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + char *TransmitterName; + + RHDFUNC(rhdPtr); + + switch (Output->Id) { + case RHD_OUTPUT_KLDSKP_LVTMA: + TransmitterName = "KLDSKP_LVTMA"; + break; + case RHD_OUTPUT_UNIPHYA: + TransmitterName = "UNIPHYA"; + break; + case RHD_OUTPUT_UNIPHYB: + TransmitterName = "UNIPHYB"; + break; + default: + return FALSE; + } + switch (Alloc) { + case RHD_OUTPUT_ALLOC: + + if (Private->EncoderID != ENCODER_NONE) + return TRUE; + + /* + * LVTMA can only use DIG2. Thus exclude + * DIG1 for LVTMA and prefer it for the + * UNIPHYs. + */ + if (Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) { + if (!rhdPtr->DigEncoderOutput[1]) { + rhdPtr->DigEncoderOutput[1] = Output; + Private->EncoderID = ENCODER_DIG2; + xf86DrvMsg(Output->scrnIndex, X_INFO, + "Mapping DIG2 encoder to %s\n",TransmitterName); + return TRUE; + } else + return FALSE; + } else { + struct ATOMTransmitterPrivate *transPrivate = + (struct ATOMTransmitterPrivate *)Private->Transmitter.Private; + struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; + if (!rhdPtr->DigEncoderOutput[0]) { + rhdPtr->DigEncoderOutput[0] = Output; + Private->EncoderID = ENCODER_DIG1; + atc->Encoder = atomEncoderDIG1; + xf86DrvMsg(Output->scrnIndex, X_INFO, + "Mapping DIG1 encoder to %s\n",TransmitterName); + return TRUE; + } else if (!rhdPtr->DigEncoderOutput[1]) { + rhdPtr->DigEncoderOutput[1] = Output; + Private->EncoderID = ENCODER_DIG2; + atc->Encoder = atomEncoderDIG2; + xf86DrvMsg(Output->scrnIndex, X_INFO, + "Mapping DIG2 encoder to %s\n",TransmitterName); + return TRUE; + } else + return FALSE; + } + + case RHD_OUTPUT_FREE: + Private->EncoderID = ENCODER_NONE; + if (rhdPtr->DigEncoderOutput[0] == Output) { + rhdPtr->DigEncoderOutput[0] = NULL; + return TRUE; + } else if (rhdPtr->DigEncoderOutput[1] == Output) { + rhdPtr->DigEncoderOutput[1] = NULL; + return TRUE; + } else + return FALSE; + break; + default: + return FALSE; + } +} + +/* + * + */ +static Bool +rhdDIGSetCoherent(RHDPtr rhdPtr,struct rhdOutput *Output) +{ + Bool coherent = FALSE; +// int from = X_CONFIG; + +// switch (RhdParseBooleanOption(&rhdPtr->coherent, Output->Name)) { +// case RHD_OPTION_NOT_SET: +// case RHD_OPTION_DEFAULT: +// from = X_DEFAULT; +// coherent = FALSE; +// break; +// case RHD_OPTION_ON: +// coherent = TRUE; +// break; +// case RHD_OPTION_OFF: +// coherent = FALSE; +// break; +// } +// xf86DrvMsg(rhdPtr->scrnIndex,from,"Setting %s to %scoherent\n", +// Output->Name,coherent ? "" : "in"); + + return coherent; +} + +/* + * + */ +#ifdef NOT_YET +static Bool +digTransmitterPropertyWrapper(struct rhdOutput *Output, + enum rhdPropertyAction Action, + enum rhdOutputProperty Property, + union rhdPropertyData *val) +{ + struct DIGPrivate *Private = (struct DIGPrivate *)Output->Private; + void *storePrivate = Output->Private; + Bool (*func)(struct rhdOutput *,enum rhdPropertyAction, enum rhdOutputProperty, + union rhdPropertyData *) = Private->Transmitter.WrappedPropertyCallback; + Bool ret; + + Output->Private = Private->Transmitter.PropertyPrivate; + ret = func(Output, Action, Property, val); + Output->Private = storePrivate; + + return ret; +} +#endif + +/* + * + */ +struct rhdOutput * +RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType) +{ + struct rhdOutput *Output; + struct DIGPrivate *Private; + struct DIGEncoder *Encoder; + + RHDFUNC(rhdPtr); + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + + Output->scrnIndex = rhdPtr->scrnIndex; + Output->Id = outputType; + + Output->Sense = NULL; + Output->ModeValid = DigModeValid; + Output->Mode = DigMode; + Output->Power = DigPower; + Output->Save = DigSave; + Output->Restore = DigRestore; + Output->Destroy = DigDestroy; + Output->Property = DigPropertyControl; + Output->AllocFree = DigAllocFree; + + Private = xnfcalloc(sizeof(struct DIGPrivate), 1); + Output->Private = Private; + + Private->EncoderID = ENCODER_NONE; + + switch (outputType) { + case RHD_OUTPUT_UNIPHYA: +#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) + Output->Name = "UNIPHY_A"; + Private->Transmitter.Private = + (struct ATOMTransmitterPrivate *)xnfcalloc(sizeof (struct ATOMTransmitterPrivate), 1); + + Private->Transmitter.Sense = NULL; + Private->Transmitter.ModeValid = ATOMTransmitterModeValid; + Private->Transmitter.Mode = ATOMTransmitterSet; + Private->Transmitter.Power = ATOMTransmitterPower; + Private->Transmitter.Save = ATOMTransmitterSave; + Private->Transmitter.Restore = ATOMTransmitterRestore; + Private->Transmitter.Destroy = ATOMTransmitterDestroy; + Private->Transmitter.Property = TMDSTransmitterPropertyControl; + { + struct ATOMTransmitterPrivate *transPrivate = + (struct ATOMTransmitterPrivate *)Private->Transmitter.Private; + struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; + atc->Coherent = Private->Coherent = rhdDIGSetCoherent(rhdPtr, Output); + atc->Link = atomTransLinkA; + atc->Encoder = atomEncoderNone; + if (RHDIsIGP(rhdPtr->ChipSet)) { + AtomBiosArgRec data; + data.val = 1; + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, ATOM_GET_PCIE_LANES, + &data) == ATOM_SUCCESS) + atc->Lanes = data.pcieLanes.Chassis; /* only do 'chassis' for now */ + else { + xfree(Private); + xfree(Output); + return NULL; + } + } + if (RHDIsIGP(rhdPtr->ChipSet)) + transPrivate->atomTransmitterID = atomTransmitterPCIEPHY; + else + transPrivate->atomTransmitterID = atomTransmitterUNIPHY; + } + break; +#else + xfree(Private); + xfree(Output); + return NULL; +#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ + + case RHD_OUTPUT_UNIPHYB: +#if defined (ATOM_BIOS) && defined (ATOM_BIOS_PARSER) + Output->Name = "UNIPHY_B"; + Private->Transmitter.Private = + (struct atomTransmitterPrivate *)xnfcalloc(sizeof (struct ATOMTransmitterPrivate), 1); + + Private->Transmitter.Sense = NULL; + Private->Transmitter.ModeValid = ATOMTransmitterModeValid; + Private->Transmitter.Mode = ATOMTransmitterSet; + Private->Transmitter.Power = ATOMTransmitterPower; + Private->Transmitter.Save = ATOMTransmitterSave; + Private->Transmitter.Restore = ATOMTransmitterRestore; + Private->Transmitter.Destroy = ATOMTransmitterDestroy; + Private->Transmitter.Property = TMDSTransmitterPropertyControl; + { + struct ATOMTransmitterPrivate *transPrivate = + (struct ATOMTransmitterPrivate *)Private->Transmitter.Private; + struct atomTransmitterConfig *atc = &transPrivate->atomTransmitterConfig; + atc->Coherent = Private->Coherent = rhdDIGSetCoherent(rhdPtr, Output); + atc->Link = atomTransLinkB; + atc->Encoder = atomEncoderNone; + if (RHDIsIGP(rhdPtr->ChipSet)) { + AtomBiosArgRec data; + data.val = 2; + if (RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, ATOM_GET_PCIE_LANES, + &data) == ATOM_SUCCESS) + atc->Lanes = data.pcieLanes.Chassis; /* only do 'chassis' for now */ + else { + xfree(Private); + xfree(Output); + return NULL; + } + } + if (RHDIsIGP(rhdPtr->ChipSet)) + transPrivate->atomTransmitterID = atomTransmitterPCIEPHY; + else + transPrivate->atomTransmitterID = atomTransmitterUNIPHY; + } + break; +#else + xfree(Private); + xfree(Output); + return NULL; +#endif /* ATOM_BIOS && ATOM_BIOS_PARSER */ + + case RHD_OUTPUT_KLDSKP_LVTMA: + Output->Name = "UNIPHY_KLDSKP_LVTMA"; + Private->Coherent = rhdDIGSetCoherent(rhdPtr, Output); + Private->Transmitter.Private = + (struct LVTMATransmitterPrivate *)xnfcalloc(sizeof (struct LVTMATransmitterPrivate), 1); + + Private->Transmitter.Sense = NULL; + Private->Transmitter.ModeValid = LVTMATransmitterModeValid; + if (ConnectorType != RHD_CONNECTOR_PANEL) { + Private->Transmitter.Mode = LVTMA_TMDSTransmitterSet; + Private->Transmitter.Power = LVTMA_TMDSTransmitterPower; + Private->Transmitter.Save = LVTMA_TMDSTransmitterSave; + Private->Transmitter.Restore = LVTMA_TMDSTransmitterRestore; + } else { + Private->Transmitter.Mode = LVTMA_LVDSTransmitterSet; + Private->Transmitter.Power = LVTMA_LVDSTransmitterPower; + Private->Transmitter.Save = LVTMA_LVDSTransmitterSave; + Private->Transmitter.Restore = LVTMA_LVDSTransmitterRestore; + } + Private->Transmitter.Destroy = LVTMATransmitterDestroy; + if (ConnectorType == RHD_CONNECTOR_PANEL) + Private->Transmitter.Property = LVDSTransmitterPropertyControl; + else + Private->Transmitter.Property = TMDSTransmitterPropertyControl; + break; + + default: + xfree(Private); + xfree(Output); + return NULL; + } + + Encoder = (struct DIGEncoder *)(xnfcalloc(sizeof (struct DIGEncoder),1)); + Private->Encoder.Private = Encoder; + Private->Encoder.ModeValid = EncoderModeValid; + Private->Encoder.Mode = EncoderSet; + Private->Encoder.Power = EncoderPower; + Private->Encoder.Save = EncoderSave; + Private->Encoder.Restore = EncoderRestore; + Private->Encoder.Destroy = EncoderDestroy; + + switch (ConnectorType) { + case RHD_CONNECTOR_PANEL: + Private->EncoderMode = LVDS; + GetLVDSInfo(rhdPtr, Private); +#ifdef ATOM_BIOS +#ifdef NOT_YET + if (Private->BlLevel < 0) { + Private->BlLevel = RhdAtomSetupBacklightControlProperty(Output, + &Private->Transmitter.WrappedPropertyCallback, + &Private->Transmitter.PropertyPrivate); + if (Private->Transmitter.PropertyPrivate) + Private->Transmitter.Property = digTransmitterPropertyWrapper; + } +#endif +#endif + Private->Hdmi = NULL; + break; + case RHD_CONNECTOR_DVI: + Private->RunDualLink = FALSE; /* will be set later acc to pxclk */ + Private->EncoderMode = TMDS_DVI; + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + break; + case RHD_CONNECTOR_DVI_SINGLE: + Private->RunDualLink = FALSE; + Private->EncoderMode = TMDS_DVI; /* changed later to HDMI if aplicateable */ + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + break; + } + + return Output; +} diff --git a/programs/system/drivers/rhd/rhd_edid.c b/programs/system/drivers/rhd/rhd_edid.c new file mode 100644 index 000000000..fd2a93d05 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_edid.c @@ -0,0 +1,359 @@ +/* + * Copyright 2006-2007 Luc Verhaegen . + * + * 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, sub license, + * 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS 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 +#endif +#ifdef HAVE_XORG_CONFIG_H +# include +#endif + +#include "xf86.h" +#include "rhd.h" +#include "edid.h" +#include "xf86DDC.h" + +#include "rhd_modes.h" +#include "rhd_monitor.h" + +/* + * TODO: + * - for those with access to the VESA DMT standard; review please. + * - swap M_T_DEFAULT for M_T_EDID_... + */ +#define MODEPREFIX(name) NULL, NULL, name, 0,M_T_DRIVER +#define MODESUFFIX 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0 + +static DisplayModeRec EDIDEstablishedModes[17] = { + { MODEPREFIX("800x600"), 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@60Hz */ + { MODEPREFIX("800x600"), 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@56Hz */ + { MODEPREFIX("640x480"), 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@75Hz */ + { MODEPREFIX("640x480"), 31500, 640, 664, 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@72Hz */ + { MODEPREFIX("640x480"), 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@67Hz */ + { MODEPREFIX("640x480"), 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 640x480@60Hz */ + { MODEPREFIX("720x400"), 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 720x400@88Hz */ + { MODEPREFIX("720x400"), 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, V_NHSYNC | V_PVSYNC, MODESUFFIX }, /* 720x400@70Hz */ + { MODEPREFIX("1280x1024"), 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1280x1024@75Hz */ + { MODEPREFIX("1024x768"), 78800, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1024x768@75Hz */ + { MODEPREFIX("1024x768"), 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@70Hz */ + { MODEPREFIX("1024x768"), 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 1024x768@60Hz */ + { MODEPREFIX("1024x768"), 44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* 1024x768@43Hz */ + { MODEPREFIX("832x624"), 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* 832x624@75Hz */ + { MODEPREFIX("800x600"), 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@75Hz */ + { MODEPREFIX("800x600"), 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 800x600@72Hz */ + { MODEPREFIX("1152x864"), 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* 1152x864@75Hz */ +}; + +static DisplayModePtr +EDIDModesFromEstablished(RHDPtr rhdPtr, struct established_timings *timing) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + CARD32 bits = (timing->t1) | (timing->t2 << 8) | + ((timing->t_manu & 0x80) << 9); + int i; + + for (i = 0; i < 17; i++) + if (bits & (0x01 << i)) { + Mode = RHDModeCopy(&(EDIDEstablishedModes[i])); + Modes = RHDModesAdd(Modes, Mode); + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +EDIDModesFromStandardTiming(RHDPtr rhdPtr, struct std_timings *timing) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + int i; + + for (i = 0; i < STD_TIMINGS; i++) + if (timing[i].hsize && timing[i].vsize && timing[i].refresh) { + Mode = RHDCVTMode(timing[i].hsize, timing[i].vsize, + timing[i].refresh, FALSE, FALSE); + Mode->type = M_T_DRIVER; + Modes = RHDModesAdd(Modes, Mode); + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +EDIDModeFromDetailedTiming(RHDPtr rhdPtr, struct detailed_timings *timing) +{ + DisplayModePtr Mode; + int scrnIndex; + + /* We don't do stereo */ + if (timing->stereo) { + xf86DrvMsg(scrnIndex, X_INFO, "%s: Ignoring: We don't handle stereo.\n", + __func__); + return NULL; + } + + /* We only do separate sync currently */ + if (timing->sync != 0x03) { + xf86DrvMsg(scrnIndex, X_INFO, "%s: Ignoring: We only handle separate" + " sync.\n", __func__); + return NULL; + } + + Mode = xnfalloc(sizeof(DisplayModeRec)); + memset(Mode, 0, sizeof(DisplayModeRec)); + + Mode->name = xnfalloc(10); /* "1234x1234" */ + snprintf(Mode->name, 20, "%dx%d", timing->h_active, timing->v_active); + + Mode->type = M_T_DRIVER; + + Mode->Clock = timing->clock / 1000.0; + + Mode->HDisplay = timing->h_active; + Mode->HSyncStart = timing->h_active + timing->h_sync_off; + Mode->HSyncEnd = Mode->HSyncStart + timing->h_sync_width; + Mode->HTotal = timing->h_active + timing->h_blanking; + + Mode->VDisplay = timing->v_active; + Mode->VSyncStart = timing->v_active + timing->v_sync_off; + Mode->VSyncEnd = Mode->VSyncStart + timing->v_sync_width; + Mode->VTotal = timing->v_active + timing->v_blanking; + + /* We ignore h/v_size and h/v_border for now. */ + + if (timing->interlaced) + Mode->Flags |= V_INTERLACE; + + if (timing->misc & 0x02) + Mode->Flags |= V_PVSYNC; + else + Mode->Flags |= V_NVSYNC; + + if (timing->misc & 0x01) + Mode->Flags |= V_PHSYNC; + else + Mode->Flags |= V_NHSYNC; + + return Mode; +} + +/* + * + */ +static void +EDIDGuessRangesFromModes(struct rhdMonitor *Monitor, DisplayModePtr Modes) +{ + DisplayModePtr Mode = Modes; + + if (!Monitor || !Modes) + return; + + for (Mode = Modes; Mode; Mode = Mode->next) { + if (!Mode->HSync) + Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal); + + if (!Mode->VRefresh) { + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + if (Mode->Flags & V_INTERLACE) + Mode->VRefresh *= 2.0; + if (Mode->Flags & V_DBLSCAN) + Mode->VRefresh /= 2.0; + } + } + + if (!Monitor->numHSync) { + /* set up the ranges for scanning through the modes */ + Monitor->numHSync = 1; + Monitor->HSync[0].lo = 1024.0; + Monitor->HSync[0].hi = 0.0; + + for (Mode = Modes; Mode; Mode = Mode->next) { + if (Mode->HSync < Monitor->HSync[0].lo) + Monitor->HSync[0].lo = Mode->HSync; + + if (Mode->HSync > Monitor->HSync[0].hi) + Monitor->HSync[0].hi = Mode->HSync; + } + } + + + if (!Monitor->numVRefresh) { + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = 1024.0; + Monitor->VRefresh[0].hi = 0.0; + + for (Mode = Modes; Mode; Mode = Mode->next) { + if (Mode->VRefresh < Monitor->VRefresh[0].lo) + Monitor->VRefresh[0].lo = Mode->VRefresh; + + if (Mode->VRefresh > Monitor->VRefresh[0].hi) + Monitor->VRefresh[0].hi = Mode->VRefresh; + } + } + + if (!Monitor->Bandwidth) + for (Mode = Modes; Mode; Mode = Mode->next) + if (Mode->Clock > Monitor->Bandwidth) + Monitor->Bandwidth = Mode->Clock; +} + +/* + * Determine whether this monitor does allow reduced blanking. + * Do not set it to false, to allow the user to specify this too. + */ +static void +EDIDReducedAllowed(struct rhdMonitor *Monitor, DisplayModePtr Modes) +{ + DisplayModePtr Mode; + + for (Mode = Modes; Mode; Mode = Mode->next) + if (((Mode->HTotal - Mode->HDisplay) == 160) && + ((Mode->HSyncEnd - Mode->HDisplay) == 80) && + ((Mode->HSyncEnd - Mode->HSyncStart) == 32) && + ((Mode->VSyncStart - Mode->VDisplay) == 3)) + Monitor->ReducedAllowed = TRUE; +} + +/* + * Fill out rhdMonitor with xf86MonPtr information. + */ +void +RHDMonitorEDIDSet(struct rhdMonitor *Monitor, xf86MonPtr EDID) +{ + DisplayModePtr Modes = NULL, Mode; + int i, preferred; + + if (!Monitor || !EDID) + return; + + /* We don't parse the detailed name yet, so use ABC-0123 */ + Monitor->Name = xnfcalloc(9, 1); + snprintf(Monitor->Name, 9, "%s-%04X", EDID->vendor.name, + EDID->vendor.prod_id); + + /* Add established timings */ + Mode = EDIDModesFromEstablished(Monitor->scrnIndex, &EDID->timings1); + Modes = RHDModesAdd(Modes, Mode); + + /* Add standard timings */ + Mode = EDIDModesFromStandardTiming(Monitor->scrnIndex, EDID->timings2); + Modes = RHDModesAdd(Modes, Mode); + + /* First DT timing preferred? */ + preferred = PREFERRED_TIMING_MODE(EDID->features.msc); + + /* Go through the detailed monitor sections */ + for (i = 0; i < DET_TIMINGS; i++) + switch (EDID->det_mon[i].type) { + case DS_RANGES: + if (!Monitor->numHSync) { + Monitor->numHSync = 1; + Monitor->HSync[0].lo = EDID->det_mon[i].section.ranges.min_h; + Monitor->HSync[0].hi = EDID->det_mon[i].section.ranges.max_h; + } else + xf86DrvMsg(Monitor->scrnIndex, X_INFO, + "\"%s\": keeping configured HSync.\n", + Monitor->Name); + + if (!Monitor->numVRefresh) { + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = EDID->det_mon[i].section.ranges.min_v; + Monitor->VRefresh[0].hi = EDID->det_mon[i].section.ranges.max_v; + } else + xf86DrvMsg(Monitor->scrnIndex, X_INFO, + "\"%s\": keeping configured VRefresh.\n", + Monitor->Name); + + if (!Monitor->Bandwidth) + Monitor->Bandwidth = + EDID->det_mon[i].section.ranges.max_clock * 1000; + + break; + case DT: + Mode = EDIDModeFromDetailedTiming(Monitor->scrnIndex, + &EDID->det_mon[i].section.d_timings); + if (Mode) { + if (preferred) { + Mode->type |= M_T_PREFERRED; + + /* also grab the DPI while we are at it */ + Monitor->xDpi = (Mode->HDisplay * 25.4) / + ((float) EDID->det_mon[i].section.d_timings.h_size) + 0.5; + Monitor->yDpi = (Mode->VDisplay * 25.4) / + ((float) EDID->det_mon[i].section.d_timings.v_size) + 0.5; + + Monitor->NativeMode = Mode; + } + preferred = FALSE; + + Modes = RHDModesAdd(Modes, Mode); + } + break; + case DS_STD_TIMINGS: + Mode = EDIDModesFromStandardTiming(Monitor->scrnIndex, + EDID->det_mon[i].section.std_t); + Modes = RHDModesAdd(Modes, Mode); + break; + case DS_NAME: + xfree(Monitor->Name); + Monitor->Name = xnfcalloc(13, 1); + memcpy(Monitor->Name, EDID->det_mon[i].section.name, 13); + break; + default: + break; + } + + if (Modes) { + EDIDGuessRangesFromModes(Monitor, Modes); + EDIDReducedAllowed(Monitor, Modes); + Monitor->Modes = RHDModesAdd(Monitor->Modes, Modes); + } + + /* Calculate DPI when we still don't have this */ + if (!Monitor->xDpi || !Monitor->yDpi) { + int HDisplay = 0, VDisplay = 0; + + for (Mode = Monitor->Modes; Mode; Mode = Mode->next) { + if (Mode->HDisplay > HDisplay) + HDisplay = Mode->HDisplay; + if (Mode->VDisplay > VDisplay) + VDisplay = Mode->VDisplay; + } + + if (HDisplay && EDID->features.hsize) + Monitor->xDpi = (HDisplay * 2.54) / ((float) EDID->features.hsize) + 0.5; + if (VDisplay && EDID->features.vsize) + Monitor->yDpi = (VDisplay * 2.54) / ((float) EDID->features.vsize) + 0.5; + + if (!Monitor->xDpi && Monitor->yDpi) + Monitor->xDpi = Monitor->yDpi; + if (!Monitor->yDpi && Monitor->xDpi) + Monitor->yDpi = Monitor->xDpi; + } +} diff --git a/programs/system/drivers/rhd/rhd_hdmi.c b/programs/system/drivers/rhd/rhd_hdmi.c new file mode 100644 index 000000000..5bf329faf --- /dev/null +++ b/programs/system/drivers/rhd/rhd_hdmi.c @@ -0,0 +1,529 @@ +/* + * Copyright 2008 Christian König + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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 + +#include "xf86.h" + +#include "rhd.h" +#include "rhd_audio.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_hdmi.h" +#include "rhd_regs.h" + +enum HdmiColorFormat { + RGB = 0, + YCC_422 = 1, + YCC_444 = 2 +}; + +struct { + CARD32 Clock; + + int N_32kHz; + int CTS_32kHz; + + int N_44_1kHz; + int CTS_44_1kHz; + + int N_48kHz; + int CTS_48kHz; + +} AudioClockRegeneration[] = { + /* 32kHz 44.1kHz 48kHz */ + /* Clock N CTS N CTS N CTS */ + { 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */ + { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */ + { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */ + { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */ + { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */ + { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */ + { 74175, 11648, 210937, 17836, 234375, 11648, 140625 }, /* 74.25/1.001 MHz */ + { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */ + { 148351, 11648, 421875, 8918, 234375, 5824, 140625 }, /* 148.50/1.001 MHz */ + { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */ + { 0, 4096, 0, 6272, 0, 6144, 0 } /* Other */ +}; + +/* + * calculate CTS value if it's not found in the table + */ +static void +HdmiCalcCTS(struct rhdHdmi *hdmi, CARD32 Clock, int* CTS, int N, int freq) +{ + if(*CTS == 0) *CTS = Clock*1000*N/(128*freq); + xf86DrvMsg(hdmi->scrnIndex, X_INFO, "Using ACR timing N=%d CTS=%d for frequency %d\n",N,*CTS,freq); +} + +/* + * update the N and CTS parameters for a given clock rate + */ +static void +HdmiAudioClockRegeneration(struct rhdHdmi *hdmi, CARD32 Clock) +{ + int CTS; + int N; + int i; + for(i=0; AudioClockRegeneration[i].Clock != Clock && AudioClockRegeneration[i].Clock != 0; i++); + + CTS = AudioClockRegeneration[i].CTS_32kHz; + N = AudioClockRegeneration[i].N_32kHz; + HdmiCalcCTS(hdmi, Clock, &CTS, N, 32000); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_32kHz_CTS, CTS << 12); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_32kHz_N, N); + + CTS = AudioClockRegeneration[i].CTS_44_1kHz; + N = AudioClockRegeneration[i].N_44_1kHz; + HdmiCalcCTS(hdmi, Clock, &CTS, N, 44100); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_44_1kHz_CTS, CTS << 12); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_44_1kHz_N, N); + + CTS = AudioClockRegeneration[i].CTS_48kHz; + N = AudioClockRegeneration[i].N_48kHz; + HdmiCalcCTS(hdmi, Clock, &CTS, N, 48000); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_48kHz_CTS, CTS << 12); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_48kHz_N, N); +} + +/* + * calculate the crc for a given info frame + */ +static void +HdmiInfoFrameChecksum(CARD8 packetType, CARD8 versionNumber, CARD8 length, CARD8* frame) +{ + int i; + frame[0] = packetType + versionNumber + length; + for(i=1;i<=length;i++) + frame[0] += frame[i]; + frame[0] = 0x100 - frame[0]; +} + +/* + * build a HDMI Video Info Frame + */ +static void +HdmiVideoInfoFrame( + struct rhdHdmi *hdmi, + enum HdmiColorFormat ColorFormat, + Bool ActiveInformationPresent, + CARD8 ActiveFormatAspectRatio, + CARD8 ScanInformation, + CARD8 Colorimetry, + CARD8 ExColorimetry, + CARD8 Quantization, + Bool ITC, + CARD8 PictureAspectRatio, + CARD8 VideoFormatIdentification, + CARD8 PixelRepetition, + CARD8 NonUniformPictureScaling, + CARD8 BarInfoDataValid, + CARD16 TopBar, + CARD16 BottomBar, + CARD16 LeftBar, + CARD16 RightBar +) +{ + CARD8 frame[14]; + + frame[0x0] = 0; + frame[0x1] = + (ScanInformation & 0x3) | + ((BarInfoDataValid & 0x3) << 2) | + ((ActiveInformationPresent & 0x1) << 4) | + ((ColorFormat & 0x3) << 5); + frame[0x2] = + (ActiveFormatAspectRatio & 0xF) | + ((PictureAspectRatio & 0x3) << 4) | + ((Colorimetry & 0x3) << 6); + frame[0x3] = + (NonUniformPictureScaling & 0x3) | + ((Quantization & 0x3) << 2) | + ((ExColorimetry & 0x7) << 4) | + ((ITC & 0x1) << 7); + frame[0x4] = (VideoFormatIdentification & 0x7F); + frame[0x5] = (PixelRepetition & 0xF); + frame[0x6] = (TopBar & 0xFF); + frame[0x7] = (TopBar >> 8); + frame[0x8] = (BottomBar & 0xFF); + frame[0x9] = (BottomBar >> 8); + frame[0xA] = (LeftBar & 0xFF); + frame[0xB] = (LeftBar >> 8); + frame[0xC] = (RightBar & 0xFF); + frame[0xD] = (RightBar >> 8); + + HdmiInfoFrameChecksum(0x82, 0x02, 0x0D, frame); + + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0, + frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1, + frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24)); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2, + frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24)); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3, + frame[0xC] | (frame[0xD] << 8)); +} + +/* + * build a Audio Info Frame + */ +static void +HdmiAudioInfoFrame( + struct rhdHdmi *hdmi, + CARD8 ChannelCount, + CARD8 CodingType, + CARD8 SampleSize, + CARD8 SampleFrequency, + CARD8 Format, + CARD8 ChannelAllocation, + CARD8 LevelShift, + Bool DownmixInhibit +) +{ + CARD8 frame[11]; + + frame[0x0] = 0; + frame[0x1] = (ChannelCount & 0x7) | ((CodingType & 0xF) << 4); + frame[0x2] = (SampleSize & 0x3) | ((SampleFrequency & 0x7) << 2); + frame[0x3] = Format; + frame[0x4] = ChannelAllocation; + frame[0x5] = ((LevelShift & 0xF) << 3) | ((DownmixInhibit & 0x1) << 7); + frame[0x6] = 0; + frame[0x7] = 0; + frame[0x8] = 0; + frame[0x9] = 0; + frame[0xA] = 0; + + HdmiInfoFrameChecksum(0x84, 0x01, 0x0A, frame); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0, + frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1, + frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24)); +} + +/* + * it's unknown what these bits do excatly, but it's indeed quite usefull for debugging + */ +static void +HdmiAudioDebugWorkaround(struct rhdHdmi* hdmi, Bool Enable) +{ + if(Enable) { + RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x1000, 0x1000); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG, 0xffffff); + } else { + RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0, 0x1000); + } +} + +/* + * allocate/initialize the HDMI structure + * and register with audio engine + * output selects which engine is used + */ +struct rhdHdmi* +RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output) +{ + struct rhdHdmi *hdmi; + RHDFUNC(rhdPtr); + + if(rhdPtr->ChipSet >= RHD_R600) { + hdmi = (struct rhdHdmi *) xnfcalloc(sizeof(struct rhdHdmi), 1); + hdmi->scrnIndex = rhdPtr->scrnIndex; + hdmi->Output = Output; + switch(Output->Id) { + case RHD_OUTPUT_TMDSA: + hdmi->Offset = HDMI_TMDS; + break; + + case RHD_OUTPUT_LVTMA: + hdmi->Offset = HDMI_LVTMA; + break; + + case RHD_OUTPUT_UNIPHYA: + hdmi->Offset = HDMI_TMDS; + break; + + case RHD_OUTPUT_KLDSKP_LVTMA: + hdmi->Offset = HDMI_DIG; + break; + + /*case RHD_OUTPUT_UNIPHYB: */ + + default: + xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__); + xfree(hdmi); + return NULL; + break; + } + hdmi->Stored = FALSE; +// RHDAudioRegisterHdmi(rhdPtr, hdmi); + return hdmi; + } else + return NULL; +} + +/* + * update the info frames with the data from the current display mode + */ +void +RHDHdmiSetMode(struct rhdHdmi *hdmi, DisplayModePtr Mode) +{ + if(!hdmi) return; + RHDFUNC(hdmi); + +// RHDAudioSetClock(RHDPTRI(hdmi), hdmi->Output, Mode->Clock); + + HdmiAudioDebugWorkaround(hdmi, FALSE); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, 0x1000); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, 0x0); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, 0x1000); + + HdmiAudioClockRegeneration(hdmi, Mode->Clock); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOCNTL, 0x13); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VERSION, 0x202); + + HdmiVideoInfoFrame(hdmi, RGB, FALSE, 0, 0, 0, + 0, 0, FALSE, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + /* audio packets per line, does anyone know how to calc this ? */ + RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x020000, 0x1F0000); + + /* update? reset? don't realy know */ + RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x14000000, 0x14000000); +} + +/* + * update settings whith current parameters from audio engine + */ +void +RHDHdmiUpdateAudioSettings( + struct rhdHdmi* hdmi, + Bool playing, + int channels, + int rate, + int bps, + CARD8 status_bits, + CARD8 category_code +) +{ + CARD32 iec; + + if(!hdmi) return; + RHDFUNC(hdmi); + + xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: %s with " + "%d channels, %d Hz sampling rate, %d bits per sample,\n", + __func__, playing ? "playing" : "stoped", channels, rate, bps); + xf86DrvMsg(hdmi->scrnIndex, X_INFO, "%s: " + "0x%02x IEC60958 status bits and 0x%02x category code\n", + __func__, (int)status_bits, (int)category_code); + + /* start delivering audio frames */ + RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, playing ? 1 : 0, 0x1); + + iec = 0; + if(status_bits & AUDIO_STATUS_PROFESSIONAL) iec |= 1 << 0; + if(status_bits & AUDIO_STATUS_NONAUDIO) iec |= 1 << 1; + if(status_bits & AUDIO_STATUS_COPYRIGHT) iec |= 1 << 2; + if(status_bits & AUDIO_STATUS_EMPHASIS) iec |= 1 << 3; + + iec |= category_code << 8; + + switch(rate) + { + case 32000: iec |= 0x3 << 24; break; + case 44100: iec |= 0x0 << 24; break; + case 88200: iec |= 0x8 << 24; break; + case 176400: iec |= 0xc << 24; break; + case 48000: iec |= 0x2 << 24; break; + case 96000: iec |= 0xa << 24; break; + case 192000: iec |= 0xe << 24; break; + } + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_IEC60958_1, iec); + + iec = 0; + switch(bps) + { + case 16: iec |= 0x2; break; + case 20: iec |= 0x3; break; + case 24: iec |= 0xb; break; + } + if(status_bits & AUDIO_STATUS_V) iec |= 0x5 << 16; + + RHDRegMask(hdmi, hdmi->Offset+HDMI_IEC60958_2, iec, 0x5000f); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOCNTL, 0x31); + HdmiAudioInfoFrame(hdmi, channels-1, 0, 0, 0, 0, 0, 0, FALSE); + + RHDRegMask(hdmi, hdmi->Offset+HDMI_CNTL, 0x400000, 0x400000); +} + +/* + * enable/disable the HDMI engine + */ +void +RHDHdmiEnable(struct rhdHdmi *hdmi, Bool Enable) +{ + if(!hdmi) return; + RHDFUNC(hdmi); + + /* some version of atombios ignore the enable HDMI flag + * so enabling/disabling HDMI was moved here for TMDSA and LVTMA */ + switch(hdmi->Output->Id) { + case RHD_OUTPUT_TMDSA: + RHDRegMask(hdmi, TMDSA_CNTL, Enable ? 0x4 : 0x0, 0x4); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, Enable ? 0x101 : 0x0); + break; + + case RHD_OUTPUT_LVTMA: + RHDRegMask(hdmi, LVTMA_CNTL, Enable ? 0x4 : 0x0, 0x4); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, Enable ? 0x105 : 0x0); + break; + + case RHD_OUTPUT_UNIPHYA: + case RHD_OUTPUT_UNIPHYB: + case RHD_OUTPUT_KLDSKP_LVTMA: + RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, Enable ? 0x110 : 0x0); + break; + + default: + xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: unknown HDMI output type\n", __func__); + break; + } +} + +/* + * save the current config of HDMI engine + */ +void +RHDHdmiSave(struct rhdHdmi *hdmi) +{ + if(!hdmi) return; + RHDFUNC(hdmi); + + hdmi->StoreEnable = RHDRegRead(hdmi, hdmi->Offset+HDMI_ENABLE); + hdmi->StoreControl = RHDRegRead(hdmi, hdmi->Offset+HDMI_CNTL); + hdmi->StoredAudioDebugWorkaround = RHDRegRead(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG); + + hdmi->StoredFrameVersion = RHDRegRead(hdmi, hdmi->Offset+HDMI_VERSION); + + hdmi->StoredVideoControl = RHDRegRead(hdmi, hdmi->Offset+HDMI_VIDEOCNTL); + hdmi->StoreVideoInfoFrame[0x0] = RHDRegRead(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0); + hdmi->StoreVideoInfoFrame[0x1] = RHDRegRead(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1); + hdmi->StoreVideoInfoFrame[0x2] = RHDRegRead(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2); + hdmi->StoreVideoInfoFrame[0x3] = RHDRegRead(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3); + + hdmi->StoredAudioControl = RHDRegRead(hdmi, hdmi->Offset+HDMI_AUDIOCNTL); + hdmi->StoreAudioInfoFrame[0x0] = RHDRegRead(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0); + hdmi->StoreAudioInfoFrame[0x1] = RHDRegRead(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1); + + hdmi->Store_32kHz_N = RHDRegRead(hdmi, hdmi->Offset+HDMI_32kHz_N); + hdmi->Store_32kHz_CTS = RHDRegRead(hdmi, hdmi->Offset+HDMI_32kHz_CTS); + + hdmi->Store_44_1kHz_N = RHDRegRead(hdmi, hdmi->Offset+HDMI_44_1kHz_N); + hdmi->Store_44_1kHz_CTS = RHDRegRead(hdmi, hdmi->Offset+HDMI_44_1kHz_CTS); + + hdmi->Store_48kHz_N = RHDRegRead(hdmi, hdmi->Offset+HDMI_48kHz_N); + hdmi->Store_48kHz_CTS = RHDRegRead(hdmi, hdmi->Offset+HDMI_48kHz_CTS); + + hdmi->StoreIEC60958[0] = RHDRegRead(hdmi, hdmi->Offset+HDMI_IEC60958_1); + hdmi->StoreIEC60958[1] = RHDRegRead(hdmi, hdmi->Offset+HDMI_IEC60958_2); + + hdmi->StoreUnknown[0x0] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_0); + hdmi->StoreUnknown[0x1] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_1); + hdmi->StoreUnknown[0x2] = RHDRegRead(hdmi, hdmi->Offset+HDMI_UNKNOWN_2); + + hdmi->Stored = TRUE; +} + +/* + * restore the saved config of HDMI engine + */ +void +RHDHdmiRestore(struct rhdHdmi *hdmi) +{ + if(!hdmi) return; + RHDFUNC(hdmi); + + if (!hdmi->Stored) { + xf86DrvMsg(hdmi->scrnIndex, X_ERROR, "%s: trying to restore " + "uninitialized values.\n", __func__); + return; + } + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_ENABLE, hdmi->StoreEnable); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_CNTL, hdmi->StoreControl); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIO_DEBUG, hdmi->StoredAudioDebugWorkaround); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VERSION, hdmi->StoredFrameVersion); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOCNTL, hdmi->StoredVideoControl); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_0, hdmi->StoreVideoInfoFrame[0x0]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_1, hdmi->StoreVideoInfoFrame[0x1]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_2, hdmi->StoreVideoInfoFrame[0x2]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_VIDEOINFOFRAME_3, hdmi->StoreVideoInfoFrame[0x3]); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOCNTL, hdmi->StoredAudioControl); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_0, hdmi->StoreAudioInfoFrame[0x0]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_AUDIOINFOFRAME_1, hdmi->StoreAudioInfoFrame[0x1]); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_32kHz_N, hdmi->Store_32kHz_N); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_32kHz_CTS, hdmi->Store_32kHz_CTS); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_44_1kHz_N, hdmi->Store_44_1kHz_N); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_44_1kHz_CTS, hdmi->Store_44_1kHz_CTS); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_48kHz_N, hdmi->Store_48kHz_N); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_48kHz_CTS, hdmi->Store_48kHz_CTS); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_IEC60958_1, hdmi->StoreIEC60958[0]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_IEC60958_2, hdmi->StoreIEC60958[1]); + + RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_0, hdmi->StoreUnknown[0x0]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_1, hdmi->StoreUnknown[0x1]); + RHDRegWrite(hdmi, hdmi->Offset+HDMI_UNKNOWN_2, hdmi->StoreUnknown[0x2]); +} + +/* + * unregister with audio engine and release memory + */ +void +RHDHdmiDestroy(struct rhdHdmi *hdmi) +{ + if(!hdmi) return; + RHDFUNC(hdmi); + +// RHDAudioUnregisterHdmi(RHDPTRI(hdmi), hdmi); + + xfree(hdmi); +} diff --git a/programs/system/drivers/rhd/rhd_hdmi.h b/programs/system/drivers/rhd/rhd_hdmi.h new file mode 100644 index 000000000..7518a1372 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_hdmi.h @@ -0,0 +1,81 @@ +/* + * Copyright 2008 Christian König + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_HDMI_H +#define _RHD_HDMI_H + +struct rhdHdmi { + struct rhdHdmi* Next; + + int scrnIndex; + + struct rhdOutput* Output; + CARD16 Offset; + + Bool Stored; + CARD32 StoreEnable; + CARD32 StoreControl; + CARD32 StoreUnknown[0x3]; + CARD32 StoredAudioDebugWorkaround; + + CARD32 StoredFrameVersion; + CARD32 StoredVideoControl; + CARD32 StoreVideoInfoFrame[0x4]; + CARD32 StoredAudioControl; + CARD32 StoreAudioInfoFrame[0x2]; + + CARD32 Store_32kHz_N; + CARD32 Store_32kHz_CTS; + + CARD32 Store_44_1kHz_N; + CARD32 Store_44_1kHz_CTS; + + CARD32 Store_48kHz_N; + CARD32 Store_48kHz_CTS; + + CARD32 StoreIEC60958[2]; +}; + +struct rhdHdmi* RHDHdmiInit(RHDPtr rhdPtr, struct rhdOutput* Output); + +void RHDHdmiSetMode(struct rhdHdmi* rhdHdmi, DisplayModePtr Mode); +void RHDHdmiEnable(struct rhdHdmi* rhdHdmi, Bool Enable); +void RHDHdmiUpdateAudioSettings( + struct rhdHdmi* rhdHdmi, + Bool playing, + int channels, + int rate, + int bps, + CARD8 status_bits, + CARD8 catgory_code +); + +void RHDHdmiSave(struct rhdHdmi* rhdHdmi); +void RHDHdmiRestore(struct rhdHdmi* rhdHdmi); + +void RHDHdmiDestroy(struct rhdHdmi* rhdHdmi); + +#endif /* _RHD_HDMI_H */ diff --git a/programs/system/drivers/rhd/rhd_i2c.c b/programs/system/drivers/rhd/rhd_i2c.c new file mode 100644 index 000000000..83e889d7c --- /dev/null +++ b/programs/system/drivers/rhd/rhd_i2c.c @@ -0,0 +1,1452 @@ +/* + * Copyright 2007, 2008 Egbert Eich + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * 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 +#include "xf86.h" +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +# include +#endif + +#include "rhd.h" +#include "edid.h" +#include "rhd_i2c.h" +#include "xf86DDC.h" + +#include "rhd_regs.h" + +#ifdef ATOM_BIOS +#include "rhd_atombios.h" +#endif + +#define MAX_I2C_LINES 6 + +#define RHD_I2C_STATUS_LOOPS 5000 + +enum rhdDDClines { + rhdDdc1data = 0, + rhdDdc2data = 2, + rhdDdc3data = 4, + rhdDdc4data = 6, /* arbirarily choosen */ + rhdVIP_DOUT_scl = 0x41, + rhdDvoData12 = 0x28, + rhdDdc5data = 0x48, + rhdDdc6data = 0x4a, + rhdDdc1clk = 1, + rhdDdc2clk = 3, + rhdDdc3clk = 5, + rhdDdc4clk = 7, /* arbirarily choosen */ + rhdVIP_DOUTvipclk = 0x42, + rhdDvoData13 = 0x29, + rhdDdc5clk = 0x49, + rhdDdc6clk = 0x4b, + rhdDdcUnknown +}; + +typedef struct _rhdI2CRec +{ + CARD16 prescale; + union { + CARD8 line; + struct i2cGpio { + enum rhdDDClines Sda; + enum rhdDDClines Scl; + CARD32 SdaReg; + CARD32 SclReg; + } Gpio; + } u; + int scrnIndex; +} rhdI2CRec; + +enum _rhdR6xxI2CBits { + /* R6_DC_I2C_TRANSACTION0 */ + R6_DC_I2C_RW0 = (0x1 << 0), + R6_DC_I2C_STOP_ON_NACK0 = (0x1 << 8), + R6_DC_I2C_ACK_ON_READ0 = (0x1 << 9), + R6_DC_I2C_START0 = (0x1 << 12), + R6_DC_I2C_STOP0 = (0x1 << 13), + R6_DC_I2C_COUNT0 = (0xff << 16), + /* R6_DC_I2C_TRANSACTION1 */ + R6_DC_I2C_RW1 = (0x1 << 0), + R6_DC_I2C_STOP_ON_NACK1 = (0x1 << 8), + R6_DC_I2C_ACK_ON_READ1 = (0x1 << 9), + R6_DC_I2C_START1 = (0x1 << 12), + R6_DC_I2C_STOP1 = (0x1 << 13), + R6_DC_I2C_COUNT1 = (0xff << 16), + /* R6_DC_I2C_DATA */ + R6_DC_I2C_DATA_RW = (0x1 << 0), + R6_DC_I2C_DATA_BIT = (0xff << 8), + R6_DC_I2C_INDEX = (0xff << 16), + R6_DC_I2C_INDEX_WRITE = (0x1 << 31), + /* R6_DC_I2C_CONTROL */ + R6_DC_I2C_GO = (0x1 << 0), + R6_DC_I2C_SOFT_RESET = (0x1 << 1), + R6_DC_I2C_SEND_RESET = (0x1 << 2), + R6_DC_I2C_SW_STATUS_RESET = (0x1 << 3), + R6_DC_I2C_SDVO_EN = (0x1 << 4), + R6_DC_I2C_SDVO_ADDR_SEL = (0x1 << 6), + R6_DC_I2C_DDC_SELECT = (0x7 << 8), + R6_DC_I2C_TRANSACTION_COUNT = (0x3 << 20), + R6_DC_I2C_SW_DONE_INT = (0x1 << 0), + R6_DC_I2C_SW_DONE_ACK = (0x1 << 1), + R6_DC_I2C_SW_DONE_MASK = (0x1 << 2), + R6_DC_I2C_DDC1_HW_DONE_INT = (0x1 << 4), + R6_DC_I2C_DDC1_HW_DONE_ACK = (0x1 << 5), + R6_DC_I2C_DDC1_HW_DONE_MASK = (0x1 << 6), + R6_DC_I2C_DDC2_HW_DONE_INT = (0x1 << 8), + R6_DC_I2C_DDC2_HW_DONE_ACK = (0x1 << 9), + R6_DC_I2C_DDC2_HW_DONE_MASK = (0x1 << 10), + R6_DC_I2C_DDC3_HW_DONE_INT = (0x1 << 12), + R6_DC_I2C_DDC3_HW_DONE_ACK = (0x1 << 13), + R6_DC_I2C_DDC3_HW_DONE_MASK = (0x1 << 14), + R6_DC_I2C_DDC4_HW_DONE_INT = (0x1 << 16), + R6_DC_I2C_DDC4_HW_DONE_ACK = (0x1 << 17), + R6_DC_I2C_DDC4_HW_DONE_MASK = (0x1 << 18), + /* R6_DC_I2C_SW_STATUS */ + R6_DC_I2C_SW_STATUS_BIT = (0x3 << 0), + R6_DC_I2C_SW_DONE = (0x1 << 2), + R6_DC_I2C_SW_ABORTED = (0x1 << 4), + R6_DC_I2C_SW_TIMEOUT = (0x1 << 5), + R6_DC_I2C_SW_INTERRUPTED = (0x1 << 6), + R6_DC_I2C_SW_BUFFER_OVERFLOW = (0x1 << 7), + R6_DC_I2C_SW_STOPPED_ON_NACK = (0x1 << 8), + R6_DC_I2C_SW_SDVO_NACK = (0x1 << 10), + R6_DC_I2C_SW_NACK0 = (0x1 << 12), + R6_DC_I2C_SW_NACK1 = (0x1 << 13), + R6_DC_I2C_SW_NACK2 = (0x1 << 14), + R6_DC_I2C_SW_NACK3 = (0x1 << 15), + R6_DC_I2C_SW_REQ = (0x1 << 18) +}; + +enum _rhdR5xxI2CBits { + /* R5_DC_I2C_STATUS1 */ + R5_DC_I2C_DONE = (0x1 << 0), + R5_DC_I2C_NACK = (0x1 << 1), + R5_DC_I2C_HALT = (0x1 << 2), + R5_DC_I2C_GO = (0x1 << 3), + /* R5_DC_I2C_RESET */ + R5_DC_I2C_SOFT_RESET = (0x1 << 0), + R5_DC_I2C_ABORT = (0x1 << 8), + /* R5_DC_I2C_CONTROL1 */ + R5_DC_I2C_START = (0x1 << 0), + R5_DC_I2C_STOP = (0x1 << 1), + R5_DC_I2C_RECEIVE = (0x1 << 2), + R5_DC_I2C_EN = (0x1 << 8), + R5_DC_I2C_PIN_SELECT = (0x3 << 16), + /* R5_DC_I2C_CONTROL2 */ + R5_DC_I2C_ADDR_COUNT = (0x7 << 0), + R5_DC_I2C_DATA_COUNT = (0xf << 8), + R5_DC_I2C_PRESCALE_LOWER = (0xff << 16), + R5_DC_I2C_PRESCALE_UPPER = (0xff << 24), + /* R5_DC_I2C_CONTROL3 */ + R5_DC_I2C_DATA_DRIVE_EN = (0x1 << 0), + R5_DC_I2C_DATA_DRIVE_SEL = (0x1 << 1), + R5_DC_I2C_CLK_DRIVE_EN = (0x1 << 7), + R5_DC_I2C_RD_INTRA_BYTE_DELAY = (0xff << 8), + R5_DC_I2C_WR_INTRA_BYTE_DELAY = (0xff << 16), + R5_DC_I2C_TIME_LIMIT = (0xff << 24), + /* R5_DC_I2C_DATA */ + R5_DC_I2C_DATA_BIT = (0xff << 0), + /* R5_DC_I2C_INTERRUPT_CONTROL */ + R5_DC_I2C_INTERRUPT_STATUS = (0x1 << 0), + R5_DC_I2C_INTERRUPT_AK = (0x1 << 8), + R5_DC_I2C_INTERRUPT_ENABLE = (0x1 << 16), + /* R5_DC_I2C_ARBITRATION */ + R5_DC_I2C_SW_WANTS_TO_USE_I2C = (0x1 << 0), + R5_DC_I2C_SW_CAN_USE_I2C = (0x1 << 1), + R5_DC_I2C_SW_DONE_USING_I2C = (0x1 << 8), + R5_DC_I2C_HW_NEEDS_I2C = (0x1 << 9), + R5_DC_I2C_ABORT_HDCP_I2C = (0x1 << 16), + R5_DC_I2C_HW_USING_I2C = (0x1 << 17) +}; + +enum _rhdRS69I2CBits { + /* RS69_DC_I2C_TRANSACTION0 */ + RS69_DC_I2C_RW0 = (0x1 << 0), + RS69_DC_I2C_STOP_ON_NACK0 = (0x1 << 8), + RS69_DC_I2C_START0 = (0x1 << 12), + RS69_DC_I2C_STOP0 = (0x1 << 13), + /* RS69_DC_I2C_TRANSACTION1 */ + RS69_DC_I2C_RW1 = (0x1 << 0), + RS69_DC_I2C_START1 = (0x1 << 12), + RS69_DC_I2C_STOP1 = (0x1 << 13), + /* RS69_DC_I2C_DATA */ + RS69_DC_I2C_DATA_RW = (0x1 << 0), + RS69_DC_I2C_INDEX_WRITE = (0x1 << 31), + /* RS69_DC_I2C_CONTROL */ + RS69_DC_I2C_GO = (0x1 << 0), + RS69_DC_I2C_TRANSACTION_COUNT = (0x3 << 20), + RS69_DC_I2C_SW_DONE_ACK = (0x1 << 1), + /* RS69_DC_I2C_SW_STATUS */ + RS69_DC_I2C_SW_DONE = (0x1 << 2), + RS69_DC_I2C_SW_ABORTED = (0x1 << 4), + RS69_DC_I2C_SW_TIMEOUT = (0x1 << 5), + RS69_DC_I2C_SW_INTERRUPTED= (0x1 << 6), + RS69_DC_I2C_SW_BUFFER_OVERFLOW= (0x1 << 7), + RS69_DC_I2C_SW_STOPPED_ON_NACK = (0x1 << 8), + RS69_DC_I2C_SW_NACK0 = (0x1 << 12), + RS69_DC_I2C_SW_NACK1 = (0x1 << 13) +}; + +/* RV620 */ +enum rv620I2CBits { + /* GENERIC_I2C_CONTROL */ + RV62_DC_I2C_GO = (0x1 << 0), + RV62_GENERIC_I2C_GO = (0x1 << 0), + RV62_GENERIC_I2C_SOFT_RESET = (0x1 << 1), + RV62_GENERIC_I2C_SEND_RESET = (0x1 << 2), + /* GENERIC_I2C_INTERRUPT_CONTROL */ + RV62_GENERIC_I2C_DONE_INT = (0x1 << 0), + RV62_GENERIC_I2C_DONE_ACK = (0x1 << 1), + RV62_GENERIC_I2C_DONE_MASK = (0x1 << 2), + /* GENERIC_I2C_STATUS */ + RV62_GENERIC_I2C_STATUS_BIT = (0xf << 0), + RV62_GENERIC_I2C_DONE = (0x1 << 4), + RV62_GENERIC_I2C_ABORTED = (0x1 << 5), + RV62_GENERIC_I2C_TIMEOUT = (0x1 << 6), + RV62_GENERIC_I2C_STOPPED_ON_NACK = (0x1 << 9), + RV62_GENERIC_I2C_NACK = (0x1 << 10), + /* GENERIC_I2C_SPEED */ + RV62_GENERIC_I2C_THRESHOLD = (0x3 << 0), + RV62_GENERIC_I2C_DISABLE_FILTER_DURING_STALL = (0x1 << 4), + RV62_GENERIC_I2C_PRESCALE = (0xffff << 16), + /* GENERIC_I2C_SETUP */ + RV62_GENERIC_I2C_DATA_DRIVE_EN = (0x1 << 0), + RV62_GENERIC_I2C_DATA_DRIVE_SEL = (0x1 << 1), + RV62_GENERIC_I2C_CLK_DRIVE_EN = (0x1 << 7), + RV62_GENERIC_I2C_INTRA_BYTE_DELAY = (0xff << 8), + RV62_GENERIC_I2C_TIME_LIMIT = (0xff << 24), + /* GENERIC_I2C_TRANSACTION */ + RV62_GENERIC_I2C_RW = (0x1 << 0), + RV62_GENERIC_I2C_STOP_ON_NACK = (0x1 << 8), + RV62_GENERIC_I2C_ACK_ON_READ = (0x1 << 9), + RV62_GENERIC_I2C_START = (0x1 << 12), + RV62_GENERIC_I2C_STOP = (0x1 << 13), + RV62_GENERIC_I2C_COUNT = (0xf << 16), + /* GENERIC_I2C_DATA */ + RV62_GENERIC_I2C_DATA_RW = (0x1 << 0), + RV62_GENERIC_I2C_DATA_BIT = (0xff << 8), + RV62_GENERIC_I2C_INDEX = (0xf << 16), + RV62_GENERIC_I2C_INDEX_WRITE = (0x1 << 31), + /* GENERIC_I2C_PIN_SELECTION */ + RV62_GENERIC_I2C_SCL_PIN_SEL_SHIFT = 0, + RV62_GENERIC_I2C_SCL_PIN_SEL = (0x7f << RV62_GENERIC_I2C_SCL_PIN_SEL_SHIFT), + RV62_GENERIC_I2C_SDA_PIN_SEL_SHIFT = 8, + RV62_GENERIC_I2C_SDA_PIN_SEL = (0x7f << RV62_GENERIC_I2C_SDA_PIN_SEL_SHIFT) +}; + +/* + * + */ +static enum rhdDDClines +getDDCLineFromGPIO(int scrnIndex, CARD32 gpio, int shift) +{ + switch (gpio) { + case 0x1f90: + switch (shift) { + case 0: + return rhdDdc1clk; /* ddc1 clk */ + case 8: + return rhdDdc1data; /* ddc1 data */ + } + break; + case 0x1f94: /* ddc2 */ + switch (shift) { + case 0: + return rhdDdc2clk; /* ddc2 clk */ + case 8: + return rhdDdc2data; /* ddc2 data */ + } + break; + case 0x1f98: /* ddc3 */ + switch (shift) { + case 0: + return rhdDdc3clk; /* ddc3 clk */ + case 8: + return rhdDdc3data; /* ddc3 data */ + } + case 0x1f80: /* ddc4 - on r6xx */ + switch (shift) { + case 0: + return rhdDdc4clk; /* ddc4 clk */ + case 8: + return rhdDdc4data; /* ddc4 data */ + } + break; + case 0x1f88: /* ddc5 */ + switch (shift) { + case 0: + return rhdVIP_DOUTvipclk; /* ddc5 clk */ + case 8: + return rhdVIP_DOUT_scl; /* ddc5 data */ + } + break; + case 0x1fda: /* ddc6 */ + switch (shift) { + case 0: + return rhdDvoData13; /* ddc6 clk */ + case 1: + return rhdDvoData12; /* ddc6 data */ + } + break; + case 0x1fc4: + switch (shift) { + case 0: + return rhdDdc5clk; + case 8: + return rhdDdc5data; + } + break; + case 0x1fe8: /* ddc6 */ + switch (shift) { + case 0: + return rhdDdc6clk; /* ddc6 clk */ + case 8: + return rhdDdc6data; /* ddc6 data */ + } + break; + } + + xf86DrvMsg(scrnIndex, X_WARNING, + "%s: Failed to match GPIO 0x%04X.%d with a known DDC line\n", + __func__, (unsigned int) gpio, shift); + return rhdDdcUnknown; +} + +/* + * + */ +static Bool +rhdI2CGetDataClkLines(RHDPtr rhdPtr, int line, + enum rhdDDClines *scl, enum rhdDDClines *sda, + CARD32 *sda_reg, CARD32 *scl_reg) +{ +#ifdef ATOM_BIOS + AtomBiosResult result; + AtomBiosArgRec data; + + /* scl register */ + data.val = line & 0x0f; + result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GPIO_I2C_CLK_MASK, &data); + if (result != ATOM_SUCCESS) + return FALSE; + *scl_reg = data.val; + + /* scl DDC line */ + data.val = line & 0x0f; + result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GPIO_I2C_CLK_MASK_SHIFT, &data); + if (result != ATOM_SUCCESS) + return FALSE; + *scl = getDDCLineFromGPIO(rhdPtr->scrnIndex, *scl_reg, data.val); + + /* sda register */ + data.val = line & 0x0f; + result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GPIO_I2C_DATA_MASK, &data); + if (result != ATOM_SUCCESS) + return FALSE; + *sda_reg = data.val; + + /* sda DDC line */ + data.val = line & 0x0f; + result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GPIO_I2C_DATA_MASK_SHIFT, &data); + if (result != ATOM_SUCCESS) + return FALSE; + *sda = getDDCLineFromGPIO(rhdPtr->scrnIndex, *sda_reg, data.val); + + if ((*scl == rhdDdcUnknown) || (*sda == rhdDdcUnknown)) { + xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, + "%s: failed to map gpio lines for DDC line %d\n", + __func__, line); + return FALSE; + } + + return TRUE; +#else /* ATOM_BIOS */ + return FALSE; +#endif +} + +/* R5xx */ +static Bool +rhd5xxI2CSetupStatus(I2CBusPtr I2CPtr, int line) +{ + RHDFUNC(I2CPtr); + + line &= 0xf; + + + switch (line) { + case 0: + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC1_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC1_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_EN, 0x0, 0xffff); + break; + case 1: + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC2_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC2_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_EN, 0x0, 0xffff); + break; + case 2: + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC3_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC3_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R5_DC_GPIO_DDC3_EN, 0x0, 0xffff); + break; + default: + xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, + "%s: Trying to initialize non-existent I2C line: %i\n", + __func__,line); + return FALSE; + } + return TRUE; +} + +static Bool +rhd5xxI2CStatus(I2CBusPtr I2CPtr) +{ + int count = RHD_I2C_STATUS_LOOPS; + CARD32 res; + + RHDFUNC(I2CPtr); + + while (count-- != 0) { + usleep (10); + if (((RHDRegRead(I2CPtr, R5_DC_I2C_STATUS1)) & R5_DC_I2C_GO) != 0) + continue; + res = RHDRegRead(I2CPtr, R5_DC_I2C_STATUS1); + RHDDebugVerb(I2CPtr->scrnIndex,1,"SW_STATUS: 0x%x %i\n", + (unsigned int)res,count); + if (res & R5_DC_I2C_DONE) + return TRUE; + else + return FALSE; + } + RHDRegMask(I2CPtr, R5_DC_I2C_RESET, R5_DC_I2C_ABORT, 0xff00); + return FALSE; +} + +Bool +rhd5xxWriteReadChunk(I2CDevPtr i2cDevPtr, int line, I2CByte *WriteBuffer, + int nWrite, I2CByte *ReadBuffer, int nRead) +{ + I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; + I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; + rhdI2CPtr I2C = (rhdI2CPtr)(I2CPtr->DriverPrivate.ptr); + int prescale = I2C->prescale; + CARD32 save_I2C_CONTROL1, save_494; + CARD32 tmp32; + Bool ret = TRUE; + + RHDFUNC(i2cDevPtr->pI2CBus); + + RHDRegMask(I2CPtr, 0x28, 0x200, 0x200); + save_I2C_CONTROL1 = RHDRegRead(I2CPtr, R5_DC_I2C_CONTROL1); + save_494 = RHDRegRead(I2CPtr, 0x494); + RHDRegMask(I2CPtr, 0x494, 1, 1); + RHDRegMask(I2CPtr, R5_DC_I2C_ARBITRATION, + R5_DC_I2C_SW_WANTS_TO_USE_I2C, + R5_DC_I2C_SW_WANTS_TO_USE_I2C); + + if (!RHDRegRead(I2CPtr, R5_DC_I2C_ARBITRATION) & R5_DC_I2C_SW_CAN_USE_I2C) { + RHDDebug(I2CPtr->scrnIndex, "%s SW cannot use I2C line %i\n",__func__,line); + ret = FALSE; + } else { + + RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_DONE + | R5_DC_I2C_NACK + | R5_DC_I2C_HALT, 0xff); + RHDRegMask(I2CPtr, R5_DC_I2C_RESET, R5_DC_I2C_SOFT_RESET, 0xffff); + RHDRegWrite(I2CPtr, R5_DC_I2C_RESET, 0); + + RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL1, + (line & 0x0f) << 16 | R5_DC_I2C_EN, + R5_DC_I2C_PIN_SELECT | R5_DC_I2C_EN); + } + + if (ret && (nWrite || !nRead)) { /* special case for bus probing */ + /* + * chip can't just write the slave address without data. + * Add a dummy byte. + */ + RHDRegWrite(I2CPtr, R5_DC_I2C_CONTROL2, + prescale << 16 | + (nWrite ? nWrite : 1) << 8 | 0x01); /* addr_cnt: 1 */ + RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL3, + 0x30 << 24, 0xff << 24); /* time limit 30 */ + + RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, slave); + + /* Add dummy byte */ + if (!nWrite) + RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, 0); + else + while (nWrite--) + RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, *WriteBuffer++); + + RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL1, + R5_DC_I2C_START | R5_DC_I2C_STOP, 0xff); + RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_GO, 0xff); + + if ((ret = rhd5xxI2CStatus(I2CPtr))) + RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1,R5_DC_I2C_DONE, 0xff); + else + ret = FALSE; + } + + if (ret && nRead) { + + RHDRegWrite(I2CPtr, R5_DC_I2C_DATA, slave | 1); /*slave*/ + RHDRegWrite(I2CPtr, R5_DC_I2C_CONTROL2, + prescale << 16 | nRead << 8 | 0x01); /* addr_cnt: 1 */ + + RHDRegMask(I2CPtr, R5_DC_I2C_CONTROL1, + R5_DC_I2C_START | R5_DC_I2C_STOP | R5_DC_I2C_RECEIVE, 0xff); + RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_GO, 0xff); + if ((ret = rhd5xxI2CStatus(I2CPtr))) { + RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, R5_DC_I2C_DONE, 0xff); + while (nRead--) { + *(ReadBuffer++) = (CARD8)RHDRegRead(I2CPtr, R5_DC_I2C_DATA); + } + } else + ret = FALSE; + } + + RHDRegMask(I2CPtr, R5_DC_I2C_STATUS1, + R5_DC_I2C_DONE | R5_DC_I2C_NACK | R5_DC_I2C_HALT, 0xff); + RHDRegMask(I2CPtr, R5_DC_I2C_RESET, R5_DC_I2C_SOFT_RESET, 0xff); + RHDRegWrite(I2CPtr,R5_DC_I2C_RESET, 0); + + RHDRegMask(I2CPtr,R5_DC_I2C_ARBITRATION, + R5_DC_I2C_SW_DONE_USING_I2C, 0xff00); + + RHDRegWrite(I2CPtr,R5_DC_I2C_CONTROL1, save_I2C_CONTROL1); + RHDRegWrite(I2CPtr,0x494, save_494); + tmp32 = RHDRegRead(I2CPtr,0x28); + RHDRegWrite(I2CPtr,0x28, tmp32 & 0xfffffdff); + + return ret; +} + +static Bool +rhd5xxWriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) +{ + /* + * Since the transaction buffer can only hold + * 15 bytes (+ the slave address) we bail out + * on every transaction that is bigger unless + * it's a read transaction following a write + * transaction sending just one byte. + * In this case we assume, that this byte is + * an offset address. Thus we will restart + * the transaction after 15 bytes sending + * a new offset. + */ + + I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; + int ddc_line; + + RHDFUNC(I2CPtr); + + if (nWrite > 15 || (nRead > 15 && nWrite != 1)) { + xf86DrvMsg(i2cDevPtr->pI2CBus->scrnIndex,X_ERROR, + "%s: Currently only I2C transfers with " + "maximally 15bytes are supported\n", + __func__); + return FALSE; + } + + ddc_line = ((rhdI2CPtr)(I2CPtr->DriverPrivate.ptr))->u.line; + + rhd5xxI2CSetupStatus(I2CPtr, ddc_line); + + if (nRead > 15) { + I2CByte offset = *WriteBuffer; + while (nRead) { + int n = nRead > 15 ? 15 : nRead; + if (!rhd5xxWriteReadChunk(i2cDevPtr, ddc_line, &offset, 1, ReadBuffer, n)) + return FALSE; + ReadBuffer += n; + nRead -= n; + offset += n; + } + return TRUE; + } else + return rhd5xxWriteReadChunk(i2cDevPtr, ddc_line, WriteBuffer, nWrite, + ReadBuffer, nRead); +} + +/* RS690 */ +static Bool +rhdRS69I2CStatus(I2CBusPtr I2CPtr) +{ + volatile CARD32 val; + int i; + + RHDFUNC(I2CPtr); + + for (i = 0; i < RHD_I2C_STATUS_LOOPS; i++) { + usleep(10); + + val = RHDRegRead(I2CPtr, RS69_DC_I2C_SW_STATUS); + + RHDDebugVerb(I2CPtr->scrnIndex, 1, "SW_STATUS: 0x%x %i\n", + (unsigned int) val, i); + + if (val & RS69_DC_I2C_SW_DONE) + break; + } + + RHDRegMask(I2CPtr, RS69_DC_I2C_INTERRUPT_CONTROL, RS69_DC_I2C_SW_DONE_ACK, + RS69_DC_I2C_SW_DONE_ACK); + + if ((i == RHD_I2C_STATUS_LOOPS) || + (val & (RS69_DC_I2C_SW_ABORTED | RS69_DC_I2C_SW_TIMEOUT | + RS69_DC_I2C_SW_INTERRUPTED | RS69_DC_I2C_SW_BUFFER_OVERFLOW | + RS69_DC_I2C_SW_STOPPED_ON_NACK | + RS69_DC_I2C_SW_NACK0 | RS69_DC_I2C_SW_NACK1 | 0x3))) + return FALSE; /* 2 */ + + return TRUE; /* 1 */ +} + +static Bool +rhdRS69I2CSetupStatus(I2CBusPtr I2CPtr, enum rhdDDClines sda, enum rhdDDClines scl, int prescale) +{ + CARD32 clk_pin, data_pin; + + RHDFUNC(I2CPtr); + + switch (sda) { + case rhdDdc1data: + data_pin = 0; + break; + case rhdDdc2data: + data_pin = 1; + break; + case rhdDdc3data: + data_pin = 2; + break; + default: + return FALSE; + } + switch (scl) { + case rhdDdc1data: + clk_pin = 4; + break; + case rhdDdc2data: + clk_pin = 5; + break; + case rhdDdc3data: + clk_pin = 6; + break; + case rhdDdc1clk: + clk_pin = 0; + break; + case rhdDdc2clk: + clk_pin = 1; + break; + case rhdDdc3clk: + clk_pin = 2; + break; + default: + return FALSE; + } + + RHDRegMask(I2CPtr, 0x28, 0x200, 0x200); + RHDRegMask(I2CPtr, RS69_DC_I2C_UNKNOWN_1, prescale << 16 | 0x2, 0xffff00ff); + RHDRegWrite(I2CPtr, RS69_DC_I2C_DDC_SETUP_Q, 0x30000000); + RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, ((data_pin & 0x3) << 16) | (clk_pin << 8), 0xffff00); + RHDRegMask(I2CPtr, RS69_DC_I2C_INTERRUPT_CONTROL, 0x2, 0x2); + RHDRegMask(I2CPtr, RS69_DC_I2C_UNKNOWN_2, 0x2, 0xff); + + return TRUE; +} + +static Bool +rhdRS69WriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, + int nWrite, I2CByte *ReadBuffer, int nRead) +{ + Bool ret = FALSE; + CARD32 data = 0; + I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; + I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; + rhdI2CPtr I2C = (rhdI2CPtr)I2CPtr->DriverPrivate.ptr; + int prescale = I2C->prescale; + int idx = 1; + + enum { + TRANS_WRITE_READ, + TRANS_WRITE, + TRANS_READ + } trans; + + RHDFUNC(i2cDevPtr->pI2CBus); + + if (nWrite > 0 && nRead > 0) { + trans = TRANS_WRITE_READ; + } else if (nWrite > 0) { + trans = TRANS_WRITE; + } else if (nRead > 0) { + trans = TRANS_READ; + } else { + /* for bus probing */ + trans = TRANS_WRITE; + } + if (slave & 0xff00) { + xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, + "%s: 10 bit I2C slave addresses not supported\n",__func__); + return FALSE; + } + + if (!rhdRS69I2CSetupStatus(I2CPtr, I2C->u.Gpio.Sda, I2C->u.Gpio.Scl, prescale)) + return FALSE; + + RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, (trans == TRANS_WRITE_READ) + ? (1 << 20) : 0, RS69_DC_I2C_TRANSACTION_COUNT); /* 2 or 1 Transaction */ + RHDRegMask(I2CPtr, RS69_DC_I2C_TRANSACTION0, + RS69_DC_I2C_STOP_ON_NACK0 + | (trans == TRANS_READ ? RS69_DC_I2C_RW0 : 0) + | RS69_DC_I2C_START0 + | (trans == TRANS_WRITE_READ ? 0 : RS69_DC_I2C_STOP0 ) + | ((trans == TRANS_READ ? nRead : nWrite) << 16), + 0xffffff); + if (trans == TRANS_WRITE_READ) + RHDRegMask(I2CPtr, RS69_DC_I2C_TRANSACTION1, + nRead << 16 + | RS69_DC_I2C_RW1 + | RS69_DC_I2C_START1 + | RS69_DC_I2C_STOP1, + 0xffffff); /* read */ + + data = RS69_DC_I2C_INDEX_WRITE + | (((slave & 0xfe) | (trans == TRANS_READ ? 1 : 0)) << 8 ) + | (0 << 16); + RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, data); + if (trans != TRANS_READ) { /* we have bytes to write */ + while (nWrite--) { + data = RS69_DC_I2C_INDEX_WRITE | ( *(WriteBuffer++) << 8 ) + | (idx++ << 16); + RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, data); + } + } + if (trans == TRANS_WRITE_READ) { /* we have bytes to read after write */ + data = RS69_DC_I2C_INDEX_WRITE | ((slave | 0x1) << 8) | (idx++ << 16); + RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, data); + } + /* Go! */ + RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, RS69_DC_I2C_GO, RS69_DC_I2C_GO); + if (rhdRS69I2CStatus(I2CPtr)) { + /* Hopefully this doesn't write data to index */ + RHDRegWrite(I2CPtr, RS69_DC_I2C_DATA, RS69_DC_I2C_INDEX_WRITE + | RS69_DC_I2C_DATA_RW | /* idx++ */3 << 16); + while (nRead--) { + data = RHDRegRead(I2CPtr, RS69_DC_I2C_DATA); + *(ReadBuffer++) = (data >> 8) & 0xff; + } + ret = TRUE; + } + + RHDRegMask(I2CPtr, RS69_DC_I2C_CONTROL, 0x2, 0xff); + usleep(10); + RHDRegWrite(I2CPtr, RS69_DC_I2C_CONTROL, 0); + + return ret; +} + + +/* R6xx */ +static Bool +rhdR6xxI2CStatus(I2CBusPtr I2CPtr) +{ + volatile CARD32 val; + int i; + + RHDFUNC(I2CPtr); + + for (i = 0; i < RHD_I2C_STATUS_LOOPS; i++) { + usleep(10); + + val = RHDRegRead(I2CPtr, R6_DC_I2C_SW_STATUS); + + RHDDebugVerb(I2CPtr->scrnIndex, 1, "SW_STATUS: 0x%x %i\n", + (unsigned int) val, i); + + if (val & R6_DC_I2C_SW_DONE) + break; + } + + RHDRegMask(I2CPtr, R6_DC_I2C_INTERRUPT_CONTROL, R6_DC_I2C_SW_DONE_ACK, + R6_DC_I2C_SW_DONE_ACK); + + if ((i == RHD_I2C_STATUS_LOOPS) || + (val & (R6_DC_I2C_SW_ABORTED | R6_DC_I2C_SW_TIMEOUT | + R6_DC_I2C_SW_INTERRUPTED | R6_DC_I2C_SW_BUFFER_OVERFLOW | + R6_DC_I2C_SW_STOPPED_ON_NACK | + R6_DC_I2C_SW_NACK0 | R6_DC_I2C_SW_NACK1 | 0x3))) + return FALSE; /* 2 */ + + return TRUE; /* 1 */ +} + +static Bool +rhd6xxI2CSetupStatus(I2CBusPtr I2CPtr, int line, int prescale) +{ + line &= 0xf; + + RHDFUNC(I2CPtr); + + switch (line) { + case 0: + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC1_EN, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_I2C_DDC1_SPEED, (prescale << 16) | 2, + 0xffff00ff); + RHDRegWrite(I2CPtr, R6_DC_I2C_DDC1_SETUP, 0x30000000); + break; + case 1: + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC2_EN, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_I2C_DDC2_SPEED, (prescale << 16) | 2, + 0xffff00ff); + RHDRegWrite(I2CPtr, R6_DC_I2C_DDC2_SETUP, 0x30000000); + break; + case 2: + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC3_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC3_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC3_EN, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_I2C_DDC3_SPEED, (prescale << 16) | 2, + 0xffff00ff); + RHDRegWrite(I2CPtr, R6_DC_I2C_DDC3_SETUP, 0x30000000); + break; + case 3: + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC4_MASK, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC4_A, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_GPIO_DDC4_EN, 0x0, 0xffff); + RHDRegMask(I2CPtr, R6_DC_I2C_DDC4_SPEED, (prescale << 16) | 2, + 0xffff00ff); + RHDRegWrite(I2CPtr, R6_DC_I2C_DDC4_SETUP, 0x30000000); + break; + default: + xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, + "%s: Trying to initialize non-existent I2C line: %i\n", + __func__,line); + return FALSE; + } + RHDRegWrite(I2CPtr, R6_DC_I2C_CONTROL, line << 8); + RHDRegMask(I2CPtr, R6_DC_I2C_INTERRUPT_CONTROL, 0x2, 0x2); + RHDRegMask(I2CPtr, R6_DC_I2C_ARBITRATION, 0, 0xff); + return TRUE; +} + +static Bool +rhd6xxWriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) +{ + Bool ret = FALSE; + CARD32 data = 0; + I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; + I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; + rhdI2CPtr I2C = (rhdI2CPtr)I2CPtr->DriverPrivate.ptr; + CARD32 ddc_line = I2C->u.line; + int prescale = I2C->prescale; + int idx = 1; + enum { + TRANS_WRITE_READ, + TRANS_WRITE, + TRANS_READ + } trans; + + RHDFUNC(i2cDevPtr->pI2CBus); + + if (nWrite > 0 && nRead > 0) { + trans = TRANS_WRITE_READ; + } else if (nWrite > 0) { + trans = TRANS_WRITE; + } else if (nRead > 0) { + trans = TRANS_READ; + } else { + /* for bus probing */ + trans = TRANS_WRITE; + } + if (slave & 0xff00) { + xf86DrvMsg(I2CPtr->scrnIndex,X_ERROR, + "%s: 10 bit I2C slave addresses not supported\n",__func__); + return FALSE; + } + + if (!rhd6xxI2CSetupStatus(I2CPtr, ddc_line, prescale)) + return FALSE; + + RHDRegMask(I2CPtr, R6_DC_I2C_CONTROL, (trans == TRANS_WRITE_READ) + ? (1 << 20) : 0, R6_DC_I2C_TRANSACTION_COUNT); /* 2 or 1 Transaction */ + RHDRegMask(I2CPtr, R6_DC_I2C_TRANSACTION0, + R6_DC_I2C_STOP_ON_NACK0 + | (trans == TRANS_READ ? R6_DC_I2C_RW0 : 0) + | R6_DC_I2C_START0 + | (trans == TRANS_WRITE_READ ? 0 : R6_DC_I2C_STOP0 ) + | ((trans == TRANS_READ ? nRead : nWrite) << 16), + 0xffffff); + if (trans == TRANS_WRITE_READ) + RHDRegMask(I2CPtr, R6_DC_I2C_TRANSACTION1, + nRead << 16 + | R6_DC_I2C_RW1 + | R6_DC_I2C_START1 + | R6_DC_I2C_STOP1, + 0xffffff); /* read */ + + data = R6_DC_I2C_INDEX_WRITE + | (((slave & 0xfe) | (trans == TRANS_READ ? 1 : 0)) << 8 ) + | (0 << 16); + RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, data); + if (trans != TRANS_READ) { /* we have bytes to write */ + while (nWrite--) { + data = R6_DC_I2C_INDEX_WRITE | ( *(WriteBuffer++) << 8 ) + | (idx++ << 16); + RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, data); + } + } + if (trans == TRANS_WRITE_READ) { /* we have bytes to read after write */ + data = R6_DC_I2C_INDEX_WRITE | ((slave | 0x1) << 8) | (idx++ << 16); + RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, data); + } + /* Go! */ + RHDRegMask(I2CPtr, R6_DC_I2C_CONTROL, R6_DC_I2C_GO, R6_DC_I2C_GO); + if (rhdR6xxI2CStatus(I2CPtr)) { + /* Hopefully this doesn't write data to index */ + RHDRegWrite(I2CPtr, R6_DC_I2C_DATA, R6_DC_I2C_INDEX_WRITE + | R6_DC_I2C_DATA_RW | /* idx++ */3 << 16); + while (nRead--) { + data = RHDRegRead(I2CPtr, R6_DC_I2C_DATA); + *(ReadBuffer++) = (data >> 8) & 0xff; + } + ret = TRUE; + } + + RHDRegMask(I2CPtr, R6_DC_I2C_CONTROL, 0x2, 0xff); + usleep(10); + RHDRegWrite(I2CPtr, R6_DC_I2C_CONTROL, 0); + + return ret; +} + +/* RV620 */ +static Bool +rhdRV620I2CStatus(I2CBusPtr I2CPtr) +{ + volatile CARD32 val; + int i; + + RHDFUNC(I2CPtr); + + for (i = 0; i < RHD_I2C_STATUS_LOOPS; i++) { + usleep(10); + + val = RHDRegRead(I2CPtr, RV62_GENERIC_I2C_STATUS); + + RHDDebugVerb(I2CPtr->scrnIndex, 1, + "SW_STATUS: 0x%x %i\n", (unsigned int) val, i); + if (val & RV62_GENERIC_I2C_DONE) + break; + } + + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_INTERRUPT_CONTROL, 0x2, 0xff); + + if ((i == RHD_I2C_STATUS_LOOPS) || + (val & (RV62_GENERIC_I2C_STOPPED_ON_NACK | RV62_GENERIC_I2C_NACK | + RV62_GENERIC_I2C_ABORTED | RV62_GENERIC_I2C_TIMEOUT))) + return FALSE; /* 2 */ + + return TRUE; /* 1 */ +} + +/* + * + */ +static Bool +rhdRV620I2CSetupStatus(I2CBusPtr I2CPtr, struct i2cGpio *Gpio, int prescale) +{ + CARD32 reg_7d9c = 0; /* 0 is invalid */ + CARD32 scl_reg; + + RHDFUNC(I2CPtr); + + scl_reg = Gpio->SclReg; + reg_7d9c = (Gpio->Scl << RV62_GENERIC_I2C_SCL_PIN_SEL_SHIFT) + | (Gpio->Sda << RV62_GENERIC_I2C_SDA_PIN_SEL_SHIFT); + + scl_reg = Gpio->SclReg; + /* Don't understand this yet */ + if (scl_reg == 0x1fda) + scl_reg = 0x1f90; + + RHDRegWrite(I2CPtr, scl_reg << 2, 0); + + RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_PIN_SELECTION, reg_7d9c); + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_SPEED, + (prescale & 0xffff) << 16 | 0x02, 0xffff00ff); + RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_SETUP, 0x30000000); + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_INTERRUPT_CONTROL, + RV62_GENERIC_I2C_DONE_ACK, RV62_GENERIC_I2C_DONE_ACK); + + return TRUE; +} + +static Bool +rhdRV620Transaction(I2CDevPtr i2cDevPtr, Bool Write, I2CByte *Buffer, int count) +{ + I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; + I2CSlaveAddr slave = i2cDevPtr->SlaveAddr; + Bool Start = TRUE; + + RHDFUNC(I2CPtr); + +#define MAX 8 + + while (count > 0 || (Write && Start)) { + int num; + int idx = 0; + CARD32 data = 0; + + if (count > MAX) { + num = MAX; + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_TRANSACTION, + (MAX - (((Start) ? 0 : 1))) << 16 + | RV62_GENERIC_I2C_STOP_ON_NACK + | RV62_GENERIC_I2C_ACK_ON_READ + | (Start ? RV62_GENERIC_I2C_START : 0) + | (!Write ? RV62_GENERIC_I2C_RW : 0 ), + 0xFFFFFF); + } else { + num = count; + data = ( count - (((Start) ? 0 : 1)) ) << 16 + | RV62_GENERIC_I2C_STOP_ON_NACK + | RV62_GENERIC_I2C_STOP + | (Start ? RV62_GENERIC_I2C_START : 0) + | (!Write ? RV62_GENERIC_I2C_RW : 0); + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_TRANSACTION, + data, + 0xFFFFFF); + } + + if (Start) { + data = RV62_GENERIC_I2C_INDEX_WRITE + | (((slave & 0xfe) | ( Write ? 0 : 1)) << 8) + | (idx++ << 16); + RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_DATA, data); + } + + if (Write) { + while (num--) { + data = RV62_GENERIC_I2C_INDEX_WRITE + | (idx++ << 16) + | *(Buffer++) << 8; + RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_DATA, data); + } + + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_CONTROL, + RV62_GENERIC_I2C_GO, RV62_GENERIC_I2C_GO); + if (!rhdRV620I2CStatus(I2CPtr)) + return FALSE; + } else { + + RHDRegMask(I2CPtr, RV62_GENERIC_I2C_CONTROL, + RV62_GENERIC_I2C_GO, RV62_GENERIC_I2C_GO); + if (!rhdRV620I2CStatus(I2CPtr)) + return FALSE; + + RHDRegWrite(I2CPtr, RV62_GENERIC_I2C_DATA, + RV62_GENERIC_I2C_INDEX_WRITE + | (idx++ << 16) + | RV62_GENERIC_I2C_RW); + + while (num--) { + data = RHDRegRead(I2CPtr, RV62_GENERIC_I2C_DATA); + *(Buffer++) = (CARD8)((data >> 8) & 0xff); + } + } + Start = FALSE; + count -= MAX; + } + + return TRUE; +} + +static Bool +rhdRV620WriteRead(I2CDevPtr i2cDevPtr, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) +{ + I2CBusPtr I2CPtr = i2cDevPtr->pI2CBus; + rhdI2CPtr I2C = (rhdI2CPtr)I2CPtr->DriverPrivate.ptr; + int prescale = I2C->prescale; + + RHDFUNC(I2C); + + rhdRV620I2CSetupStatus(I2CPtr, &I2C->u.Gpio, prescale); + + if (nWrite || !nRead) + if (!rhdRV620Transaction(i2cDevPtr, TRUE, WriteBuffer, nWrite)) + return FALSE; + if (nRead) + if (!rhdRV620Transaction(i2cDevPtr, FALSE, ReadBuffer, nRead)) + return FALSE; + + return TRUE; +} + +static void +rhdTearDownI2C(I2CBusPtr *I2C) +{ + int i; + + /* + * xf86I2CGetScreenBuses() is + * broken in older server versions. + * So we cannot use it. How bad! + */ + for (i = 0; i < I2C_LINES; i++) { + char *name; + if (!I2C[i]) + break; + name = I2C[i]->BusName; + xfree(I2C[i]->DriverPrivate.ptr); + xf86DestroyI2CBusRec(I2C[i], TRUE, TRUE); + xfree(name); + } + xfree(I2C); +} + +#define TARGET_HW_I2C_CLOCK 25 /* kHz */ +#define DEFAULT_ENGINE_CLOCK 453000 /* kHz (guessed) */ +#define DEFAULT_REF_CLOCK 27000 + +static CARD32 +rhdGetI2CPrescale(RHDPtr rhdPtr) +{ +#ifdef ATOM_BIOS + AtomBiosArgRec atomBiosArg; + RHDFUNC(rhdPtr); + + if (rhdPtr->ChipSet < RHD_R600) { + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + GET_DEFAULT_ENGINE_CLOCK, &atomBiosArg) + == ATOM_SUCCESS) + return (0x7f << 8) + + (atomBiosArg.val / (4 * 0x7f * TARGET_HW_I2C_CLOCK)); + else + return (0x7f << 8) + + (DEFAULT_ENGINE_CLOCK / (4 * 0x7f * TARGET_HW_I2C_CLOCK)); + } else if (rhdPtr->ChipSet < RHD_RV620) { + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + GET_REF_CLOCK, &atomBiosArg) == ATOM_SUCCESS) + return (atomBiosArg.val / TARGET_HW_I2C_CLOCK); + else + return (DEFAULT_REF_CLOCK / TARGET_HW_I2C_CLOCK); + } else { + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + GET_REF_CLOCK, &atomBiosArg) == ATOM_SUCCESS) + return (atomBiosArg.val / (4 * TARGET_HW_I2C_CLOCK)); + else + return (DEFAULT_REF_CLOCK / (4 * TARGET_HW_I2C_CLOCK)); + } +#else + RHDFUNC(rhdPtr); + + if (rhdPtr->ChipSet < RHD_R600) { + return (0x7f << 8) + + (DEFAULT_ENGINE_CLOCK) / (4 * 0x7f * TARGET_HW_I2C_CLOCK); + } else if (rhdPtr->ChipSet < RHD_RV620) { + return (DEFAULT_REF_CLOCK / TARGET_HW_I2C_CLOCK); + } else + return (DEFAULT_REF_CLOCK / (4 * TARGET_HW_I2C_CLOCK)); +#endif +} + +static Bool +rhdI2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + d->SlaveAddr = addr; + return xf86I2CWriteRead(d, NULL, 0, NULL, 0); +} + +/* + * This stub is needed to keep xf86I2CProbeAddress() happy. + */ +static void +rhdI2CStop(I2CDevPtr d) +{ +} + +static I2CBusPtr * +rhdInitI2C(int scrnIndex) +{ + int i; + rhdI2CPtr I2C; + I2CBusPtr I2CPtr = NULL; + RHDPtr rhdPtr = (RHDPtr)scrnIndex; + I2CBusPtr *I2CList; + int numLines; + CARD16 prescale = rhdGetI2CPrescale(rhdPtr); + enum rhdDDClines sda = 0, scl = 0; + CARD32 scl_reg = 0, sda_reg = 0; + Bool valid; + + RHDFUNCI(scrnIndex); + + if (rhdPtr->ChipSet < RHD_RS600) + numLines = 3; + else if (rhdPtr->ChipSet < RHD_R600) + numLines = 4; + else if (rhdPtr->ChipSet < RHD_RV730) + numLines = 4; + else + numLines = MAX_I2C_LINES; + + if (!(I2CList = xcalloc(MAX_I2C_LINES, sizeof(I2CBusPtr)))) { + xf86DrvMsg(scrnIndex, X_ERROR, + "%s: Out of memory.\n",__func__); + } + /* We have 4 I2C lines */ + for (i = 0; i < numLines; i++) { + if (!(I2C = xcalloc(sizeof(rhdI2CRec),1))) { + xf86DrvMsg(scrnIndex, X_ERROR, + "%s: Out of memory.\n",__func__); + goto error; + } + I2C->scrnIndex = scrnIndex; + + valid = rhdI2CGetDataClkLines(rhdPtr, i, &scl, &sda, &sda_reg, &scl_reg); + if (rhdPtr->ChipSet < RHD_RS600 + || (rhdPtr->ChipSet > RHD_RS740 && rhdPtr->ChipSet < RHD_RV620)) { + + if (valid) { + if (sda == rhdDdc1data && scl == rhdDdc1clk) + I2C->u.line = 0; + else if (sda == rhdDdc2data && scl == rhdDdc2clk) + I2C->u.line = 1; + else if (sda == rhdDdc3data && scl == rhdDdc3clk) + I2C->u.line = 2; + else if (rhdPtr->ChipSet > RHD_RS740 && sda == rhdDdc4data && scl == rhdDdc4clk) + I2C->u.line = 3; /* R6XX only */ + else { + xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "No DDC line found for index %i: scl=0x%2.2x sda=0x%2.2x\n", + i, scl, sda); + xfree(I2C); + continue; + } + + } else + I2C->u.line = i; + + } else if (rhdPtr->ChipSet <= RHD_RS740) { + + if (valid) { + if (sda != rhdDdc1data && sda != rhdDdc2data && sda != rhdDdc3data) { + xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "Invalid DDC CLK pin found: %i\n", + sda); + xfree(I2C); + continue; + } + if (scl != rhdDdc1data && scl != rhdDdc2data && scl != rhdDdc3data + && scl != rhdDdc1clk && scl != rhdDdc2clk && scl != rhdDdc3clk) { + xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "Invalid DDC CLK pin found: %i\n", + scl); + xfree(I2C); + continue; + } + I2C->u.Gpio.Sda = sda; + I2C->u.Gpio.Scl = scl; + I2C->u.Gpio.SdaReg = sda_reg; + I2C->u.Gpio.SclReg = scl_reg; + + } else { + xf86DrvMsg(I2CPtr->scrnIndex, X_ERROR, "Invalid ClkLine for DDC. " + "AtomBIOS reported wrong or AtomBIOS unavailable\n"); + xfree(I2C); + goto error; + } + + } else { + + if (valid) { + I2C->u.Gpio.Sda = sda; + I2C->u.Gpio.Scl = scl; + I2C->u.Gpio.SdaReg = sda_reg; + I2C->u.Gpio.SclReg = scl_reg; + } else { + CARD32 gpioReg[] = { 0x1f90, 0x1f94, 0x1f98 }; + enum rhdDDClines sdaList[] = { rhdDdc1data, rhdDdc2data, rhdDdc3data }; + enum rhdDDClines sclList[] = { rhdDdc1clk, rhdDdc2clk, rhdDdc3clk }; + if (i > 2) { + xfree(I2C); + continue; + } + I2C->u.Gpio.Sda = sdaList[i]; + I2C->u.Gpio.Scl = sclList[i]; + I2C->u.Gpio.SclReg = I2C->u.Gpio.SdaReg = gpioReg[i]; + } + + } + + /* + * This is a value that has been found to work on many cards. + * It nees to be replaced by the proper calculation formula + * once this is available. + */ + I2C->prescale = prescale; + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, "I2C clock prescale value: %x\n",I2C->prescale); + + if (!(I2CPtr = xf86CreateI2CBusRec())) { + xf86DrvMsg(scrnIndex, X_ERROR, + "Cannot allocate I2C BusRec.\n"); + xfree(I2C); + goto error; + } + I2CPtr->DriverPrivate.ptr = I2C; + if (!(I2CPtr->BusName = xalloc(18))) { + xf86DrvMsg(scrnIndex, X_ERROR, + "%s: Cannot allocate memory.\n",__func__); + xfree(I2C); + xf86DestroyI2CBusRec(I2CPtr, TRUE, FALSE); + goto error; + } + snprintf(I2CPtr->BusName,17,"RHD I2C line %1.1i",i); + I2CPtr->scrnIndex = scrnIndex; + if (rhdPtr->ChipSet < RHD_RS600) + I2CPtr->I2CWriteRead = rhd5xxWriteRead; + else if (rhdPtr->ChipSet >= RHD_RS600 && rhdPtr->ChipSet <= RHD_RS740) + I2CPtr->I2CWriteRead = rhdRS69WriteRead; + else if (rhdPtr->ChipSet < RHD_RV620) + I2CPtr->I2CWriteRead = rhd6xxWriteRead; + else + I2CPtr->I2CWriteRead = rhdRV620WriteRead; + I2CPtr->I2CAddress = rhdI2CAddress; + I2CPtr->I2CStop = rhdI2CStop; + + if (!(xf86I2CBusInit(I2CPtr))) { + xf86DrvMsg(scrnIndex, X_ERROR, + "I2C BusInit failed for bus %i\n",i); + xfree(I2CPtr->BusName); + xfree(I2C); + xf86DestroyI2CBusRec(I2CPtr, TRUE, FALSE); + goto error; + } + I2CList[i] = I2CPtr; + } + return I2CList; + error: + rhdTearDownI2C(I2CList); + return NULL; +} + +RHDI2CResult +rhdI2CProbeAddress(int scrnIndex, I2CBusPtr I2CBusPtr, CARD8 slave) +{ + I2CDevPtr dev; + char *name = "I2CProbe"; + + if ((dev = xf86CreateI2CDevRec())) { + dev->DevName = name; + dev->pI2CBus = I2CBusPtr; + + if (xf86I2CDevInit(dev)) { + Bool ret; + + dev->SlaveAddr = slave & 0xFE; + + ret = xf86I2CWriteRead(dev, NULL, 0, NULL, 0); + + if (ret) { + unsigned char offset = 0; + unsigned char buf[2]; + + /* + ASUS M2A-VM (R690) motherboards ACK all I2C slaves on the + HDMI line when the HDMI riser card is not installed. + We therefore need to read the first two bytes and check + if they are part of an I2C header. + */ + ret = xf86I2CWriteRead(dev, &offset, 1, buf, 2); + if (ret && (buf[0] != 0 || buf[1] != 0xff)) + ret = FALSE; + } + xf86DestroyI2CDevRec(dev, TRUE); + + return ret ? RHD_I2C_SUCCESS : RHD_I2C_FAILED; + } + } + + return RHD_I2C_FAILED; +} + +RHDI2CResult +RHDI2CFunc(int scrnIndex, I2CBusPtr *I2CList, RHDi2cFunc func, + RHDI2CDataArgPtr datap) +{ + RHDFUNCI(scrnIndex); + + if (func == RHD_I2C_INIT) { + if (!(datap->I2CBusList = rhdInitI2C(scrnIndex))) + return RHD_I2C_FAILED; + else + return RHD_I2C_SUCCESS; + } + if (func == RHD_I2C_DDC) { + if (datap->i >= MAX_I2C_LINES || !I2CList[datap->i]) + return RHD_I2C_NOLINE; + + datap->monitor = xf86DoEDID_DDC2(scrnIndex, I2CList[datap->i]); + return RHD_I2C_SUCCESS; + } + if (func == RHD_I2C_PROBE_ADDR_LINE) { + + if (datap->target.line >= MAX_I2C_LINES || !I2CList[datap->target.line]) + return RHD_I2C_NOLINE; + return rhdI2CProbeAddress(scrnIndex, I2CList[datap->target.line], datap->target.slave); + } + if (func == RHD_I2C_PROBE_ADDR) { + return rhdI2CProbeAddress(scrnIndex, datap->probe.i2cBusPtr, datap->probe.slave); + } + if (func == RHD_I2C_GETBUS) { + if (datap->i >= MAX_I2C_LINES || !I2CList[datap->i]) + return RHD_I2C_NOLINE; + + datap->i2cBusPtr = I2CList[datap->i]; + return RHD_I2C_SUCCESS; + } + if (func == RHD_I2C_TEARDOWN) { + if (I2CList) + rhdTearDownI2C(I2CList); + return RHD_I2C_SUCCESS; + } + return RHD_I2C_FAILED; +} + diff --git a/programs/system/drivers/rhd/rhd_i2c.h b/programs/system/drivers/rhd/rhd_i2c.h new file mode 100644 index 000000000..d9f1f20b1 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_i2c.h @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ +#ifndef RHD_I2C_H_ +# define RHD_I2C_H_ + +//#include "xf86DDC.h" +#include "xf86i2c.h" + +#define I2C_LINES 5 + +typedef enum { + RHD_I2C_INIT, + RHD_I2C_DDC, + RHD_I2C_PROBE_ADDR_LINE, + RHD_I2C_PROBE_ADDR, + RHD_I2C_GETBUS, + RHD_I2C_TEARDOWN +} RHDi2cFunc; + +typedef union RHDI2CDataArg +{ + I2CBusPtr *I2CBusList; + int i; + struct { + int line; + CARD8 slave; + } target; + struct { + CARD8 slave; + I2CBusPtr i2cBusPtr; + } probe; + struct + { + int line; + CARD32 slaves[4]; + } scanbus; + xf86MonPtr monitor; + I2CBusPtr i2cBusPtr; +} RHDI2CDataArg, *RHDI2CDataArgPtr; + +typedef enum { + RHD_I2C_SUCCESS, + RHD_I2C_NOLINE, + RHD_I2C_FAILED +} RHDI2CResult; + +RHDI2CResult +RHDI2CFunc(int scrnIndex, I2CBusPtr *I2CList, RHDi2cFunc func, + RHDI2CDataArgPtr data); +#endif diff --git a/programs/system/drivers/rhd/rhd_id.c b/programs/system/drivers/rhd/rhd_id.c new file mode 100644 index 000000000..5f818eccf --- /dev/null +++ b/programs/system/drivers/rhd/rhd_id.c @@ -0,0 +1,858 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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 + +#include "xf86.h" +#include "rhd.h" +#ifdef ATOM_BIOS +#include "rhd_atombios.h" +#endif +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_card.h" + +SymTabRec RHDChipsets[] = { + /* R500 */ + { RHD_RV505, "RV505" }, + { RHD_RV515, "RV515" }, + { RHD_RV516, "RV516" }, + { RHD_R520, "R520" }, + { RHD_RV530, "RV530" }, + { RHD_RV535, "RV535" }, + { RHD_RV550, "RV550" }, + { RHD_RV560, "RV560" }, + { RHD_RV570, "RV570" }, + { RHD_R580, "R580" }, + /* R500 Mobility */ + { RHD_M52, "M52" }, + { RHD_M54, "M54" }, + { RHD_M56, "M56" }, + { RHD_M58, "M58" }, + { RHD_M62, "M62" }, + { RHD_M64, "M64" }, + { RHD_M66, "M66" }, + { RHD_M68, "M68" }, + { RHD_M71, "M71" }, + /* R500 integrated */ + { RHD_RS600, "RS600" }, + { RHD_RS690, "RS690" }, + { RHD_RS740, "RS740" }, + /* R600 */ + { RHD_R600, "R600" }, + { RHD_RV610, "RV610" }, + { RHD_RV630, "RV630" }, + /* R600 Mobility */ + { RHD_M72, "M72" }, + { RHD_M74, "M74" }, + { RHD_M76, "M76" }, + /* RV670 came into existence after RV6x0 and M7x */ + { RHD_RV670, "RV670" }, + { RHD_M88, "M88" }, + { RHD_R680, "R680" }, + { RHD_RV620, "RV620" }, + { RHD_M82, "M82" }, + { RHD_RV635, "RV635" }, + { RHD_M86, "M86" }, + { RHD_RS780, "RS780" }, + { RHD_RV770, "RV770" }, + { RHD_RV730, "RV730" }, + { RHD_RV710, "RV710" }, + { -1, NULL } +}; + +# define RHD_DEVICE_MATCH(d, i) { (d),(i) } +# define PCI_ID_LIST PciChipset_t RHDPCIchipsets[] +# define LIST_END { 0, 0} + +const PCI_ID_LIST = { + RHD_DEVICE_MATCH( 0x7100, RHD_R520 ), /* Radeon X1800 */ + RHD_DEVICE_MATCH( 0x7101, RHD_M58 ), /* Mobility Radeon X1800 XT */ + RHD_DEVICE_MATCH( 0x7102, RHD_M58 ), /* Mobility Radeon X1800 */ + RHD_DEVICE_MATCH( 0x7103, RHD_M58 ), /* Mobility FireGL V7200 */ + RHD_DEVICE_MATCH( 0x7104, RHD_R520 ), /* FireGL V7200 */ + RHD_DEVICE_MATCH( 0x7105, RHD_R520 ), /* FireGL V5300 */ + RHD_DEVICE_MATCH( 0x7106, RHD_M58 ), /* Mobility FireGL V7100 */ + RHD_DEVICE_MATCH( 0x7108, RHD_R520 ), /* Radeon X1800 */ + RHD_DEVICE_MATCH( 0x7109, RHD_R520 ), /* Radeon X1800 */ + RHD_DEVICE_MATCH( 0x710A, RHD_R520 ), /* Radeon X1800 */ + RHD_DEVICE_MATCH( 0x710B, RHD_R520 ), /* Radeon X1800 */ + RHD_DEVICE_MATCH( 0x710C, RHD_R520 ), /* Radeon X1800 */ + RHD_DEVICE_MATCH( 0x710E, RHD_R520 ), /* FireGL V7300 */ + RHD_DEVICE_MATCH( 0x710F, RHD_R520 ), /* FireGL V7350 */ + RHD_DEVICE_MATCH( 0x7140, RHD_RV515 ), /* Radeon X1600/X1550 */ + RHD_DEVICE_MATCH( 0x7141, RHD_RV505 ), /* RV505 */ + RHD_DEVICE_MATCH( 0x7142, RHD_RV515 ), /* Radeon X1300/X1550 */ + RHD_DEVICE_MATCH( 0x7143, RHD_RV505 ), /* Radeon X1550 */ + RHD_DEVICE_MATCH( 0x7144, RHD_M54 ), /* M54-GL */ + RHD_DEVICE_MATCH( 0x7145, RHD_M54 ), /* Mobility Radeon X1400 */ + RHD_DEVICE_MATCH( 0x7146, RHD_RV515 ), /* Radeon X1300/X1550 */ + RHD_DEVICE_MATCH( 0x7147, RHD_RV505 ), /* Radeon X1550 64-bit */ + RHD_DEVICE_MATCH( 0x7149, RHD_M52 ), /* Mobility Radeon X1300 */ + RHD_DEVICE_MATCH( 0x714A, RHD_M52 ), /* Mobility Radeon X1300 */ + RHD_DEVICE_MATCH( 0x714B, RHD_M52 ), /* Mobility Radeon X1300 */ + RHD_DEVICE_MATCH( 0x714C, RHD_M52 ), /* Mobility Radeon X1300 */ + RHD_DEVICE_MATCH( 0x714D, RHD_RV515 ), /* Radeon X1300 */ + RHD_DEVICE_MATCH( 0x714E, RHD_RV515 ), /* Radeon X1300 */ + RHD_DEVICE_MATCH( 0x714F, RHD_RV505 ), /* RV505 */ + RHD_DEVICE_MATCH( 0x7151, RHD_RV505 ), /* RV505 */ + RHD_DEVICE_MATCH( 0x7152, RHD_RV515 ), /* FireGL V3300 */ + RHD_DEVICE_MATCH( 0x7153, RHD_RV515 ), /* FireGL V3350 */ + RHD_DEVICE_MATCH( 0x715E, RHD_RV515 ), /* Radeon X1300 */ + RHD_DEVICE_MATCH( 0x715F, RHD_RV505 ), /* Radeon X1550 64-bit */ + RHD_DEVICE_MATCH( 0x7180, RHD_RV516 ), /* Radeon X1300/X1550 */ + RHD_DEVICE_MATCH( 0x7181, RHD_RV516 ), /* Radeon X1600 */ + RHD_DEVICE_MATCH( 0x7183, RHD_RV516 ), /* Radeon X1300/X1550 */ + RHD_DEVICE_MATCH( 0x7186, RHD_M64 ), /* Mobility Radeon X1450 */ + RHD_DEVICE_MATCH( 0x7187, RHD_RV516 ), /* Radeon X1300/X1550 */ + RHD_DEVICE_MATCH( 0x7188, RHD_M64 ), /* Mobility Radeon X2300 */ + RHD_DEVICE_MATCH( 0x718A, RHD_M64 ), /* Mobility Radeon X2300 */ + RHD_DEVICE_MATCH( 0x718B, RHD_M62 ), /* Mobility Radeon X1350 */ + RHD_DEVICE_MATCH( 0x718C, RHD_M62 ), /* Mobility Radeon X1350 */ + RHD_DEVICE_MATCH( 0x718D, RHD_M64 ), /* Mobility Radeon X1450 */ + RHD_DEVICE_MATCH( 0x718F, RHD_RV516 ), /* Radeon X1300 */ + RHD_DEVICE_MATCH( 0x7193, RHD_RV516 ), /* Radeon X1550 */ + RHD_DEVICE_MATCH( 0x7196, RHD_M62 ), /* Mobility Radeon X1350 */ + RHD_DEVICE_MATCH( 0x719B, RHD_RV516 ), /* FireMV 2250 */ + RHD_DEVICE_MATCH( 0x719F, RHD_RV516 ), /* Radeon X1550 64-bit */ + RHD_DEVICE_MATCH( 0x71C0, RHD_RV530 ), /* Radeon X1600 */ + RHD_DEVICE_MATCH( 0x71C1, RHD_RV535 ), /* Radeon X1650 */ + RHD_DEVICE_MATCH( 0x71C2, RHD_RV530 ), /* Radeon X1600 */ + RHD_DEVICE_MATCH( 0x71C3, RHD_RV535 ), /* Radeon X1600 */ + RHD_DEVICE_MATCH( 0x71C4, RHD_M56 ), /* Mobility FireGL V5200 */ + RHD_DEVICE_MATCH( 0x71C5, RHD_M56 ), /* Mobility Radeon X1600 */ + RHD_DEVICE_MATCH( 0x71C6, RHD_RV530 ), /* Radeon X1650 */ + RHD_DEVICE_MATCH( 0x71C7, RHD_RV535 ), /* Radeon X1650 */ + RHD_DEVICE_MATCH( 0x71CD, RHD_RV530 ), /* Radeon X1600 */ + RHD_DEVICE_MATCH( 0x71CE, RHD_RV530 ), /* Radeon X1300 XT/X1600 Pro */ + RHD_DEVICE_MATCH( 0x71D2, RHD_RV530 ), /* FireGL V3400 */ + RHD_DEVICE_MATCH( 0x71D4, RHD_M66 ), /* Mobility FireGL V5250 */ + RHD_DEVICE_MATCH( 0x71D5, RHD_M66 ), /* Mobility Radeon X1700 */ + RHD_DEVICE_MATCH( 0x71D6, RHD_M66 ), /* Mobility Radeon X1700 XT */ + RHD_DEVICE_MATCH( 0x71DA, RHD_RV530 ), /* FireGL V5200 */ + RHD_DEVICE_MATCH( 0x71DE, RHD_M66 ), /* Mobility Radeon X1700 */ + RHD_DEVICE_MATCH( 0x7200, RHD_RV550 ), /* Radeon X2300HD */ + RHD_DEVICE_MATCH( 0x7210, RHD_M71 ), /* Mobility Radeon HD 2300 */ + RHD_DEVICE_MATCH( 0x7211, RHD_M71 ), /* Mobility Radeon HD 2300 */ + RHD_DEVICE_MATCH( 0x7240, RHD_R580 ), /* Radeon X1950 */ + RHD_DEVICE_MATCH( 0x7243, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7244, RHD_R580 ), /* Radeon X1950 */ + RHD_DEVICE_MATCH( 0x7245, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7246, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7247, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7248, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7249, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x724A, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x724B, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x724C, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x724D, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x724E, RHD_R580 ), /* AMD Stream Processor */ + RHD_DEVICE_MATCH( 0x724F, RHD_R580 ), /* Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7280, RHD_RV570 ), /* Radeon X1950 */ + RHD_DEVICE_MATCH( 0x7281, RHD_RV560 ), /* RV560 */ + RHD_DEVICE_MATCH( 0x7283, RHD_RV560 ), /* RV560 */ + RHD_DEVICE_MATCH( 0x7284, RHD_M68 ), /* Mobility Radeon X1900 */ + RHD_DEVICE_MATCH( 0x7287, RHD_RV560 ), /* RV560 */ + RHD_DEVICE_MATCH( 0x7288, RHD_RV570 ), /* Radeon X1950 GT */ + RHD_DEVICE_MATCH( 0x7289, RHD_RV570 ), /* RV570 */ + RHD_DEVICE_MATCH( 0x728B, RHD_RV570 ), /* RV570 */ + RHD_DEVICE_MATCH( 0x728C, RHD_RV570 ), /* ATI FireGL V7400 */ + RHD_DEVICE_MATCH( 0x7290, RHD_RV560 ), /* RV560 */ + RHD_DEVICE_MATCH( 0x7291, RHD_RV560 ), /* Radeon X1650 */ + RHD_DEVICE_MATCH( 0x7293, RHD_RV560 ), /* Radeon X1650 */ + RHD_DEVICE_MATCH( 0x7297, RHD_RV560 ), /* RV560 */ + RHD_DEVICE_MATCH( 0x791E, RHD_RS690 ), /* Radeon X1200 */ + RHD_DEVICE_MATCH( 0x791F, RHD_RS690 ), /* Radeon X1200 */ + RHD_DEVICE_MATCH( 0x793F, RHD_RS600 ), /* Radeon Xpress 1200 */ + RHD_DEVICE_MATCH( 0x7941, RHD_RS600 ), /* Radeon Xpress 1200 */ + RHD_DEVICE_MATCH( 0x7942, RHD_RS600 ), /* Radeon Xpress 1200 (M) */ + RHD_DEVICE_MATCH( 0x796C, RHD_RS740 ), /* RS740 */ + RHD_DEVICE_MATCH( 0x796D, RHD_RS740 ), /* RS740M */ + RHD_DEVICE_MATCH( 0x796E, RHD_RS740 ), /* ATI Radeon 2100 RS740 */ + RHD_DEVICE_MATCH( 0x796F, RHD_RS740 ), /* RS740M */ + RHD_DEVICE_MATCH( 0x9400, RHD_R600 ), /* Radeon HD 2900 XT */ + RHD_DEVICE_MATCH( 0x9401, RHD_R600 ), /* Radeon HD 2900 XT */ + RHD_DEVICE_MATCH( 0x9402, RHD_R600 ), /* Radeon HD 2900 XT */ + RHD_DEVICE_MATCH( 0x9403, RHD_R600 ), /* Radeon HD 2900 Pro */ + RHD_DEVICE_MATCH( 0x9405, RHD_R600 ), /* Radeon HD 2900 GT */ + RHD_DEVICE_MATCH( 0x940A, RHD_R600 ), /* FireGL V8650 */ + RHD_DEVICE_MATCH( 0x940B, RHD_R600 ), /* FireGL V8600 */ + RHD_DEVICE_MATCH( 0x940F, RHD_R600 ), /* FireGL V7600 */ + RHD_DEVICE_MATCH( 0x9440, RHD_RV770 ), /* ATI Radeon 4800 Series */ + RHD_DEVICE_MATCH( 0x9441, RHD_RV770 ), /* ATI Radeon 4870 X2 */ + RHD_DEVICE_MATCH( 0x9442, RHD_RV770 ), /* ATI Radeon 4800 Series */ +// RHD_DEVICE_MATCH( 0x9443, RHD_R700 ), /* ATI Radeon 4800 Series */ + RHD_DEVICE_MATCH( 0x9444, RHD_RV770 ), /* Everest ATI FirePro Graphics Accelerator */ + RHD_DEVICE_MATCH( 0x9446, RHD_RV770 ), /* K2 ATI FirePro Graphics Accelerator */ +// RHD_DEVICE_MATCH( 0x9447, RHD_R700 ), /* K2 ATI FirePro Graphics Accelerator */ + RHD_DEVICE_MATCH( 0x944A, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x944B, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x944E, RHD_RV770 ), /* RV770 */ +// RHD_DEVICE_MATCH( 0x944F, RHD_R700 ), /* R700 */ + RHD_DEVICE_MATCH( 0x9456, RHD_RV770 ), /* Denali ATI FirePro Graphics Accelerator */ + RHD_DEVICE_MATCH( 0x945A, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x945B, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x946A, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x946B, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x947A, RHD_M98 ), /* M98 */ + RHD_DEVICE_MATCH( 0x947B, RHD_M98 ), /* M96 */ + RHD_DEVICE_MATCH( 0x9480, RHD_M96 ), /* M98 */ + RHD_DEVICE_MATCH( 0x9487, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x9488, RHD_M96 ), /* M96 */ + RHD_DEVICE_MATCH( 0x9489, RHD_M96 ), /* M96M GL */ + RHD_DEVICE_MATCH( 0x948F, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x9487, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x9490, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x9498, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x949E, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x949F, RHD_RV730 ), /* RV730 */ + RHD_DEVICE_MATCH( 0x94C0, RHD_RV610 ), /* RV610 */ + RHD_DEVICE_MATCH( 0x94C1, RHD_RV610 ), /* Radeon HD 2400 XT */ + RHD_DEVICE_MATCH( 0x94C3, RHD_RV610 ), /* Radeon HD 2400 Pro */ + RHD_DEVICE_MATCH( 0x94C4, RHD_RV610 ), /* ATI Radeon HD 2400 PRO AGP */ + RHD_DEVICE_MATCH( 0x94C5, RHD_RV610 ), /* FireGL V4000 */ + RHD_DEVICE_MATCH( 0x94C6, RHD_RV610 ), /* RV610 */ + RHD_DEVICE_MATCH( 0x94C7, RHD_RV610 ), /* ATI Radeon HD 2350 */ + RHD_DEVICE_MATCH( 0x94C8, RHD_M74 ), /* Mobility Radeon HD 2400 XT */ + RHD_DEVICE_MATCH( 0x94C9, RHD_M72 ), /* Mobility Radeon HD 2400 */ + RHD_DEVICE_MATCH( 0x94CB, RHD_M72 ), /* ATI RADEON E2400 */ + RHD_DEVICE_MATCH( 0x94CC, RHD_RV610 ), /* ATI Radeon HD 2400 */ + RHD_DEVICE_MATCH( 0x9500, RHD_RV670 ), /* RV670 */ + RHD_DEVICE_MATCH( 0x9501, RHD_RV670 ), /* ATI Radeon HD3870 */ + RHD_DEVICE_MATCH( 0x9504, RHD_M88 ), /* ATI Mobility Radeon HD 3850 */ + RHD_DEVICE_MATCH( 0x9505, RHD_RV670 ), /* ATI Radeon HD3850 */ + RHD_DEVICE_MATCH( 0x9506, RHD_M88 ), /* ATI Mobility Radeon HD 3850 X2 */ + RHD_DEVICE_MATCH( 0x9507, RHD_RV670 ), /* RV670 */ + RHD_DEVICE_MATCH( 0x9508, RHD_M88 ), /* ATI Mobility Radeon HD 3870 */ + RHD_DEVICE_MATCH( 0x9509, RHD_M88 ), /* ATI Mobility Radeon HD 3870 X2 */ + RHD_DEVICE_MATCH( 0x950F, RHD_R680 ), /* ATI Radeon HD3870 X2 */ + RHD_DEVICE_MATCH( 0x9511, RHD_RV670 ), /* ATI FireGL V7700 */ + RHD_DEVICE_MATCH( 0x9515, RHD_RV670 ), /* ATI Radeon HD 3850 AGP */ + RHD_DEVICE_MATCH( 0x9517, RHD_RV670 ), /* ATI Radeon HD 3960 */ + RHD_DEVICE_MATCH( 0x9519, RHD_RV670 ), /* FireStream 9170 */ + RHD_DEVICE_MATCH( 0x9540, RHD_RV710 ), /* */ + RHD_DEVICE_MATCH( 0x9541, RHD_RV710 ), /* */ + RHD_DEVICE_MATCH( 0x9542, RHD_RV710 ), /* */ + RHD_DEVICE_MATCH( 0x954E, RHD_RV710 ), /* */ + RHD_DEVICE_MATCH( 0x954f, RHD_RV710 ), /* */ + RHD_DEVICE_MATCH( 0x9580, RHD_RV630 ), /* RV630 */ + RHD_DEVICE_MATCH( 0x9581, RHD_M76 ), /* Mobility Radeon HD 2600 */ + RHD_DEVICE_MATCH( 0x9583, RHD_M76 ), /* Mobility Radeon HD 2600 XT */ + RHD_DEVICE_MATCH( 0x9586, RHD_RV630 ), /* ATI Radeon HD 2600 XT AGP */ + RHD_DEVICE_MATCH( 0x9587, RHD_RV630 ), /* ATI Radeon HD 2600 Pro AGP */ + RHD_DEVICE_MATCH( 0x9588, RHD_RV630 ), /* Radeon HD 2600 XT */ + RHD_DEVICE_MATCH( 0x9589, RHD_RV630 ), /* Radeon HD 2600 Pro */ + RHD_DEVICE_MATCH( 0x958A, RHD_RV630 ), /* Gemini RV630 */ + RHD_DEVICE_MATCH( 0x958B, RHD_M76 ), /* Gemini ATI Mobility Radeon HD 2600 XT */ + RHD_DEVICE_MATCH( 0x958C, RHD_RV630 ), /* FireGL V5600 */ + RHD_DEVICE_MATCH( 0x958D, RHD_RV630 ), /* FireGL V3600 */ + RHD_DEVICE_MATCH( 0x958E, RHD_RV630 ), /* ATI Radeon HD 2600 LE */ + RHD_DEVICE_MATCH( 0x958F, RHD_M76 ), /* ATI Mobility FireGL Graphics Processor */ + RHD_DEVICE_MATCH( 0x9590, RHD_RV635 ), /* ATI Radeon HD 3600 Series */ + RHD_DEVICE_MATCH( 0x9591, RHD_M86 ), /* Mobility Radeon HD 3650 */ + RHD_DEVICE_MATCH( 0x9593, RHD_M86 ), /* Mobility Radeon HD 3670 */ + RHD_DEVICE_MATCH( 0x9595, RHD_M86 ), /* Mobility FireGL V5700 */ + RHD_DEVICE_MATCH( 0x9596, RHD_RV635 ), /* ATI Radeon HD 3650 AGP */ + RHD_DEVICE_MATCH( 0x9597, RHD_RV635 ), /* ATI Radeon HD 3600 Series */ + RHD_DEVICE_MATCH( 0x9598, RHD_RV635 ), /* ATI Radeon HD 3670 */ + RHD_DEVICE_MATCH( 0x9599, RHD_RV635 ), /* ATI Radeon HD 3600 Series */ + RHD_DEVICE_MATCH( 0x959B, RHD_M86 ), /* Mobility FireGL Graphics Processor */ + RHD_DEVICE_MATCH( 0x95C0, RHD_RV620 ), /* ATI Radeon HD 3470 */ + RHD_DEVICE_MATCH( 0x95C2, RHD_M82 ), /* ATI Mobility Radeon HD 3430 (M82) */ + RHD_DEVICE_MATCH( 0x95C4, RHD_M82 ), /* Mobility Radeon HD 3400 Series (M82) */ + RHD_DEVICE_MATCH( 0x95C5, RHD_RV620 ), /* ATI Radeon HD 3450 */ + RHD_DEVICE_MATCH( 0x95C6, RHD_RV620 ), /* ATI Radeon HD 3450 */ + RHD_DEVICE_MATCH( 0x95C7, RHD_RV620 ), /* ATI Radeon HD 3430 */ + RHD_DEVICE_MATCH( 0x95CC, RHD_RV620 ), /* Fire PRO Professional Graphics ASIC */ + RHD_DEVICE_MATCH( 0x95CD, RHD_RV620 ), /* ATI FireMV 2450 */ + RHD_DEVICE_MATCH( 0x95CE, RHD_RV620 ), /* ATI FireMV 2260 */ + RHD_DEVICE_MATCH( 0x95CF, RHD_RV620 ), /* ATI FireMV 2260 */ + RHD_DEVICE_MATCH( 0x9610, RHD_RS780 ), /* ATI Radeon HD 3200 Graphics */ + RHD_DEVICE_MATCH( 0x9611, RHD_RS780 ), /* ATI Radeon 3100 Graphics */ + RHD_DEVICE_MATCH( 0x9612, RHD_RS780 ), /* ATI Radeon HD 3200 Graphics */ + RHD_DEVICE_MATCH( 0x9613, RHD_RS780 ), /* ATI Radeon 3100 Graphics */ + RHD_DEVICE_MATCH( 0x9614, RHD_RS780 ), /* ATI Radeon HD 3300 Graphics */ + LIST_END +}; + +static enum RHD_CHIPSETS rhdIGPChipsetList[] = { + RHD_RS690, + RHD_RS690, + RHD_RS690, + RHD_RS780, + RHD_UNKNOWN /* end marker */ +}; + +/* + * + */ +void +RHDIdentify(int flags) +{ + +} + +/* + * + */ +Bool +RHDIsIGP(enum RHD_CHIPSETS chipset) +{ + int i = 0; + while (rhdIGPChipsetList[i] != RHD_UNKNOWN) { + if (chipset == (rhdIGPChipsetList[i])) + return TRUE; + i++; + } + return FALSE; +} + +/* + * Some macros to help us make connector tables less messy. + * There are, after all, a limited number of possibilities at the moment. + */ +#define ID_CONNECTORINFO_EMPTY \ + { {RHD_CONNECTOR_NONE, "NULL", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_NONE, RHD_OUTPUT_NONE}}} + +#ifdef ATOM_BIOS +# define DEVINFO_EMPTY { { atomNone, atomNone } } +#endif + +/* Radeon RV610 0x94C3 0x0000 0x0000 */ +#define VGA_B1_TV_B_DVI_AA00 \ +{{ RHD_CONNECTOR_DVI_SINGLE, "VGA CRT2", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_NONE, RHD_OUTPUT_DACB }}, \ + {RHD_CONNECTOR_TV, "7PIN_DIN TV1 CV", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, \ + {RHD_CONNECTOR_DVI_SINGLE, "SINGLE_LINK_DVI CRT1 DFP2", RHD_DDC_0, RHD_HPD_0, \ + {RHD_OUTPUT_LVTMA, RHD_OUTPUT_DACA }}} + + +/* Radeon X1300 0x7187:0x1545:0x1930 */ +#define VGA_A0_TV_B_DVI_B11 \ + { { RHD_CONNECTOR_VGA, "VGA CRT1", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_TV, "SVIDEO TV1", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_DVI, "DVI-D DFP3", RHD_DDC_1, RHD_HPD_1, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE }}} + +/* Sapphire X1550 reports 2x DVI-I but has only 1 VGA and 1 DVI */ +#define VGA_A0_DVI_BB11 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_1, RHD_HPD_1, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_LVTMA}}} + +/* 0x7249:0x1043:0x0168 */ +#define DVI_AB10_DVI_A01 \ + { { RHD_CONNECTOR_DVI, "DVI-I DFP1 CRT2", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_TMDSA, RHD_OUTPUT_DACB }}, \ + { RHD_CONNECTOR_DVI, "DVI-I DFP2", RHD_DDC_0, RHD_HPD_1, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_TV, "SVIDEO TV1", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}} + +#define VISIONTEK_C1550 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE } }, \ + {RHD_CONNECTOR_TV, "SVIDEO", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE } }, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_DACB } } } + +/* MacBook Pro provides a weird atombios connector table. */ +#define ID_CONNECTORINFO_MACBOOKPRO \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_2, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_0, RHD_HPD_0, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_TMDSA}}} + +#ifdef ATOM_BIOS +# define DEVINFO_MACBOOKPRO \ + { { atomLCD1, atomNone }, { atomCRT2, atomDFP1 } } +#endif + +/* GeCube HD 2400PRO AGP (GC-RX24PGA2-D3) specifies 2 DVI again.*/ +#define BROKEN_VGA_B1_DVI_AB00 \ + { {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_0, RHD_HPD_0, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_LVTMA}}, \ + {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE}}} + +/* Fujitsu Siemens Amilo PI1536 has no HPD on its DVI connector. */ +#define PANEL_B_DVI_AA1 \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_TMDSA}}} + +/* Sapphire Radeon HD 2600 PRO AGP reports VGA output as DVI */ +#define DVI_BA10_TV_B0_VGA_A0 \ + { { RHD_CONNECTOR_DVI, "DUAL_LINK_DVI_I", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_TMDSA, RHD_OUTPUT_DACB }}, \ + { RHD_CONNECTOR_TV, "7PIN_DIN TV1 CV", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_NONE, RHD_OUTPUT_DACA }}} + +/* MSI RX2600PRO-T2D512Z/D2 */ +#define DVI_BA12_TV_B0_DVI_AB01 \ + { { RHD_CONNECTOR_DVI, "DUAL_LINK_DVI_I DFP1 CRT2", RHD_DDC_1, RHD_HPD_2, \ + { RHD_OUTPUT_TMDSA, RHD_OUTPUT_DACB }}, \ + { RHD_CONNECTOR_TV, "7PIN_DIN TV1 CV", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_DVI, "DUAL_LINK_DVI_I CRT1 DFP2", RHD_DDC_0, RHD_HPD_1, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_DACA }}} + +#if defined(USE_ID_CONNECTORS) || !defined(ATOM_BIOS) + +#define VGA_A0_TVB_DVI_BB12 \ + { { RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_TV, "SVIDEO", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE }}, \ + { RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_1, RHD_HPD_2, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_LVTMA }}} + +#define VGA_A0_DVI_BA10 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_TMDSA}}} + +#define VGA_A0_DVI_BB10 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_LVTMA}}} + +#define VGA_B1_DVI_AA00 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_0, RHD_HPD_0, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_TMDSA}}} + +#define VGA_B1_DVI_AB01 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_0, RHD_HPD_1, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_LVTMA}}} + +#define VGA_B1_DVI_AB00 \ + { {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-I", RHD_DDC_0, RHD_HPD_0, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_LVTMA}}} + +#define DVI_AA00_DVI_BB11 \ + { {RHD_CONNECTOR_DVI, "DVI-I 1", RHD_DDC_0, RHD_HPD_0, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_TMDSA}}, \ + {RHD_CONNECTOR_DVI, "DVI-I 2", RHD_DDC_1, RHD_HPD_1, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_LVTMA}}} + +#define DVI_BA10_DVI_AB01 \ + { {RHD_CONNECTOR_DVI, "DVI-I 1", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_TMDSA}}, \ + {RHD_CONNECTOR_DVI, "DVI-I 2", RHD_DDC_0, RHD_HPD_1, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_LVTMA}}} + +#define DVI_BB11_DVI_AA00 \ + { {RHD_CONNECTOR_DVI, "DVI-I 1", RHD_DDC_1, RHD_HPD_1, \ + { RHD_OUTPUT_DACB, RHD_OUTPUT_LVTMA}}, \ + {RHD_CONNECTOR_DVI, "DVI-I 2", RHD_DDC_0, RHD_HPD_0, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_TMDSA}}} + +#define PANEL_B_VGA_A0 \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_NONE, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}} + +#define PANEL_B1_VGA_A0 \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}} + +#define PANEL_B1_VGA_A2 \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_1, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_2, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}} + +#define PANEL_B2_VGA_A0 \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_2, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}} + +#define PANEL_B2_VGA_A0_DVI_A10 \ + { {RHD_CONNECTOR_PANEL, "Panel", RHD_DDC_2, RHD_HPD_NONE, \ + { RHD_OUTPUT_LVTMA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_VGA, "VGA", RHD_DDC_0, RHD_HPD_NONE, \ + { RHD_OUTPUT_DACA, RHD_OUTPUT_NONE}}, \ + {RHD_CONNECTOR_DVI, "DVI-D", RHD_DDC_1, RHD_HPD_0, \ + { RHD_OUTPUT_TMDSA, RHD_OUTPUT_NONE}}} + +#else /* if !defined(USE_ID_CONNECTORS) && defined(ATOM_BIOS) */ + +#define VGA_A0_TVB_DVI_BB12 ID_CONNECTORINFO_EMPTY +#define VGA_A0_DVI_BA10 ID_CONNECTORINFO_EMPTY +#define VGA_A0_DVI_BB10 ID_CONNECTORINFO_EMPTY +#define VGA_B1_DVI_AA00 ID_CONNECTORINFO_EMPTY +#define VGA_B1_DVI_AB01 ID_CONNECTORINFO_EMPTY +#define VGA_B1_DVI_AB00 ID_CONNECTORINFO_EMPTY +#define DVI_AA00_DVI_BB11 ID_CONNECTORINFO_EMPTY +#define DVI_BA10_DVI_AB01 ID_CONNECTORINFO_EMPTY +#define DVI_BB11_DVI_AA00 ID_CONNECTORINFO_EMPTY +#define PANEL_B_VGA_A0 ID_CONNECTORINFO_EMPTY +#define PANEL_B1_VGA_A0 ID_CONNECTORINFO_EMPTY +#define PANEL_B1_VGA_A2 ID_CONNECTORINFO_EMPTY +#define PANEL_B2_VGA_A0 ID_CONNECTORINFO_EMPTY +#define PANEL_B2_VGA_A0_DVI_A10 ID_CONNECTORINFO_EMPTY + +#endif /* if defined(USE_ID_CONNECTORS) || !defined(ATOM_BIOS) */ + +/* + * List of pci subsystem / card ids. + * + * Used for: + * - printing card name. + * - connector mapping. + * + */ +static struct rhdCard +rhdCards[] = +{ + /* 0x7100 : R520 : Radeon X1800 */ + { 0x7100, 0x1002, 0x0B12, "Powercolor X1800XT", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x7101 : M58 : Mobility Radeon X1800 XT */ + /* 0x7102 : M58 : Mobility Radeon X1800 */ + /* 0x7103 : M58 : Mobility FireGL V7200 */ + /* 0x7104 : R520 : FireGL V7200 */ + { 0x7104, 0x1002, 0x0B32, "ATI FireGL V7200 RH", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x7105 : R520 : FireGL V5300 */ + /* 0x7106 : M58 : Mobility FireGL V7100 */ + /* 0x7108 : R520 : Radeon X1800 */ + /* 0x7109 : R520 : Radeon X1800 */ + /* 0x710A : R520 : Radeon X1800 */ + /* 0x710B : R520 : Radeon X1800 */ + /* 0x710C : R520 : Radeon X1800 */ + /* 0x710E : R520 : FireGL V7300 */ + /* 0x710F : R520 : FireGL V7350 */ + /* 0x7140 : RV515 : Radeon X1600 */ + { 0x7140, 0x1787, 0x3000, "PowerColor X1550", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x7141 : RV505 : RV505 */ + /* 0x7142 : RV515 : Radeon X1300/X1550 */ + /* 0x7143 : RV505 : Radeon X1550 */ + /* 0x7144 : M54 : M54-GL */ + /* 0x7145 : M54 : Mobility Radeon X1400 */ + { 0x7145, 0x1028, 0x2002, "Dell Inspiron 9400", RHD_CARD_FLAG_NONE, PANEL_B2_VGA_A0_DVI_A10, DEVINFO_EMPTY }, + { 0x7145, 0x1028, 0x2003, "Dell Inspiron 6400", RHD_CARD_FLAG_NONE, PANEL_B_VGA_A0, DEVINFO_EMPTY }, + { 0x7145, 0x1179, 0xFF10, "Toshiba Satellite A100-773", RHD_CARD_FLAG_NONE, PANEL_B1_VGA_A2, DEVINFO_EMPTY }, + { 0x7145, 0x1297, 0x3058, "M54P X1440", RHD_CARD_FLAG_HPDOFF, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x7145, 0x1734, 0x10B0, "Fujitsu Siemens Amilo PI1536", RHD_CARD_FLAG_NONE, PANEL_B_DVI_AA1, DEVINFO_EMPTY }, + { 0x7145, 0x17AA, 0x2006, "Lenovo Thinkpad T60 (2007)", RHD_CARD_FLAG_NONE, PANEL_B2_VGA_A0_DVI_A10, DEVINFO_EMPTY }, + { 0x7145, 0x17AA, 0x202A, "Lenovo Thinkpad Z61m", RHD_CARD_FLAG_NONE, PANEL_B2_VGA_A0, DEVINFO_EMPTY }, + /* 0x7146 : RV515 : Radeon X1300/X1550 */ + { 0x7146, 0x174B, 0x0470, "Sapphire X1300", RHD_CARD_FLAG_NONE, VGA_B1_DVI_AB01, DEVINFO_EMPTY }, + { 0x7146, 0x174B, 0x0920, "Sapphire X1300", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x7146, 0x1545, 0x2350, "Visiontek C1550", RHD_CARD_FLAG_NONE, VISIONTEK_C1550, DEVINFO_EMPTY }, + /* 0x7147 : RV505 : Radeon X1550 64-bit */ + { 0x7147, 0x174B, 0x0840, "Sapphire X1550", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x7149 : M52 : Mobility Radeon X1300 */ + { 0x7149, 0x1028, 0x2003, "Dell Inspiron E1505", RHD_CARD_FLAG_NONE, PANEL_B_VGA_A0, DEVINFO_EMPTY }, + { 0x7149, 0x17AA, 0x2005, "Lenovo Thinkpad T60 (2008)", RHD_CARD_FLAG_NONE, PANEL_B2_VGA_A0_DVI_A10, DEVINFO_EMPTY }, + /* 0x714A : M52 : Mobility Radeon X1300 */ + /* 0x714B : M52 : Mobility Radeon X1300 */ + /* 0x714C : M52 : Mobility Radeon X1300 */ + /* 0x714D : RV515 : Radeon X1300 */ + /* 0x714E : RV515 : Radeon X1300 */ + /* 0x714F : RV505 : RV505 */ + /* 0x7151 : RV505 : RV505 */ + /* 0x7152 : RV515 : FireGL V3300 */ + { 0x7152, 0x1002, 0x0B02, "ATI FireGL V3300", RHD_CARD_FLAG_NONE, DVI_BB11_DVI_AA00, DEVINFO_EMPTY }, + /* 0x7153 : RV515 : FireGL V3350 */ + /* 0x715E : RV515 : Radeon X1300 */ + /* 0x715F : RV505 : Radeon X1550 64-bit */ + /* 0x7180 : RV516 : Radeon X1300/X1550 */ + /* 0x7181 : RV516 : Radeon X1600 */ + /* 0x7183 : RV516 : Radeon X1300/X1550 */ + { 0x7183, 0x1028, 0x0D02, "Dell ATI Radeon X1300", RHD_CARD_FLAG_DMS59, DVI_AA00_DVI_BB11, DEVINFO_EMPTY }, + { 0x7183, 0x1092, 0x3000, "RX155PCI", RHD_CARD_FLAG_NONE, VGA_A0_TVB_DVI_BB12, DEVINFO_EMPTY }, + /* 0x7186 : M64 : Mobility Radeon X1450 */ + /* 0x7187 : RV516 : Radeon X1300/X1550 */ + { 0x7187, 0x174B, 0x3000, "RV516 : Radeon X1300/X1550", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x7187, 0x1458, 0x215C, "RV516 : Radeon X1300/X1550", RHD_CARD_FLAG_DMS59, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x7187, 0x1545, 0x1930, "RV516 : Radeon X1300", RHD_CARD_FLAG_NONE, VGA_A0_TV_B_DVI_B11, DEVINFO_EMPTY }, + /* 0x7188 : M64 : Mobility Radeon X2300 */ + /* 0x718A : M64 : Mobility Radeon X2300 */ + /* 0x718B : M62 : Mobility Radeon X1350 */ + /* 0x718C : M62 : Mobility Radeon X1350 */ + /* 0x718D : M64 : Mobility Radeon X1450 */ + /* 0x718F : RV516 : Radeon X1300 */ + /* 0x7193 : RV516 : Radeon X1550 */ + /* 0x7196 : M62 : Mobility Radeon X1350 */ + /* 0x719B : RV516 : FireMV 2250 */ + /* 0x719F : RV516 : Radeon X1550 64-bit */ + /* 0x71C0 : RV530 : Radeon X1600 */ + /* 0x71C1 : RV535 : Radeon X1650 */ + { 0x71C1, 0x174B, 0x0840, "Sapphire X1650 Pro", RHD_CARD_FLAG_NONE, DVI_AA00_DVI_BB11, DEVINFO_EMPTY }, + /* 0x71C2 : RV530 : Radeon X1600 */ + { 0x71C2, 0x1458, 0x2146, "Gigabyte GV-RX16P256DE-RH", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x71C2, 0x17EE, 0x71C0, "Connect3D Radeon X1600 Pro", RHD_CARD_FLAG_NONE, VGA_B1_DVI_AA00, DEVINFO_EMPTY }, + /* 0x71C3 : RV535 : Radeon X1600 */ + /* 0x71C4 : M56 : Mobility FireGL V5200 */ + { 0x71C4, 0x17AA, 0x2007, "Lenovo Thinkpad T60p V5200", RHD_CARD_FLAG_HPDOFF, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x71C5 : M56 : Mobility Radeon X1600 */ + { 0x71C5, 0x103C, 0x30A3, "HP/Compaq nc8430", RHD_CARD_FLAG_NONE, PANEL_B1_VGA_A0, DEVINFO_EMPTY }, + { 0x71C5, 0x103C, 0x30B4, "HP/Compaq nw8440", RHD_CARD_FLAG_NONE, PANEL_B1_VGA_A0, DEVINFO_EMPTY }, + { 0x71C5, 0x1043, 0x10B2, "Asus W3J/Z96", RHD_CARD_FLAG_NONE, PANEL_B_VGA_A0, DEVINFO_EMPTY }, + { 0x71C5, 0x106B, 0x0080, "Macbook Pro", RHD_CARD_FLAG_NONE, ID_CONNECTORINFO_MACBOOKPRO, DEVINFO_MACBOOKPRO }, + { 0x71C5, 0x1179, 0xFF10, "Toshiba Satellite A100-237", RHD_CARD_FLAG_NONE, PANEL_B1_VGA_A2, DEVINFO_EMPTY }, + /* 0x71C6 : RV530 : Radeon X1650 */ + { 0x71C6, 0x174B, 0x0850, "Sapphire X1650 Pro AGP", RHD_CARD_FLAG_NONE, VGA_A0_DVI_BA10, DEVINFO_EMPTY }, + { 0x71C6, 0x1462, 0x0400, "MSI RX1650 Pro", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x71C7 : RV535 : Radeon X1650 */ + { 0x71C7, 0x1043, 0x01B6, "Asus EAX1650 Silent", RHD_CARD_FLAG_NONE, VGA_A0_DVI_BB10, DEVINFO_EMPTY }, + { 0x71C7, 0x1787, 0x2227, "Diamond Viper X1650 Pro", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x71CD : RV530 : Radeon X1600 */ + { 0x71CD, 0x174B, 0x0840, "PCP X1600 400M/500E", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x71CE : RV530 : Radeon X1300 XT/X1600 Pro */ + { 0x71CE, 0x18BC, 0x2770, "Radeon X1300 XT/X1600 Pro", RHD_CARD_FLAG_HPDOFF, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x71D2 : RV530 : FireGL V3400 */ + { 0x71D2, 0x1002, 0x2B02, "ATI FireGL V3400", RHD_CARD_FLAG_NONE, DVI_BB11_DVI_AA00, DEVINFO_EMPTY }, + /* 0x71D4 : M66 : Mobility FireGL V5250 */ + { 0x71D4, 0x17AA, 0x20A4, "Lenovo Thinkpad T60p V5250", RHD_CARD_FLAG_HPDOFF, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x71D5 : M66 : Mobility Radeon X1700 */ + /* 0x71D6 : M66 : Mobility Radeon X1700 XT */ + /* 0x71DA : RV530 : FireGL V5200 */ + /* 0x71DE : M66 : Mobility Radeon X1700 */ + /* 0x7200 : RV550 : Radeon X2300HD */ + /* 0x7210 : M71 : Mobility Radeon HD 2300 */ + /* 0x7211 : M71 : Mobility Radeon HD 2300 */ + /* 0x7240 : R580 : Radeon X1950 */ + /* 0x7243 : R580 : Radeon X1900 */ + /* 0x7244 : R580 : Radeon X1950 */ + /* 0x7245 : R580 : Radeon X1900 */ + /* 0x7246 : R580 : Radeon X1900 */ + /* 0x7247 : R580 : Radeon X1900 */ + /* 0x7248 : R580 : Radeon X1900 */ + /* 0x7249 : R580 : Radeon X1900 */ + { 0x7249, 0x1002, 0x0B12, "ATI Radeon X1900 XTX", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* { 0x7249, 0x1043, 0x016B, "ATI Radeon X1900 XTX", RHD_CARD_FLAG_NONE, DVI_AB10_DVI_A01, DEVINFO_EMPTY }, */ + /* 0x724A : R580 : Radeon X1900 */ + /* 0x724B : R580 : Radeon X1900 */ + { 0x724B, 0x1002, 0x0B12, "Sapphire Radeon X1900 GT", RHD_CARD_FLAG_NONE, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x724C : R580 : Radeon X1900 */ + /* 0x724D : R580 : Radeon X1900 */ + /* 0x724E : R580 : AMD Stream Processor */ + /* 0x724F : R580 : Radeon X1900 */ + /* 0x7280 : RV570 : Radeon X1950 */ + { 0x7280, 0x174B, 0xE190, "Sapphire X1950 Pro", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + { 0x7280, 0x18BC, 0x2870, "GeCube X1950 Pro", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x7281 : RV560 : RV560 */ + /* 0x7283 : RV560 : RV560 */ + /* 0x7284 : M68 : Mobility Radeon X1900 */ + /* 0x7287 : RV560 : RV560 */ + /* 0x7288 : RV570 : Radeon X1950 GT */ + { 0x7288, 0x174B, 0xE190, "Sapphire X1950 GT", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x7289 : RV570 : RV570 */ + /* 0x728B : RV570 : RV570 */ + /* 0x728C : RV570 : ATI FireGL V7400 */ + /* 0x7290 : RV560 : RV560 */ + /* 0x7291 : RV560 : Radeon X1650 */ + /* 0x7293 : RV560 : Radeon X1650 */ + /* 0x7297 : RV560 : RV560 */ + /* 0x791E : RS690 : Radeon X1200 */ + { 0x791E, 0x1043, 0x826D, "Asus M2A-VM", RHD_CARD_FLAG_NONE, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x791F : RS690 : Radeon X1200 */ + { 0x791F, 0x103C, 0x30C2, "HP/Compaq 6715b", RHD_CARD_FLAG_NONE, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + /* 0x793F : RS600 : Radeon Xpress 1200 */ + /* 0x7941 : RS600 : Radeon Xpress 1200 */ + /* 0x7942 : RS600 : Radeon Xpress 1200 (M) */ + /* 0x796C : RS740 : RS740 */ + /* 0x796D : RS740 : RS740M */ + /* 0x796E : RS740 : RS740 */ + /* 0x796F : RS740 : RS740M */ + /* 0x9400 : R600 : Radeon HD 2900 XT */ + { 0x9400, 0x1002, 0x3142, "Sapphire HD 2900 XT", RHD_CARD_FLAG_NONE, DVI_BB11_DVI_AA00, DEVINFO_EMPTY }, + /* 0x9401 : R600 : Radeon HD 2900 XT */ + /* 0x9402 : R600 : Radeon HD 2900 XT */ + /* 0x9403 : R600 : Radeon HD 2900 Pro */ + /* 0x9405 : R600 : ATI Radeon HD 2900 GT */ + /* 0x940A : R600 : ATI FireGL V8650 */ + /* 0x940B : R600 : ATI FireGL V8600 */ + /* 0x940F : R600 : ATI FireGL V7600 */ + /* 0x94C0 : RV610 : RV610 */ + /* 0x94C1 : RV610 : Radeon HD 2400 XT */ + { 0x94C1, 0x1002, 0x0D02, "ATI Radeon HD 2400 XT", RHD_CARD_FLAG_DMS59, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x94C1, 0x1028, 0x0D02, "Dell Radeon HD 2400 XT", RHD_CARD_FLAG_DMS59, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x94C1, 0x174B, 0xE390, "Sapphire HD 2400 XT", RHD_CARD_FLAG_NONE, VGA_B1_DVI_AB00, DEVINFO_EMPTY }, + { 0x94C3, 0x0000, 0x0000, "ATI Radeon 2400 HD GENERIC", RHD_CARD_FLAG_NONE, VGA_B1_TV_B_DVI_AA00, DEVINFO_EMPTY }, + /* 0x94C3 : RV610 : Radeon HD 2400 Pro */ + { 0x94C3, 0x1545, 0x3210, "ATI Radeon 2400HD Pro", RHD_CARD_FLAG_HPDSWAP, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0x94C3, 0x174B, 0xE370, "Sapphire HD 2400 Pro", RHD_CARD_FLAG_NONE, VGA_A0_DVI_BB10, DEVINFO_EMPTY }, + /* 0x94C4 : RV610 : ATI Radeon HD 2400 PRO AGP */ + { 0x94C4, 0x18BC, 0x0028, "GeCube Radeon HD 2400PRO AGP", RHD_CARD_FLAG_NONE, BROKEN_VGA_B1_DVI_AB00, DEVINFO_EMPTY }, + /* 0x94C5 : RV610 : ATI FireGL V4000 */ + /* 0x94C6 : RV610 : RV610 */ + /* 0x94C7 : RV610 : ATI Radeon HD 2350 */ + /* 0x94C8 : M74 : Mobility Radeon HD 2400 XT */ + /* 0x94C9 : M72 : Mobility Radeon HD 2400 */ + /* 0x94CB : M72 : ATI RADEON E2400 */ + /* 0x94CC : RV610 : RV610 */ + /* 0x9505 : RV670 : ATI Radeon HD 3850 */ + /* 0x9580 : RV630 : RV630 */ + /* 0x9581 : M76 : Mobility Radeon HD 2600 */ + /* 0x9583 : M76 : Mobility Radeon HD 2600 XT */ + /* 0x9586 : RV630 : ATI Radeon HD 2600 XT AGP */ + /* 0x9587 : RV630 : ATI Radeon HD 2600 Pro AGP */ + { 0x9587, 0x1002, 0x0028, "Sapphire Radeon HD 2600 PRO AGP", RHD_CARD_FLAG_NONE, DVI_BA10_TV_B0_VGA_A0, DEVINFO_EMPTY }, + { 0x9587, 0x1462, 0x0028, "MSI HD2600PRO AGP", RHD_CARD_FLAG_NONE, DVI_BA12_TV_B0_DVI_AB01, DEVINFO_EMPTY }, + /* 0x9588 : RV630 : Radeon HD 2600 XT */ + { 0x9588, 0x1002, 0x2542, "ATI Radeon HD 2600XT DDR4", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + { 0x9588, 0x1448, 0x216C, "Gigabyte HD 2600 XT 256MB DDR3", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + { 0x9588, 0x174B, 0x2E42, "Sapphire HD 2600 XT", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x9589 : RV630 : Radeon HD 2600 Pro */ + { 0x9589, 0x174B, 0xE410, "Sapphire HD 2600 Pro", RHD_CARD_FLAG_NONE, DVI_BA10_DVI_AB01, DEVINFO_EMPTY }, + /* 0x958A : RV630 : Gemini RV630 */ + /* 0x958B : M76 : Gemini ATI Mobility Radeon HD 2600 XT */ + /* 0x958C : RV630 : ATI FireGL V5600 */ + /* 0x958D : RV630 : ATI FireGL V3600 */ + /* 0x958E : RV630 : ATI Radeon HD 2600 LE */ + { 0x9610, 0x105B, 0x0E0F, "Foxconn A7GM-S (RS780)", RHD_CARD_FLAG_HPDOFF, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY }, + { 0, 0, 0, NULL, 0, ID_CONNECTORINFO_EMPTY, DEVINFO_EMPTY } /* KEEP THIS: End marker. */ +}; + +/* + * + */ + +struct rhdCard *RHDCardIdentify(RHDPtr rhdPtr) +{ + unsigned int deviceID, subVendorID, subDeviceID; + int i; + + deviceID = (unsigned int) rhdPtr->PciDeviceID; + subVendorID = (unsigned int)rhdPtr->subvendor_id; + subDeviceID = (unsigned int)rhdPtr->subdevice_id; + + for (i = 0; rhdCards[i].name; i++) + if ((rhdCards[i].device == deviceID) && + (rhdCards[i].card_vendor == subVendorID) && + (rhdCards[i].card_device == subDeviceID)) + return rhdCards + i; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Unknown card detected: 0x%04X:0x%04X:0x%04X.\n", + deviceID, subVendorID, subDeviceID); + return NULL; +} + +#define USE_ATOMBIOS RHD_RV770 +#define USE_ATOM_CRTC USE_ATOMBIOS +#define USE_ATOM_PLL USE_ATOMBIOS +#define USE_ATOM_OUTPUT USE_ATOMBIOS + +/* + * + */ +Bool +RHDUseAtom(RHDPtr rhdPtr, enum RHD_CHIPSETS *BlackList, + enum atomSubSystem subsys) +{ +#ifdef ATOM_BIOS + Bool FromSys = FALSE, ret = FALSE; + CARD32 FromUser = 0; + int i = 0; + char *message = NULL; + enum RHD_CHIPSETS AtomChip; + int from = 0; + + switch (subsys) { + case atomUsageCrtc: + AtomChip = USE_ATOM_CRTC; + message = "Crtcs"; + FromUser = (rhdPtr->UseAtomFlags >> RHD_ATOMBIOS_CRTC) & 0x7; + break; + case atomUsagePLL: + AtomChip = USE_ATOM_PLL; + message = "PLLs"; + FromUser = (rhdPtr->UseAtomFlags >> RHD_ATOMBIOS_PLL) & 0x7; + break; + case atomUsageOutput: + AtomChip = USE_ATOM_OUTPUT; + message = "Outputs"; + FromUser = (rhdPtr->UseAtomFlags >> RHD_ATOMBIOS_OUTPUT) & 0x7; + break; + case atomUsageAny: + AtomChip = min(USE_ATOM_OUTPUT,min(USE_ATOM_PLL, USE_ATOM_CRTC)); + message = "All"; + FromUser = ((rhdPtr->UseAtomFlags >> RHD_ATOMBIOS_OUTPUT) + | (rhdPtr->UseAtomFlags >> RHD_ATOMBIOS_PLL) + | (rhdPtr->UseAtomFlags >> RHD_ATOMBIOS_CRTC)) & 0x7; + break; + } + + if (rhdPtr->ChipSet >= AtomChip) + FromSys = TRUE; + + if (!FromSys && BlackList) { + while (BlackList[i] != RHD_CHIP_END) { + if (BlackList[i++] == rhdPtr->ChipSet) { + FromSys = TRUE; + } + } + } + if (!FromSys) { + if (rhdPtr->UseAtomBIOS.set) { +// from = X_CONFIG; + ret = rhdPtr->UseAtomBIOS.val.bool; + } + if (FromUser & RHD_ATOMBIOS_ON) + ret = TRUE; + if (FromUser & RHD_ATOMBIOS_OFF) + ret = FALSE; + } else { + ret = TRUE; + if ((FromUser & RHD_ATOMBIOS_FORCE) && (FromUser & RHD_ATOMBIOS_OFF)) { + // from = X_CONFIG; + ret = FALSE; + } + } + if (ret) + xf86DrvMsg(rhdPtr->scrnIndex, from, "Using AtomBIOS for %s\n", + message); + + return ret; +#else + return 0; +#endif /* ATOM_BIOS */ +} diff --git a/programs/system/drivers/rhd/rhd_lut.c b/programs/system/drivers/rhd/rhd_lut.c new file mode 100644 index 000000000..a2f2bfdf9 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_lut.c @@ -0,0 +1,304 @@ +/* + * Copyright 2007-2008 Luc Verhaegen + * Copyright 2007-2008 Matthias Hopf + * Copyright 2007-2008 Egbert Eich + * + * 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 + +#include "xf86.h" + +#include "rhd.h" +#include "rhd_lut.h" +#include "rhd_regs.h" + +#define RHD_REGOFFSET_LUTA 0x000 +#define RHD_REGOFFSET_LUTB 0x800 + +/* + * + */ +static void +LUTxSave(struct rhdLUT *LUT) +{ + CARD16 RegOff; + int i; + RHDFUNC(LUT); + + if (LUT->Id == RHD_LUT_A) + RegOff = RHD_REGOFFSET_LUTA; + else + RegOff = RHD_REGOFFSET_LUTB; + + LUT->StoreControl = RHDRegRead(LUT, RegOff + DC_LUTA_CONTROL); + + LUT->StoreBlackBlue = RHDRegRead(LUT, RegOff + DC_LUTA_BLACK_OFFSET_BLUE); + LUT->StoreBlackGreen = RHDRegRead(LUT, RegOff + DC_LUTA_BLACK_OFFSET_GREEN); + LUT->StoreBlackRed = RHDRegRead(LUT, RegOff + DC_LUTA_BLACK_OFFSET_RED); + + LUT->StoreWhiteBlue = RHDRegRead(LUT, RegOff + DC_LUTA_WHITE_OFFSET_BLUE); + LUT->StoreWhiteGreen = RHDRegRead(LUT, RegOff + DC_LUTA_WHITE_OFFSET_GREEN); + LUT->StoreWhiteRed = RHDRegRead(LUT, RegOff + DC_LUTA_WHITE_OFFSET_RED); + + RHDRegWrite(LUT, DC_LUT_RW_MODE, 0); /* Table */ + if (LUT->Id == RHD_LUT_A) + RHDRegWrite(LUT, DC_LUT_READ_PIPE_SELECT, 0); + else + RHDRegWrite(LUT, DC_LUT_READ_PIPE_SELECT, 1); + + RHDRegWrite(LUT, DC_LUT_RW_INDEX, 0); + for (i = 0; i < 0x300; i++) + LUT->StoreEntry[i] = RHDRegRead(LUT, DC_LUT_SEQ_COLOR); + + LUT->Stored = TRUE; +} + +/* + * + */ +static void +LUTxRestore(struct rhdLUT *LUT) +{ + CARD16 RegOff; + int i; + RHDFUNC(LUT); + + if (!LUT->Stored) { + xf86DrvMsg(LUT->scrnIndex, X_ERROR, "%s: %s: nothing stored!\n", + __func__, LUT->Name); + return; + } + + if (LUT->Id == RHD_LUT_A) + RegOff = RHD_REGOFFSET_LUTA; + else + RegOff = RHD_REGOFFSET_LUTB; + + RHDRegWrite(LUT, RegOff + DC_LUTA_BLACK_OFFSET_BLUE, LUT->StoreBlackBlue); + RHDRegWrite(LUT, RegOff + DC_LUTA_BLACK_OFFSET_GREEN, LUT->StoreBlackGreen); + RHDRegWrite(LUT, RegOff + DC_LUTA_BLACK_OFFSET_RED, LUT->StoreBlackRed); + + RHDRegWrite(LUT, RegOff + DC_LUTA_WHITE_OFFSET_BLUE, LUT->StoreWhiteBlue); + RHDRegWrite(LUT, RegOff + DC_LUTA_WHITE_OFFSET_GREEN, LUT->StoreWhiteGreen); + RHDRegWrite(LUT, RegOff + DC_LUTA_WHITE_OFFSET_RED, LUT->StoreWhiteRed); + + if (LUT->Id == RHD_LUT_A) + RHDRegWrite(LUT, DC_LUT_RW_SELECT, 0); + else + RHDRegWrite(LUT, DC_LUT_RW_SELECT, 1); + + RHDRegWrite(LUT, DC_LUT_RW_MODE, 0); /* Table */ + RHDRegWrite(LUT, DC_LUT_WRITE_EN_MASK, 0x0000003F); + RHDRegWrite(LUT, DC_LUT_RW_INDEX, 0); + for (i = 0; i < 0x300; i++) + RHDRegWrite(LUT, DC_LUT_SEQ_COLOR, LUT->StoreEntry[i]); + + RHDRegWrite(LUT, RegOff + DC_LUTA_CONTROL, LUT->StoreControl); +} + +/* + * + */ +static void +LUTxSet(struct rhdLUT *LUT, int numColors, int *indices, LOCO *colors) +{ + //ScrnInfoPtr pScrn = xf86Screens[LUT->scrnIndex]; + CARD16 RegOff; + int i, index; + + LUT->Initialised = TRUE; /* thank you RandR */ + + if (LUT->Id == RHD_LUT_A) + RegOff = RHD_REGOFFSET_LUTA; + else + RegOff = RHD_REGOFFSET_LUTB; + + RHDRegWrite(LUT, RegOff + DC_LUTA_CONTROL, 0); + + RHDRegWrite(LUT, RegOff + DC_LUTA_BLACK_OFFSET_BLUE, 0); + RHDRegWrite(LUT, RegOff + DC_LUTA_BLACK_OFFSET_GREEN, 0); + RHDRegWrite(LUT, RegOff + DC_LUTA_BLACK_OFFSET_RED, 0); + + RHDRegWrite(LUT, RegOff + DC_LUTA_WHITE_OFFSET_BLUE, 0x0000FFFF); + RHDRegWrite(LUT, RegOff + DC_LUTA_WHITE_OFFSET_GREEN, 0x0000FFFF); + RHDRegWrite(LUT, RegOff + DC_LUTA_WHITE_OFFSET_RED, 0x0000FFFF); + + if (LUT->Id == RHD_LUT_A) + RHDRegWrite(LUT, DC_LUT_RW_SELECT, 0); + else + RHDRegWrite(LUT, DC_LUT_RW_SELECT, 1); + + RHDRegWrite(LUT, DC_LUT_RW_MODE, 0); /* table */ + RHDRegWrite(LUT, DC_LUT_WRITE_EN_MASK, 0x0000003F); + + int depth = 32; + + switch (depth) { + case 8: + case 24: + case 32: + for (i = 0; i < numColors; i++) { + index = indices[i]; + RHDRegWrite(LUT, DC_LUT_RW_INDEX, index); + RHDRegWrite(LUT, DC_LUT_30_COLOR, (colors[index].red << 22) | + (colors[index].green << 12) | (colors[index].blue << 2)); + } + break; + case 16: + for (i = 0; i < numColors; i++) { + int j; + + index = indices[i]; + RHDRegWrite(LUT, DC_LUT_RW_INDEX, 4 * index); + + for (j = 0; j < 4; j++) + RHDRegWrite(LUT, DC_LUT_30_COLOR, (colors[index/2].red << 24) | + (colors[index].green << 14) | (colors[index/2].blue << 4)); + } + break; + case 15: + for (i = 0; i < numColors; i++) { + int j; + + index = indices[i]; + RHDRegWrite(LUT, DC_LUT_RW_INDEX, 8 * index); + + for (j = 0; j < 8; j++) + RHDRegWrite(LUT, DC_LUT_30_COLOR, (colors[index].red << 25) | + (colors[index].green << 15) | (colors[index].blue << 5)); + } + break; + } +} + +/* + * + */ +void +RHDLUTsInit(RHDPtr rhdPtr) +{ + struct rhdLUT *LUT; + + RHDFUNC(rhdPtr); + + LUT = xnfcalloc(sizeof(struct rhdLUT), 1); + + LUT->scrnIndex = rhdPtr->scrnIndex; + LUT->Name = "LUT A"; + LUT->Id = RHD_LUT_A; + + LUT->Save = LUTxSave; + LUT->Restore = LUTxRestore; + LUT->Set = LUTxSet; + + rhdPtr->LUT[0] = LUT; + + LUT = xnfcalloc(sizeof(struct rhdLUT), 1); + + LUT->scrnIndex = rhdPtr->scrnIndex; + LUT->Name = "LUT B"; + LUT->Id = RHD_LUT_B; + + LUT->Save = LUTxSave; + LUT->Restore = LUTxRestore; + LUT->Set = LUTxSet; + + rhdPtr->LUT[1] = LUT; +} + +/* + * + */ +struct rhdLUTStore { + CARD32 Select; + CARD32 Mode; + CARD32 Index; + CARD32 Color; + CARD32 ReadPipe; + CARD32 WriteMask; +}; + +/* + * + */ +void +RHDLUTsSave(RHDPtr rhdPtr) +{ + struct rhdLUTStore *Store = rhdPtr->LUTStore; + + RHDFUNC(rhdPtr); + + if (!Store) { + Store = xnfcalloc(sizeof(struct rhdLUTStore), 1); + rhdPtr->LUTStore = Store; + } + + Store->Select = _RHDRegRead(rhdPtr, DC_LUT_RW_SELECT); + Store->Mode = _RHDRegRead(rhdPtr, DC_LUT_RW_MODE); + Store->Index = _RHDRegRead(rhdPtr, DC_LUT_RW_INDEX); + Store->Color = _RHDRegRead(rhdPtr, DC_LUT_30_COLOR); + Store->ReadPipe = _RHDRegRead(rhdPtr, DC_LUT_READ_PIPE_SELECT); + Store->WriteMask = _RHDRegRead(rhdPtr, DC_LUT_WRITE_EN_MASK); + + rhdPtr->LUT[0]->Save(rhdPtr->LUT[0]); + rhdPtr->LUT[1]->Save(rhdPtr->LUT[1]); +} + +/* + * + */ +void +RHDLUTsRestore(RHDPtr rhdPtr) +{ + struct rhdLUTStore *Store = rhdPtr->LUTStore; + + RHDFUNC(rhdPtr); + + rhdPtr->LUT[0]->Restore(rhdPtr->LUT[0]); + rhdPtr->LUT[1]->Restore(rhdPtr->LUT[1]); + + if (!Store) { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: nothing stored!\n", __func__); + return; + } + + _RHDRegWrite(rhdPtr, DC_LUT_RW_SELECT, Store->Select); + _RHDRegWrite(rhdPtr, DC_LUT_RW_MODE, Store->Mode); + _RHDRegWrite(rhdPtr, DC_LUT_RW_INDEX, Store->Index); + _RHDRegWrite(rhdPtr, DC_LUT_30_COLOR, Store->Color); + _RHDRegWrite(rhdPtr, DC_LUT_READ_PIPE_SELECT, Store->ReadPipe); + _RHDRegWrite(rhdPtr, DC_LUT_WRITE_EN_MASK, Store->WriteMask); +} + +/* + * + */ +void +RHDLUTsDestroy(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + xfree(rhdPtr->LUT[0]); + xfree(rhdPtr->LUT[1]); + xfree(rhdPtr->LUTStore); +} diff --git a/programs/system/drivers/rhd/rhd_lut.h b/programs/system/drivers/rhd/rhd_lut.h new file mode 100644 index 000000000..84c8bf796 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_lut.h @@ -0,0 +1,68 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_LUT_H +#define _RHD_LUT_H + +struct rhdLUT { + int scrnIndex; + + char *Name; +#define RHD_LUT_A 0 +#define RHD_LUT_B 1 + int Id; + + void (*Save) (struct rhdLUT *LUT); + void (*Restore) (struct rhdLUT *LUT); + void (*Set) (struct rhdLUT *LUT, int numColors, int *indices, LOCO *colors); + + /* because RandR does not specifically initialise a gamma ramp when + setting up a CRTC */ + Bool Initialised; + + Bool Stored; + + CARD32 StoreControl; + + CARD32 StoreBlackRed; + CARD32 StoreBlackGreen; + CARD32 StoreBlackBlue; + + CARD32 StoreWhiteRed; + CARD32 StoreWhiteGreen; + CARD32 StoreWhiteBlue; + + CARD16 StoreEntry[0x300]; +}; + +void RHDLUTsInit(RHDPtr rhdPtr); +void RHDLUTsSave(RHDPtr rhdPtr); +void RHDLUTsRestore(RHDPtr rhdPtr); +void RHDLUTsDestroy(RHDPtr rhdPtr); + +/* For missing RandR functionality */ +void RHDLUTCopyForRR(struct rhdLUT *LUT); + +#endif /* _RHD_LUT_H */ diff --git a/programs/system/drivers/rhd/rhd_lvtma.c b/programs/system/drivers/rhd/rhd_lvtma.c new file mode 100644 index 000000000..8a414c2d2 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_lvtma.c @@ -0,0 +1,1387 @@ +/* + * Copyright 2007-2008 Luc Verhaegen + * Copyright 2007-2008 Matthias Hopf + * Copyright 2007-2008 Egbert Eich + * 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. + */ + +/* + * Deals with the Shared LVDS/TMDS encoder. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" + +#ifdef ATOM_BIOS +#include "rhd_atombios.h" +#include "rhd_atomout.h" +#endif + +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_regs.h" +#include "rhd_card.h" + +/* + * First of all, make it more managable to code for both R500 and R600, as + * there was a 1 register shift, right in the middle of the register block. + * There are of course much nicer ways to do the workaround i am doing here, + * but speed is not an issue here. + */ +static inline CARD16 +LVTMAChipGenerationSelect(int ChipSet, CARD32 R500, CARD32 R600) +{ + if (ChipSet >= RHD_RS600) + return R600; + else + return R500; +} + +#define LVTMAGENSEL(r500, r600) LVTMAChipGenerationSelect(rhdPtr->ChipSet, (r500), (r600)) +#define LVTMA_DATA_SYNCHRONIZATION \ + LVTMAGENSEL(LVTMA_R500_DATA_SYNCHRONIZATION, LVTMA_R600_DATA_SYNCHRONIZATION) +#define LVTMA_PWRSEQ_REF_DIV \ + LVTMAGENSEL(LVTMA_R500_PWRSEQ_REF_DIV, LVTMA_R600_PWRSEQ_REF_DIV) +#define LVTMA_PWRSEQ_DELAY1 \ + LVTMAGENSEL(LVTMA_R500_PWRSEQ_DELAY1, LVTMA_R600_PWRSEQ_DELAY1) +#define LVTMA_PWRSEQ_DELAY2 \ + LVTMAGENSEL(LVTMA_R500_PWRSEQ_DELAY2, LVTMA_R600_PWRSEQ_DELAY2) +#define LVTMA_PWRSEQ_CNTL \ + LVTMAGENSEL(LVTMA_R500_PWRSEQ_CNTL, LVTMA_R600_PWRSEQ_CNTL) +#define LVTMA_PWRSEQ_STATE \ + LVTMAGENSEL(LVTMA_R500_PWRSEQ_STATE, LVTMA_R600_PWRSEQ_STATE) +#define LVTMA_LVDS_DATA_CNTL \ + LVTMAGENSEL(LVTMA_R500_LVDS_DATA_CNTL, LVTMA_R600_LVDS_DATA_CNTL) +#define LVTMA_MODE LVTMAGENSEL(LVTMA_R500_MODE, LVTMA_R600_MODE) +#define LVTMA_TRANSMITTER_ENABLE \ + LVTMAGENSEL(LVTMA_R500_TRANSMITTER_ENABLE, LVTMA_R600_TRANSMITTER_ENABLE) +#define LVTMA_MACRO_CONTROL \ + LVTMAGENSEL(LVTMA_R500_MACRO_CONTROL, LVTMA_R600_MACRO_CONTROL) +#define LVTMA_TRANSMITTER_CONTROL \ + LVTMAGENSEL(LVTMA_R500_TRANSMITTER_CONTROL, LVTMA_R600_TRANSMITTER_CONTROL) +#define LVTMA_REG_TEST_OUTPUT \ + LVTMAGENSEL(LVTMA_R500_REG_TEST_OUTPUT, LVTMA_R600_REG_TEST_OUTPUT) +#define LVTMA_BL_MOD_CNTL \ + LVTMAGENSEL(LVTMA_R500_BL_MOD_CNTL, LVTMA_R600_BL_MOD_CNTL) + +#define LVTMA_DITHER_RESET_BIT LVTMAGENSEL(0x04000000, 0x02000000) + +/* + * + * Handling for LVTMA block as LVDS. + * + */ + +struct LVDSPrivate { + Bool DualLink; + Bool LVDS24Bit; + Bool FPDI; /* LDI otherwise */ + CARD16 TXClockPattern; + int BlLevel; + CARD32 MacroControl; + + /* Power timing for LVDS */ + CARD16 PowerRefDiv; + CARD16 BlonRefDiv; + CARD16 PowerDigToDE; + CARD16 PowerDEToBL; + CARD16 OffDelay; + Bool TemporalDither; + Bool SpatialDither; + int GreyLevel; + + Bool Stored; + + CARD32 StoreControl; + CARD32 StoreSourceSelect; + CARD32 StoreBitDepthControl; + CARD32 StoreDataSynchronisation; + CARD32 StorePWRSEQRefDiv; + CARD32 StorePWRSEQDelay1; + CARD32 StorePWRSEQDelay2; + CARD32 StorePWRSEQControl; + CARD32 StorePWRSEQState; + CARD32 StoreLVDSDataControl; + CARD32 StoreMode; + CARD32 StoreTxEnable; + CARD32 StoreMacroControl; + CARD32 StoreTXControl; + CARD32 StoreBlModCntl; +#ifdef NOT_YET + /* to hook in AtomBIOS property callback */ + Bool (*WrappedPropertyCallback) (struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val); + void *PropertyPrivate; +#endif +}; + +/* + * + */ +static ModeStatus +LVDSModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + return MODE_OK; +} + +/* + * + */ +static void +LVDSDebugBacklight(struct rhdOutput *Output) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + CARD32 tmp; + Bool Blon, BlonOvrd, BlonPol, BlModEn; + int BlModLevel, BlModRes = 0; + + if (rhdPtr->verbosity < 7) + return; + + tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 3) & 0x01; + RHDDebug(rhdPtr->scrnIndex, "%s: PWRSEQ BLON State: %s\n", + __func__, tmp ? "on" : "off"); + tmp = RHDRegRead(rhdPtr, LVTMA_PWRSEQ_CNTL); + Blon = (tmp >> 24) & 0x1; + BlonOvrd = (tmp >> 25) & 0x1; + BlonPol = (tmp >> 26) & 0x1; + + RHDDebug(rhdPtr->scrnIndex, "%s: BLON: %s BLON_OVRD: %s BLON_POL: %s\n", + __func__, Blon ? "on" : "off", + BlonOvrd ? "enabled" : "disabled", + BlonPol ? "invert" : "non-invert"); + + tmp = RHDRegRead(rhdPtr, LVTMA_BL_MOD_CNTL); + BlModEn = tmp & 0x1; + BlModLevel = (tmp >> 8) & 0xFF; + if (rhdPtr->ChipSet >= RHD_RS600) + BlModRes = (tmp >> 16) & 0xFF; + + xf86DrvMsgVerb(rhdPtr->scrnIndex, X_INFO, 3, + "%s: BL_MOD: %s BL_MOD_LEVEL: %d BL_MOD_RES: %d\n", + __func__, BlModEn ? "enable" : "disable", + BlModLevel, BlModRes); +} + +/* + * + */ +static void +LVDSSetBacklight(struct rhdOutput *Output, int level) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + Private->BlLevel = level; + + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, + "%s: trying to set BL_MOD_LEVEL to: %d\n", + __func__, level); + + if (rhdPtr->ChipSet >= RHD_RS600) + _RHDRegMask(rhdPtr, LVTMA_BL_MOD_CNTL, + 0xFF << 16 | (level << 8) | 0x1, + 0xFFFF01); + else + _RHDRegMask(rhdPtr, LVTMA_BL_MOD_CNTL, + (level << 8) | 0x1, + 0xFF01); + + /* + * Poor man's debug + */ + LVDSDebugBacklight(Output); +} + +/* + * + */ +static Bool +LVDSPropertyControl(struct rhdOutput *Output, enum rhdPropertyAction Action, + enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + + switch (Action) { + case rhdPropertyCheck: + switch (Property) { + if (Private->BlLevel < 0) + return FALSE; + case RHD_OUTPUT_BACKLIGHT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + if (Private->BlLevel < 0) + return FALSE; + val->integer = Private->BlLevel; + break; + default: + return FALSE; + } + break; + case rhdPropertySet: + switch (Property) { + case RHD_OUTPUT_BACKLIGHT: + if (Private->BlLevel < 0) + return FALSE; + LVDSSetBacklight(Output, val->integer); + break; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static void +LVDSSet(struct rhdOutput *Output, DisplayModePtr Mode) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + RHDRegMask(Output, LVTMA_CNTL, 0x00000001, 0x00000001); /* enable */ + usleep(20); + + RHDRegWrite(Output, LVTMA_MODE, 0); /* set to LVDS */ + + /* Select CRTC, select syncA, no stereosync */ + RHDRegMask(Output, LVTMA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101); + + if (Private->LVDS24Bit) { /* 24bits */ + RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0x00000001, 0x00000001); /* enable 24bits */ + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0x00101010, 0x00101010); /* dithering bit depth = 24 */ + + if (Private->FPDI) /* FPDI? */ + RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0x00000010, 0x00000010); /* 24 bit format: FPDI or LDI? */ + else + RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0, 0x00000010); + } else { + RHDRegMask(Output, LVTMA_LVDS_DATA_CNTL, 0, 0x00000001); /* disable 24bits */ + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00101010); /* dithering bit depth != 24 */ + } + + /* enable temporal dithering, disable spatial dithering and disable truncation */ + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, + Private->TemporalDither ? 1 << 16 : 0 + | Private->SpatialDither ? 1 << 8 : 0 + | (Private->GreyLevel > 2) ? 1 << 24 : 0, + 0x01010101); + + /* reset the temporal dithering */ + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT); + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, LVTMA_DITHER_RESET_BIT); + + /* go for RGB 4:4:4 RGB/YCbCr */ + RHDRegMask(Output, LVTMA_CNTL, 0, 0x00010000); + + if (Private->DualLink) + RHDRegMask(Output, LVTMA_CNTL, 0x01000000, 0x01000000); + else + RHDRegMask(Output, LVTMA_CNTL, 0, 0x01000000); + + /* PLL and TX voltages */ + RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->MacroControl); + + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010); /* use pclk_lvtma_direct */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0xCC000000); + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, Private->TXClockPattern << 16, 0x03FF0000); + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001); /* enable PLL */ + usleep(20); + + /* reset transmitter */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); + usleep(2); + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002); + usleep(20); + + /* start data synchronisation */ + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000001, 0x00000001); + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000100, 0x00000100); /* reset */ + usleep(2); + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000100); +} + +/* + * + */ +static void +LVDSPWRSEQInit(struct rhdOutput *Output) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + CARD32 tmp = 0; + + tmp = Private->PowerDigToDE >> 2; + RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp, 0x000000FF); + RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 24, 0xFF000000); + + tmp = Private->PowerDEToBL >> 2; + RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 8, 0x0000FF00); + RHDRegMask(Output, LVTMA_PWRSEQ_DELAY1, tmp << 16, 0x00FF0000); + + RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY2, Private->OffDelay >> 2); + RHDRegWrite(Output, LVTMA_PWRSEQ_REF_DIV, + Private->PowerRefDiv | (Private->BlonRefDiv << 16)); + + /* Enable power sequencer and allow it to override everything */ + RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0x0000000D, 0x0000000D); + + /* give full control to the sequencer */ + RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0, 0x02020200); +} + +/* + * + */ +static void +LVDSEnable(struct rhdOutput *Output) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + CARD32 tmp = 0; + int i; + + RHDFUNC(Output); + + LVDSPWRSEQInit(Output); + + /* set up the transmitter */ + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x0000001E, 0x0000001E); + if (Private->LVDS24Bit) /* 24bit ? */ + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00000020, 0x00000020); + + if (Private->DualLink) { + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00001E00, 0x00001E00); + + if (Private->LVDS24Bit) + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00002000, 0x00002000); + } + + RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0x00000010, 0x00000010); + + for (i = 0; i <= Private->OffDelay; i++) { + usleep(1000); + + tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 8) & 0x0F; + if (tmp == 4) + break; + } + + if (i == Private->OffDelay) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: failed to reach " + "POWERUP_DONE state after %d loops (%d)\n", + __func__, i, (int) tmp); + } + if (Private->BlLevel >= 0) { + union rhdPropertyData data; + data.integer = Private->BlLevel; + Output->Property(Output, rhdPropertySet, RHD_OUTPUT_BACKLIGHT, + &data); + } +} + +/* + * + */ +static void +LVDSDisable(struct rhdOutput *Output) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + CARD32 tmp = 0; + int i; + + RHDFUNC(Output); + + if (!(RHDRegRead(Output, LVTMA_PWRSEQ_CNTL) & 0x00000010)) + return; + + LVDSPWRSEQInit(Output); + + RHDRegMask(Output, LVTMA_PWRSEQ_CNTL, 0, 0x00000010); + + for (i = 0; i <= Private->OffDelay; i++) { + usleep(1000); + + tmp = (RHDRegRead(Output, LVTMA_PWRSEQ_STATE) >> 8) & 0x0F; + if (tmp == 9) + break; + } + + if (i == Private->OffDelay) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: failed to reach " + "POWERDOWN_DONE state after %d loops (%d)\n", + __func__, i, (int) tmp); + } + + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x0000FFFF); +} + +#if 0 +/* + * + */ +static void +LVDSShutdown(struct rhdOutput *Output) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + RHDFUNC(Output); + + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); /* PLL in reset */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001); /* disable LVDS */ + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000001); + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT); /* reset temp dithering */ + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00111111); /* disable all dithering */ + RHDRegWrite(Output, LVTMA_CNTL, 0); /* disable */ +} +#endif + +/* + * + */ +static void +LVDSPower(struct rhdOutput *Output, int Power) +{ + RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, + rhdPowerString[Power]); + + switch (Power) { + case RHD_POWER_ON: + LVDSEnable(Output); + break; + case RHD_POWER_RESET: + /* LVDSDisable(Output); + break;*/ + case RHD_POWER_SHUTDOWN: + default: + LVDSDisable(Output); + /* LVDSShutdown(Output); */ + break; + } + return; +} + +/* + * + */ +static void +LVDSSave(struct rhdOutput *Output) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL); + Private->StoreSourceSelect = RHDRegRead(Output, LVTMA_SOURCE_SELECT); + Private->StoreBitDepthControl = RHDRegRead(Output, LVTMA_BIT_DEPTH_CONTROL); + Private->StoreDataSynchronisation = RHDRegRead(Output, LVTMA_DATA_SYNCHRONIZATION); + Private->StorePWRSEQRefDiv = RHDRegRead(Output, LVTMA_PWRSEQ_REF_DIV); + Private->StorePWRSEQDelay1 = RHDRegRead(Output, LVTMA_PWRSEQ_DELAY1); + Private->StorePWRSEQDelay2 = RHDRegRead(Output, LVTMA_PWRSEQ_DELAY2); + Private->StorePWRSEQControl = RHDRegRead(Output, LVTMA_PWRSEQ_CNTL); + Private->StorePWRSEQState = RHDRegRead(Output, LVTMA_PWRSEQ_STATE); + Private->StoreLVDSDataControl = RHDRegRead(Output, LVTMA_LVDS_DATA_CNTL); + Private->StoreMode = RHDRegRead(Output, LVTMA_MODE); + Private->StoreTxEnable = RHDRegRead(Output, LVTMA_TRANSMITTER_ENABLE); + Private->StoreMacroControl = RHDRegRead(Output, LVTMA_MACRO_CONTROL); + Private->StoreTXControl = RHDRegRead(Output, LVTMA_TRANSMITTER_CONTROL); + Private->StoreBlModCntl = RHDRegRead(Output, LVTMA_BL_MOD_CNTL); + + Private->Stored = TRUE; +} + +/* + * This needs to reset things like the temporal dithering and the TX appropriately. + * Currently it's a dumb register dump. + */ +static void +LVDSRestore(struct rhdOutput *Output) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + if (!Private->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + RHDRegWrite(Output, LVTMA_CNTL, Private->StoreControl); + RHDRegWrite(Output, LVTMA_SOURCE_SELECT, Private->StoreSourceSelect); + RHDRegWrite(Output, LVTMA_BIT_DEPTH_CONTROL, Private->StoreBitDepthControl); + RHDRegWrite(Output, LVTMA_DATA_SYNCHRONIZATION, Private->StoreDataSynchronisation); + RHDRegWrite(Output, LVTMA_PWRSEQ_REF_DIV, Private->StorePWRSEQRefDiv); + RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY1, Private->StorePWRSEQDelay1); + RHDRegWrite(Output, LVTMA_PWRSEQ_DELAY2, Private->StorePWRSEQDelay2); + RHDRegWrite(Output, LVTMA_PWRSEQ_CNTL, Private->StorePWRSEQControl); + RHDRegWrite(Output, LVTMA_PWRSEQ_STATE, Private->StorePWRSEQState); + RHDRegWrite(Output, LVTMA_LVDS_DATA_CNTL, Private->StoreLVDSDataControl); + RHDRegWrite(Output, LVTMA_MODE, Private->StoreMode); + RHDRegWrite(Output, LVTMA_TRANSMITTER_ENABLE, Private->StoreTxEnable); + RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->StoreMacroControl); + RHDRegWrite(Output, LVTMA_TRANSMITTER_CONTROL, Private->StoreTXControl); + RHDRegWrite(Output, LVTMA_BL_MOD_CNTL, Private->StoreBlModCntl); + + /* + * Poor man's debug + */ + LVDSDebugBacklight(Output); +} + +/* + * Here we pretty much assume that ATOM has either initialised the panel already + * or that we can find information from ATOM BIOS data tables. We know that the + * latter assumption is false for some values, but there is no getting around + * ATI clinging desperately to a broken concept. + */ +static struct LVDSPrivate * +LVDSInfoRetrieve(RHDPtr rhdPtr) +{ + struct LVDSPrivate *Private = xnfcalloc(sizeof(struct LVDSPrivate), 1); + CARD32 tmp; + + /* These values are not available from atombios data tables at all. */ + Private->MacroControl = RHDRegRead(rhdPtr, LVTMA_MACRO_CONTROL); + Private->TXClockPattern = + (_RHDRegRead(rhdPtr, LVTMA_TRANSMITTER_CONTROL) >> 16) & 0x3FF; + + /* For these values, we try to retrieve them from register space first, + and later override with atombios data table information */ + Private->PowerDigToDE = + (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY1) & 0x000000FF) << 2; + + Private->PowerDEToBL = + (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY1) & 0x0000FF00) >> 6; + + Private->OffDelay = (_RHDRegRead(rhdPtr, LVTMA_PWRSEQ_DELAY2) & 0xFF) << 2; + + tmp = _RHDRegRead(rhdPtr, LVTMA_PWRSEQ_REF_DIV); + Private->PowerRefDiv = tmp & 0x0FFF; + Private->BlonRefDiv = (tmp >> 16) & 0x0FFF; + tmp = _RHDRegRead(rhdPtr, LVTMA_BL_MOD_CNTL); + if (tmp & 0x1) + Private->BlLevel = (tmp >> 8) & 0xff; + else + Private->BlLevel = -1; /* Backlight control seems to be done some other way */ + + Private->DualLink = (_RHDRegRead(rhdPtr, LVTMA_CNTL) >> 24) & 0x00000001; + Private->LVDS24Bit = _RHDRegRead(rhdPtr, LVTMA_LVDS_DATA_CNTL) & 0x00000001; + Private->FPDI = _RHDRegRead(rhdPtr, LVTMA_LVDS_DATA_CNTL) & 0x00000010; + + tmp = _RHDRegRead(rhdPtr, LVTMA_BIT_DEPTH_CONTROL); + Private->TemporalDither = ((tmp & (1 << 16)) != 0); + Private->SpatialDither = ((tmp & (1 << 8)) != 0); + Private->GreyLevel = (tmp & (1 << 24)) ? 4 : 2; + +#ifdef ATOM_BIOS + { + AtomBiosArgRec data; + + if(RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_SEQ_DIG_ONTO_DE, &data) == ATOM_SUCCESS) + Private->PowerDigToDE = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_SEQ_DE_TO_BL, &data) == ATOM_SUCCESS) + Private->PowerDEToBL = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_OFF_DELAY, &data) == ATOM_SUCCESS) + Private->OffDelay = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_DUALLINK, &data) == ATOM_SUCCESS) + Private->DualLink = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_24BIT, &data) == ATOM_SUCCESS) + Private->LVDS24Bit = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_FPDI, &data) == ATOM_SUCCESS) + Private->FPDI = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_TEMPORAL_DITHER, &data) == ATOM_SUCCESS) + Private->TemporalDither = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_SPATIAL_DITHER, &data) == ATOM_SUCCESS) + Private->SpatialDither = data.val; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_LVDS_GREYLVL, &data) == ATOM_SUCCESS) { + Private->GreyLevel = data.val; + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "AtomBIOS returned %i Grey Levels\n", + Private->GreyLevel); + } + } +#endif + + if (Private->LVDS24Bit) + xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED, + "Detected a 24bit %s, %s link panel.\n", + Private->DualLink ? "dual" : "single", + Private->FPDI ? "FPDI": "LDI"); + else + xf86DrvMsg(rhdPtr->scrnIndex, X_PROBED, + "Detected a 18bit %s link panel.\n", + Private->DualLink ? "dual" : "single"); + + /* extra noise */ + RHDDebug(rhdPtr->scrnIndex, "Printing LVDS paramaters:\n"); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tMacroControl: 0x%08X\n", + (unsigned int) Private->MacroControl); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tTXClockPattern: 0x%04X\n", + Private->TXClockPattern); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerDigToDE: 0x%04X\n", + Private->PowerDigToDE); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerDEToBL: 0x%04X\n", + Private->PowerDEToBL); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tOffDelay: 0x%04X\n", + Private->OffDelay); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tPowerRefDiv: 0x%04X\n", + Private->PowerRefDiv); + xf86MsgVerb(X_NONE, LOG_DEBUG, "\tBlonRefDiv: 0x%04X\n", + Private->BlonRefDiv); + + return Private; +} + +/* + * + */ +static void +LVDSDestroy(struct rhdOutput *Output) +{ + + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + + RHDFUNC(Output); + + if (!Private) + return; + +#ifdef NOT_YET + if (Private->PropertyPrivate) + RhdAtomDestroyBacklightControlProperty(Output, Private->PropertyPrivate); +#endif + xfree(Private); + Output->Private = NULL; +} + +/* + * + * Handling for LVTMA block as TMDS. + * + */ +struct rhdTMDSBPrivate { + Bool RunsDualLink; + Bool Coherent; + DisplayModePtr Mode; + + struct rhdHdmi *Hdmi; + + Bool Stored; + + CARD32 StoreControl; + CARD32 StoreSource; + CARD32 StoreFormat; + CARD32 StoreForce; + CARD32 StoreReduction; + CARD32 StoreDCBalancer; + CARD32 StoreDataSynchro; + CARD32 StoreMode; + CARD32 StoreTXEnable; + CARD32 StoreMacro; + CARD32 StoreTXControl; + CARD32 StoreTXAdjust; + CARD32 StoreTestOutput; + + CARD32 StoreRs690Unknown; + CARD32 StoreRv600TXAdjust; + CARD32 StoreRv600PreEmphasis; +}; + +/* + * + */ +static ModeStatus +TMDSBModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + if (Mode->Clock < 25000) + return MODE_CLOCK_LOW; + + if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) { + if (Mode->Clock > 165000) + return MODE_CLOCK_HIGH; + } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) { + if (Mode->Clock > 330000) /* could go higher still */ + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + +/* + * + */ +static void +RS600VoltageControl(struct rhdOutput *Output, DisplayModePtr Mode) +{ + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + + RHDFUNC(Output); +#ifdef NOTYET + if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) { + int clock = Mode->SynthClock; + + if (Private->RunsDualLink) + clock >>= 1; + if (clock <= 75000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00010213); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x000a0000); + } else { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00000213); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000); + } + } else +#endif + { + if (Private->RunsDualLink) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000020f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000); + } else { + if (Mode->SynthClock < 39000) + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0002020f); + else + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000020f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x00100000); + } + } +} + +/* + * + */ +static void +RS690VoltageControl(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + CARD32 rev = (RHDRegRead(Output, CONFIG_CNTL) && RS69_CFG_ATI_REV_ID_MASK) >> RS69_CFG_ATI_REV_ID_SHIFT; + + if (rev < 3) { +#ifdef NOTYET + if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) { + if (Mode->SynthClock > 75000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0xa001632f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + } else if (Mode->SynthClock > 41000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000632f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + } else { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0003632f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x050b000); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000); + } + } else +#endif + { + int clock = Mode->SynthClock; + + if (Private->RunsDualLink) + clock >>= 1; + + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x05120000); + + if (clock > 75000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0xa001631f); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + } else if (clock > 41000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000631f); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + } else { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0003631f); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000); + } + } + } else { +#ifdef NOTYET + if (Output->Connector == RHD_CONNECTOR_HDMI || Output->Connector == RHD_CONNECTOR_HDMI_DUAL) { + if (Mode->SynthClock <= 75000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0002612f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x010b0000); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x0, 0x10000000); + } else { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x0000642f); + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x01120000); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + } + } else +#endif + { + int clock = Mode->SynthClock; + + if (Private->RunsDualLink) + clock >>= 1; + + RHDRegWrite(Output, LVTMA_R600_REG_TEST_OUTPUT, 0x01120000); + RHDRegMask(Output, LVTMA_R600_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + + if (Mode->SynthClock > 75000) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00016318); + } else { + { +#ifdef ATOM_BIOS + AtomBiosArgRec data; + + if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOM_GET_CAPABILITY_FLAG, &data) == ATOM_SUCCESS) { + if (((data.val & 0x60) == 0x20 || (data.val & 0x80))) { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00016318); + } else { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00006318); + } + } else +#endif + { + RHDRegWrite(Output, LVTMA_R600_MACRO_CONTROL, 0x00006318); + } + } + } + } + } +} + +/* + * This information is not provided in an atombios data table. + */ +static struct R5xxTMDSBMacro { + CARD16 Device; + CARD32 MacroSingle; + CARD32 MacroDual; +} R5xxTMDSBMacro[] = { + /* + * this list isn't complete yet. + * Some more values for dual need to be dug up + */ + { 0x7104, 0x00F20616, 0x00F20616 }, /* R520 */ + { 0x7142, 0x00F2061C, 0x00F2061C }, /* RV515 */ + { 0x7145, 0x00F1061D, 0x00F2061D }, /**/ + { 0x7146, 0x00F1061D, 0x00F1061D }, /* RV515 */ + { 0x7147, 0x0082041D, 0x0082041D }, /* RV505 */ + { 0x7149, 0x00F1061D, 0x00D2061D }, /**/ + { 0x7152, 0x00F2061C, 0x00F2061C }, /* RV515 */ + { 0x7183, 0x00B2050C, 0x00B2050C }, /* RV530 */ + { 0x71C0, 0x00F1061F, 0x00f2061D }, /**/ + { 0x71C1, 0x0062041D, 0x0062041D }, /* RV535 *//**/ + { 0x71C2, 0x00F1061D, 0x00F2061D }, /* RV530 *//**/ + { 0x71C5, 0x00D1061D, 0x00D2061D }, /**/ + { 0x71C6, 0x00F2061D, 0x00F2061D }, /* RV530 */ + { 0x71D2, 0x00F10610, 0x00F20610 }, /* RV530: atombios uses 0x00F1061D *//**/ + { 0x7249, 0x00F1061D, 0x00F1061D }, /* R580 */ + { 0x724B, 0x00F10610, 0x00F10610 }, /* R580: atombios uses 0x00F1061D */ + { 0x7280, 0x0042041F, 0x0042041F }, /* RV570 *//**/ + { 0x7288, 0x0042041F, 0x0042041F }, /* RV570 */ + { 0x791E, 0x0001642F, 0x0001642F }, /* RS690 */ + { 0x791F, 0x0001642F, 0x0001642F }, /* RS690 */ + { 0x9400, 0x00020213, 0x00020213 }, /* R600 */ + { 0x9401, 0x00020213, 0x00020213 }, /* R600 */ + { 0x9402, 0x00020213, 0x00020213 }, /* R600 */ + { 0x9403, 0x00020213, 0x00020213 }, /* R600 */ + { 0x9405, 0x00020213, 0x00020213 }, /* R600 */ + { 0x940A, 0x00020213, 0x00020213 }, /* R600 */ + { 0x940B, 0x00020213, 0x00020213 }, /* R600 */ + { 0x940F, 0x00020213, 0x00020213 }, /* R600 */ + { 0, 0, 0 } /* End marker */ +}; + +static struct RV6xxTMDSBMacro { + CARD16 Device; + CARD32 Macro; + CARD32 TX; + CARD32 PreEmphasis; +} RV6xxTMDSBMacro[] = { + { 0x94C1, 0x01030311, 0x10001A00, 0x01801015}, /* RV610 */ + { 0x94C3, 0x01030311, 0x10001A00, 0x01801015}, /* RV610 */ + { 0x9501, 0x0533041A, 0x020010A0, 0x41002045}, /* RV670 */ + { 0x9505, 0x0533041A, 0x020010A0, 0x41002045}, /* RV670 */ + { 0x950F, 0x0533041A, 0x020010A0, 0x41002045}, /* R680 */ + { 0x9587, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */ + { 0x9588, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */ + { 0x9589, 0x01030311, 0x10001C00, 0x01C01011}, /* RV630 */ + { 0, 0, 0, 0} /* End marker */ +}; + +static void +TMDSBVoltageControl(struct rhdOutput *Output, DisplayModePtr Mode) +{ + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + int i; + + /* IGP chipsets are rather special */ + if (rhdPtr->ChipSet == RHD_RS690) { + RS690VoltageControl(Output, Mode); + return; + } else if (rhdPtr->ChipSet == RHD_RS600) { + RS600VoltageControl(Output, Mode); + return; + } + + /* TEST_OUTPUT register - IGPs are handled above */ + if (rhdPtr->ChipSet < RHD_RS600) /* r5xx */ + RHDRegMask(Output, LVTMA_REG_TEST_OUTPUT, 0x00200000, 0x00200000); + else if (rhdPtr->ChipSet < RHD_RV670) + RHDRegMask(Output, LVTMA_REG_TEST_OUTPUT, 0x00100000, 0x00100000); + + /* macro control values */ + if (rhdPtr->ChipSet < RHD_RV610) { /* R5xx and R600 */ + for (i = 0; R5xxTMDSBMacro[i].Device; i++) + if (R5xxTMDSBMacro[i].Device == rhdPtr->PciDeviceID) { + if (!Private->RunsDualLink) + RHDRegWrite(Output, LVTMA_MACRO_CONTROL, R5xxTMDSBMacro[i].MacroSingle); + else + RHDRegWrite(Output, LVTMA_MACRO_CONTROL, R5xxTMDSBMacro[i].MacroDual); + return; + } + + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n", + __func__, rhdPtr->PciDeviceID); + xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_MACRO_CONTROL: 0x%08X\n", + (unsigned int) RHDRegRead(Output, LVTMA_MACRO_CONTROL)); + } else { /* RV6x0 and up */ + for (i = 0; RV6xxTMDSBMacro[i].Device; i++) + if (RV6xxTMDSBMacro[i].Device == rhdPtr->PciDeviceID) { + RHDRegWrite(Output, LVTMA_MACRO_CONTROL, RV6xxTMDSBMacro[i].Macro); + RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST, RV6xxTMDSBMacro[i].TX); + RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL, RV6xxTMDSBMacro[i].PreEmphasis); + return; + } + + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n", + __func__, rhdPtr->PciDeviceID); + xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_MACRO_CONTROL: 0x%08X\n", + (unsigned int) RHDRegRead(Output, LVTMA_MACRO_CONTROL)); + xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_TRANSMITTER_ADJUST: 0x%08X\n", + (unsigned int) RHDRegRead(Output, LVTMA_TRANSMITTER_ADJUST)); + xf86DrvMsg(Output->scrnIndex, X_INFO, "LVTMA_PREEMPHASIS_CONTROL: 0x%08X\n", + (unsigned int) RHDRegRead(Output, LVTMA_PREEMPHASIS_CONTROL)); + } +} + +/* + * + */ +static Bool +TMDSBPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + + RHDFUNC(Output); + switch (Action) { + case rhdPropertyCheck: + switch (Property) { + case RHD_OUTPUT_COHERENT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + val->Bool = Private->Coherent; + return TRUE; + default: + return FALSE; + } + break; + case rhdPropertySet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + Private->Coherent = val->Bool; + Output->Mode(Output, Private->Mode); + Output->Power(Output, RHD_POWER_ON); + break; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static void +TMDSBSet(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + + RHDFUNC(Output); + + RHDRegMask(Output, LVTMA_MODE, 0x00000001, 0x00000001); /* select TMDS */ + + /* Clear out some HPD events first: this should be under driver control. */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x0000000C); + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00070000); + RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000010); + + /* Disable the transmitter */ + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E); + + /* Disable bit reduction and reset temporal dither */ + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0x00010101); + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, LVTMA_DITHER_RESET_BIT, LVTMA_DITHER_RESET_BIT); + usleep(2); + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, LVTMA_DITHER_RESET_BIT); + RHDRegMask(Output, LVTMA_BIT_DEPTH_CONTROL, 0, 0xF0000000); /* not documented */ + + /* reset phase on vsync and use RGB */ + RHDRegMask(Output, LVTMA_CNTL, 0x00001000, 0x00011000); + + /* Select CRTC, select syncA, no stereosync */ + RHDRegMask(Output, LVTMA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101); + + RHDRegWrite(Output, LVTMA_COLOR_FORMAT, 0); + + Private->Mode = Mode; + if (Mode->SynthClock > 165000) { + RHDRegMask(Output, LVTMA_CNTL, 0x01000000, 0x01000000); + Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSBPower */ + } else { + RHDRegMask(Output, LVTMA_CNTL, 0, 0x01000000); + Private->RunsDualLink = FALSE; + } + + if (rhdPtr->ChipSet > RHD_R600) /* Rv6xx: disable split mode */ + RHDRegMask(Output, LVTMA_CNTL, 0, 0x20000000); + + /* Disable force data */ + RHDRegMask(Output, LVTMA_FORCE_OUTPUT_CNTL, 0, 0x00000001); + + /* DC balancer enable */ + RHDRegMask(Output, LVTMA_DCBALANCER_CONTROL, 0x00000001, 0x00000001); + + TMDSBVoltageControl(Output, Mode); + + /* use IDCLK */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010); + /* LVTMA only: use clock selected by next write */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x20000000, 0x20000000); + /* coherent mode */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, + Private->Coherent ? 0 : 0x10000000, 0x10000000); + /* clear LVDS clock pattern */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x03FF0000); + + /* reset transmitter pll */ + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); + usleep(2); + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002); + usleep(20); + + /* restart data synchronisation */ + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000001, 0x00000001); + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0x00000100, 0x00000100); + usleep(2); + RHDRegMask(Output, LVTMA_DATA_SYNCHRONIZATION, 0, 0x00000001); + + RHDHdmiSetMode(Private->Hdmi, Mode); +} + +/* + * + */ +static void +TMDSBPower(struct rhdOutput *Output, int Power) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + + RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, + rhdPowerString[Power]); + + RHDRegMask(Output, LVTMA_MODE, 0x00000001, 0x00000001); /* select TMDS */ + + switch (Power) { + case RHD_POWER_ON: + RHDRegMask(Output, LVTMA_CNTL, 0x1, 0x00000001); + + if (Private->RunsDualLink) + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x00003E3E,0x00003E3E); + else + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0x0000003E, 0x00003E3E); + + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001); + usleep(2); + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000002); + if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector)) + RHDHdmiEnable(Private->Hdmi, TRUE); + else + RHDHdmiEnable(Private->Hdmi, FALSE); + return; + case RHD_POWER_RESET: + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E); + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); + usleep(2); + RHDRegMask(Output, LVTMA_TRANSMITTER_CONTROL, 0, 0x00000001); + RHDRegMask(Output, LVTMA_TRANSMITTER_ENABLE, 0, 0x00003E3E); + RHDRegMask(Output, LVTMA_CNTL, 0, 0x00000001); + RHDHdmiEnable(Private->Hdmi, FALSE); + return; + } +} + +/* + * + */ +static void +TMDSBSave(struct rhdOutput *Output) +{ + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + Private->StoreControl = RHDRegRead(Output, LVTMA_CNTL); + Private->StoreSource = RHDRegRead(Output, LVTMA_SOURCE_SELECT); + Private->StoreFormat = RHDRegRead(Output, LVTMA_COLOR_FORMAT); + Private->StoreForce = RHDRegRead(Output, LVTMA_FORCE_OUTPUT_CNTL); + Private->StoreReduction = RHDRegRead(Output, LVTMA_BIT_DEPTH_CONTROL); + Private->StoreDCBalancer = RHDRegRead(Output, LVTMA_DCBALANCER_CONTROL); + + Private->StoreDataSynchro = RHDRegRead(Output, LVTMA_DATA_SYNCHRONIZATION); + Private->StoreMode = RHDRegRead(Output, LVTMA_MODE); + Private->StoreTXEnable = RHDRegRead(Output, LVTMA_TRANSMITTER_ENABLE); + Private->StoreMacro = RHDRegRead(Output, LVTMA_MACRO_CONTROL); + Private->StoreTXControl = RHDRegRead(Output, LVTMA_TRANSMITTER_CONTROL); + Private->StoreTestOutput = RHDRegRead(Output, LVTMA_REG_TEST_OUTPUT); + + if (rhdPtr->ChipSet > RHD_R600) { /* Rv6x0 */ + Private->StoreRv600TXAdjust = RHDRegRead(Output, LVTMA_TRANSMITTER_ADJUST); + Private->StoreRv600PreEmphasis = RHDRegRead(Output, LVTMA_PREEMPHASIS_CONTROL); + } + + RHDHdmiSave(Private->Hdmi); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +TMDSBRestore(struct rhdOutput *Output) +{ + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + RHDPtr rhdPtr = RHDPTRI(Output); + + RHDFUNC(Output); + + if (!Private->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + RHDRegWrite(Output, LVTMA_CNTL, Private->StoreControl); + RHDRegWrite(Output, LVTMA_SOURCE_SELECT, Private->StoreSource); + RHDRegWrite(Output, LVTMA_COLOR_FORMAT, Private->StoreFormat); + RHDRegWrite(Output, LVTMA_FORCE_OUTPUT_CNTL, Private->StoreForce); + RHDRegWrite(Output, LVTMA_BIT_DEPTH_CONTROL, Private->StoreReduction); + RHDRegWrite(Output, LVTMA_DCBALANCER_CONTROL, Private->StoreDCBalancer); + + RHDRegWrite(Output, LVTMA_DATA_SYNCHRONIZATION, Private->StoreDataSynchro); + RHDRegWrite(Output, LVTMA_MODE, Private->StoreMode); + RHDRegWrite(Output, LVTMA_TRANSMITTER_ENABLE, Private->StoreTXEnable); + RHDRegWrite(Output, LVTMA_MACRO_CONTROL, Private->StoreMacro); + RHDRegWrite(Output, LVTMA_TRANSMITTER_CONTROL, Private->StoreTXControl); + RHDRegWrite(Output, LVTMA_REG_TEST_OUTPUT, Private->StoreTestOutput); + + if (rhdPtr->ChipSet > RHD_R600) { /* Rv6x0 */ + RHDRegWrite(Output, LVTMA_TRANSMITTER_ADJUST, Private->StoreRv600TXAdjust); + RHDRegWrite(Output, LVTMA_PREEMPHASIS_CONTROL, Private->StoreRv600PreEmphasis); + } + + RHDHdmiRestore(Private->Hdmi); +} + + +/* + * + */ +static void +TMDSBDestroy(struct rhdOutput *Output) +{ + struct rhdTMDSBPrivate *Private = (struct rhdTMDSBPrivate *) Output->Private; + RHDFUNC(Output); + + if (!Private) + return; + + RHDHdmiDestroy(Private->Hdmi); + + xfree(Private); + Output->Private = NULL; +} + +#ifdef NOT_YET +static Bool +LVDSPropertyWrapper(struct rhdOutput *Output, + enum rhdPropertyAction Action, + enum rhdOutputProperty Property, + union rhdPropertyData *val) +{ + struct LVDSPrivate *Private = (struct LVDSPrivate *) Output->Private; + void *storePrivate = Output->Private; + Bool (*func)(struct rhdOutput *,enum rhdPropertyAction, enum rhdOutputProperty, + union rhdPropertyData *) = Private->WrappedPropertyCallback; + Bool ret; + + Output->Private = Private->PropertyPrivate; + ret = func(Output, Action, Property, val); + Output->Private = storePrivate; + + return ret; +} +#endif + +/* + * + */ +struct rhdOutput * +RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type) +{ + struct rhdOutput *Output; + + RHDFUNC(rhdPtr); + + /* Stop weird connector types */ + if ((Type != RHD_CONNECTOR_PANEL) + && (Type != RHD_CONNECTOR_DVI) + && (Type != RHD_CONNECTOR_DVI_SINGLE)) { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "%s: unhandled connector type:" + " %d\n", __func__, Type); + return NULL; + } + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + + Output->scrnIndex = rhdPtr->scrnIndex; + Output->Id = RHD_OUTPUT_LVTMA; + + Output->Sense = NULL; /* not implemented in hw */ + + if (Type == RHD_CONNECTOR_PANEL) { + struct LVDSPrivate *Private; + + Output->Name = "LVDS"; + + Output->ModeValid = LVDSModeValid; + Output->Mode = LVDSSet; + Output->Power = LVDSPower; + Output->Save = LVDSSave; + Output->Restore = LVDSRestore; + Output->Property = LVDSPropertyControl; + Output->Destroy = LVDSDestroy; + Output->Private = Private = LVDSInfoRetrieve(rhdPtr); +#ifdef NOT_YET + if (Private->BlLevel < 0) { + Private->BlLevel = RhdAtomSetupBacklightControlProperty(Output, &Private->WrappedPropertyCallback, + &Private->PropertyPrivate); + if (Private->PropertyPrivate) + Output->Property = LVDSPropertyWrapper; + } else +#else + if (Private->BlLevel >= 0) +#endif + LVDSDebugBacklight(Output); + + } else { + struct rhdTMDSBPrivate *Private = xnfcalloc(sizeof(struct rhdTMDSBPrivate), 1); + + Output->Name = "TMDS B"; + + Output->ModeValid = TMDSBModeValid; + Output->Mode = TMDSBSet; + Output->Power = TMDSBPower; + Output->Save = TMDSBSave; + Output->Restore = TMDSBRestore; + Output->Property = TMDSBPropertyControl; + Output->Destroy = TMDSBDestroy; + + Private->Hdmi = RHDHdmiInit(rhdPtr, Output); + Output->Private = Private; + + Private->RunsDualLink = FALSE; + Private->Coherent = FALSE; + } + + return Output; +} diff --git a/programs/system/drivers/rhd/rhd_mc.c b/programs/system/drivers/rhd/rhd_mc.c new file mode 100644 index 000000000..09a6ebf39 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_mc.c @@ -0,0 +1,882 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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 + +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "xf86.h" + +#include "rhd.h" +#include "rhd_regs.h" + +Bool RHDMCIdle(RHDPtr rhdPtr, CARD32 count); + +Bool RHDMCIdle(RHDPtr rhdPtr, CARD32 count); + +struct rhdMC { + CARD32 FbLocation; + CARD32 HdpFbBase; + CARD32 MiscLatencyTimer; + Bool Stored; + void (*SaveMC)(RHDPtr rhdPtr); + void (*RestoreMC)(RHDPtr rhdPtr); + void (*SetupMC)(RHDPtr rhdPtr); + Bool (*MCIdle)(RHDPtr rhdPtr); + CARD32 (*GetFBLocation)(RHDPtr rhdPtr, CARD32 *size); + void (*TuneMCAccessForDisplay)(RHDPtr rhdPtr, int crtc, + DisplayModePtr Mode, DisplayModePtr ScaledToMode); + Bool RV515Variant; +}; + +/* + * Save MC_VM state. + */ +static void +rs600SaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + MC->FbLocation = RHDReadMC(rhdPtr, RS60_NB_FB_LOCATION); + MC->HdpFbBase = RHDRegRead(rhdPtr, HDP_FB_LOCATION); +} + +/* + * + */ +static void +rs690SaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + MC->FbLocation = RHDReadMC(rhdPtr, RS69_MCCFG_FB_LOCATION); + MC->HdpFbBase = RHDRegRead(rhdPtr, HDP_FB_LOCATION); + MC->MiscLatencyTimer = RHDReadMC(rhdPtr, RS69_MC_INIT_MISC_LAT_TIMER); +} + +/* + * + */ +static void +r6xxSaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + MC->FbLocation = RHDRegRead(rhdPtr, R6XX_MC_VM_FB_LOCATION); + MC->HdpFbBase = RHDRegRead(rhdPtr, R6XX_HDP_NONSURFACE_BASE); +} + +/* + * + */ +#ifdef NOTYET +static void +rs780SaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + MC->FbLocation = RHDReadMC(rhdPtr, RS78_MC_FB_LOCATION); + /* RS780 uses the same register as R6xx */ + MC->HdpFbBase = RHDRegRead(rhdPtr, R6XX_HDP_NONSURFACE_BASE); +} +#endif + +/* + * + */ +static void +r7xxSaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + MC->FbLocation = RHDRegRead(rhdPtr, R7XX_MC_VM_FB_LOCATION); + MC->HdpFbBase = RHDRegRead(rhdPtr, R6XX_HDP_NONSURFACE_BASE); +} + +/* + * + */ +static void +r5xxRestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + if (MC->RV515Variant) { + RHDWriteMC(rhdPtr, MC_IND_ALL | RV515_MC_FB_LOCATION, + MC->FbLocation); + RHDWriteMC(rhdPtr, MC_IND_ALL | RV515_MC_MISC_LAT_TIMER, + MC->MiscLatencyTimer); + } else + RHDWriteMC(rhdPtr, MC_IND_ALL | R5XX_MC_FB_LOCATION, + MC->FbLocation); + RHDRegWrite(rhdPtr, HDP_FB_LOCATION, MC->HdpFbBase); +} + +/* + * + */ +static void +rs600RestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + RHDWriteMC(rhdPtr, RS60_NB_FB_LOCATION, MC->FbLocation); + RHDRegWrite(rhdPtr, HDP_FB_LOCATION, MC->HdpFbBase); +} + +/* + * + */ +static void +rs690RestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + RHDWriteMC(rhdPtr, RS69_MCCFG_FB_LOCATION, MC->FbLocation); + RHDRegWrite(rhdPtr, HDP_FB_LOCATION, MC->HdpFbBase); + RHDWriteMC(rhdPtr, RS69_MC_INIT_MISC_LAT_TIMER, MC->MiscLatencyTimer); +} + +/* + * + */ +static void +r6xxRestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + RHDRegWrite(rhdPtr, R6XX_MC_VM_FB_LOCATION, MC->FbLocation); + RHDRegWrite(rhdPtr, R6XX_HDP_NONSURFACE_BASE, MC->HdpFbBase); +} + +/* + * + */ +#ifdef NOTYET +static void +rs780RestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + RHDWriteMC(rhdPtr, RS78_MC_FB_LOCATION, MC->FbLocation); + /* RS780 uses the same register as R6xx */ + RHDRegWrite(rhdPtr, R6XX_HDP_NONSURFACE_BASE, MC->HdpFbBase); +} +#endif + +/* + * + */ +static void +r7xxRestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + RHDRegWrite(rhdPtr, R7XX_MC_VM_FB_LOCATION, MC->FbLocation); + RHDRegWrite(rhdPtr, R6XX_HDP_NONSURFACE_BASE, MC->HdpFbBase); +} + +/* + * Setup the MC + */ + +/* + * + */ +static void +r5xxSetupMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + CARD32 fb_location, fb_location_tmp; + CARD16 fb_size; + unsigned int reg; + + RHDFUNC(rhdPtr); + + + if (MC->RV515Variant) + reg = RV515_MC_FB_LOCATION | MC_IND_ALL; + else + reg = R5XX_MC_FB_LOCATION | MC_IND_ALL; + + fb_location = RHDReadMC(rhdPtr, reg); + fb_size = (fb_location >> 16) - (fb_location & 0xFFFF); + fb_location_tmp = rhdPtr->FbIntAddress >> 16; + fb_location_tmp |= (fb_location_tmp + fb_size) << 16; + + RHDDebug(rhdPtr->scrnIndex, "%s: fb_location: 0x%08X " + "[fb_size: 0x%04X] -> fb_location: 0x%08X\n", + __func__, (unsigned int)fb_location, + fb_size,(unsigned int)fb_location_tmp); + RHDWriteMC(rhdPtr, reg, fb_location_tmp); + RHDRegWrite(rhdPtr, HDP_FB_LOCATION, fb_location_tmp & 0xFFFF); +} + +/* + * + */ +static void +rs600SetupMC(RHDPtr rhdPtr) +{ + CARD32 fb_location, fb_location_tmp; + CARD16 fb_size; + + RHDFUNC(rhdPtr); + + fb_location = RHDReadMC(rhdPtr, RS60_NB_FB_LOCATION); + fb_size = (fb_location >> 16) - (fb_location & 0xFFFF); + fb_location_tmp = rhdPtr->FbIntAddress >> 16; + fb_location_tmp |= (fb_location_tmp + fb_size) << 16; + + RHDDebug(rhdPtr->scrnIndex, "%s: fb_location: 0x%08X " + "[fb_size: 0x%04X] -> fb_location: 0x%08X\n", + __func__, (unsigned int)fb_location, + fb_size,(unsigned int)fb_location_tmp); + RHDWriteMC(rhdPtr, RS60_NB_FB_LOCATION, fb_location_tmp); + RHDRegWrite(rhdPtr, HDP_FB_LOCATION, fb_location_tmp & 0xFFFF); /* same ;) */ +} + +/* + * + */ +static void +rs690SetupMC(RHDPtr rhdPtr) +{ + CARD32 fb_location, fb_location_tmp; + CARD16 fb_size; + + RHDFUNC(rhdPtr); + + fb_location = RHDReadMC(rhdPtr, RS69_MCCFG_FB_LOCATION); + fb_size = (fb_location >> 16) - (fb_location & 0xFFFF); + fb_location_tmp = rhdPtr->FbIntAddress >> 16; + fb_location_tmp |= (fb_location_tmp + fb_size) << 16; + + RHDDebug(rhdPtr->scrnIndex, "%s: fb_location: 0x%08X " + "[fb_size: 0x%04X] -> fb_location: 0x%08X\n", + __func__, (unsigned int)fb_location, + fb_size,(unsigned int)fb_location_tmp); + RHDWriteMC(rhdPtr, RS69_MCCFG_FB_LOCATION, fb_location_tmp); + RHDRegWrite(rhdPtr, HDP_FB_LOCATION, fb_location_tmp & 0xFFFF); +} + +/* + * + */ +static void +r6xxSetupMC(RHDPtr rhdPtr) +{ + CARD32 fb_location, fb_location_tmp, hdp_fbbase_tmp; + CARD16 fb_size; + + RHDFUNC(rhdPtr); + + fb_location = RHDRegRead(rhdPtr, R6XX_MC_VM_FB_LOCATION); + fb_size = (fb_location >> 16) - (fb_location & 0xFFFF); + fb_location_tmp = rhdPtr->FbIntAddress >> 24; + fb_location_tmp |= (fb_location_tmp + fb_size) << 16; + hdp_fbbase_tmp = (rhdPtr->FbIntAddress >> 8) & 0xff0000; + + RHDDebug(rhdPtr->scrnIndex, "%s: fb_location: 0x%08X " + "fb_offset: 0x%08X [fb_size: 0x%04X] -> fb_location: 0x%08X " + "fb_offset: 0x%08X\n", + __func__, (unsigned int)fb_location, + RHDRegRead(rhdPtr,R6XX_HDP_NONSURFACE_BASE), fb_size, + (unsigned int)fb_location_tmp, (unsigned int)hdp_fbbase_tmp); + + RHDRegWrite(rhdPtr, R6XX_MC_VM_FB_LOCATION, fb_location_tmp); + RHDRegWrite(rhdPtr, R6XX_HDP_NONSURFACE_BASE, hdp_fbbase_tmp); +} + +/* + * + */ +#ifdef NOTYET +static void +rs780SetupMC(RHDPtr rhdPtr) +{ + CARD32 fb_location, fb_location_tmp, hdp_fbbase_tmp; + CARD16 fb_size; + + RHDFUNC(rhdPtr); + + fb_location = RHDReadMC(rhdPtr, RS78_MC_FB_LOCATION); + fb_size = (fb_location >> 16) - (fb_location & 0xFFFF); + fb_location_tmp = rhdPtr->FbIntAddress >> 16; + fb_location_tmp |= (fb_location_tmp + fb_size) << 16; + hdp_fbbase_tmp = (rhdPtr->FbIntAddress >> 8) & 0xff0000; + + RHDDebug(rhdPtr->scrnIndex, "%s: fb_location: 0x%08X " + "[fb_size: 0x%04X] -> fb_location: 0x%08X\n", + __func__, (unsigned int)fb_location, + fb_size,(unsigned int)fb_location_tmp); + RHDWriteMC(rhdPtr, RS78_MC_FB_LOCATION, fb_location_tmp); + /* RS780 uses the same register as R6xx */ + RHDRegWrite(rhdPtr, R6XX_HDP_NONSURFACE_BASE, hdp_fbbase_tmp); +} +#endif + +/* + * + */ +static void +r7xxSetupMC(RHDPtr rhdPtr) +{ + CARD32 fb_location, fb_location_tmp, hdp_fbbase_tmp; + CARD16 fb_size; + + RHDFUNC(rhdPtr); + + fb_location = RHDRegRead(rhdPtr, R7XX_MC_VM_FB_LOCATION); + fb_size = (fb_location >> 16) - (fb_location & 0xFFFF); + fb_location_tmp = rhdPtr->FbIntAddress >> 24; + fb_location_tmp |= (fb_location_tmp + fb_size) << 16; + hdp_fbbase_tmp = (rhdPtr->FbIntAddress >> 8) & 0xff0000; + + RHDDebug(rhdPtr->scrnIndex, "%s: fb_location: 0x%08X " + "fb_offset: 0x%08X [fb_size: 0x%04X] -> fb_location: 0x%08X " + "fb_offset: 0x%08X\n", + __func__, (unsigned int)fb_location, + RHDRegRead(rhdPtr,R6XX_HDP_NONSURFACE_BASE), fb_size, + (unsigned int)fb_location_tmp, (unsigned int)hdp_fbbase_tmp); + + RHDRegWrite(rhdPtr, R7XX_MC_VM_FB_LOCATION, fb_location_tmp); + RHDRegWrite(rhdPtr, R6XX_HDP_NONSURFACE_BASE, hdp_fbbase_tmp); +} + +/* + * + */ +void +RHDMCSetup(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + RHDFUNC(rhdPtr); + + if (!MC) + return; + /* + * make sure the hw is in a state such that we can update + * the MC - ie no subsystem is currently accessing memory. + */ + ASSERT((RHDRegRead(rhdPtr, D1VGA_CONTROL) & D1VGA_MODE_ENABLE) != D1VGA_MODE_ENABLE); + ASSERT((RHDRegRead(rhdPtr, D2VGA_CONTROL) & D2VGA_MODE_ENABLE) != D2VGA_MODE_ENABLE); + ASSERT((RHDRegRead(rhdPtr, D1CRTC_CONTROL) & 0x1) != 0x1); + ASSERT((RHDRegRead(rhdPtr, D2CRTC_CONTROL) & 0x1) != 0x1); + ASSERT(RHDMCIdle(rhdPtr, 1)); + + MC->SetupMC(rhdPtr); +} + +/* + * Get FB location and size. + */ +static CARD32 +r5xxGetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + struct rhdMC *MC = rhdPtr->MC; + CARD32 val; + CARD32 reg; + + if (MC->RV515Variant) + reg = RV515_MC_FB_LOCATION | MC_IND_ALL; + else + reg = R5XX_MC_FB_LOCATION | MC_IND_ALL; + + val = RHDReadMC(rhdPtr, reg); + + if (size) *size = ((val >> 16) - (val & 0xFFFF)) << 16; + + return (val & 0xFFFF) << 16; +} + +/* + * + */ +static CARD32 +rs600GetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + CARD32 val = RHDReadMC(rhdPtr, RS60_NB_FB_LOCATION); + + if (size) *size = ((val >> 16) - (val & 0xFFFF)) << 16; + + return (val & 0xFFFF) << 16; +} + +/* + * + */ +static CARD32 +rs690GetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + CARD32 val = RHDReadMC(rhdPtr, RS69_MCCFG_FB_LOCATION); + + if (size) *size = ((val >> 16) - (val & 0xFFFF)) << 16; + + return (val & 0xFFFF) << 16; +} + +/* + * + */ +static CARD32 +r6xxGetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + CARD32 val = RHDRegRead(rhdPtr, R6XX_MC_VM_FB_LOCATION); + + if (size) *size = ((val >> 16) - (val & 0xFFFF)) << 24; + + return (val & 0xFFFF) << 24; +} + +/* + * + */ +#ifdef NOTYET +static CARD32 +rs780GetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + CARD32 val = RHDReadMC(rhdPtr, RS78_MC_FB_LOCATION); + if (size) *size = ((val >> 16) - (val & 0xFFFF)) << 16; + + return (val & 0xFFFF) << 16; +} +#endif + +/* + * + */ +static CARD32 +r7xxGetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + CARD32 val = RHDRegRead(rhdPtr, R7XX_MC_VM_FB_LOCATION); + + if (size) *size = ((val >> 16) - (val & 0xFFFF)) << 24; + + return (val & 0xFFFF) << 24; +} + +/* + * + */ +CARD32 +RHDGetFBLocation(RHDPtr rhdPtr, CARD32 *size) +{ + struct rhdMC *MC = rhdPtr->MC; + RHDFUNC(rhdPtr); + + if (!MC) { + if (size) *size = 0; + return 0; + } + + return MC->GetFBLocation(rhdPtr, size); +} + +/* + * + */ +static Bool +rv515MCIdle(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (RHDReadMC(rhdPtr, MC_IND_ALL | RV515_MC_STATUS) & RV515_MC_IDLE) + return TRUE; + return FALSE; +} + + +/* + * + */ +static Bool +r5xxMCIdle(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (RHDReadMC(rhdPtr, MC_IND_ALL | R5XX_MC_STATUS) & R5XX_MC_IDLE) + return TRUE; + return FALSE; +} + +/* + * + */ +static Bool +rs600MCIdle(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (RHDReadMC(rhdPtr, RS60_MC_SYSTEM_STATUS) & RS6X_MC_SEQUENCER_IDLE) + return TRUE; + return FALSE; +} + +/* + * + */ +static Bool +rs690MCIdle(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (RHDReadMC(rhdPtr, RS69_MC_SYSTEM_STATUS) & RS6X_MC_SEQUENCER_IDLE) + return TRUE; + return FALSE; +} + +/* + * + */ +static Bool +r6xxMCIdle(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (!(RHDRegRead(rhdPtr, SRBM_STATUS) & 0x3f00)) + return TRUE; + return FALSE; +} + +/* + * + */ +#ifdef NOTYET +static Bool +rs780MCIdle(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (RHDReadMC(rhdPtr, RS78_MC_SYSTEM_STATUS) & RS78_MC_SEQUENCER_IDLE) + return TRUE; + return FALSE; +} +#endif + +/* + * + */ +Bool +RHDMCIdle(RHDPtr rhdPtr, CARD32 count) +{ + struct rhdMC *MC = rhdPtr->MC; + RHDFUNC(rhdPtr); + + if (!MC) + return TRUE; + + do { + if (MC->MCIdle(rhdPtr)) + return TRUE; + usleep(10); + } while (count--); + + RHDDebug(rhdPtr->scrnIndex, "%s: MC not idle\n",__func__); + + return FALSE; +} + +/* + * + */ +void +RHDSaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + RHDFUNC(rhdPtr); + + if (!MC) + return; + + MC->SaveMC(rhdPtr); + + MC->Stored = TRUE; +} + +/* + * Restore MC VM state. + */ +void +RHDRestoreMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + RHDFUNC(rhdPtr); + + if (!MC) + return; + + if (!MC->Stored) { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "%s: trying to restore uninitialized values.\n",__func__); + return; + } + /* + * make sure the hw is in a state such that we can update + * the MC - ie no subsystem is currently accessing memory. + */ + ASSERT((RHDRegRead(rhdPtr, D1VGA_CONTROL) & D1VGA_MODE_ENABLE) != D1VGA_MODE_ENABLE); + ASSERT((RHDRegRead(rhdPtr, D2VGA_CONTROL) & D2VGA_MODE_ENABLE) != D2VGA_MODE_ENABLE); + ASSERT((RHDRegRead(rhdPtr, D1CRTC_CONTROL) & 0x1) != 0x1); + ASSERT((RHDRegRead(rhdPtr, D2CRTC_CONTROL) & 0x1) != 0x1); + ASSERT(RHDMCIdle(rhdPtr, 1)); + + MC->RestoreMC(rhdPtr); +} + +/* + * + */ +static void +r5xxSaveMC(RHDPtr rhdPtr) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + if (MC->RV515Variant) { + MC->FbLocation = RHDReadMC(rhdPtr, MC_IND_ALL | RV515_MC_FB_LOCATION); + MC->MiscLatencyTimer = RHDReadMC(rhdPtr, MC_IND_ALL | RV515_MC_MISC_LAT_TIMER); + } else + MC->FbLocation = RHDReadMC(rhdPtr, MC_IND_ALL | R5XX_MC_FB_LOCATION); + MC->HdpFbBase = RHDRegRead(rhdPtr, HDP_FB_LOCATION); +} + +/* + * + */ +static void +rv515TuneMCAccessForDisplay(RHDPtr rhdPtr, int crtc, + DisplayModePtr Mode, DisplayModePtr ScaledToMode) +{ + CARD32 value, setting = 0x1; + + RHDFUNC(rhdPtr); + + value = RHDReadMC(rhdPtr, RV515_MC_MISC_LAT_TIMER); + + value |= (setting << (crtc ? MC_DISP1R_INIT_LAT_SHIFT : MC_DISP0R_INIT_LAT_SHIFT)); + RHDWriteMC(rhdPtr, RV515_MC_MISC_LAT_TIMER, value); +} + +/* + * + */ +static void +rs690TuneMCAccessForDisplay(RHDPtr rhdPtr, int crtc, + DisplayModePtr Mode, DisplayModePtr ScaledToMode) +{ + CARD32 value, setting = 0x1; + + RHDFUNC(rhdPtr); + + value = RHDReadMC(rhdPtr, RS69_MC_INIT_MISC_LAT_TIMER); + value |= setting << (crtc ? MC_DISP1R_INIT_LAT_SHIFT : MC_DISP0R_INIT_LAT_SHIFT); + RHDWriteMC(rhdPtr, RS69_MC_INIT_MISC_LAT_TIMER, value); +} + +/* + * + */ +void +RHDTuneMCAccessForDisplay(RHDPtr rhdPtr, int crtc, + DisplayModePtr Mode, DisplayModePtr ScaledToMode) +{ + struct rhdMC *MC = rhdPtr->MC; + + RHDFUNC(rhdPtr); + + if (MC->TuneMCAccessForDisplay) + MC->TuneMCAccessForDisplay(rhdPtr, crtc, Mode, ScaledToMode); +} + +/* + * + */ +void +RHDMCInit(RHDPtr rhdPtr) +{ + struct rhdMC *MC; + + RHDFUNC(rhdPtr); + + /* These devices have an internal address reference, which some other + * address registers in there also use. This can be different from the + * address in the BAR. + * + * We read out the address here from some known location. This address + * is as good a guess as any, we just need to pick one, but then make + * sure that it is made consistent in MCSetup and the various MC + * accessing subsystems. + */ + if (rhdPtr->ChipSet < RHD_R600) + rhdPtr->FbIntAddress = RHDRegRead(rhdPtr, HDP_FB_LOCATION) << 16; + else + rhdPtr->FbIntAddress = RHDRegRead(rhdPtr, R6XX_CONFIG_FB_BASE); + + RHDDebug(rhdPtr->scrnIndex, "MC FB Address: 0x%08X.\n", + rhdPtr->FbIntAddress); + + MC = xnfcalloc(1, sizeof(struct rhdMC)); + MC->Stored = FALSE; + + if (rhdPtr->ChipSet < RHD_RS600) { + MC->SaveMC = r5xxSaveMC; + MC->RestoreMC = r5xxRestoreMC; + MC->SetupMC = r5xxSetupMC; + MC->GetFBLocation = r5xxGetFBLocation; + + if (rhdPtr->ChipSet == RHD_RV515 + || rhdPtr->ChipSet == RHD_RV505 + || rhdPtr->ChipSet == RHD_RV516 + || rhdPtr->ChipSet == RHD_RV550 + || rhdPtr->ChipSet == RHD_M52 + || rhdPtr->ChipSet == RHD_M54 + || rhdPtr->ChipSet == RHD_M62 + || rhdPtr->ChipSet == RHD_M64 + || rhdPtr->ChipSet == RHD_M71) { + + MC->RV515Variant = TRUE; + MC->MCIdle = rv515MCIdle; + MC->TuneMCAccessForDisplay = rv515TuneMCAccessForDisplay; + } else { + + MC->RV515Variant = FALSE; + MC->MCIdle = r5xxMCIdle; + + } + + } else if (rhdPtr->ChipSet == RHD_RS600) { + MC->SaveMC = rs600SaveMC; + MC->RestoreMC = rs600RestoreMC; + MC->SetupMC = rs600SetupMC; + MC->MCIdle = rs600MCIdle; + MC->GetFBLocation = rs600GetFBLocation; + } else if (rhdPtr->ChipSet < RHD_R600) { + MC->SaveMC = rs690SaveMC; + MC->RestoreMC = rs690RestoreMC; + MC->SetupMC = rs690SetupMC; + MC->MCIdle = rs690MCIdle; + MC->GetFBLocation = rs690GetFBLocation; + MC->TuneMCAccessForDisplay = rs690TuneMCAccessForDisplay; + } else if (rhdPtr->ChipSet <= RHD_RS780) { + MC->SaveMC = r6xxSaveMC; + MC->RestoreMC = r6xxRestoreMC; + MC->SetupMC = r6xxSetupMC; + MC->MCIdle = r6xxMCIdle; + MC->GetFBLocation = r6xxGetFBLocation; + } +#if 0 + else if (rhdPtr->ChipSet == RHD_RS780) { + MC->SaveMC = rs780SaveMC; + MC->RestoreMC = rs780RestoreMC; + MC->SetupMC = rs780SetupMC; + MC->MCIdle = rs780MCIdle; + MC->GetFBLocation = rs780GetFBLocation; + } +#endif + else if (rhdPtr->ChipSet >= RHD_RV770) { + MC->SaveMC = r7xxSaveMC; + MC->RestoreMC = r7xxRestoreMC; + MC->SetupMC = r7xxSetupMC; + MC->MCIdle = r6xxMCIdle; + MC->GetFBLocation = r7xxGetFBLocation; + } else { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "I don't know anything about MC on this chipset\n"); + xfree(MC); + return; + } + rhdPtr->MC = MC; + +} + +/* + * Free structure. + */ +void +RHDMCDestroy(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (!rhdPtr->MC) + return; + + xfree(rhdPtr->MC); + rhdPtr->MC = NULL; +} + +/* + * + */ +Bool +RHD_MC_IGP_SideportMemoryPresent(RHDPtr rhdPtr) +{ + Bool Present = FALSE; + + RHDFUNC(rhdPtr); + + switch (rhdPtr->ChipSet) { + case RHD_RS690: + case RHD_RS740: + Present = (RHDReadMC(rhdPtr, RS69_MC_MISC_UMA_CNTL) & RS69_SIDE_PORT_PRESENT_R) != 0; + break; + case RHD_RS780: + Present = (RHDReadMC(rhdPtr, RS78_MC_MISC_UMA_CNTL) & RS78_SIDE_PORT_PRESENT_R) != 0; + break; + default: + break; + } + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "IPG sideport memory %s present.\n", Present ? "" : "not"); + + return Present; +} diff --git a/programs/system/drivers/rhd/rhd_mc.h b/programs/system/drivers/rhd/rhd_mc.h new file mode 100644 index 000000000..a0481cdbc --- /dev/null +++ b/programs/system/drivers/rhd/rhd_mc.h @@ -0,0 +1,40 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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. + */ +#ifndef RHD_MC_H +# define RHD_MC_H + +extern void RHDMCInit(RHDPtr rhdPtr); +extern void RHDMCDestroy(RHDPtr rhdPtr); +extern void RHDSaveMC(RHDPtr rhdPtr); +extern void RHDRestoreMC(RHDPtr rhdPtr); +extern void RHDMCSetup(RHDPtr rhdPtr); +extern Bool RHDMCIdle(RHDPtr rhdPtr, CARD32 count); +extern void RHDTuneMCAccessForDisplay(RHDPtr rhdPtr, int crtc, + DisplayModePtr Mode, DisplayModePtr ScaledToMode); +extern CARD32 RHDGetFBLocation(RHDPtr rhdPtr, CARD32 *size); + +extern Bool RHD_MC_IGP_SideportMemoryPresent(RHDPtr rhdPtr); + +#endif /* RHD_MC_H */ diff --git a/programs/system/drivers/rhd/rhd_mem.c b/programs/system/drivers/rhd/rhd_mem.c new file mode 100644 index 000000000..ac0031a6c --- /dev/null +++ b/programs/system/drivers/rhd/rhd_mem.c @@ -0,0 +1,211 @@ +/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */ +/* + * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + * + * The Weather Channel (TM) funded Tungsten Graphics to develop the + * initial release of the Radeon 8500 driver under the XFree86 license. + * This notice must be preserved. + * + * 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 (including the next + * paragraph) 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + * + * Authors: + * Keith Whitwell + */ + +#include "common.h" +#include "rhd.h" + +#define USED_BLOCK 1 + +#define list_for_each(entry, head) \ + for (entry = (head)->next; entry != head; entry = (entry)->next) + + +/* Very simple allocator for GART memory, working on a static range + * already mapped into each client's address space. + */ + +struct mem_block { + struct mem_block *next; + struct mem_block *prev; + int start; + int size; +}; + +/* Initialize. How to check for an uninitialized heap? + */ +static int init_heap(struct mem_block **heap, int start, int size) +{ + struct mem_block *blocks = malloc(sizeof(*blocks)); + + if (!blocks) + return -1; //-ENOMEM; + + *heap = malloc(sizeof(**heap)); + if (!*heap) + { + free(blocks); + return -1; //-ENOMEM; + } + + blocks->start = start; + blocks->size = size; + blocks->next = blocks->prev = *heap; + + __clear(*heap,sizeof(**heap)); + (*heap)->next = (*heap)->prev = blocks; + return 0; +} + +static struct mem_block **get_heap(RHDPtr rhdPtr, int region) +{ + switch (region) + { + case RHD_MEM_GART: + return &rhdPtr->gart_heap; + case RHD_MEM_FB: + return &rhdPtr->fb_heap; + default: + return NULL; + } +} + +static struct mem_block *split_block(struct mem_block *p, int size) +{ + + /* Maybe cut off the end of an existing block */ + if (size < p->size) + { + struct mem_block *newblock = malloc(sizeof(*newblock)); + if (!newblock) + goto out; + newblock->start = p->start + size; + newblock->size = p->size - size; + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + p->size = size; + p->start|=1; + } + +out: + return p; +} + +static struct mem_block *alloc_block(struct mem_block *heap, int size) +{ + struct mem_block *p; + + list_for_each(p, heap) + { + if ( !(p->start & USED_BLOCK) && size <= p->size) + return split_block(p, size); + } + + return NULL; +} + + +static struct mem_block *find_block(struct mem_block *heap, int start) +{ + struct mem_block *p; + + list_for_each(p, heap) + if ((p->start & ~USED_BLOCK) == start) + return p; + + return NULL; +} + +static void free_block(struct mem_block *p) +{ + + /* Assumes a single contiguous range. Needs a special file_priv in + * 'heap' to stop it being subsumed. + */ + if ( !(p->next->start & USED_BLOCK)) + { + struct mem_block *q = p->next; + p->size += q->size; + p->next = q->next; + p->next->prev = p; + free(q); + } + + if ( !(p->prev->start & USED_BLOCK)) + { + struct mem_block *q = p->prev; + q->size += p->size; + q->next = p->next; + q->next->prev = q; + free(p); + } +} + +int rhdInitHeap(RHDPtr rhdPtr) +{ + int base = rhdPtr->FbBase + rhdPtr->FbFreeStart; + + return init_heap(&rhdPtr->fb_heap, base, rhdPtr->FbFreeSize); +}; + +void *rhd_mem_alloc(RHDPtr rhdPtr,int region, int size) +{ + struct mem_block *block, **heap; + + heap = get_heap(rhdPtr, region); + if (!heap || !*heap) + return NULL; + + /* Make things easier on ourselves: all allocations at least + * 4k aligned. + */ + + size = (size+4095) & ~4095; + + block = alloc_block(*heap, size); + + if (!block) + return NULL; + + return (void*)(block->start & ~USED_BLOCK); +} + +int rhd_mem_free(RHDPtr rhdPtr, int region, void *offset) +{ + struct mem_block *block, **heap; + + heap = get_heap(rhdPtr, region); + if (!heap || !*heap) + return -1; + + block = find_block(*heap, (int)offset); + if (!block) + return -1; + + if ( !(block->start & 1)) + return -1; + + free_block(block); + return 0; +} + + diff --git a/programs/system/drivers/rhd/rhd_modes.c b/programs/system/drivers/rhd/rhd_modes.c new file mode 100644 index 000000000..073385464 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_modes.c @@ -0,0 +1,1950 @@ +/* + * Copyright 2004-2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +# include +#endif + + +#include "rhd.h" + +#include "edid.h" +#include "xf86DDC.h" + +#include "rhd_crtc.h" +#include "rhd_pll.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_modes.h" +#include "rhd_monitor.h" + +/* For Acceleration FB validation */ +//#include "r5xx_accel.h" + +/* + * Define a set of own mode errors. + */ +#define RHD_MODE_STATUS 0x51B00 +#ifndef MONREC_HAS_REDUCED +#define MODE_NO_REDUCED 0x01 + RHD_MODE_STATUS +#endif +#define MODE_MEM_BW 0x02 + RHD_MODE_STATUS +#define MODE_OUTPUT_UNDEF 0x03 + RHD_MODE_STATUS +#define MODE_NOT_PAL 0x04 + RHD_MODE_STATUS +#define MODE_NOT_NTSC 0x05 + RHD_MODE_STATUS +#define MODE_HTOTAL_WIDE 0x06 + RHD_MODE_STATUS +#define MODE_HDISPLAY_WIDE 0x07 + RHD_MODE_STATUS +#define MODE_HSYNC_RANGE 0x08 + RHD_MODE_STATUS +#define MODE_HBLANK_RANGE 0x09 + RHD_MODE_STATUS +#define MODE_VTOTAL_WIDE 0x0A + RHD_MODE_STATUS +#define MODE_VDISPLAY_WIDE 0x0B + RHD_MODE_STATUS +#define MODE_VSYNC_RANGE 0x0C + RHD_MODE_STATUS +#define MODE_VBLANK_RANGE 0x0D + RHD_MODE_STATUS +#define MODE_PITCH 0x0E + RHD_MODE_STATUS +#define MODE_OFFSET 0x0F + RHD_MODE_STATUS +#define MODE_MINHEIGHT 0x10 + RHD_MODE_STATUS +#define MODE_FIXED 0x11 + RHD_MODE_STATUS +#define MODE_SCALE 0x12 + RHD_MODE_STATUS + +/* + * Don't bother with checking whether X offers this. Just use the internal one + * I'm the author of the X side one anyway. + */ + +/* + * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh. + * + * These calculations are stolen from the CVT calculation spreadsheet written + * by Graham Loveridge. He seems to be claiming no copyright and there seems to + * be no license attached to this. He apparently just wants to see his name + * mentioned. + * + * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls + * + * Comments and structure corresponds to the comments and structure of the xls. + * This should ease importing of future changes to the standard (not very + * likely though). + * + * About margins; i'm sure that they are to be the bit between HDisplay and + * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and + * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking + * outside sync "margin" for some reason. Since we prefer seeing proper + * blanking instead of the overscan colour, and since the Crtc* values will + * probably get altered after us, we will disable margins altogether. With + * these calculations, Margins will plainly expand H/VDisplay, and we don't + * want that. -- libv + * + */ +DisplayModePtr +RHDCVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced, + Bool Interlaced) +{ + DisplayModeRec *Mode = xnfalloc(sizeof(DisplayModeRec)); + + /* 1) top/bottom margin size (% of height) - default: 1.8 */ +#define CVT_MARGIN_PERCENTAGE 1.8 + + /* 2) character cell horizontal granularity (pixels) - default 8 */ +#define CVT_H_GRANULARITY 1 + + /* 4) Minimum vertical porch (lines) - default 3 */ +#define CVT_MIN_V_PORCH 3 + + /* 4) Minimum number of vertical back porch lines - default 6 */ +#define CVT_MIN_V_BPORCH 6 + + /* Pixel Clock step (kHz) */ +#define CVT_CLOCK_STEP 250 + + Bool Margins = FALSE; + float VFieldRate, HPeriod; + int HDisplayRnd, HMargin; + int VDisplayRnd, VMargin, VSync; + float Interlace; /* Please rename this */ + + memset(Mode, 0, sizeof(DisplayModeRec)); + + /* CVT default is 60.0Hz */ + if (!VRefresh) + VRefresh = 60.0; + + /* 1. Required field rate */ + if (Interlaced) + VFieldRate = VRefresh * 2; + else + VFieldRate = VRefresh; + + /* 2. Horizontal pixels */ + HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY); + + /* 3. Determine left and right borders */ + if (Margins) { + /* right margin is actually exactly the same as left */ + HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + HMargin -= HMargin % CVT_H_GRANULARITY; + } else + HMargin = 0; + + /* 4. Find total active pixels */ + Mode->HDisplay = HDisplayRnd + 2*HMargin; + + /* 5. Find number of lines per field */ + if (Interlaced) + VDisplayRnd = VDisplay / 2; + else + VDisplayRnd = VDisplay; + + /* 6. Find top and bottom margins */ + /* nope. */ + if (Margins) + /* top and bottom margins are equal again. */ + VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0); + else + VMargin = 0; + + Mode->VDisplay = VDisplay + 2*VMargin; + + /* 7. Interlace */ + if (Interlaced) + Interlace = 0.5; + else + Interlace = 0.0; + + /* Determine VSync Width from aspect ratio */ + if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay)) + VSync = 4; + else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay)) + VSync = 5; + else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay)) + VSync = 6; + else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay)) + VSync = 7; + else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay)) + VSync = 7; + else /* Custom */ + VSync = 10; + + if (!Reduced) { /* simplified GTF calculation */ + + /* 4) Minimum time of vertical sync + back porch interval (µs) + * default 550.0 */ +#define CVT_MIN_VSYNC_BP 550.0 + + /* 3) Nominal HSync width (% of line period) - default 8 */ +#define CVT_HSYNC_PERCENTAGE 8 + + float HBlankPercentage; + int VSyncAndBackPorch, VBackPorch; + int HBlank; + + /* 8. Estimated Horizontal period */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) / + (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace); + + /* 9. Find number of lines in sync + backporch */ + if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH)) + VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH; + else + VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1; + + /* 10. Find number of lines in back porch */ + VBackPorch = VSyncAndBackPorch - VSync; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace + + CVT_MIN_V_PORCH; + + /* 5) Definition of Horizontal blanking time limitation */ + /* Gradient (%/kHz) - default 600 */ +#define CVT_M_FACTOR 600 + + /* Offset (%) - default 40 */ +#define CVT_C_FACTOR 40 + + /* Blanking time scaling factor - default 128 */ +#define CVT_K_FACTOR 128 + + /* Scaling factor weighting - default 20 */ +#define CVT_J_FACTOR 20 + +#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256 +#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \ + CVT_J_FACTOR + + /* 12. Find ideal blanking duty cycle from formula */ + HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0; + + /* 13. Blanking time */ + if (HBlankPercentage < 20) + HBlankPercentage = 20; + + HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage); + HBlank -= HBlank % (2*CVT_H_GRANULARITY); + + /* 14. Find total number of pixels in a line. */ + Mode->HTotal = Mode->HDisplay + HBlank; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + HBlank / 2; + + Mode->HSyncStart = Mode->HSyncEnd - + (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100; + Mode->HSyncStart += CVT_H_GRANULARITY - + Mode->HSyncStart % CVT_H_GRANULARITY; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + + } else { /* Reduced blanking */ + /* Minimum vertical blanking interval time (µs) - default 460 */ +#define CVT_RB_MIN_VBLANK 460.0 + + /* Fixed number of clocks for horizontal sync */ +#define CVT_RB_H_SYNC 32.0 + + /* Fixed number of clocks for horizontal blanking */ +#define CVT_RB_H_BLANK 160.0 + + /* Fixed number of lines for vertical front porch - default 3 */ +#define CVT_RB_VFPORCH 3 + + int VBILines; + + /* 8. Estimate Horizontal period. */ + HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) / + (VDisplayRnd + 2*VMargin); + + /* 9. Find number of lines in vertical blanking */ + VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1; + + /* 10. Check if vertical blanking is sufficient */ + if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH)) + VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH; + + /* 11. Find total number of lines in vertical field */ + Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines; + + /* 12. Find total number of pixels in a line */ + Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK; + + /* Fill in HSync values */ + Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2; + Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC; + + /* Fill in VSync values */ + Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH; + Mode->VSyncEnd = Mode->VSyncStart + VSync; + } + + /* 15/13. Find pixel clock frequency (kHz for xf86) */ + Mode->Clock = Mode->HTotal * 1000.0 / HPeriod; + Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP; + + /* 16/14. Find actual Horizontal Frequency (kHz) */ + Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal); + + /* 17/15. Find actual Field rate */ + Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) / + ((float) (Mode->HTotal * Mode->VTotal)); + + /* 18/16. Find actual vertical frame frequency */ + /* ignore - just set the mode flag for interlaced */ + if (Interlaced) + Mode->VTotal *= 2; + + { + char Name[256]; + Name[0] = 0; + + snprintf(Name, 256, "%dx%d", HDisplay, VDisplay); + Mode->name = strdup(Name); + } + + if (Reduced) + Mode->Flags |= V_PHSYNC | V_NVSYNC; + else + Mode->Flags |= V_NHSYNC | V_PVSYNC; + + if (Interlaced) + Mode->Flags |= V_INTERLACE; + + return Mode; +} + +/* + * Temporary. + */ +static void +add(char **p, char *new) +{ +// char *tmp = kmalloc(strlen(*p) + strlen(new) + 2); + + *p = (char*)realloc(*p, strlen(*p) + strlen(new) + 2); + strcat(*p, " "); + strcat(*p, new); +} + +/* + * + */ +Bool +rhdModesEqual(DisplayModePtr mode1, DisplayModePtr mode2) +{ + if (mode1->Clock == mode2->Clock + && mode1->HDisplay == mode2->HDisplay + && mode1->HSyncStart == mode2->HSyncStart + && mode1->HSyncEnd == mode2->HSyncEnd + && mode1->HTotal == mode2->HTotal + && mode1->HSkew == mode2->HSkew + && mode1->VDisplay == mode2->VDisplay + && mode1->VSyncStart == mode2->VSyncStart + && mode1->VSyncEnd == mode2->VSyncEnd + && mode1->VTotal == mode2->VTotal + && mode1->VScan == mode2->VScan + && mode1->Flags == mode2->Flags) + return TRUE; + + return FALSE; +} + +/* + * + */ +void +RHDPrintModeline(DisplayModePtr mode) +{ + char tmp[256]; + char *flags = xnfcalloc(1, 1); + + if (mode->HSkew) { + snprintf(tmp, 256, "hskew %i", mode->HSkew); + add(&flags, tmp); + } + if (mode->VScan) { + snprintf(tmp, 256, "vscan %i", mode->VScan); + add(&flags, tmp); + } + if (mode->Flags & V_INTERLACE) add(&flags, "interlace"); + if (mode->Flags & V_CSYNC) add(&flags, "composite"); + if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan"); + if (mode->Flags & V_BCAST) add(&flags, "bcast"); + if (mode->Flags & V_PHSYNC) add(&flags, "+hsync"); + if (mode->Flags & V_NHSYNC) add(&flags, "-hsync"); + if (mode->Flags & V_PVSYNC) add(&flags, "+vsync"); + if (mode->Flags & V_NVSYNC) add(&flags, "-vsync"); + if (mode->Flags & V_PCSYNC) add(&flags, "+csync"); + if (mode->Flags & V_NCSYNC) add(&flags, "-csync"); +#if 0 + if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2"); +#endif + xf86Msg(X_NONE, "Modeline \"%s\" %6.2f %i %i %i %i %i %i %i %i%s\n", + mode->name, mode->Clock/1000., + mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal, + mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal, + flags); + xfree(flags); +} + +/* + * xf86Mode.c should have a some more DisplayModePtr list handling. + */ +DisplayModePtr +RHDModesAdd(DisplayModePtr Modes, DisplayModePtr Additions) +{ + if (!Modes) { + if (Additions) + return Additions; + else + return NULL; + } + + if (Additions) { + DisplayModePtr Mode = Modes; + + while (Mode->next) + Mode = Mode->next; + + Mode->next = Additions; + Additions->prev = Mode; + } + + return Modes; +} + +/* + * + */ +static DisplayModePtr +rhdModeDelete(DisplayModePtr Modes, DisplayModePtr Delete) +{ + DisplayModePtr Next, Previous; + + if (!Delete) + return Modes; + + if (Modes == Delete) + Modes = NULL; + + if (Delete->next == Delete) + Delete->next = NULL; + + if (Delete->prev == Delete) + Delete->next = NULL; + + Next = Delete->next; + Previous = Delete->prev; + + if (Next) + Next->prev = Previous; + + if (Previous) + Previous->next = Next; + + xfree(Delete->name); + xfree(Delete); + + if (Modes) + return Modes; + + if (Next) + return Next; + + if (Previous) + while (Previous->prev) + Previous = Previous->prev; + + return Previous; +} + +/* + * + */ +DisplayModePtr +RHDModeCopy(DisplayModePtr Mode) +{ + DisplayModePtr New; + + if (!Mode) + return NULL; + + New = xnfalloc(sizeof(DisplayModeRec)); + memcpy(New, Mode, sizeof(DisplayModeRec)); /* re-use private */ + New->name = strdup(Mode->name); + New->prev = NULL; + New->next = NULL; + New->Private = Mode->Private; + New->PrivSize = Mode->PrivSize; + + return New; +} + +/* + * + */ +static void +rhdModesDestroy(DisplayModePtr Modes) +{ + DisplayModePtr mode = Modes, next; + + while (mode) { + next = mode->next; + xfree(mode->name); + xfree(mode); + mode = next; + } +} + +/* + * Basic sanity checks. + */ +static int +rhdModeSanity(RHDPtr rhdPtr, DisplayModePtr Mode) +{ + /* do we need to bother at all? */ + if (Mode->status != MODE_OK) + return Mode->status; + + if (!Mode->name) { + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, + "Validation found mode without name.\n"); + return MODE_ERROR; + } + + if (Mode->Clock <= 0) + return MODE_NOCLOCK; + + if ((Mode->HDisplay <= 0) || (Mode->HSyncStart <= 0) || + (Mode->HSyncEnd <= 0) || (Mode->HTotal <= 0)) + return MODE_H_ILLEGAL; + + if ((Mode->HTotal <= Mode->HSyncEnd) || + (Mode->HSyncEnd <= Mode->HSyncStart) || + (Mode->HSyncStart < Mode->HDisplay)) + return MODE_H_ILLEGAL; + + /* HSkew? */ + + if ((Mode->VDisplay <= 0) || (Mode->VSyncStart <= 0) || + (Mode->VSyncEnd <= 0) || (Mode->VTotal <= 0)) + return MODE_V_ILLEGAL; + + if ((Mode->VTotal <= Mode->VSyncEnd) || + (Mode->VSyncEnd <= Mode->VSyncStart) || + (Mode->VSyncStart < Mode->VDisplay)) + return MODE_V_ILLEGAL; + + if ((Mode->VScan != 0) && (Mode->VScan != 1)) + return MODE_NO_VSCAN; + + if (Mode->Flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + /* Flags */ + return MODE_OK; +} + +/* + * After we passed the initial sanity check, we need to fill out the CRTC + * values. + */ +static void +rhdModeFillOutCrtcValues(DisplayModePtr Mode) +{ + /* do we need to bother at all? */ + if (Mode->status != MODE_OK) + return; + + Mode->ClockIndex = -1; /* Always! direct non-programmable support must die. */ + + if (!Mode->SynthClock) + Mode->SynthClock = Mode->Clock; + + if (!Mode->CrtcHDisplay) + Mode->CrtcHDisplay = Mode->HDisplay; + + if (!Mode->CrtcHBlankStart) + Mode->CrtcHBlankStart = Mode->HDisplay; + + if (!Mode->CrtcHSyncStart) + Mode->CrtcHSyncStart = Mode->HSyncStart; + + if (!Mode->CrtcHSyncEnd) + Mode->CrtcHSyncEnd = Mode->HSyncEnd; + + if (!Mode->CrtcHBlankEnd) + Mode->CrtcHBlankEnd = Mode->HTotal; + + if (!Mode->CrtcHTotal) + Mode->CrtcHTotal = Mode->HTotal; + + if (!Mode->CrtcHSkew) + Mode->CrtcHSkew = Mode->HSkew; + + if (!Mode->CrtcVDisplay) + Mode->CrtcVDisplay = Mode->VDisplay; + + if (!Mode->CrtcVBlankStart) + Mode->CrtcVBlankStart = Mode->VDisplay; + + if (!Mode->CrtcVSyncStart) + Mode->CrtcVSyncStart = Mode->VSyncStart; + + if (!Mode->CrtcVSyncEnd) + Mode->CrtcVSyncEnd = Mode->VSyncEnd; + + if (!Mode->CrtcVBlankEnd) + Mode->CrtcVBlankEnd = Mode->VTotal; + + if (!Mode->CrtcVTotal) + Mode->CrtcVTotal = Mode->VTotal; + + /* Always change these */ + Mode->HSync = ((float) Mode->SynthClock) / Mode->CrtcHTotal; + Mode->VRefresh = (Mode->SynthClock * 1000.0) / + (Mode->CrtcHTotal * Mode->CrtcVTotal); + if (Mode->Flags & V_INTERLACE) + Mode->VRefresh *= 2.0; + if (Mode->Flags & V_DBLSCAN) + Mode->VRefresh /= 2.0; + + /* We're usually first in the chain, right after rhdModeSanity. */ + Mode->CrtcHAdjusted = FALSE; + Mode->CrtcVAdjusted = FALSE; + + /* Steer clear of PrivSize, Private and PrivFlags */ +} + +/* + * Basic sanity checks. + */ +static int +rhdModeCrtcSanity(DisplayModePtr Mode) +{ + if (Mode->SynthClock <= 0) + return MODE_NOCLOCK; + + if ((Mode->CrtcHDisplay <= 0) || (Mode->CrtcHBlankStart <= 0) || + (Mode->CrtcHSyncStart <= 0) || (Mode->CrtcHSyncEnd <= 0) || + (Mode->CrtcHBlankEnd <= 0) || (Mode->CrtcHTotal <= 0)) + return MODE_H_ILLEGAL; + + /* there seem to be no alignment constraints on horizontal timing on our + hardware here */ + + if ((Mode->CrtcHTotal < Mode->CrtcHBlankEnd) || + (Mode->CrtcHBlankEnd <= Mode->CrtcHSyncEnd) || + (Mode->CrtcHSyncEnd <= Mode->CrtcHSyncStart) || + (Mode->CrtcHSyncStart < Mode->CrtcHBlankStart) || + (Mode->CrtcHBlankStart < Mode->CrtcHDisplay)) + return MODE_H_ILLEGAL; + + /* CrtcHSkew? */ + + if ((Mode->CrtcVDisplay <= 0) || (Mode->CrtcVBlankStart <= 0) || + (Mode->CrtcVSyncStart <= 0) || (Mode->CrtcVSyncEnd <= 0) || + (Mode->CrtcVBlankEnd <= 0) || (Mode->CrtcVTotal <= 0)) + return MODE_V_ILLEGAL; + + if ((Mode->CrtcVTotal < Mode->CrtcVBlankEnd) || + (Mode->CrtcVBlankEnd <= Mode->CrtcVSyncEnd) || + (Mode->CrtcVSyncEnd <= Mode->CrtcVSyncStart) || + (Mode->CrtcVSyncStart < Mode->CrtcVBlankStart) || + (Mode->CrtcVBlankStart < Mode->CrtcVDisplay)) + return MODE_V_ILLEGAL; + + return MODE_OK; +} + +/* + * + */ +static Bool +rhdMonitorFixedValid(struct rhdMonitor *Monitor, DisplayModePtr Mode) +{ + DisplayModePtr Fixed; + + for (Fixed = Monitor->Modes; Fixed; Fixed = Fixed->next) { + if ((Mode->Flags != Fixed->Flags) || + (Mode->Clock != Fixed->Clock) || + (Mode->SynthClock != Fixed->Clock)) + continue; + + if ((Mode->HDisplay > Fixed->HDisplay) || + (Mode->VDisplay > Fixed->VDisplay)) + continue; + + if ((Mode->HSyncStart != Fixed->HSyncStart) || + (Mode->HSyncEnd != Fixed->HSyncEnd)) + continue; + + if ((Mode->VSyncStart != Fixed->VSyncStart) || + (Mode->VSyncEnd != Fixed->VSyncEnd)) + continue; + + if ((Mode->CrtcHDisplay > Fixed->HDisplay) || + (Mode->CrtcVDisplay > Fixed->VDisplay)) + continue; + + if ((Mode->CrtcHBlankStart != Fixed->HDisplay) || + (Mode->CrtcHSyncStart != Fixed->HSyncStart) || + (Mode->CrtcHSyncEnd != Fixed->HSyncEnd) || + (Mode->CrtcHBlankEnd != Fixed->HTotal)) + continue; + + if ((Mode->CrtcVBlankStart != Fixed->VDisplay) || + (Mode->CrtcVSyncStart != Fixed->VSyncStart) || + (Mode->CrtcVSyncEnd != Fixed->VSyncEnd) || + (Mode->CrtcVBlankEnd != Fixed->VTotal)) + continue; + + return TRUE; + } + + return FALSE; +} +/* + * TODO: review fixed modes when doing different modes on both crtcs. + */ +static int +rhdMonitorValid(struct rhdMonitor *Monitor, DisplayModePtr Mode) +{ + int i; + Bool isNative = FALSE; + + if (Monitor->NativeMode && rhdModesEqual(Mode, Monitor->NativeMode)) + isNative = TRUE; + + for (i = 0; i < Monitor->numHSync; i++) + if ((Mode->HSync >= (Monitor->HSync[i].lo * (1.0 - SYNC_TOLERANCE))) && + (Mode->HSync <= (Monitor->HSync[i].hi * (1.0 + SYNC_TOLERANCE)))) + break; + if (Monitor->numHSync && (i == Monitor->numHSync)) + return MODE_HSYNC; + + for (i = 0; i < Monitor->numVRefresh; i++) + if ((Mode->VRefresh >= (Monitor->VRefresh[i].lo * (1.0 - SYNC_TOLERANCE))) && + (Mode->VRefresh <= (Monitor->VRefresh[i].hi * (1.0 + SYNC_TOLERANCE)))) + break; + if (Monitor->numVRefresh && (i == Monitor->numVRefresh)) + return MODE_VSYNC; + + if (Monitor->Bandwidth && + (Mode->SynthClock > (Monitor->Bandwidth * (1 + SYNC_TOLERANCE)))) + return MODE_CLOCK_HIGH; + + if (isNative) { /* if it's this monitor's native mode be less strict on validation */ + if (Monitor->ReducedAllowed) { + if ((Mode->CrtcHDisplay * 101) > (Mode->CrtcHTotal * 100)) /* 1% */ + return MODE_HBLANK_NARROW; + } else { /* no reduced blanking */ + if ((Mode->CrtcHDisplay * 23) > (Mode->CrtcHTotal * 20)) /* 15% */ + return MODE_HBLANK_NARROW; + } + } else { + if (((Mode->CrtcHDisplay * 5 / 4) & ~0x07) > Mode->CrtcHTotal) { + /* is this a cvt -r Mode, and only a cvt -r Mode? */ + if (((Mode->CrtcHTotal - Mode->CrtcHDisplay) == 160) && + ((Mode->CrtcHSyncEnd - Mode->CrtcHDisplay) == 80) && + ((Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart) == 32) && + ((Mode->CrtcVSyncStart - Mode->CrtcVDisplay) == 3)) { + if (!Monitor->ReducedAllowed) + return MODE_NO_REDUCED; + } else if ((Mode->CrtcHDisplay * 11) > (Mode->CrtcHTotal * 10)) + return MODE_HSYNC_NARROW; + } + } + + if (Monitor->UseFixedModes && !rhdMonitorFixedValid(Monitor, Mode)) + return MODE_FIXED; + + return MODE_OK; +} + +#define RHD_MODE_VALIDATION_LOOPS 10 + +enum ValidationKind { + VALIDATE_SCALE_NONE, + VALIDATE_SCALE_FROM, + VALIDATE_SCALE_TO +}; + +/* + * + */ +static int +rhdModeValidateCrtc(struct rhdCrtc *Crtc, DisplayModePtr Mode, enum ValidationKind ValidateScaleModeKind) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + ScrnInfoPtr pScrn = rhdPtr->pScrn; + int Status, i; + + RHDFUNC(Crtc); + + Status = rhdModeSanity(rhdPtr, Mode); + if (Status != MODE_OK) + return Status; + + rhdModeFillOutCrtcValues(Mode); + + /* We don't want to loop around this forever */ + for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) { + struct rhdOutput *Output; + + Mode->CrtcHAdjusted = FALSE; + Mode->CrtcVAdjusted = FALSE; + + Status = rhdModeCrtcSanity(Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + if (ValidateScaleModeKind != VALIDATE_SCALE_TO) { + + Status = Crtc->FBValid(Crtc, Mode->CrtcHDisplay, Mode->CrtcVDisplay, + pScrn->bitsPerPixel, rhdPtr->FbScanoutStart, + rhdPtr->FbScanoutSize, NULL); + if (Status != MODE_OK) + return Status; + + if (Crtc->ScaleValid) { + if (ValidateScaleModeKind == VALIDATE_SCALE_NONE) + Status = Crtc->ScaleValid(Crtc, RHD_CRTC_SCALE_TYPE_NONE, Mode, NULL); + else + Status = Crtc->ScaleValid(Crtc, Crtc->ScaleType, Mode, Crtc->ScaledToMode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + } + } + + if (ValidateScaleModeKind != VALIDATE_SCALE_FROM) { + Status = Crtc->ModeValid(Crtc, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + if (Crtc->PLL && Crtc->PLL->Valid) { /* RandR may not have PLL filled out. oh well... */ + Status = Crtc->PLL->Valid(Crtc->PLL, Mode->Clock); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + } + + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) + if (Output->Active && (Output->Crtc == Crtc)) { + /* Check the output */ + Status = Output->ModeValid(Output, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + break; /* restart. */ + + /* Check the monitor attached to this output */ + if (Output->Connector && Output->Connector->Monitor) + Status = rhdMonitorValid(Output->Connector->Monitor, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + break; /* restart. */ + } + + if (Output) /* We're done. This must be a good mode. */ + continue; + } + + return MODE_OK; + } + + /* Mode has been bouncing around for ages, on adjustments */ + xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was" + " thrown around for too long.\n", __func__, Mode->name, + Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0); + return MODE_ERROR; +} + +/* + * + */ +int +RHDValidateScaledToMode(struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Crtc); + int Status; + + RHDFUNC(Crtc); + + Status = rhdModeSanity(rhdPtr, Mode); + if (Status != MODE_OK) + return Status; + + rhdModeFillOutCrtcValues(Mode); + + Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_TO); + if (Status != MODE_OK) + return Status; + + /* Do we want to also validate against a configured monitor? */ + if (rhdPtr->ConfigMonitor) { + Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode); + if (Status != MODE_OK) + return Status; + } + + return MODE_OK; +} + +/* + * + */ +static int +rhdModeValidate(ScrnInfoPtr pScrn, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTR(pScrn); + struct rhdCrtc *Crtc; + int Status; + int i; + + Status = rhdModeSanity(rhdPtr, Mode); + if (Status != MODE_OK) + return Status; + + rhdModeFillOutCrtcValues(Mode); + + /* now let our modesetting tree have its say */ + for (i = 0; i < 2; i++) { + Crtc = rhdPtr->Crtc[i]; + if (!Crtc->Active) + continue; + + if (!Crtc->ScaledToMode) { + + Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_NONE); + if (Status != MODE_OK) + return Status; + + } else { + Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_FROM); + if (Status != MODE_OK) + return Status; + } + } + + /* throw them at the configured monitor, so that the inadequate + * conf file at least has some influence. */ + if (rhdPtr->ConfigMonitor) { + Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode); + if (Status != MODE_OK) + return Status; + } + + /* Did we set up virtual resolution already? */ + if ((pScrn->virtualX > 0) && (pScrn->virtualY > 0)) { + if (pScrn->virtualX < Mode->CrtcHDisplay) + return MODE_VIRTUAL_X; + if (pScrn->virtualY < Mode->CrtcVDisplay) + return MODE_VIRTUAL_Y; + } + + return MODE_OK; +} + +/* + * Wrap the limited xf86 Mode statusses with our own message. + */ +struct { + int Status; + char *Message; +} rhdModeStatusMessages[] = { + { MODE_NO_REDUCED, "Reduced blanking is not supported."}, + { MODE_MEM_BW, "Memory bandwidth exceeded."}, + { MODE_OUTPUT_UNDEF, "Mode not defined by output device."}, + { MODE_NOT_PAL, "This is not a PAL TV mode."}, + { MODE_NOT_NTSC, "This is not an NTSC TV mode."}, + { MODE_HTOTAL_WIDE, "Horizontal Total is out of range."}, + { MODE_HDISPLAY_WIDE, "Mode is too wide."}, + { MODE_HSYNC_RANGE, "Horizontal Sync Start is out of range."}, + { MODE_HBLANK_RANGE, "Horizontal Blanking Start is out of range."}, + { MODE_VTOTAL_WIDE, "Vertical Total is out of range.\n"}, + { MODE_VDISPLAY_WIDE, "Mode is too high."}, + { MODE_VSYNC_RANGE, "Vertical Sync Start is out of range.\n"}, + { MODE_VBLANK_RANGE, "Vertical Blanking Start is out of range."}, + { MODE_PITCH, "Scanout buffer Pitch too wide."}, + { MODE_OFFSET, "Scanout buffer offset too high in FB."}, + { MODE_MINHEIGHT, "Height too low."}, + { MODE_FIXED, "Mode not compatible with fixed mode."}, + { MODE_SCALE, "Mode cannot be scaled to fixed mode."}, + { 0, NULL} +}; + +const char * +xf86ModeStatusToString(ModeStatus status) +{ + switch (status) { + case MODE_OK: + return "Mode OK"; + case MODE_HSYNC: + return "hsync out of range"; + case MODE_VSYNC: + return "vrefresh out of range"; + case MODE_H_ILLEGAL: + return "illegal horizontal timings"; + case MODE_V_ILLEGAL: + return "illegal vertical timings"; + case MODE_BAD_WIDTH: + return "width requires unsupported line pitch"; + case MODE_NOMODE: + return "no mode of this name"; + case MODE_NO_INTERLACE: + return "interlace mode not supported"; + case MODE_NO_DBLESCAN: + return "doublescan mode not supported"; + case MODE_NO_VSCAN: + return "multiscan mode not supported"; + case MODE_MEM: + return "insufficient memory for mode"; + case MODE_VIRTUAL_X: + return "width too large for virtual size"; + case MODE_VIRTUAL_Y: + return "height too large for virtual size"; + case MODE_MEM_VIRT: + return "insufficient memory given virtual size"; + case MODE_NOCLOCK: + return "no clock available for mode"; + case MODE_CLOCK_HIGH: + return "mode clock too high"; + case MODE_CLOCK_LOW: + return "mode clock too low"; + case MODE_CLOCK_RANGE: + return "bad mode clock/interlace/doublescan"; + case MODE_BAD_HVALUE: + return "horizontal timing out of range"; + case MODE_BAD_VVALUE: + return "vertical timing out of range"; + case MODE_BAD_VSCAN: + return "VScan value out of range"; + case MODE_HSYNC_NARROW: + return "horizontal sync too narrow"; + case MODE_HSYNC_WIDE: + return "horizontal sync too wide"; + case MODE_HBLANK_NARROW: + return "horizontal blanking too narrow"; + case MODE_HBLANK_WIDE: + return "horizontal blanking too wide"; + case MODE_VSYNC_NARROW: + return "vertical sync too narrow"; + case MODE_VSYNC_WIDE: + return "vertical sync too wide"; + case MODE_VBLANK_NARROW: + return "vertical blanking too narrow"; + case MODE_VBLANK_WIDE: + return "vertical blanking too wide"; + case MODE_PANEL: + return "exceeds panel dimensions"; + case MODE_INTERLACE_WIDTH: + return "width too large for interlaced mode"; + case MODE_ONE_WIDTH: + return "all modes must have the same width"; + case MODE_ONE_HEIGHT: + return "all modes must have the same height"; + case MODE_ONE_SIZE: + return "all modes must have the same resolution"; + case MODE_BAD: + return "unknown reason"; + case MODE_ERROR: + return "internal error"; + default: + return "unknown"; + } +} + +const char *RHDModeStatusToString(int Status) +{ + if ((Status & 0xFFF00) == RHD_MODE_STATUS) { + int i; + + for (i = 0; rhdModeStatusMessages[i].Message; i++) + if (rhdModeStatusMessages[i].Status == Status) + return rhdModeStatusMessages[i].Message; + ErrorF("%s: unhandled Status type: 0x%X\n", __func__, Status); + return "Unknown status."; + + } else + return xf86ModeStatusToString(Status); +} + +/* + * + */ +static DisplayModePtr +rhdModesGrabOnNameAll(DisplayModePtr *Modes, char *name) +{ + DisplayModePtr Mode, Matched = NULL, Temp; + + for (Mode = *Modes; Mode; ) { + if (!strcmp(Mode->name, name)) { + Temp = Mode; + Mode = Mode->next; + + if (Temp->prev) + Temp->prev->next = Mode; + else + *Modes = Mode; + + if (Mode) + Mode->prev = Temp->prev; + + Temp->prev = NULL; + Temp->next = Matched; + if (Matched) + Matched->prev = Temp; + Matched = Temp; + } else + Mode = Mode->next; + } + + return Matched; +} + +/* + * + */ +static DisplayModePtr +rhdModesGrabOnTypeAll(DisplayModePtr *Modes, int Type, int Mask) +{ + DisplayModePtr Mode, Matched = NULL, Temp; + + for (Mode = *Modes; Mode; ) { + if ((Mode->type & Mask) == (Type & Mask)) { + Temp = Mode; + Mode = Mode->next; + + if (Temp->prev) + Temp->prev->next = Mode; + else + *Modes = Mode; + + if (Mode) + Mode->prev = Temp->prev; + + Temp->next = Matched; + if (Matched) + Matched->prev = Temp; + Temp->prev = NULL; + Matched = Temp; + } else + Mode = Mode->next; + } + + return Matched; +} + +/* + * + */ +static DisplayModePtr +rhdModesGrabBestRefresh(DisplayModePtr *Modes) +{ + DisplayModePtr Mode, Best = NULL; + + if (!*Modes) + return NULL; + + Best = *Modes; + + for (Mode = Best->next; Mode; Mode = Mode->next) + if (Best->VRefresh < Mode->VRefresh) + Best = Mode; + else if (Best->VRefresh == Mode->VRefresh) { + /* Same name != same resolution */ + if ((Best->HDisplay * Best->VDisplay) < + (Mode->HDisplay * Mode->VDisplay)) + Best = Mode; + else if ((Best->HDisplay * Best->VDisplay) == + (Mode->HDisplay * Mode->VDisplay)) { + /* Lower bandwidth == better! */ + if (Best->Clock > Mode->Clock) + Best = Mode; + } + } + + if (Best->next) + Best->next->prev = Best->prev; + if (Best->prev) + Best->prev->next = Best->next; + if (Best == *Modes) + *Modes = (*Modes)->next; + + Best->next = NULL; + Best->prev = NULL; + + return Best; +} + +/* + * + */ +static DisplayModePtr +rhdModesGrabOnHighestType(DisplayModePtr *Modes) +{ + DisplayModePtr Mode; + + /* User provided, but can also have another source. */ + Mode = rhdModesGrabOnTypeAll(Modes, M_T_USERDEF, 0xF0); + if (Mode) + return Mode; + + /* Often EDID provided, but can also have another source. */ + Mode = rhdModesGrabOnTypeAll(Modes, M_T_DRIVER, 0xF0); + if (Mode) + return Mode; + + /* No reason why we should treat built-in and vesa separately */ + Mode = *Modes; + *Modes = NULL; + return Mode; +} + +/* + * + */ +static DisplayModePtr +rhdModesSortOnSize(DisplayModePtr Modes) +{ + DisplayModePtr Sorted, Mode, Temp, Next; + + if (!Modes) + return NULL; + + Sorted = Modes; + Modes = Modes->next; + + Sorted->next = NULL; + Sorted->prev = NULL; + + for (Next = Modes; Next; ) { + /* since we're taking modelines from in between */ + Mode = Next; + Next = Next->next; + + for (Temp = Sorted; Temp; Temp = Temp->next) { + /* nasty ! */ + if (((Temp->CrtcHDisplay * Temp->CrtcVDisplay) < + (Mode->CrtcHDisplay * Mode->CrtcVDisplay)) || + (((Temp->CrtcHDisplay * Temp->CrtcVDisplay) == + (Mode->CrtcHDisplay * Mode->CrtcVDisplay)) && + ((Temp->VRefresh < Mode->VRefresh) || + ((Temp->VRefresh < Mode->VRefresh) && + (Temp->SynthClock < Mode->SynthClock))))) { + Mode->next = Temp; + Mode->prev = Temp->prev; + Temp->prev = Mode; + if (Mode->prev) + Mode->prev->next = Mode; + else + Sorted = Mode; + break; + } + + if (!Temp->next) { + Temp->next = Mode; + Mode->prev = Temp; + Mode->next = NULL; + break; + } + } + } + + return Sorted; +} + +#if 0 +/* + * take a modename, try to parse it, if that works, generate the CVT modeline. + */ +static DisplayModePtr +rhdModeCreateFromName(ScrnInfoPtr pScrn, char *name, Bool Silent) +{ + DisplayModePtr Mode; + int HDisplay = 0, VDisplay = 0, tmp; + float VRefresh = 0; + Bool Reduced; + int Status; + + sscanf(name, "%dx%d@%f", &HDisplay, &VDisplay, &VRefresh); + if (!HDisplay || !VDisplay) { + if (!Silent) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s: Unable to generate " + "Modeline for Mode \"%s\"\n", __func__, name); + return NULL; + } + + tmp = strlen(name) - 1; + if ((name[tmp] == 'r') || (name[tmp] == 'R')) + Reduced = TRUE; + else + Reduced = FALSE; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Generating Modeline for \"%s\"\n", name); + + /* First, try a plain CVT mode */ + Mode = RHDCVTMode(HDisplay, VDisplay, VRefresh, Reduced, FALSE); + xfree(Mode->name); + Mode->name = xnfstrdup(name); + Mode->type = M_T_USERDEF; + + Status = rhdModeValidate(pScrn, Mode); + if (Status == MODE_OK) + return Mode; + rhdModesDestroy(Mode); + +#if 0 /* noscale mode */ + /* Now see if we have fixed modes */ + for (i = 0; i < 2; i++) { + Crtc = rhdPtr->Crtc[i]; + + if (!Crtc->Active || !Crtc->FixedMode) + continue; + + Mode = RHDModeCopy(Crtc->FixedMode); + xfree(Mode->name); + Mode->name = xnfstrdup(name); + Mode->type = M_T_USERDEF; + + Mode->HDisplay = HDisplay; + Mode->CrtcHDisplay = 0; /* set by validation code */ + Mode->VDisplay = VDisplay; + Mode->CrtcVDisplay = 0; + + Status = rhdModeValidate(pScrn, Mode); + if (Status == MODE_OK) + return Mode; + rhdModesDestroy(Mode); + } +#endif + + if (!Silent) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rejected mode \"%s\" " + "(%dx%d):\n\t %s\n", name, HDisplay, VDisplay, + RHDModeStatusToString(Status)); + return NULL; +} +#endif + +/* + * + */ +static DisplayModePtr +rhdModesListValidateAndCopy(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent) +{ + DisplayModePtr Keepers = NULL, Check, Mode; + int Status; + + for (Check = Modes; Check; Check = Check->next) { + Mode = RHDModeCopy(Check); + + Status = rhdModeValidate(pScrn, Mode); + if (Status == MODE_OK) + Keepers = RHDModesAdd(Keepers, Mode); + else { + if (!Silent) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rejected mode \"%s\" " + "(%dx%d:%3.1fMhz): %s\n", Mode->name, + Mode->HDisplay, Mode->VDisplay, + Mode->Clock / 1000.0, RHDModeStatusToString(Status)); + xfree(Mode->name); + xfree(Mode); + } + } + + return Keepers; +} + +/* + * Create the list of all modes that are currently valid + */ +static DisplayModePtr +rhdCreateModesListAndValidate(ScrnInfoPtr pScrn, Bool Silent) +{ + RHDPtr rhdPtr = RHDPTR(pScrn); + DisplayModePtr Keepers = NULL, Modes; + struct rhdCrtc *Crtc; + struct rhdOutput *Output; + int i; + + RHDFUNC(pScrn); + + /* Cycle through our monitors list, and find a fixed mode one */ + for (i = 0; i < 2; i++) { + Crtc = rhdPtr->Crtc[i]; + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) { + if (Output->Active && (Output->Crtc == Crtc)) { + if (Output->Connector && Output->Connector->Monitor + && Output->Connector->Monitor->UseFixedModes + && !Crtc->ScaledToMode) { + Modes = Output->Connector->Monitor->Modes; + if (!Silent && Modes) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating Fixed" + " Modes from Monitor \"%s\"\n\t on Connector" + " \"%s\"\n", Output->Connector->Monitor->Name, + Output->Connector->Name); + + Modes = rhdModesListValidateAndCopy(pScrn, Modes, Silent); + Keepers = RHDModesAdd(Keepers, Modes); + return Keepers; + } + } + } + } + + + /* Cycle through our actual monitors list */ + for (i = 0; i < 2; i++) { + Crtc = rhdPtr->Crtc[i]; + + for (Output = rhdPtr->Outputs; Output; Output = Output->Next) { + if (Output->Active && (Output->Crtc == Crtc)) { + if (Output->Connector && Output->Connector->Monitor) { + Modes = Output->Connector->Monitor->Modes; + if (!Silent && Modes) + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating Modes " + "from Monitor \"%s\" on \"%s\"\n", + Output->Connector->Monitor->Name, + Output->Connector->Name); + + Modes = rhdModesListValidateAndCopy(pScrn, Modes, Silent); + Keepers = RHDModesAdd(Keepers, Modes); + } + } + } + } + + return Keepers; +} + +/* + * + */ +DisplayModePtr +RHDModesPoolCreate(ScrnInfoPtr pScrn, Bool Silent) +{ + DisplayModePtr Pool = NULL, List, TempList, Temp; + char **ModeNames = NULL; //pScrn->display->modes; + int i; + + RHDFUNC(pScrn); + + List = rhdCreateModesListAndValidate(pScrn, Silent); + if (!List) + return List; + + /* Reduce our list */ + if (ModeNames && ModeNames[0]) { /* Find the best matching mode for each name */ + for (i = 0; ModeNames[i]; i++) { + TempList = rhdModesGrabOnNameAll(&List, ModeNames[i]); + if (TempList) { + Temp = rhdModesGrabOnHighestType(&TempList); + rhdModesDestroy(TempList); + + TempList = Temp; + Temp = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED); + if (Temp) { + rhdModesDestroy(TempList); + TempList = Temp; + } + + Temp = rhdModesGrabBestRefresh(&TempList); + + rhdModesDestroy(TempList); + } + // else /* No matching modes found, generate */ + // Temp = rhdModeCreateFromName(pScrn, ModeNames[i], Silent); + + if (Temp) + Pool = RHDModesAdd(Pool, Temp); + } + rhdModesDestroy(List); + } else { /* No names, just work the list directly */ + Temp = rhdModesGrabOnHighestType(&List); + rhdModesDestroy(List); + List = Temp; + + while (List) { + TempList = rhdModesGrabOnNameAll(&List, List->name); + + Temp = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED); + if (Temp) { + rhdModesDestroy(TempList); + TempList = Temp; + } + + Temp = rhdModesGrabBestRefresh(&TempList); + rhdModesDestroy(TempList); + + Pool = RHDModesAdd(Pool, Temp); + } + + /* Sort our list */ + TempList = Pool; + + /* Sort higher priority modes separately */ + Pool = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED); + Pool = rhdModesSortOnSize(Pool); + + TempList = rhdModesSortOnSize(TempList); + + Pool = RHDModesAdd(Pool, TempList); + } + + return Pool; +} + +/* + * + */ +void +RHDModesAttach(ScrnInfoPtr pScrn, DisplayModePtr Modes) +{ + DisplayModePtr Mode = Modes; + + pScrn->modes = Modes; + pScrn->currentMode = Modes; + + while (Mode->next) { + Mode->type = M_T_USERDEF; /* satisfy xf86ZoomViewport */ + Mode = Mode->next; + } + + Mode->type = M_T_USERDEF; + + /* Make our list circular */ + Mode->next = pScrn->modes; + pScrn->modes->prev = Mode; +} + +/* + * + */ +#if 0 +Bool +RHDGetVirtualFromConfig(ScrnInfoPtr pScrn) +{ + RHDPtr rhdPtr = RHDPTR(pScrn); + struct rhdCrtc *Crtc1 = rhdPtr->Crtc[0], *Crtc2 = rhdPtr->Crtc[1]; + CARD32 VirtualX = pScrn->display->virtualX; + CARD32 VirtualY = pScrn->display->virtualY; + CARD32 Pitch1, Pitch2; + float Ratio = (float) pScrn->display->virtualY / pScrn->display->virtualX; + int ret = FALSE; + + RHDFUNC(pScrn); + + while (VirtualX && VirtualY) { + ret = Crtc1->FBValid(Crtc1, VirtualX, VirtualY, pScrn->bitsPerPixel, + rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch1); + if (ret != MODE_OK) + goto shrink; + ret = Crtc2->FBValid(Crtc2, VirtualX, VirtualY, pScrn->bitsPerPixel, + rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch2); + if (ret != MODE_OK) + goto shrink; + + if (Pitch1 != Pitch2) + goto shrink; +#if 0 + /* let 2d acceleration have a say as well */ + if (rhdPtr->AccelMethod >= RHD_ACCEL_XAA) + if (rhdPtr->ChipSet < RHD_R600) /* badly abstracted, i know */ + if (!R5xx2DFBValid(rhdPtr, VirtualX, VirtualY, pScrn->bitsPerPixel, + rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, Pitch1)) + goto shrink; +#endif + break; /* must be good then. */ + shrink: + VirtualX--; + VirtualY = Ratio * VirtualX; + } + + if (VirtualX && VirtualY) { + pScrn->virtualX = VirtualX; + pScrn->virtualY = VirtualY; + pScrn->displayWidth = Pitch1; + return TRUE; + } else + return FALSE; +} + +/* + * + */ +void +RHDGetVirtualFromModesAndFilter(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent) +{ + RHDPtr rhdPtr = RHDPTR(pScrn); + struct rhdCrtc *Crtc1 = rhdPtr->Crtc[0], *Crtc2 = rhdPtr->Crtc[1]; + DisplayModePtr Mode, Next; + CARD32 VirtualX = 0; + CARD32 VirtualY = 0; + CARD32 Pitch1, Pitch2; + int ret = FALSE; + + RHDFUNC(pScrn); + + /* assert */ + if (!Modes) + return; + + Mode = Modes; + + while (Mode) { + if ((Mode->CrtcHDisplay > pScrn->virtualX) || + (Mode->CrtcVDisplay > pScrn->virtualY)) { + if (Mode->CrtcHDisplay > pScrn->virtualX) + VirtualX = Mode->CrtcHDisplay; + else + VirtualX = pScrn->virtualX; + + if (Mode->CrtcVDisplay > pScrn->virtualY) + VirtualY = Mode->CrtcVDisplay; + else + VirtualY = pScrn->virtualY; + + /* Check what Crtc1 thinks this should be. */ + ret = Crtc1->FBValid(Crtc1, VirtualX, VirtualY, pScrn->bitsPerPixel, + rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch1); + if (ret != MODE_OK) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s rejected mode \"%s\" " + "(%dx%d): %s\n", Crtc1->Name, Mode->name, + Mode->HDisplay, Mode->VDisplay, + RHDModeStatusToString(ret)); + goto rejected; + } + + /* Check what Crtc2 thinks this should be. */ + ret = Crtc2->FBValid(Crtc2, VirtualX, VirtualY, pScrn->bitsPerPixel, + rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch2); + if (ret != MODE_OK) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s rejected mode \"%s\" " + "(%dx%d): %s\n", Crtc2->Name, Mode->name, + Mode->HDisplay, Mode->VDisplay, + RHDModeStatusToString(ret)); + goto rejected; + } + + /* when needed, check whether this matches our 2D engine as well. */ + if (rhdPtr->AccelMethod >= RHD_ACCEL_XAA) + if (rhdPtr->ChipSet < RHD_R600) /* badly abstracted, i know */ +#if 0 + if (!R5xx2DFBValid(rhdPtr, VirtualX, VirtualY, + pScrn->bitsPerPixel, rhdPtr->FbScanoutStart, + rhdPtr->FbScanoutSize, Pitch1)) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration " + "rejected mode \"%s\" (%dx%d).\n", + Mode->name, Mode->HDisplay, Mode->VDisplay); + goto rejected; + } +#endif + /* mode is perfectly valid FB wise */ + Mode = Mode->next; + pScrn->virtualX = VirtualX; + pScrn->virtualY = VirtualY; + pScrn->displayWidth = Pitch1; + continue; + + rejected: + Next = Mode->next; + Modes = rhdModeDelete(Modes, Mode); + Mode = Next; + } else + Mode = Mode->next; + } +} + +/* + * RandR entry point: fixup per Crtc and Output (in RandR speech) + * Due to misconceptions we might end up fixing *everything* here. + */ +int +RHDRRModeFixup(ScrnInfoPtr pScrn, DisplayModePtr Mode, struct rhdCrtc *Crtc, + struct rhdConnector *Connector, struct rhdOutput *Output, + struct rhdMonitor *Monitor, Bool ScaledMode) +{ + RHDPtr rhdPtr = RHDPTR(pScrn); + int i, Status; + + ASSERT(Connector); + ASSERT(Output); + RHDFUNC(Output); + + Status = rhdModeSanity(rhdPtr, Mode); + if (Status != MODE_OK) + return Status; + + rhdModeFillOutCrtcValues(Mode); + + if (!ScaledMode) { + /* We don't want to loop around this forever */ + for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) { + Mode->CrtcHAdjusted = FALSE; + Mode->CrtcVAdjusted = FALSE; + + /* Sanitize */ + Status = rhdModeCrtcSanity(Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + if (Crtc) { + /* Check FB */ + Status = Crtc->FBValid(Crtc, Mode->CrtcHDisplay, Mode->CrtcVDisplay, + pScrn->bitsPerPixel, rhdPtr->FbScanoutStart, + rhdPtr->FbScanoutSize, NULL); + if (Status != MODE_OK) + return Status; + + if (Crtc->ScaleValid) { + Status = Crtc->ScaleValid(Crtc, RHD_CRTC_SCALE_TYPE_NONE, Mode, NULL); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + } + + /* Check Crtc */ + Status = Crtc->ModeValid(Crtc, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + /* Check PLL */ + if (Crtc->PLL->Valid) { + Status = Crtc->PLL->Valid(Crtc->PLL, Mode->Clock); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + } + } + + /* Check Output */ + Status = Output->ModeValid(Output, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + /* Check the monitor attached to this output */ + if (Connector->Monitor) + Status = rhdMonitorValid(Connector->Monitor, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + /* Seems to be good */ + break; + } + + if (i == RHD_MODE_VALIDATION_LOOPS) { + /* Mode has been bouncing around for ages, on adjustments */ + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was thrown around" + " for too long.\n", __func__, Mode->name, + Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0); + return MODE_ERROR; + } + + /* throw them at the configured monitor */ + if (Monitor) { + Status = rhdMonitorValid(Monitor, Mode); + if (Status != MODE_OK) + return Status; + } + + } else { + if (Crtc) { + Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_FROM); + if (Status != MODE_OK) + return Status; + } + } + + /* Did we set up virtual resolution already? */ + if ((pScrn->virtualX > 0) && (pScrn->virtualY > 0)) { + if (pScrn->virtualX < Mode->CrtcHDisplay) + return MODE_VIRTUAL_X; + if (pScrn->virtualY < Mode->CrtcVDisplay) + return MODE_VIRTUAL_Y; + } + + return MODE_OK; +} +#endif + +/* + * RHDRRValidateScaledToMode(): like RHDValidateScaledMode() - but we cannot validate against a CRTC + * as this isn't known when this function is called. So at least validate against the 'output' here. + */ +int +RHDRRValidateScaledToMode(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + int Status; + int i; + + RHDFUNC(Output); + + Status = rhdModeSanity(rhdPtr, Mode); + if (Status != MODE_OK) + return Status; + + rhdModeFillOutCrtcValues(Mode); + + for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) { + + Mode->CrtcHAdjusted = FALSE; + Mode->CrtcVAdjusted = FALSE; + + Status = rhdModeCrtcSanity(Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + /* Check the output */ + Status = Output->ModeValid(Output, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; /* restart. */ + + /* Check the monitor attached to this output */ + if (Output->Connector && Output->Connector->Monitor) + Status = rhdMonitorValid(Output->Connector->Monitor, Mode); + if (Status != MODE_OK) + return Status; + if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted) + continue; + + break; + } + + if (i == RHD_MODE_VALIDATION_LOOPS) { + /* Mode has been bouncing around for ages, on adjustments */ + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was thrown around" + " for too long.\n", __func__, Mode->name, + Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0); + return MODE_ERROR; + } + + /* Do we want to also validate against a configured monitor? */ + if (rhdPtr->ConfigMonitor) { + Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode); + if (Status != MODE_OK) + return Status; + } + + return MODE_OK; +} + +/* + * RHDSynthModes(): synthesize CVT modes for well known resolutions. + * For now we assume we want reduced modes only. + */ +void +RHDSynthModes(int scrnIndex, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = (RHDPtr)(scrnIndex); + DisplayModePtr Tmp; + unsigned int i; + + struct resolution{ + int x; + int y; + } resolution_list[] = { + { 320, 200 }, /* CGA */ + { 320, 240 }, /* QVGA */ + { 640, 480 }, /* VGA */ + { 720, 480 }, /* NTSC */ + { 854, 480 }, /* WVGA */ + { 768, 576 }, /* PAL */ + { 800, 600 }, /* SVGA */ + { 1024, 768 }, /* XGA */ + { 1152, 768 }, + { 1280, 720 }, /* HD720 */ + { 1280, 960 }, + { 1280, 854 }, + { 1280, 960 }, + { 1280, 1024 }, /* SXGA */ + { 1440, 960 }, + { 1400, 1050 }, /* SXGA+ */ + { 1680, 1050 }, /* WSXGA+ */ + { 1600, 1200 }, /* UXGA */ + { 1920, 1080 }, /* HD1080 */ + { 1920, 1200 }, /* WUXGA */ + { 2048, 1536 }, /* QXGA */ + { 2560, 1600 }, /* WQXGA */ + { 2560, 2048 } /* QSXGA */ + }; + + RHDFUNC(pScrn); + + for (i = 0; i < (sizeof(resolution_list) / sizeof(struct resolution)); i++) { + /* + * chances are that the native mode of a display is a CVT mode with 60 Hz. + * This will make RandR share the CRTC which is undesireable for scaling. + * This we 'tweak' the frequency to be slightly higher. + * Don't tell me it's ugly - I know this already. + */ + Tmp = RHDCVTMode(resolution_list[i].x, resolution_list[i].y, 60.5, TRUE, FALSE); + Tmp->status = MODE_OK; + rhdModeFillOutCrtcValues(Tmp); + xfree(Tmp->name); + Tmp->name = xnfalloc(20); + snprintf(Tmp->name, 20, "%ix%iScaled",resolution_list[i].x,resolution_list[i].y); + Tmp->type = M_T_BUILTIN; + // if (rhdPtr->verbosity > 6) { + // xf86DrvMsg(scrnIndex, X_INFO, "%s: Adding Modeline ",__func__); + // RHDPrintModeline(Tmp); + // } + RHDModesAdd(Mode, Tmp); + } +} diff --git a/programs/system/drivers/rhd/rhd_modes.h b/programs/system/drivers/rhd/rhd_modes.h new file mode 100644 index 000000000..d76785ca8 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_modes.h @@ -0,0 +1,88 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_MODES_H +#define _RHD_MODES_H + +/* + * Define a set of own mode errors. + */ +#define RHD_MODE_STATUS 0x51B00 +#ifndef MONREC_HAS_REDUCED +#define MODE_NO_REDUCED 0x01 + RHD_MODE_STATUS +#endif +#define MODE_MEM_BW 0x02 + RHD_MODE_STATUS +#define MODE_OUTPUT_UNDEF 0x03 + RHD_MODE_STATUS +#define MODE_NOT_PAL 0x04 + RHD_MODE_STATUS +#define MODE_NOT_NTSC 0x05 + RHD_MODE_STATUS +#define MODE_HTOTAL_WIDE 0x06 + RHD_MODE_STATUS +#define MODE_HDISPLAY_WIDE 0x07 + RHD_MODE_STATUS +#define MODE_HSYNC_RANGE 0x08 + RHD_MODE_STATUS +#define MODE_HBLANK_RANGE 0x09 + RHD_MODE_STATUS +#define MODE_VTOTAL_WIDE 0x0A + RHD_MODE_STATUS +#define MODE_VDISPLAY_WIDE 0x0B + RHD_MODE_STATUS +#define MODE_VSYNC_RANGE 0x0C + RHD_MODE_STATUS +#define MODE_VBLANK_RANGE 0x0D + RHD_MODE_STATUS +#define MODE_PITCH 0x0E + RHD_MODE_STATUS +#define MODE_OFFSET 0x0F + RHD_MODE_STATUS +#define MODE_MINHEIGHT 0x10 + RHD_MODE_STATUS +#define MODE_FIXED 0x11 + RHD_MODE_STATUS +#define MODE_SCALE 0x12 + RHD_MODE_STATUS +#define MODE_NO_ENCODER 0x13 + RHD_MODE_STATUS + +/* + * In case this isn't in xf86str.h yet. + */ + +#define M_T_BUILTIN 0x01 /* built-in mode */ + +#ifndef M_T_PREFERRED +#define M_T_PREFERRED 0x08 +#endif +#ifndef M_T_DRIVER +#define M_T_DRIVER 0x40 +#endif + +DisplayModePtr RHDCVTMode(int HDisplay, int VDisplay, float VRefresh, + Bool Reduced, Bool Interlaced); +void RHDPrintModeline(DisplayModePtr mode); +DisplayModePtr RHDModesAdd(DisplayModePtr Modes, DisplayModePtr Additions); +const char *RHDModeStatusToString(int Status); + +DisplayModePtr RHDModesPoolCreate(ScrnInfoPtr pScrn, Bool Silent); +void RHDModesAttach(ScrnInfoPtr pScrn, DisplayModePtr Modes); +DisplayModePtr RHDModeCopy(DisplayModePtr Mode); + +Bool RHDGetVirtualFromConfig(ScrnInfoPtr pScrn); +void RHDGetVirtualFromModesAndFilter(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent); + +int RHDRRModeFixup(ScrnInfoPtr pScrn, DisplayModePtr Mode, struct rhdCrtc *Crtc, + struct rhdConnector *Connector, struct rhdOutput *Output, + struct rhdMonitor *Monitor, Bool ScaledMode); +int RHDValidateScaledToMode(struct rhdCrtc *Crtc, DisplayModePtr Mode); +int RHDRRValidateScaledToMode(struct rhdOutput *Output, DisplayModePtr Mode); +void RHDSynthModes(int scrnIndex, DisplayModePtr Mode); + +#endif /* _RHD_MODES_H */ diff --git a/programs/system/drivers/rhd/rhd_monitor.c b/programs/system/drivers/rhd/rhd_monitor.c new file mode 100644 index 000000000..afadcaf4d --- /dev/null +++ b/programs/system/drivers/rhd/rhd_monitor.c @@ -0,0 +1,1335 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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. + */ +#define _PARSE_EDID_ + +#include "common.h" +#include "rhd.h" + +#include "edid.h" + +#include "xf86DDC.h" + +#include "rhd_connector.h" +#include "rhd_modes.h" +#include "rhd_monitor.h" +#ifdef ATOM_BIOS +# include "rhd_atombios.h" +#endif + +/* From rhd_edid.c */ +void RHDMonitorEDIDSet(struct rhdMonitor *Monitor, xf86MonPtr EDID); + + +/* + * + */ + +void +RHDMonitorPrint(struct rhdMonitor *Monitor) +{ + int i; + + xf86Msg(X_NONE, " Bandwidth: %dMHz\n", Monitor->Bandwidth / 1000); + xf86Msg(X_NONE, " Horizontal timing:\n"); + for (i = 0; i < Monitor->numHSync; i++) + xf86Msg(X_NONE, " %3.1f - %3.1fkHz\n", Monitor->HSync[i].lo, + Monitor->HSync[i].hi); + xf86Msg(X_NONE, " Vertical timing:\n"); + for (i = 0; i < Monitor->numVRefresh; i++) + xf86Msg(X_NONE, " %3.1f - %3.1fHz\n", Monitor->VRefresh[i].lo, + Monitor->VRefresh[i].hi); + xf86Msg(X_NONE, " DPI: %dx%d\n", Monitor->xDpi, Monitor->yDpi); + if (Monitor->ReducedAllowed) + xf86Msg(X_NONE, " Allows reduced blanking.\n"); + if (Monitor->UseFixedModes) + xf86Msg(X_NONE, " Uses Fixed Modes.\n"); + + if (!Monitor->Modes) + xf86Msg(X_NONE, " No modes are provided.\n"); + else { + DisplayModePtr Mode; + + xf86Msg(X_NONE, " Attached modes:\n"); + for (Mode = Monitor->Modes; Mode; Mode = Mode->next) { + xf86Msg(X_NONE, " "); + RHDPrintModeline(Mode); + } + } +} + + +#if 0 + +/* + * + */ +static struct rhdMonitor * +rhdMonitorFromConfig(int scrnIndex, MonPtr Config) +{ + struct rhdMonitor *Monitor; + DisplayModePtr Mode; + int i; + + Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); + + Monitor->Name = xnfstrdup(Config->id); + Monitor->scrnIndex = scrnIndex; + + if (Config->nHsync) { + Monitor->numHSync = Config->nHsync; + for (i = 0; i < Config->nHsync; i++) { + Monitor->HSync[i].lo = Config->hsync[i].lo; + Monitor->HSync[i].hi = Config->hsync[i].hi; + } + } else if (!Monitor->numHSync) { + Monitor->numHSync = 3; + Monitor->HSync[0].lo = 31.5; + Monitor->HSync[0].hi = 31.5; + Monitor->HSync[1].lo = 35.15; + Monitor->HSync[1].hi = 35.15; + Monitor->HSync[2].lo = 35.5; + Monitor->HSync[2].hi = 35.5; + } + + if (Config->nVrefresh) { + Monitor->numVRefresh = Config->nVrefresh; + for (i = 0; i < Config->nVrefresh; i++) { + Monitor->VRefresh[i].lo = Config->vrefresh[i].lo; + Monitor->VRefresh[i].hi = Config->vrefresh[i].hi; + } + } else if (!Monitor->numVRefresh) { + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = 50; + Monitor->VRefresh[0].hi = 61; + } + +#ifdef MONREC_HAS_REDUCED + if (Config->reducedblanking) + Monitor->ReducedAllowed = TRUE; +#endif + +#ifdef MONREC_HAS_BANDWIDTH + if (Config->maxPixClock) + Monitor->Bandwidth = Config->maxPixClock; +#endif + + for (Mode = Config->Modes; Mode; Mode = Mode->next) + Monitor->Modes = RHDModesAdd(Monitor->Modes, RHDModeCopy(Mode)); + + return Monitor; +} +#endif + +/* + * + */ +static struct rhdMonitor * +rhdMonitorFromDefault(RHDPtr rhdPtr) +{ + struct rhdMonitor *Monitor; + DisplayModePtr Mode; + + Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); + + Monitor->Name = strdup("Default (SVGA)"); + Monitor->scrnIndex = rhdPtr->scrnIndex; + + /* timing for pathetic 14" svga monitors */ + Monitor->numHSync = 3; + Monitor->HSync[0].lo = 31.5; + Monitor->HSync[0].hi = 31.5; + Monitor->HSync[1].lo = 35.15; + Monitor->HSync[1].hi = 35.15; + Monitor->HSync[2].lo = 35.5; + Monitor->HSync[2].hi = 35.5; + + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = 50; + Monitor->VRefresh[0].hi = 61; + + return Monitor; +} + +/* + * This function tries to handle a configured monitor correctly. + * + * This either can be forced through the option, or is used when + * no monitors are autodetected. + */ +void +RHDConfigMonitorSet(RHDPtr rhdPtr, Bool UseConfig) +{ + int i; + + for (i = 0; i < RHD_CONNECTORS_MAX; i++) + if (rhdPtr->Connector[i] && rhdPtr->Connector[i]->Monitor) + break; + + if (i == RHD_CONNECTORS_MAX) + xf86DrvMsg(scrnIndex, X_INFO, "No monitors autodetected; " + "attempting to work around this.\n"); + + if (i == RHD_CONNECTORS_MAX) + { + rhdPtr->ConfigMonitor = rhdMonitorFromDefault(rhdPtr); + + DBG(dbgprintf("Created monitor from default: \"%s\":\n", + rhdPtr->ConfigMonitor->Name)); + + RHDMonitorPrint(rhdPtr->ConfigMonitor); + }; +} + +/* + * Make sure that we keep only a single mode in our list. This mode should + * hopefully match our panel at native resolution correctly. + */ +static void +rhdPanelEDIDModesFilter(struct rhdMonitor *Monitor) +{ + DisplayModeRec *Best = Monitor->Modes, *Mode, *Temp; + + RHDFUNC(Monitor); + + if (!Best || !Best->next) + return; /* don't bother */ + + /* don't go for preferred, just take the biggest */ + for (Mode = Best->next; Mode; Mode = Mode->next) { + if (((Best->HDisplay <= Mode->HDisplay) && + (Best->VDisplay < Mode->VDisplay)) || + ((Best->HDisplay < Mode->HDisplay) && + (Best->VDisplay <= Mode->VDisplay))) + Best = Mode; + } + + xf86DrvMsg(Monitor->scrnIndex, X_INFO, "Monitor \"%s\": Using Mode \"%s\"" + " for native resolution.\n", Monitor->Name, Best->name); + + /* kill all other modes */ + Mode = Monitor->Modes; + while (Mode) { + Temp = Mode->next; + + if (Mode != Best) { + RHDDebug(Monitor->scrnIndex, "Monitor \"%s\": Discarding Mode \"%s\"\n", + Monitor->Name, Mode->name); + + xfree(Mode->name); + xfree(Mode); + } + Mode = Temp; + } + + Best->next = NULL; + Best->prev = NULL; + Best->type |= M_T_PREFERRED; + Monitor->NativeMode = Best; + Monitor->Modes = Monitor->NativeMode; + Monitor->numHSync = 1; + Monitor->HSync[0].lo = Best->HSync; + Monitor->HSync[0].hi = Best->HSync; + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = Best->VRefresh; + Monitor->VRefresh[0].hi = Best->VRefresh; + Monitor->Bandwidth = Best->Clock; +} + +/* + * + */ +void +rhdMonitorPrintEDID(struct rhdMonitor *Monitor, xf86MonPtr EDID) +{ + xf86DrvMsg(EDID->scrnIndex, X_INFO, "EDID data for %s\n", + Monitor->Name); + xf86PrintEDID(EDID); +} + +/* + * Panels are the most complicated case we need to handle here. + * Information can come from several places, and we need to make sure + * that we end up with only the native resolution in our table. + */ +static struct rhdMonitor * +rhdMonitorPanel(struct rhdConnector *Connector) +{ + struct rhdMonitor *Monitor; + DisplayModeRec *Mode = NULL; + xf86MonPtr EDID = NULL; + + RHDFUNC(Connector); + + /* has priority over AtomBIOS EDID */ + if (Connector->DDC) + EDID = xf86DoEDID_DDC2(Connector->scrnIndex, Connector->DDC); + +#ifdef ATOM_BIOS + { + RHDPtr rhdPtr = (RHDPtr)Connector->scrnIndex; + AtomBiosArgRec data; + AtomBiosResult Result; + + Result = RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS, + ATOMBIOS_GET_PANEL_MODE, &data); + if (Result == ATOM_SUCCESS) { + Mode = data.mode; + Mode->type |= M_T_PREFERRED; + } + if (!EDID) { + Result = RHDAtomBiosFunc(rhdPtr,rhdPtr->atomBIOS, + ATOMBIOS_GET_PANEL_EDID, &data); + if (Result == ATOM_SUCCESS) + EDID = xf86InterpretEDID(rhdPtr, data.EDIDBlock); + } + } +#endif + + Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); + + Monitor->scrnIndex = Connector->scrnIndex; + Monitor->EDID = EDID; + + if (Mode) { + Monitor->Name = xstrdup("LVDS Panel"); + Monitor->Modes = RHDModesAdd(Monitor->Modes, Mode); + Monitor->NativeMode = Mode; + Monitor->numHSync = 1; + Monitor->HSync[0].lo = Mode->HSync; + Monitor->HSync[0].hi = Mode->HSync; + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = Mode->VRefresh; + Monitor->VRefresh[0].hi = Mode->VRefresh; + Monitor->Bandwidth = Mode->SynthClock; + + /* Clueless atombios does give us a mode, but doesn't give us a + * DPI or a size. It is just perfect, right? */ + if (EDID) { + if (EDID->features.hsize) + Monitor->xDpi = (Mode->HDisplay * 2.54) / ((float) EDID->features.hsize) + 0.5; + if (EDID->features.vsize) + Monitor->yDpi = (Mode->VDisplay * 2.54) / ((float) EDID->features.vsize) + 0.5; + } + } else if (EDID) { + RHDMonitorEDIDSet(Monitor, EDID); + rhdPanelEDIDModesFilter(Monitor); + } else { + xf86DrvMsg(Connector->scrnIndex, X_ERROR, + "%s: No panel mode information found.\n", __func__); + xfree(Monitor); + return NULL; + } + + /* panel should be driven at native resolution only. */ + Monitor->UseFixedModes = TRUE; + Monitor->ReducedAllowed = TRUE; + + if (EDID) + rhdMonitorPrintEDID(Monitor, EDID); + + return Monitor; +} + +/* + * rhdMonitorTV(): get TV modes. Currently we can only get this from AtomBIOS. + */ +static struct rhdMonitor * +rhdMonitorTV(struct rhdConnector *Connector) +{ + struct rhdMonitor *Monitor = NULL; +#ifdef ATOM_BIOS + RHDPtr rhdPtr = RHDPTRI(Connector); + DisplayModeRec *Mode = NULL; + AtomBiosArgRec arg; + + RHDFUNC(Connector); + + arg.tvMode = rhdPtr->tvMode; + if (RHDAtomBiosFunc(Connector->scrnIndex, rhdPtr->atomBIOS, + ATOM_ANALOG_TV_MODE, &arg) + != ATOM_SUCCESS) + return NULL; + + Mode = arg.mode; + Mode->type |= M_T_PREFERRED; + + Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); + + Monitor->scrnIndex = Connector->scrnIndex; + Monitor->EDID = NULL; + + Monitor->Name = xstrdup("TV"); + Monitor->Modes = RHDModesAdd(Monitor->Modes, Mode); + Monitor->NativeMode= Mode; + Monitor->numHSync = 1; + Monitor->HSync[0].lo = Mode->HSync; + Monitor->HSync[0].hi = Mode->HSync; + Monitor->numVRefresh = 1; + Monitor->VRefresh[0].lo = Mode->VRefresh; + Monitor->VRefresh[0].hi = Mode->VRefresh; + Monitor->Bandwidth = Mode->SynthClock; + + /* TV should be driven at native resolution only. */ + Monitor->UseFixedModes = TRUE; + Monitor->ReducedAllowed = FALSE; + /* + * hack: the TV encoder takes care of that. + * The mode that goes in isn't what comes out. + */ + Mode->Flags &= ~(V_INTERLACE); +#endif + return Monitor; +} + +/* + * + */ +struct rhdMonitor * +RHDMonitorInit(struct rhdConnector *Connector) +{ + struct rhdMonitor *Monitor = NULL; + + RHDFUNC(Connector); + + if (Connector->Type == RHD_CONNECTOR_PANEL) + Monitor = rhdMonitorPanel(Connector); + else if (Connector->Type == RHD_CONNECTOR_TV) + Monitor = rhdMonitorTV(Connector); + else if (Connector->DDC) { + xf86MonPtr EDID = xf86DoEDID_DDC2(Connector->scrnIndex, Connector->DDC); + if (EDID) { + Monitor = xnfcalloc(sizeof(struct rhdMonitor), 1); + Monitor->scrnIndex = Connector->scrnIndex; + Monitor->EDID = EDID; + Monitor->NativeMode = NULL; + + RHDMonitorEDIDSet(Monitor, EDID); + rhdMonitorPrintEDID(Monitor, EDID); + } + } + return Monitor; +} + +/* + * + */ +void +RHDMonitorDestroy(struct rhdMonitor *Monitor) +{ + DisplayModePtr Mode, Next; + + for (Mode = Monitor->Modes; Mode;) { + Next = Mode->next; + + xfree(Mode->name); + xfree(Mode); + + Mode = Next; + } + + if (Monitor->EDID) + xfree(Monitor->EDID->rawData); + xfree(Monitor->EDID); + xfree(Monitor->Name); + xfree(Monitor); +} + + +static unsigned char * VDIFRead(RHDPtr rhdPtr, I2CBusPtr pBus, int start); + +#define RETRIES 4 + +static xf86VdifLimitsPtr* get_limits(CARD8 *c); +static xf86VdifGammaPtr* get_gamma(CARD8 *c); +static xf86VdifTimingPtr* get_timings(CARD8 *c); + +xf86vdifPtr xf86InterpretVdif(CARD8 *c) +{ + xf86VdifPtr p = (xf86VdifPtr)c; + xf86vdifPtr vdif; + int i; + + unsigned long l = 0; + + if (c == NULL) return NULL; + if (p->VDIFId[0] != 'V' || p->VDIFId[1] != 'D' || p->VDIFId[2] != 'I' + || p->VDIFId[3] != 'F') return NULL; + for ( i = 12; i < p->FileLength; i++) + l += c[i]; + if ( l != p->Checksum) return NULL; + vdif = malloc(sizeof(xf86vdif)); + vdif->vdif = p; + vdif->limits = get_limits(c); + vdif->timings = get_timings(c); + vdif->gamma = get_gamma(c); + vdif->strings = VDIF_STRING(((xf86VdifPtr)c),0); + free(c); + return vdif; +} + +static xf86VdifLimitsPtr* +get_limits(CARD8 *c) +{ + int num, i, j; + xf86VdifLimitsPtr *pp; + xf86VdifLimitsPtr p; + + num = ((xf86VdifPtr)c)->NumberOperationalLimits; + pp = malloc(sizeof(xf86VdifLimitsPtr) * (num+1)); + p = VDIF_OPERATIONAL_LIMITS(((xf86VdifPtr)c)); + j = 0; + for ( i = 0; iHeader.ScnTag == VDIF_OPERATIONAL_LIMITS_TAG) + pp[j++] = p; + VDIF_NEXT_OPERATIONAL_LIMITS(p); + } + pp[j] = NULL; + return pp; +} + +static xf86VdifGammaPtr* +get_gamma(CARD8 *c) +{ + int num, i, j; + xf86VdifGammaPtr *pp; + xf86VdifGammaPtr p; + + num = ((xf86VdifPtr)c)->NumberOptions; + pp = malloc(sizeof(xf86VdifGammaPtr) * (num+1)); + p = (xf86VdifGammaPtr)VDIF_OPTIONS(((xf86VdifPtr)c)); + j = 0; + for ( i = 0; iHeader.ScnTag == VDIF_GAMMA_TABLE_TAG) + pp[j++] = p; + VDIF_NEXT_OPTIONS(p); + } + pp[j] = NULL; + return pp; +} + +static xf86VdifTimingPtr* +get_timings(CARD8 *c) +{ + int num, num_limits; + int i,j,k; + xf86VdifLimitsPtr lp; + xf86VdifTimingPtr *pp; + xf86VdifTimingPtr p; + + num = ((xf86VdifPtr)c)->NumberOperationalLimits; + lp = VDIF_OPERATIONAL_LIMITS(((xf86VdifPtr)c)); + num_limits = 0; + for (i = 0; i < num; i++) { + if (lp->Header.ScnTag == VDIF_OPERATIONAL_LIMITS_TAG) + num_limits += lp->NumberPreadjustedTimings; + VDIF_NEXT_OPERATIONAL_LIMITS(lp); + } + pp = malloc(sizeof(xf86VdifTimingPtr) + * (num_limits+1)); + j = 0; + lp = VDIF_OPERATIONAL_LIMITS(((xf86VdifPtr) c)); + for (i = 0; i < num; i++) { + p = VDIF_PREADJUSTED_TIMING(lp); + for (k = 0; k < lp->NumberPreadjustedTimings; k++) { + if (p->Header.ScnTag == VDIF_PREADJUSTED_TIMING_TAG) + pp[j++] = p; + VDIF_NEXT_PREADJUSTED_TIMING(p); + } + VDIF_NEXT_OPERATIONAL_LIMITS(lp); + } + pp[j] = NULL; + return pp; +} + +int DDC_checksum(unsigned char *block, int len) +{ + int i, result = 0; + int not_null = 0; + + for (i=0;iDevName = "ddc2"; + dev->SlaveAddr = 0xA0; + dev->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + dev->StartTimeout = 550; + dev->BitTimeout = 40; + dev->ByteTimeout = 40; + dev->AcknTimeout = 40; + + dev->pI2CBus = pBus; + if (!xf86I2CDevInit(dev)) + { + DBG(dbgprintf("No DDC2 device\n")); + return NULL; + } + } + if (start < 0x100) + { + w_bytes = 1; + W_Buffer[0] = start; + } + else + { + w_bytes = 2; + W_Buffer[0] = start & 0xFF; + W_Buffer[1] = (start & 0xFF00) >> 8; + } + + R_Buffer = calloc(1,sizeof(unsigned char)* (len)); + + if( !R_Buffer) + { + DBG(dbgprintf("R_Buffer = NULL\n")); + return NULL; + }; + + for (i=0; ino_sections)); + + VDIF_Block = + VDIFRead(rhdPtr, pBus, EDID1_LEN * (tmp->no_sections + 1)); + tmp->vdif = xf86InterpretVdif(VDIF_Block); + + return tmp; +} + +static unsigned char* +VDIFRead(RHDPtr rhdPtr, I2CBusPtr pBus, int start) +{ + unsigned char * Buffer, *v_buffer = NULL, *v_bufferp = NULL; + int i, num = 0; + + /* read VDIF length in 64 byte blocks */ + Buffer = DDCRead_DDC2(rhdPtr, pBus,start,64); + if (Buffer == NULL) + return NULL; + + DBG(dbgprintf("number of 64 bit blocks: %i\n",Buffer[0])); + + if ((num = Buffer[0]) > 0) + v_buffer = v_bufferp = malloc(sizeof(unsigned char) * 64 * num); + + for (i = 0; i < num; i++) + { + Buffer = DDCRead_DDC2(rhdPtr, pBus,start,64); + if (Buffer == NULL) + { + free (v_buffer); + return NULL; + } + memcpy(v_bufferp,Buffer,63); /* 64th byte is checksum */ + free(Buffer); + v_bufferp += 63; + } + return v_buffer; +} + + + +static void print_vendor(RHDPtr rhdPtr, struct vendor *); +static void print_version(RHDPtr rhdPtr, struct edid_version *); +static void print_display(RHDPtr rhdPtr, struct disp_features *, + struct edid_version *); +static void print_established_timings(RHDPtr rhdPtr, + struct established_timings *); +static void print_std_timings(RHDPtr rhdPtr, struct std_timings *); +static void print_detailed_monitor_section(RHDPtr rhdPtr, + struct detailed_monitor_section *); +static void print_detailed_timings(RHDPtr rhdPtr, struct detailed_timings *); + +static void print_input_features(RHDPtr rhdPtr, struct disp_features *); +static void print_dpms_features(RHDPtr rhdPtr, struct disp_features *, + struct edid_version *v); +static void print_whitepoint(RHDPtr rhdPtr, struct disp_features *); +static void print_number_sections(RHDPtr rhdPtr, int); + +xf86MonPtr +xf86PrintEDID(xf86MonPtr m) +{ + if (!(m)) return NULL; + print_vendor(m->rhdPtr,&m->vendor); + print_version(m->rhdPtr,&m->ver); + print_display(m->rhdPtr,&m->features, &m->ver); + print_established_timings(m->rhdPtr,&m->timings1); + print_std_timings(m->rhdPtr,m->timings2); + print_detailed_monitor_section(m->rhdPtr,m->det_mon); + print_number_sections(m->rhdPtr,m->no_sections); + + return m; +} + +static void +print_vendor(RHDPtr rhdPtr, struct vendor *c) +{ + DBG(dbgprintf("Manufacturer: %s Model: %x Serial#: %u\n", + (char *)&c->name, c->prod_id, c->serial)); + DBG(dbgprintf("Year: %u Week: %u\n", c->year, c->week)); +} + +static void +print_version(RHDPtr rhdPtr, struct edid_version *c) +{ + DBG(dbgprintf("EDID Version: %u.%u\n",c->version,c->revision)); +} + +static void +print_display(RHDPtr rhdPtr, struct disp_features *disp, + struct edid_version *version) +{ + print_input_features(rhdPtr,disp); + DBG(dbgprintf("Max H-Image Size [cm]: ")); + if (disp->hsize) + DBG(dbgprintf("horiz.: %i ",disp->hsize)); + else + DBG(dbgprintf("H-Size may change, ")); + if (disp->vsize) + DBG(dbgprintf("vert.: %i\n",disp->vsize)); + else + DBG(dbgprintf("V-Size may change\n")); + DBG(dbgprintf("Gamma: %.2f\n", (double)disp->gamma)); + print_dpms_features(rhdPtr,disp,version); + print_whitepoint(rhdPtr,disp); +} + +static void +print_input_features(RHDPtr rhdPtr, struct disp_features *c) +{ + if (DIGITAL(c->input_type)) + { + DBG(dbgprintf("Digital Display Input\n")); + if (DFP1(c->input_dfp)) + DBG(dbgprintf("DFP 1.x compatible TMDS\n")); + } + else + { + DBG(dbgprintf("Analog Display Input, ")); + DBG(dbgprintf("Input Voltage Level: ")); + switch (c->input_voltage) + { + case V070: + DBG(dbgprintf("0.700/0.300 V\n")); + break; + case V071: + DBG(dbgprintf("0.714/0.286 V\n")); + break; + case V100: + DBG(dbgprintf("1.000/0.400 V\n")); + break; + case V007: + DBG(dbgprintf("0.700/0.700 V\n")); + break; + default: + DBG(dbgprintf("undefined\n")); + } + if (SIG_SETUP(c->input_setup)) + DBG(dbgprintf("Signal levels configurable\n")); + DBG(dbgprintf("Sync:")); + if (SEP_SYNC(c->input_sync)) + DBG(dbgprintf(" Separate")); + if (COMP_SYNC(c->input_sync)) + DBG(dbgprintf(" Composite")); + if (SYNC_O_GREEN(c->input_sync)) + DBG(dbgprintf(" SyncOnGreen")); + if (SYNC_SERR(c->input_sync)) + DBG(dbgprintf("Serration on. " + "V.Sync Pulse req. if CompSync or SyncOnGreen\n")); + else + DBG(dbgprintf("\n")); + } +} + +static void +print_dpms_features(RHDPtr rhdPtr, struct disp_features *c, + struct edid_version *v) +{ + if (c->dpms) + { + DBG(dbgprintf("DPMS capabilities:")); + if (DPMS_STANDBY(c->dpms)) + DBG(dbgprintf(" StandBy")); + if (DPMS_SUSPEND(c->dpms)) + DBG(dbgprintf(" Suspend")); + if (DPMS_OFF(c->dpms)) + DBG(dbgprintf(" Off")); + } + else + DBG(dbgprintf("No DPMS capabilities specified")); + switch (c->display_type) + { + case DISP_MONO: + DBG(dbgprintf("; Monochorome/GrayScale Display\n")); + break; + case DISP_RGB: + DBG(dbgprintf("; RGB/Color Display\n")); + break; + case DISP_MULTCOLOR: + DBG(dbgprintf("; Non RGB Multicolor Display\n")); + break; + default: + DBG(dbgprintf("\n")); + break; + } + if (STD_COLOR_SPACE(c->msc)) + DBG(dbgprintf("Default color space is primary color space\n")); + if (PREFERRED_TIMING_MODE(c->msc)) + DBG(dbgprintf("First detailed timing is preferred mode\n")); + else + if (v->version == 1 && v->revision >= 3) + DBG(dbgprintf("First detailed timing not preferred " + "mode in violation of standard!")); + if (GFT_SUPPORTED(c->msc)) + DBG(dbgprintf("GTF timings supported\n")); +} + +static void +print_whitepoint(RHDPtr rhdPtr, struct disp_features *disp) +{ + DBG(dbgprintf("redX: %.3f redY: %.3f ", + (double)disp->redx,(double)disp->redy)); + DBG(dbgprintf("greenX: %.3f greenY: %.3f\n", + (double)disp->greenx,(double)disp->greeny)); + DBG(dbgprintf("blueX: %.3f blueY: %.3f ", + (double)disp->bluex,(double)disp->bluey)); + DBG(dbgprintf("whiteX: %.3f whiteY: %.3f\n", + (double)disp->whitex,(double)disp->whitey)); +} + +static void +print_established_timings(RHDPtr rhdPtr, struct established_timings *t) +{ + unsigned char c; + + if (t->t1 || t->t2 || t->t_manu) + DBG(dbgprintf("Supported VESA Video Modes:\n")); + c=t->t1; + if (c&0x80) DBG(dbgprintf("720x400@70Hz\n")); + if (c&0x40) DBG(dbgprintf("720x400@88Hz\n")); + if (c&0x20) DBG(dbgprintf("640x480@60Hz\n")); + if (c&0x10) DBG(dbgprintf("640x480@67Hz\n")); + if (c&0x08) DBG(dbgprintf("640x480@72Hz\n")); + if (c&0x04) DBG(dbgprintf("640x480@75Hz\n")); + if (c&0x02) DBG(dbgprintf("800x600@56Hz\n")); + if (c&0x01) DBG(dbgprintf("800x600@60Hz\n")); + c=t->t2; + if (c&0x80) DBG(dbgprintf("800x600@72Hz\n")); + if (c&0x40) DBG(dbgprintf("800x600@75Hz\n")); + if (c&0x20) DBG(dbgprintf("832x624@75Hz\n")); + if (c&0x10) DBG(dbgprintf("1024x768@87Hz (interlaced)\n")); + if (c&0x08) DBG(dbgprintf("1024x768@60Hz\n")); + if (c&0x04) DBG(dbgprintf("1024x768@70Hz\n")); + if (c&0x02) DBG(dbgprintf("1024x768@75Hz\n")); + if (c&0x01) DBG(dbgprintf("1280x1024@75Hz\n")); + c=t->t_manu; + if (c&0x80) DBG(dbgprintf("1152x870@75Hz\n")); + DBG(dbgprintf("Manufacturer's mask: %X\n",c&0x7F)); +} + +static void +print_std_timings(RHDPtr rhdPtr, struct std_timings *t) +{ + int i; + char done = 0; + for (i=0;i 256) /* sanity check */ + { + if (!done) + { + DBG(dbgprintf("Supported Future Video Modes:\n")); + done = 1; + } + DBG(dbgprintf("#%d: hsize: %i vsize %i refresh: %i vid: %i\n", + i, t[i].hsize, t[i].vsize, t[i].refresh, t[i].id)); + } + } +} + +static void +print_detailed_monitor_section(RHDPtr rhdPtr, + struct detailed_monitor_section *m) +{ + int i,j; + + for (i=0;i 0) + DBG(dbgprintf(" 2nd GTF parameters: f: %i kHz " + "c: %i m: %i k %i j %i\n", + m[i].section.ranges.gtf_2nd_f, + m[i].section.ranges.gtf_2nd_c, + m[i].section.ranges.gtf_2nd_m, + m[i].section.ranges.gtf_2nd_k, + m[i].section.ranges.gtf_2nd_j)); + break; + case DS_STD_TIMINGS: + for (j = 0; j<5; j++) + DBG(dbgprintf("#%i: hsize: %i vsize %i refresh: %i " + "vid: %i\n",i,m[i].section.std_t[i].hsize, + m[i].section.std_t[j].vsize,m[i].section.std_t[j].refresh, + m[i].section.std_t[j].id)); + break; + case DS_WHITE_P: + for (j = 0; j<2; j++) + if (m[i].section.wp[j].index != 0) + DBG(dbgprintf("White point %i: whiteX: %f, whiteY: %f; gamma: %f\n", + m[i].section.wp[j].index,(double)m[i].section.wp[j].white_x, + (double)m[i].section.wp[j].white_y, + (double)m[i].section.wp[j].white_gamma)); + break; + case DS_DUMMY: + default: + break; + } + } +} + +static void +print_detailed_timings(RHDPtr rhdPtr, struct detailed_timings *t) +{ + + if (t->clock > 15000000) /* sanity check */ + { + DBG(dbgprintf("Supported additional Video Mode:\n")); + DBG(dbgprintf("clock: %.1f MHz ",(double)t->clock/1000000.0)); + DBG(dbgprintf("Image Size: %i x %i mm\n",t->h_size,t->v_size)); + DBG(dbgprintf("h_active: %i h_sync: %i h_sync_end %i h_blank_end %i ", + t->h_active, t->h_sync_off + t->h_active, + t->h_sync_off + t->h_sync_width + t->h_active, + t->h_active + t->h_blanking)); + DBG(dbgprintf("h_border: %i\n",t->h_border)); + DBG(dbgprintf("v_active: %i v_sync: %i v_sync_end %i v_blanking: %i ", + t->v_active, t->v_sync_off + t->v_active, + t->v_sync_off + t->v_sync_width + t->v_active, + t->v_active + t->v_blanking)); + DBG(dbgprintf("v_border: %i\n",t->v_border)); + if (IS_STEREO(t->stereo)) + { + DBG(dbgprintf("Stereo: ")); + if (IS_RIGHT_STEREO(t->stereo)) + { + if (!t->stereo_1) + DBG(dbgprintf("right channel on sync\n")); + else + DBG(dbgprintf("left channel on sync\n")); + } + else + if (IS_LEFT_STEREO(t->stereo)) + { + if (!t->stereo_1) + DBG(dbgprintf("right channel on even line\n")); + else + DBG(dbgprintf("left channel on evel line\n")); + } + if (IS_4WAY_STEREO(t->stereo)) + { + if (!t->stereo_1) + DBG(dbgprintf("4-way interleaved\n")); + else + DBG(dbgprintf("side-by-side interleaved")); + } + } + } +} + +static void +print_number_sections(RHDPtr rhdPtr, int num) +{ + if (num) + DBG(dbgprintf("Number of EDID sections to follow: %i\n",num)); +} + + + +static void get_vendor_section(Uchar*, struct vendor *); +static void get_version_section(Uchar*, struct edid_version *); +static void get_display_section(Uchar*, struct disp_features *, + struct edid_version *); +static void get_established_timing_section(Uchar*, struct established_timings *); +static void get_std_timing_section(Uchar*, struct std_timings *, + struct edid_version *); +static void get_dt_md_section(Uchar *, struct edid_version *, + struct detailed_monitor_section *det_mon); +static void copy_string(Uchar *, Uchar *); +static void get_dst_timing_section(Uchar *, struct std_timings *, + struct edid_version *); +static void get_monitor_ranges(Uchar *, struct monitor_ranges *); +static void get_whitepoint_section(Uchar *, struct whitePoints *); +static void get_detailed_timing_section(Uchar*, struct detailed_timings *); +static Bool validate_version(RHDPtr rhdPtr, struct edid_version *); + + +xf86MonPtr +xf86InterpretEDID(int scrnIndex, Uchar *block) +{ + xf86MonPtr m; + RHDPtr rhdPtr = (RHDPtr)scrnIndex; + + if (!block) return NULL; + if (! (m = calloc(sizeof(xf86Monitor),1))) return NULL; + m->rhdPtr = rhdPtr; + m->rawData = block; + + get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor); + get_version_section(SECTION(VERSION_SECTION,block),&m->ver); + if (!validate_version(rhdPtr, &m->ver)) goto error; + get_display_section(SECTION(DISPLAY_SECTION,block),&m->features, + &m->ver); + get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block), + &m->timings1); + get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2, + &m->ver); + get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon); + m->no_sections = (int)*(char *)SECTION(NO_EDID,block); + + return (m); + + error: + free(m); + return NULL; +} + +static void +get_vendor_section(Uchar *c, struct vendor *r) +{ + r->name[0] = L1; + r->name[1] = L2; + r->name[2] = L3; + r->name[3] = '\0'; + + r->prod_id = PROD_ID; + r->serial = SERIAL_NO; + r->week = WEEK; + r->year = YEAR; +} + +static void +get_version_section(Uchar *c, struct edid_version *r) +{ + r->version = VERSION; + r->revision = REVISION; +} + +static void +get_display_section(Uchar *c, struct disp_features *r, + struct edid_version *v) +{ + r->input_type = INPUT_TYPE; + if (!DIGITAL(r->input_type)) + { + r->input_voltage = INPUT_VOLTAGE; + r->input_setup = SETUP; + r->input_sync = SYNC; + } + else + if (v->version > 1 || v->revision > 2) + r->input_dfp = DFP; + r->hsize = HSIZE_MAX; + r->vsize = VSIZE_MAX; + r->gamma = GAMMA; + r->dpms = DPMS; + r->display_type = DISPLAY_TYPE; + r->msc = MSC; + r->redx = REDX; + r->redy = REDY; + r->greenx = GREENX; + r->greeny = GREENY; + r->bluex = BLUEX; + r->bluey = BLUEY; + r->whitex = WHITEX; + r->whitey = WHITEY; +} + +static void +get_established_timing_section(Uchar *c, struct established_timings *r) +{ + r->t1 = T1; + r->t2 = T2; + r->t_manu = T_MANU; +} + +static void +get_std_timing_section(Uchar *c, struct std_timings *r, + struct edid_version *v) +{ + int i; + + for (i=0;iversion == 1 && ver->revision >= 1 && IS_MONITOR_DESC) { + + switch (MONITOR_DESC_TYPE) { + case SERIAL_NUMBER: + det_mon[i].type = DS_SERIAL; + copy_string(c,det_mon[i].section.serial); + break; + case ASCII_STR: + det_mon[i].type = DS_ASCII_STR; + copy_string(c,det_mon[i].section.ascii_data); + break; + case MONITOR_RANGES: + det_mon[i].type = DS_RANGES; + get_monitor_ranges(c,&det_mon[i].section.ranges); + break; + case MONITOR_NAME: + det_mon[i].type = DS_NAME; + copy_string(c,det_mon[i].section.name); + break; + case ADD_COLOR_POINT: + det_mon[i].type = DS_WHITE_P; + get_whitepoint_section(c,det_mon[i].section.wp); + break; + case ADD_STD_TIMINGS: + det_mon[i].type = DS_STD_TIMINGS; + get_dst_timing_section(c,det_mon[i].section.std_t, ver); + break; + case ADD_DUMMY: + det_mon[i].type = DS_DUMMY; + break; + } + } else { + det_mon[i].type = DT; + get_detailed_timing_section(c,&det_mon[i].section.d_timings); + } + NEXT_DT_MD_SECTION; + } +} + +static void +copy_string(Uchar *c, Uchar *s) +{ + int i; + c = c + 5; + for (i = 0; (i < 13 && *c != 0x0A); i++) + *(s++) = *(c++); + *s = 0; + while (i-- && (*--s == 0x20)) *s = 0; +} + +static void +get_dst_timing_section(Uchar *c, struct std_timings *t, + struct edid_version *v) +{ + int j; + c = c + 5; + for (j = 0; j < 5; j++) { + t[j].hsize = HSIZE1; + VSIZE1(t[j].vsize); + t[j].refresh = REFRESH_R; + t[j].id = STD_TIMING_ID; + NEXT_STD_TIMING; + } +} + +static void +get_monitor_ranges(Uchar *c, struct monitor_ranges *r) +{ + r->min_v = MIN_V; + r->max_v = MAX_V; + r->min_h = MIN_H; + r->max_h = MAX_H; + r->max_clock = 0; + if(MAX_CLOCK != 0xff) /* is specified? */ + r->max_clock = MAX_CLOCK * 10; + if (HAVE_2ND_GTF) { + r->gtf_2nd_f = F_2ND_GTF; + r->gtf_2nd_c = C_2ND_GTF; + r->gtf_2nd_m = M_2ND_GTF; + r->gtf_2nd_k = K_2ND_GTF; + r->gtf_2nd_j = J_2ND_GTF; + } else + r->gtf_2nd_f = 0; +} + +static void +get_whitepoint_section(Uchar *c, struct whitePoints *wp) +{ + wp[1].white_x = WHITEX1; + wp[1].white_y = WHITEY1; + wp[2].white_x = WHITEX2; + wp[2].white_y = WHITEY2; + wp[1].index = WHITE_INDEX1; + wp[2].index = WHITE_INDEX2; + wp[1].white_gamma = WHITE_GAMMA1; + wp[2].white_gamma = WHITE_GAMMA2; +} + +static void +get_detailed_timing_section(Uchar *c, struct detailed_timings *r) +{ + r->clock = PIXEL_CLOCK; + r->h_active = H_ACTIVE; + r->h_blanking = H_BLANK; + r->v_active = V_ACTIVE; + r->v_blanking = V_BLANK; + r->h_sync_off = H_SYNC_OFF; + r->h_sync_width = H_SYNC_WIDTH; + r->v_sync_off = V_SYNC_OFF; + r->v_sync_width = V_SYNC_WIDTH; + r->h_size = H_SIZE; + r->v_size = V_SIZE; + r->h_border = H_BORDER; + r->v_border = V_BORDER; + r->interlaced = INTERLACED; + r->stereo = STEREO; + r->stereo_1 = STEREO1; + r->sync = SYNC_T; + r->misc = MISC; +} + + +static Bool +validate_version(RHDPtr rhdPtr, struct edid_version *r) +{ + if (r->version != 1) + return FALSE; + if (r->revision > 3) + { + DBG(dbgprintf("EDID Version 1.%d not yet supported\n",r->revision)); + return FALSE; + } + return TRUE; +} diff --git a/programs/system/drivers/rhd/rhd_monitor.h b/programs/system/drivers/rhd/rhd_monitor.h new file mode 100644 index 000000000..24d8850a1 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_monitor.h @@ -0,0 +1,62 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_MONITOR_H +#define _RHD_MONITOR_H + +struct rhdMonitor { + int scrnIndex; + + char *Name; + + int xDpi; + int yDpi; + + int numHSync; /* default: 0 */ + range HSync[MAX_HSYNC]; + int numVRefresh; /* default: 0 */ + range VRefresh[MAX_VREFRESH]; + int Bandwidth; /* default 0 */ + + Bool ReducedAllowed; + + Bool UseFixedModes; + DisplayModePtr Modes; /* default: NULL */ + DisplayModePtr NativeMode; + + xf86MonPtr EDID; +}; + + +void RHDConfigMonitorSet(RHDPtr rhdPtr, Bool UseConfig); + +#ifdef _RHD_CONNECTOR_H +struct rhdMonitor *RHDMonitorInit(struct rhdConnector *Connector); +#endif + +void RHDMonitorDestroy(struct rhdMonitor *Monitor); +void RHDMonitorPrint(struct rhdMonitor *Monitor); + +#endif /* _RHD_MONITOR_H */ diff --git a/programs/system/drivers/rhd/rhd_output.c b/programs/system/drivers/rhd/rhd_output.c new file mode 100644 index 000000000..1f465f7ed --- /dev/null +++ b/programs/system/drivers/rhd/rhd_output.c @@ -0,0 +1,207 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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 + +#include "xf86.h" + +#include "rhd.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_crtc.h" + +char *rhdPowerString[] = { + "POWER_ON", + "POWER_RESET", + "POWER_SHUTDOWN", + "POWER_UNKNOWN" +}; + +void +RHDOutputAdd(RHDPtr rhdPtr, struct rhdOutput *New) +{ + struct rhdOutput *Last = rhdPtr->Outputs; + + RHDFUNC(rhdPtr); + + if (!New) + return; + + if (Last) { + while (Last->Next) + Last = Last->Next; + + Last->Next = New; + } else + rhdPtr->Outputs = New; +} + +/* + * + */ +void +RHDOutputsMode(RHDPtr rhdPtr, struct rhdCrtc *Crtc, DisplayModePtr Mode) +{ + struct rhdOutput *Output = rhdPtr->Outputs; + + RHDFUNC(rhdPtr); + + while (Output) { + if (Output->Active && Output->Mode && (Output->Crtc == Crtc)) + Output->Mode(Output, Mode); + + Output = Output->Next; + } +} + +/* + * + */ +void +RHDOutputsPower(RHDPtr rhdPtr, int Power) +{ + struct rhdOutput *Output = rhdPtr->Outputs; + + RHDFUNC(rhdPtr); + + while (Output) { + if (Output->Active && Output->Power) + Output->Power(Output, Power); + + Output = Output->Next; + } +} + +/* + * + */ +void +RHDOutputsShutdownInactive(RHDPtr rhdPtr) +{ + struct rhdOutput *Output = rhdPtr->Outputs; + + RHDFUNC(rhdPtr); + + while (Output) { + if (!Output->Active && Output->Power) { + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Shutting down %s\n", Output->Name); + Output->Power(Output, RHD_POWER_SHUTDOWN); + } + + Output = Output->Next; + } +} + +/* + * + */ +void +RHDOutputsSave(RHDPtr rhdPtr) +{ + struct rhdOutput *Output = rhdPtr->Outputs; + + RHDFUNC(rhdPtr); + + while (Output) { + if (Output->Save) + Output->Save(Output); + + Output = Output->Next; + } +} + +/* + * + */ +void +RHDOutputsRestore(RHDPtr rhdPtr) +{ + struct rhdOutput *Output = rhdPtr->Outputs; + + RHDFUNC(rhdPtr); + + while (Output) { + if (Output->Restore) + Output->Restore(Output); + + Output = Output->Next; + } +} + +/* + * + */ +void +RHDOutputsDestroy(RHDPtr rhdPtr) +{ + struct rhdOutput *Output = rhdPtr->Outputs, *Next; + + RHDFUNC(rhdPtr); + + while (Output) { + Next = Output->Next; + + xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Destroying %s\n", Output->Name); + + if (Output->Destroy) + Output->Destroy(Output); + + if (Output->OutputDriverPrivate) + xfree(Output->OutputDriverPrivate); + xfree(Output); + + Output = Next; + } +} + +/* + * + */ +void +RHDOutputPrintSensedType(struct rhdOutput *Output) +{ + struct { enum rhdSensedOutput type; char *name; } + list[] = { { RHD_SENSED_NONE, "none" }, + { RHD_SENSED_VGA, "VGA" }, + { RHD_SENSED_DVI, "DVI" }, + { RHD_SENSED_TV_SVIDEO, "TV_SVIDEO"}, + { RHD_SENSED_TV_COMPOSITE, "TV_COMPOSITE" }, + { RHD_SENSED_TV_COMPONENT, "TV_COMPONENT" }, + { 0, NULL } + }; + int i = 0; + + while (list[i].name) { + if (list[i].type == Output->SensedType) { + xf86DrvMsgVerb(Output->scrnIndex, X_INFO, 3, + "%s: Sensed Output: %s\n",Output->Name, + list[i].name); + return; + } + i++; + } +} diff --git a/programs/system/drivers/rhd/rhd_output.h b/programs/system/drivers/rhd/rhd_output.h new file mode 100644 index 000000000..f8b9c54dd --- /dev/null +++ b/programs/system/drivers/rhd/rhd_output.h @@ -0,0 +1,127 @@ +/* + * Copyright 2004-2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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. + */ + +#ifndef _RHD_OUTPUT_H +#define _RHD_OUTPUT_H + +/* Also needed for connector -> output mapping */ +typedef enum rhdOutputType { + RHD_OUTPUT_NONE = 0, + RHD_OUTPUT_DAC_EXTERNAL = RHD_OUTPUT_NONE, + RHD_OUTPUT_DACA, + RHD_OUTPUT_DACB, + RHD_OUTPUT_TMDSA, + RHD_OUTPUT_LVTMA, + RHD_OUTPUT_DVO, + RHD_OUTPUT_KLDSKP_LVTMA, + RHD_OUTPUT_UNIPHYA, + RHD_OUTPUT_UNIPHYB, + RHD_OUTPUT_UNIPHYC, + RHD_OUTPUT_UNIPHYD, + RHD_OUTPUT_UNIPHYE, + RHD_OUTPUT_UNIPHYF, + RHD_OUTPUT_TMDSB = RHD_OUTPUT_NONE, + RHD_OUTPUT_LVDS = RHD_OUTPUT_NONE, + RHD_OUTPUT_LVTMB = RHD_OUTPUT_NONE +} rhdOutputType; + +typedef enum rhdSensedOutput { + RHD_SENSED_NONE = 0, + RHD_SENSED_VGA, + RHD_SENSED_DVI, + RHD_SENSED_TV_SVIDEO, + RHD_SENSED_TV_COMPOSITE, + RHD_SENSED_TV_COMPONENT +} rhdSensedOutput; + +enum rhdOutputProperty { + RHD_OUTPUT_BACKLIGHT, + RHD_OUTPUT_COHERENT +}; + +enum rhdOutputAllocation { + RHD_OUTPUT_ALLOC, + RHD_OUTPUT_FREE +}; + +char *rhdPowerString[4]; + +/* + * + * This structure should deal with everything output related. + * + */ +struct rhdOutput { + struct rhdOutput *Next; + + int scrnIndex; + RHDPtr rhdPtr; + + char *Name; + enum rhdOutputType Id; + + Bool Active; + + struct rhdCrtc *Crtc; + struct rhdConnector *Connector; + + enum rhdSensedOutput SensedType; + + enum rhdSensedOutput (*Sense) (struct rhdOutput *Output, + struct rhdConnector *Connector); + ModeStatus (*ModeValid) (struct rhdOutput *Output, DisplayModePtr Mode); + void (*Mode) (struct rhdOutput *Output, DisplayModePtr Mode); + void (*Power) (struct rhdOutput *Output, int Power); + void (*Save) (struct rhdOutput *Output); + void (*Restore) (struct rhdOutput *Output); + void (*Destroy) (struct rhdOutput *Output); + Bool (*Property) (struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val); + Bool (*AllocFree) (struct rhdOutput *Output, enum rhdOutputAllocation Alloc); + /* Driver Private data */ + rhdOutputDriverPrivate *OutputDriverPrivate; + /* Output Private data */ + void *Private; +}; + +void RHDOutputAdd(RHDPtr rhdPtr, struct rhdOutput *Output); +void RHDOutputsMode(RHDPtr rhdPtr, struct rhdCrtc *Crtc, DisplayModePtr Mode); +void RHDOutputsPower(RHDPtr rhdPtr, int Power); +void RHDOutputsShutdownInactive(RHDPtr rhdPtr); +void RHDOutputsSave(RHDPtr rhdPtr); +void RHDOutputsRestore(RHDPtr rhdPtr); +void RHDOutputsDestroy(RHDPtr rhdPtr); +void RHDOutputPrintSensedType(struct rhdOutput *Output); + +/* output local functions. */ +struct rhdOutput *RHDDACAInit(RHDPtr rhdPtr); +struct rhdOutput *RHDDACBInit(RHDPtr rhdPtr); +struct rhdOutput *RHDTMDSAInit(RHDPtr rhdPtr); +struct rhdOutput *RHDLVTMAInit(RHDPtr rhdPtr, CARD8 Type); +struct rhdOutput *RHDDIGInit(RHDPtr rhdPtr, enum rhdOutputType outputType, CARD8 ConnectorType); +struct rhdOutput *RHDDDIAInit(RHDPtr rhdPtr); +struct rhdOutput *RHDAtomOutputInit(RHDPtr rhdPtr, rhdConnectorType ConnectorType, rhdOutputType OutputType); + +#endif /* _RHD_OUTPUT_H */ diff --git a/programs/system/drivers/rhd/rhd_pll.c b/programs/system/drivers/rhd/rhd_pll.c new file mode 100644 index 000000000..5d9207bae --- /dev/null +++ b/programs/system/drivers/rhd/rhd_pll.c @@ -0,0 +1,1547 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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 + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif + +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_pll.h" +#include "rhd_regs.h" +#include "rhd_atombios.h" + + +#define PLL_CALIBRATE_WAIT 0x100000 + +/* + * Get gain, charge pump, loop filter and current bias. + * For R500, this is done in atombios by ASIC_RegistersInit + * Some data table in atom should've provided this information. + */ + +struct PLL_Control { + CARD16 FeedbackDivider; /* 0xFFFF/-1 is the endmarker here */ + CARD32 Control; +}; + +/* From hardcoded values. */ +static struct PLL_Control RV610PLLControl[] = +{ + { 0x0049, 0x159F8704 }, + { 0x006C, 0x159B8704 }, + { 0xFFFF, 0x159EC704 } +}; + +/* Some tables are provided by atombios, + * it's just that they are hidden away deliberately and not exposed */ +static struct PLL_Control RV670PLLControl[] = +{ + { 0x004A, 0x159FC704 }, + { 0x0067, 0x159BC704 }, + { 0x00C4, 0x159EC704 }, + { 0x00F4, 0x1593A704 }, + { 0x0136, 0x1595A704 }, + { 0x01A4, 0x1596A704 }, + { 0x022C, 0x159CE504 }, + { 0xFFFF, 0x1591E404 } +}; + +/* + * Used by PLLElectrical() for r5xx+ and by rv620/35 code. + */ +static CARD32 +PLLControlTableRetrieve(struct PLL_Control *Table, CARD16 FeedbackDivider) +{ + int i; + + for (i = 0; Table[i].FeedbackDivider < 0xFFFF ; i++) + if (Table[i].FeedbackDivider >= FeedbackDivider) + break; + + return Table[i].Control; +} + +/* + * Not used by rv620/35 code. + */ +static CARD32 +PLLElectrical(RHDPtr rhdPtr, CARD16 FeedbackDivider) +{ + switch (rhdPtr->ChipSet) { + case RHD_RV515: + if (rhdPtr->PciDeviceID == 0x7146) + return 0x00120704; + else + return 0; + case RHD_RV535: + if (rhdPtr->PciDeviceID == 0x71C1) + return 0x00230704; + else + return 0; + case RHD_RS600: + case RHD_RS690: + case RHD_RS740: + /* depending on MiscInfo also 0x00120004 */ + return 0x00120704; + case RHD_R600: + return 0x01130704; + case RHD_RV610: + case RHD_RV630: + case RHD_M72: + case RHD_M74: + case RHD_M76: + return PLLControlTableRetrieve(RV610PLLControl, FeedbackDivider); + case RHD_RV670: + case RHD_R680: + return PLLControlTableRetrieve(RV670PLLControl, FeedbackDivider); + default: + return 0; + } +} + +/* + * All R500s, RS6x0, R600, RV610 and RV630. + */ + +/* + * + */ +static void +PLL1Calibrate(struct rhdPLL *PLL) +{ + int i; + + RHDFUNC(PLL); + + RHDRegMask(PLL, P1PLL_CNTL, 1, 0x01); /* Reset */ + usleep(2); + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x01); /* Set */ + for (i = 0; i < PLL_CALIBRATE_WAIT; i++) + if (((RHDRegRead(PLL, P1PLL_CNTL) >> 20) & 0x03) == 0x03) + break; + + if (i == PLL_CALIBRATE_WAIT) { + if (RHDRegRead(PLL, P1PLL_CNTL) & 0x00100000) /* Calibration done? */ + xf86DrvMsg(PLL->scrnIndex, X_ERROR, + "%s: Calibration failed.\n", __func__); + if (RHDRegRead(PLL, P1PLL_CNTL) & 0x00200000) /* PLL locked? */ + xf86DrvMsg(PLL->scrnIndex, X_ERROR, + "%s: Locking failed.\n", __func__); + } else + RHDDebug(PLL->scrnIndex, "%s: lock in %d loops\n", __func__, i); +} + +/* + * + */ +static void +PLL2Calibrate(struct rhdPLL *PLL) +{ + int i; + + RHDFUNC(PLL); + + RHDRegMask(PLL, P2PLL_CNTL, 1, 0x01); /* Reset */ + usleep(2); + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x01); /* Set */ + + for (i = 0; i < PLL_CALIBRATE_WAIT; i++) + if (((RHDRegRead(PLL, P2PLL_CNTL) >> 20) & 0x03) == 0x03) + break; + + if (i == PLL_CALIBRATE_WAIT) { + if (RHDRegRead(PLL, P2PLL_CNTL) & 0x00100000) /* Calibration done? */ + xf86DrvMsg(PLL->scrnIndex, X_ERROR, + "%s: Calibration failed.\n", __func__); + if (RHDRegRead(PLL, P2PLL_CNTL) & 0x00200000) /* PLL locked? */ + xf86DrvMsg(PLL->scrnIndex, X_ERROR, + "%s: Locking failed.\n", __func__); + } else + RHDDebug(PLL->scrnIndex, "%s: lock in %d loops\n", __func__, i); +} + +/* + * + */ +static void +R500PLL1Power(struct rhdPLL *PLL, int Power) +{ + RHDFUNC(PLL); + + switch (Power) { + case RHD_POWER_ON: + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + PLL1Calibrate(PLL); + + return; + case RHD_POWER_RESET: + RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P1PLL_CNTL, 0x02, 0x02); /* Power down */ + usleep(200); + + return; + } +} + +/* + * + */ +static void +R500PLL2Power(struct rhdPLL *PLL, int Power) +{ + RHDFUNC(PLL); + + switch (Power) { + case RHD_POWER_ON: + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + PLL2Calibrate(PLL); + + return; + case RHD_POWER_RESET: + RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + return; + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P2PLL_CNTL, 0x02, 0x02); /* Power down */ + usleep(200); + + return; + } +} + +/* + * + */ +static void +R500PLL1SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv, + CARD32 Control) +{ + RHDFUNC(PLL); + RHDRegWrite(PLL, EXT1_PPLL_REF_DIV_SRC, 0x01); /* XTAL */ + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00); /* source = reference */ + + RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 0x01); /* lock */ + + RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, RefDiv); + RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, FBDiv); + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV, PostDiv); + RHDRegWrite(PLL, EXT1_PPLL_CNTL, Control); + + RHDRegMask(PLL, EXT1_PPLL_UPDATE_CNTL, 0x00010000, 0x00010000); /* no autoreset */ + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x04); /* don't bypass calibration */ + + /* We need to reset the anti glitch logic */ + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00000002); /* power up */ + + /* reset anti glitch logic */ + RHDRegMask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000); + usleep(2); + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00002000); + + /* powerdown and reset */ + RHDRegMask(PLL, P1PLL_CNTL, 0x00000003, 0x00000003); + usleep(2); + + RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 0); /* unlock */ + RHDRegMask(PLL, EXT1_PPLL_UPDATE_CNTL, 0, 0x01); /* we're done updating! */ + + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + PLL1Calibrate(PLL); + + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x01); /* source is PLL itself */ +} + +/* + * + */ +static void +R500PLL2SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv, + CARD32 Control) +{ + RHDRegWrite(PLL, EXT2_PPLL_REF_DIV_SRC, 0x01); /* XTAL */ + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x00); /* source = reference */ + + RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 0x01); /* lock */ + + RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, RefDiv); + RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, FBDiv); + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV, PostDiv); + RHDRegWrite(PLL, EXT2_PPLL_CNTL, Control); + + RHDRegMask(PLL, EXT2_PPLL_UPDATE_CNTL, 0x00010000, 0x00010000); /* no autoreset */ + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x04); /* don't bypass calibration */ + + /* We need to reset the anti glitch logic */ + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00000002); /* power up */ + + /* reset anti glitch logic */ + RHDRegMask(PLL, P2PLL_CNTL, 0x00002000, 0x00002000); + usleep(2); + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00002000); + + /* powerdown and reset */ + RHDRegMask(PLL, P2PLL_CNTL, 0x00000003, 0x00000003); + usleep(2); + + RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 0); /* unlock */ + RHDRegMask(PLL, EXT2_PPLL_UPDATE_CNTL, 0, 0x01); /* we're done updating! */ + + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + PLL2Calibrate(PLL); + + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x01); /* source is PLL itself */ +} + +/* + * The CRTC ownership of each PLL is multiplexed on the PLL blocks, and the + * ownership can only be switched when the currently referenced PLL is active. + * This makes handling a slight bit more complex. + */ +static void +R500PLLCRTCGrab(struct rhdPLL *PLL, Bool Crtc2) +{ + CARD32 Stored; + Bool PLL2IsCurrent; + + if (!Crtc2) { + PLL2IsCurrent = RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000; + + if (PLL->Id == PLL_ID_PLL1) + RHDRegMask(PLL, PCLK_CRTC1_CNTL, 0, 0x00010000); + else + RHDRegMask(PLL, PCLK_CRTC1_CNTL, 0x00010000, 0x00010000); + } else { + PLL2IsCurrent = RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000; + + if (PLL->Id == PLL_ID_PLL1) + RHDRegMask(PLL, PCLK_CRTC2_CNTL, 0, 0x00010000); + else + RHDRegMask(PLL, PCLK_CRTC2_CNTL, 0x00010000, 0x00010000); + } + + /* if the current pll is not active, then poke it just enough to flip + * owners */ + if (!PLL2IsCurrent) { + Stored = RHDRegRead(PLL, P1PLL_CNTL); + + if (Stored & 0x03) { + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x03); + usleep(10); + RHDRegMask(PLL, P1PLL_CNTL, Stored, 0x03); + } + } else { + Stored = RHDRegRead(PLL, P2PLL_CNTL); + + if (Stored & 0x03) { + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x03); + usleep(10); + RHDRegMask(PLL, P2PLL_CNTL, Stored, 0x03); + } + } +} + +/* + * + */ +static void +R500PLL1Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, + CARD16 FeedbackDivider, CARD8 PostDivider) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + CARD32 RefDiv, FBDiv, PostDiv, Control; + + RHDFUNC(PLL); + + RefDiv = ReferenceDivider; + + FBDiv = FeedbackDivider << 16; + + if (rhdPtr->ChipSet > RHD_R600) { /* set up Feedbackdivider slip */ + if (FeedbackDivider <= 0x24) + FBDiv |= 0x00000030; + else if (FeedbackDivider <= 0x3F) + FBDiv |= 0x00000020; + } else if (rhdPtr->ChipSet >= RHD_RS600) /* RS600, RS690, R600 */ + FBDiv |= 0x00000030; + else + FBDiv |= RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & 0x00000030; + + PostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & ~0x0000007F; + PostDiv |= PostDivider & 0x0000007F; + + Control = PLLElectrical(rhdPtr, FeedbackDivider); + if (!Control) + Control = RHDRegRead(PLL, EXT1_PPLL_CNTL); + + /* Disable Spread Spectrum */ + RHDRegMask(PLL, P1PLL_INT_SS_CNTL, 0, 0x00000001); + + R500PLL1SetLow(PLL, RefDiv, FBDiv, PostDiv, Control); + + if (rhdPtr->Crtc[0]->PLL == PLL) + R500PLLCRTCGrab(PLL, FALSE); + if (rhdPtr->Crtc[1]->PLL == PLL) + R500PLLCRTCGrab(PLL, TRUE); +} + +/* + * + */ +static void +R500PLL2Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, + CARD16 FeedbackDivider, CARD8 PostDivider) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + CARD32 RefDiv, FBDiv, PostDiv, Control; + + RHDFUNC(PLL); + + RefDiv = ReferenceDivider; + + FBDiv = FeedbackDivider << 16; + + if (rhdPtr->ChipSet > RHD_R600) { /* set up Feedbackdivider slip */ + if (FeedbackDivider <= 0x24) + FBDiv |= 0x00000030; + else if (FeedbackDivider <= 0x3F) + FBDiv |= 0x00000020; + } else if (rhdPtr->ChipSet >= RHD_RS600) /* RS600, RS690, R600 */ + FBDiv |= 0x00000030; + else + FBDiv |= RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & 0x00000030; + + PostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & ~0x0000007F; + PostDiv |= PostDivider & 0x0000007F; + + Control = PLLElectrical(rhdPtr, FeedbackDivider); + if (!Control) + Control = RHDRegRead(PLL, EXT2_PPLL_CNTL); + + /* Disable Spread Spectrum */ + RHDRegMask(PLL, P2PLL_INT_SS_CNTL, 0, 0x00000001); + + R500PLL2SetLow(PLL, RefDiv, FBDiv, PostDiv, Control); + + if (rhdPtr->Crtc[0]->PLL == PLL) + R500PLLCRTCGrab(PLL, FALSE); + if (rhdPtr->Crtc[1]->PLL == PLL) + R500PLLCRTCGrab(PLL, TRUE); +} + +/* + * + */ +static void +R500PLL1Save(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + PLL->StoreActive = !(RHDRegRead(PLL, P1PLL_CNTL) & 0x03); + PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV); + PLL->StoreFBDiv = RHDRegRead(PLL, EXT1_PPLL_FB_DIV); + PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV); + PLL->StoreControl = RHDRegRead(PLL, EXT1_PPLL_CNTL); + PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL); + PLL->StoreCrtc1Owner = !(RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000); + PLL->StoreCrtc2Owner = !(RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000); + + PLL->Stored = TRUE; +} + +/* + * + */ +static void +R500PLL2Save(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + PLL->StoreActive = !(RHDRegRead(PLL, P2PLL_CNTL) & 0x03); + PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV); + PLL->StoreFBDiv = RHDRegRead(PLL, EXT2_PPLL_FB_DIV); + PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV); + PLL->StoreControl = RHDRegRead(PLL, EXT2_PPLL_CNTL); + PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL); + PLL->StoreCrtc1Owner = RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000; + PLL->StoreCrtc2Owner = RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000; + + PLL->Stored = TRUE; +} + +/* + * + */ +static void +R500PLL1Restore(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + if (!PLL->Stored) { + xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore " + "uninitialized values.\n", __func__, PLL->Name); + return; + } + + if (PLL->StoreActive) { + R500PLL1SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv, + PLL->StorePostDiv, PLL->StoreControl); + + /* HotFix: always keep spread spectrum disabled on restore */ + if (0 && RHDPTRI(PLL)->ChipSet != RHD_M54) + RHDRegMask(PLL, P1PLL_INT_SS_CNTL, + PLL->StoreSpreadSpectrum, 0x00000001); + } else { + PLL->Power(PLL, RHD_POWER_SHUTDOWN); + + /* lame attempt at at least restoring the old values */ + RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, PLL->StoreRefDiv); + RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, PLL->StoreFBDiv); + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV, PLL->StorePostDiv); + RHDRegWrite(PLL, EXT1_PPLL_CNTL, PLL->StoreControl); + RHDRegWrite(PLL, P1PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum); + } + + if (PLL->StoreCrtc1Owner) + R500PLLCRTCGrab(PLL, FALSE); + if (PLL->StoreCrtc2Owner) + R500PLLCRTCGrab(PLL, TRUE); +} + +/* + * + */ +static void +R500PLL2Restore(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + if (!PLL->Stored) { + xf86DrvMsg(PLL->scrnIndex, X_ERROR, "%s: %s: trying to restore " + "uninitialized values.\n", __func__, PLL->Name); + return; + } + + if (PLL->StoreActive) { + R500PLL2SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv, + PLL->StorePostDiv, PLL->StoreControl); + + if (RHDPTRI(PLL)->ChipSet != RHD_M54) + RHDRegMask(PLL, P2PLL_INT_SS_CNTL, + PLL->StoreSpreadSpectrum, 0x00000001); + } else { + PLL->Power(PLL, RHD_POWER_SHUTDOWN); + + /* lame attempt at at least restoring the old values */ + RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, PLL->StoreRefDiv); + RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, PLL->StoreFBDiv); + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV, PLL->StorePostDiv); + RHDRegWrite(PLL, EXT2_PPLL_CNTL, PLL->StoreControl); + RHDRegWrite(PLL, P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum); + } + + if (PLL->StoreCrtc1Owner) + R500PLLCRTCGrab(PLL, FALSE); + if (PLL->StoreCrtc2Owner) + R500PLLCRTCGrab(PLL, TRUE); +} + +/* + * RV620 and up + */ + +/* + * + */ +#define RV620_DCCGCLK_RESET 0 +#define RV620_DCCGCLK_GRAB 1 +#define RV620_DCCGCLK_RELEASE 2 + +/* + * I still have no idea what DCCG stands for and why it needs to hook off some + * pixelclock... + */ +static void +RV620DCCGCLKSet(struct rhdPLL *PLL, int set) +{ + CARD32 tmp; + + RHDFUNC(PLL); + + switch(set) { + case RV620_DCCGCLK_GRAB: + if (PLL->Id == PLL_ID_PLL1) + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003); + else if (PLL->Id == PLL_ID_PLL2) + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003); + else + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003); + break; + case RV620_DCCGCLK_RELEASE: + tmp = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03; + + if ((PLL->Id == PLL_ID_PLL1) && (tmp == 0)) { + /* set to other PLL or external */ + tmp = RHDRegRead(PLL, P2PLL_CNTL); + if (!(tmp & 0x03) && /* powered and not in reset */ + ((tmp & 0x00300000) == 0x00300000)) /* calibrated and locked */ + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 1, 0x00000003); + else + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003); + } else if ((PLL->Id == PLL_ID_PLL2) && (tmp == 1)) { + /* set to other PLL or external */ + tmp = RHDRegRead(PLL, P1PLL_CNTL); + if (!(tmp & 0x03) && /* powered and not in reset */ + ((tmp & 0x00300000) == 0x00300000)) /* calibrated and locked */ + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0, 0x00000003); + else + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003); + + } /* no other action needs to be taken */ + break; + case RV620_DCCGCLK_RESET: + tmp = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03; + + if (((PLL->Id == PLL_ID_PLL1) && (tmp == 0)) || + ((PLL->Id == PLL_ID_PLL2) && (tmp == 1))) + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 3, 0x00000003); + break; + default: + break; + } +} + +/* + * + */ +static Bool +RV620DCCGCLKAvailable(struct rhdPLL *PLL) +{ + CARD32 Dccg = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL) & 0x03; + + RHDFUNC(PLL); + + if (Dccg & 0x02) + return TRUE; + + if ((PLL->Id == PLL_ID_PLL1) && (Dccg == 0)) + return TRUE; + if ((PLL->Id == PLL_ID_PLL2) && (Dccg == 1)) + return TRUE; + + return FALSE; +} + +/* + * + */ +static void +RV620PLL1Power(struct rhdPLL *PLL, int Power) +{ + RHDFUNC(PLL); + + switch (Power) { + case RHD_POWER_ON: + { + Bool HasDccg = RV620DCCGCLKAvailable(PLL); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET); + + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + PLL1Calibrate(PLL); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB); + return; + } + case RHD_POWER_RESET: + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE); + + RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + return; + case RHD_POWER_SHUTDOWN: + default: + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE); + + RHDRegMask(PLL, P1PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P1PLL_CNTL, 0x02, 0x02); /* Power down */ + usleep(200); + + return; + } +} + +/* + * + */ +static void +RV620PLL2Power(struct rhdPLL *PLL, int Power) +{ + RHDFUNC(PLL); + + switch (Power) { + case RHD_POWER_ON: + { + Bool HasDccg = RV620DCCGCLKAvailable(PLL); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET); + + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + PLL2Calibrate(PLL); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB); + return; + } + case RHD_POWER_RESET: + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE); + + RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x02); /* Powah */ + usleep(2); + + return; + case RHD_POWER_SHUTDOWN: + default: + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RELEASE); + + RHDRegMask(PLL, P2PLL_CNTL, 0x01, 0x01); /* Reset */ + usleep(2); + + RHDRegMask(PLL, P2PLL_CNTL, 0x02, 0x02); /* Power down */ + usleep(200); + + return; + } +} + +/* + * + */ +static void +RV620PLL1SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv, + CARD8 ScalerDiv, CARD8 SymPostDiv, CARD32 Control) +{ + RHDFUNC(PLL); + + /* switch to external */ + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0); + RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, 0x00000200, 0x00000300); + RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, 0, 0x00000100); + + RHDRegMask(PLL, P1PLL_CNTL, 0x00000001, 0x00000001); /* reset */ + usleep(2); + RHDRegMask(PLL, P1PLL_CNTL, 0x00000002, 0x00000002); /* power down */ + usleep(10); + RHDRegMask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000); /* reset anti-glitch */ + + RHDRegWrite(PLL, EXT1_PPLL_CNTL, Control); + + RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, ScalerDiv, 0x0000003F); + + RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 1); /* lock */ + + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00000001); + + RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, RefDiv); + RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, FBDiv); + RHDRegMask(PLL, EXT1_PPLL_POST_DIV, PostDiv, 0x0000007F); + RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, SymPostDiv, 0x0000007F); + + usleep(10); + RHDRegWrite(PLL, EXT1_PPLL_UPDATE_LOCK, 0); /* unlock */ + + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00000002); /* power up */ + usleep(10); + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00002000); /* undo reset anti-glitch */ + + PLL1Calibrate(PLL); + + /* switch back to the pll */ + RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, 0, 0x00000300); + RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, 0x00000100, 0x00000100); + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, 0x00000001); + + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x80000000); /* new and undocumented */ +} + +/* + * + */ +static void +RV620PLL2SetLow(struct rhdPLL *PLL, CARD32 RefDiv, CARD32 FBDiv, CARD32 PostDiv, + CARD8 ScalerDiv, CARD8 SymPostDiv, CARD32 Control) +{ + RHDFUNC(PLL); + + /* switch to external */ + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0); + RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, 0x00000200, 0x00000300); + RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, 0, 0x00000100); + + RHDRegMask(PLL, P2PLL_CNTL, 0x00000001, 0x00000001); /* reset */ + usleep(2); + RHDRegMask(PLL, P2PLL_CNTL, 0x00000002, 0x00000002); /* power down */ + usleep(10); + RHDRegMask(PLL, P2PLL_CNTL, 0x00002000, 0x00002000); /* reset anti-glitch */ + + RHDRegWrite(PLL, EXT2_PPLL_CNTL, Control); + + RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, ScalerDiv, 0x0000003F); + + RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 1); /* lock */ + + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x00000001); + + RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, RefDiv); + RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, FBDiv); + RHDRegMask(PLL, EXT2_PPLL_POST_DIV, PostDiv, 0x0000007F); + RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, SymPostDiv, 0x0000007F); + + usleep(10); + RHDRegWrite(PLL, EXT2_PPLL_UPDATE_LOCK, 0); /* unlock */ + + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00000002); /* power up */ + usleep(10); + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00002000); /* undo reset anti-glitch */ + + PLL2Calibrate(PLL); + + /* switch back to the pll */ + RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, 0, 0x00000300); + RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, 0x00000100, 0x00000100); + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, 0x00000001); + + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x80000000); /* new and undocumented */ +} + +/* + * + */ +static void +RV620PLL1Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, + CARD16 FeedbackDivider, CARD8 PostDivider) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + Bool HasDccg = RV620DCCGCLKAvailable(PLL); + CARD32 RefDiv, FBDiv, PostDiv, Control; + CARD8 ScalerDiv, SymPostDiv; + + RHDFUNC(PLL); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET); + + /* Disable Spread Spectrum */ + RHDRegMask(PLL, P1PLL_INT_SS_CNTL, 0, 0x00000001); + + RefDiv = ReferenceDivider; + + FBDiv = RHDRegRead(PLL, EXT1_PPLL_FB_DIV) & ~0x07FF003F; + FBDiv |= ((FeedbackDivider << 16) | 0x0030) & 0x07FF003F; + + PostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV) & ~0x0000007F; + PostDiv |= PostDivider & 0x0000007F; + + /* introduce flags for this, like on unichrome */ + ScalerDiv = 2; /* scaler post divider, 4 for UPDP */ + + SymPostDiv = PostDivider & 0x0000007F; + + Control = PLLControlTableRetrieve(RV670PLLControl, FeedbackDivider); + + RV620PLL1SetLow(PLL, RefDiv, FBDiv, PostDiv, ScalerDiv, SymPostDiv, + Control); + + if (rhdPtr->Crtc[0]->PLL == PLL) + R500PLLCRTCGrab(PLL, FALSE); + if (rhdPtr->Crtc[1]->PLL == PLL) + R500PLLCRTCGrab(PLL, TRUE); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB); +} + +/* + * + */ +static void +RV620PLL2Set(struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, + CARD16 FeedbackDivider, CARD8 PostDivider) +{ + RHDPtr rhdPtr = RHDPTRI(PLL); + Bool HasDccg = RV620DCCGCLKAvailable(PLL); + CARD32 RefDiv, FBDiv, PostDiv, Control; + CARD8 ScalerDiv, SymPostDiv; + + RHDFUNC(PLL); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_RESET); + + /* Disable Spread Spectrum */ + RHDRegMask(PLL, P2PLL_INT_SS_CNTL, 0, 0x00000001); + + RefDiv = ReferenceDivider; + + FBDiv = RHDRegRead(PLL, EXT2_PPLL_FB_DIV) & ~0x07FF003F; + FBDiv |= ((FeedbackDivider << 16) | 0x0030) & 0x07FF003F; + + PostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV) & ~0x0000007F; + PostDiv |= PostDivider & 0x0000007F; + + /* introduce flags for this, like on unichrome */ + ScalerDiv = 2; /* scaler post divider, 4 for UPDP */ + + SymPostDiv = PostDivider & 0x0000007F; + + Control = PLLControlTableRetrieve(RV670PLLControl, FeedbackDivider); + + RV620PLL2SetLow(PLL, RefDiv, FBDiv, PostDiv, ScalerDiv, SymPostDiv, + Control); + + if (rhdPtr->Crtc[0]->PLL == PLL) + R500PLLCRTCGrab(PLL, FALSE); + if (rhdPtr->Crtc[1]->PLL == PLL) + R500PLLCRTCGrab(PLL, TRUE); + + if (HasDccg) + RV620DCCGCLKSet(PLL, RV620_DCCGCLK_GRAB); +} + +/* + * + */ +static void +RV620PLL1Save(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + PLL->StoreActive = !(RHDRegRead(PLL, P1PLL_CNTL) & 0x03); + PLL->StoreRefDiv = RHDRegRead(PLL, EXT1_PPLL_REF_DIV); + PLL->StoreFBDiv = RHDRegRead(PLL, EXT1_PPLL_FB_DIV); + PLL->StorePostDiv = RHDRegRead(PLL, EXT1_PPLL_POST_DIV); + PLL->StorePostDivSrc = RHDRegRead(PLL, EXT1_PPLL_POST_DIV_SRC); + PLL->StoreControl = RHDRegRead(PLL, EXT1_PPLL_CNTL); + PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P1PLL_INT_SS_CNTL); + + PLL->StoreGlitchReset = RHDRegRead(PLL, P1PLL_CNTL) & 0x00002000; + + PLL->StoreScalerPostDiv = RHDRegRead(PLL, P1PLL_DISP_CLK_CNTL) & 0x003F; + PLL->StoreSymPostDiv = RHDRegRead(PLL, EXT1_SYM_PPLL_POST_DIV) & 0x007F; + + PLL->StoreCrtc1Owner = !(RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000); + PLL->StoreCrtc2Owner = !(RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000); + + PLL->StoreDCCGCLKOwner = RV620DCCGCLKAvailable(PLL); + if (PLL->StoreDCCGCLKOwner) + PLL->StoreDCCGCLK = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL); + else + PLL->StoreDCCGCLK = 0; + + PLL->Stored = TRUE; +} + +/* + * + */ +static void +RV620PLL2Save(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + PLL->StoreActive = !(RHDRegRead(PLL, P2PLL_CNTL) & 0x03); + PLL->StoreRefDiv = RHDRegRead(PLL, EXT2_PPLL_REF_DIV); + PLL->StoreFBDiv = RHDRegRead(PLL, EXT2_PPLL_FB_DIV); + PLL->StorePostDiv = RHDRegRead(PLL, EXT2_PPLL_POST_DIV); + PLL->StorePostDivSrc = RHDRegRead(PLL, EXT2_PPLL_POST_DIV_SRC); + PLL->StoreControl = RHDRegRead(PLL, EXT2_PPLL_CNTL); + PLL->StoreSpreadSpectrum = RHDRegRead(PLL, P2PLL_INT_SS_CNTL); + + PLL->StoreGlitchReset = RHDRegRead(PLL, P2PLL_CNTL) & 0x00002000; + + PLL->StoreScalerPostDiv = RHDRegRead(PLL, P2PLL_DISP_CLK_CNTL) & 0x003F; + PLL->StoreSymPostDiv = RHDRegRead(PLL, EXT2_SYM_PPLL_POST_DIV) & 0x007F; + + PLL->StoreCrtc1Owner = RHDRegRead(PLL, PCLK_CRTC1_CNTL) & 0x00010000; + PLL->StoreCrtc2Owner = RHDRegRead(PLL, PCLK_CRTC2_CNTL) & 0x00010000; + + PLL->StoreDCCGCLKOwner = RV620DCCGCLKAvailable(PLL); + if (PLL->StoreDCCGCLKOwner) + PLL->StoreDCCGCLK = RHDRegRead(PLL, DCCG_DISP_CLK_SRCSEL); + else + PLL->StoreDCCGCLK = 0; + + PLL->Stored = TRUE; +} + +/* + * Notice how we handle the DCCG ownership here. There is a difference between + * currently holding the DCCG and what was held when in the VT. With the + * solution here we no longer hardlock, but we do have the danger of keeping + * the DCCG in external mode for too long a time, if both PLL restores are + * too far apart. This is currently not an issue as VT restoration goes over + * the whole device in one go anyway; no partial restoration going on + */ +static void +RV620PLL1Restore(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + if (RV620DCCGCLKAvailable(PLL)) + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0x03, 0x00000003); + + if (PLL->StoreActive) { + RV620PLL1SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv, + PLL->StorePostDiv, PLL->StoreScalerPostDiv, + PLL->StoreSymPostDiv, PLL->StoreControl); + RHDRegMask(PLL, P1PLL_INT_SS_CNTL, + PLL->StoreSpreadSpectrum, 0x00000001); + + if (PLL->StoreDCCGCLKOwner) + RHDRegWrite(PLL, DCCG_DISP_CLK_SRCSEL, PLL->StoreDCCGCLK); + + } else { + PLL->Power(PLL, RHD_POWER_SHUTDOWN); + + /* lame attempt at at least restoring the old values */ + RHDRegWrite(PLL, EXT1_PPLL_REF_DIV, PLL->StoreRefDiv); + RHDRegWrite(PLL, EXT1_PPLL_FB_DIV, PLL->StoreFBDiv); + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV, PLL->StorePostDiv); + RHDRegWrite(PLL, EXT1_PPLL_POST_DIV_SRC, PLL->StorePostDivSrc); + RHDRegWrite(PLL, EXT1_PPLL_CNTL, PLL->StoreControl); + RHDRegMask(PLL, P1PLL_DISP_CLK_CNTL, PLL->StoreScalerPostDiv, 0x003F); + RHDRegMask(PLL, EXT1_SYM_PPLL_POST_DIV, PLL->StoreSymPostDiv, 0x007F); + RHDRegWrite(PLL, P1PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum); + + if (PLL->StoreGlitchReset) + RHDRegMask(PLL, P1PLL_CNTL, 0x00002000, 0x00002000); + else + RHDRegMask(PLL, P1PLL_CNTL, 0, 0x00002000); + } + + if (PLL->StoreCrtc1Owner) + R500PLLCRTCGrab(PLL, FALSE); + if (PLL->StoreCrtc2Owner) + R500PLLCRTCGrab(PLL, TRUE); + + if (PLL->StoreDCCGCLKOwner) + RHDRegWrite(PLL, DCCG_DISP_CLK_SRCSEL, PLL->StoreDCCGCLK); +} + +/* + * + */ +static void +RV620PLL2Restore(struct rhdPLL *PLL) +{ + RHDFUNC(PLL); + + if (RV620DCCGCLKAvailable(PLL)) + RHDRegMask(PLL, DCCG_DISP_CLK_SRCSEL, 0x03, 0x00000003); + + if (PLL->StoreActive) { + RV620PLL2SetLow(PLL, PLL->StoreRefDiv, PLL->StoreFBDiv, + PLL->StorePostDiv, PLL->StoreScalerPostDiv, + PLL->StoreSymPostDiv, PLL->StoreControl); + RHDRegMask(PLL, P2PLL_INT_SS_CNTL, + PLL->StoreSpreadSpectrum, 0x00000001); + } else { + PLL->Power(PLL, RHD_POWER_SHUTDOWN); + + /* lame attempt at at least restoring the old values */ + RHDRegWrite(PLL, EXT2_PPLL_REF_DIV, PLL->StoreRefDiv); + RHDRegWrite(PLL, EXT2_PPLL_FB_DIV, PLL->StoreFBDiv); + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV, PLL->StorePostDiv); + RHDRegWrite(PLL, EXT2_PPLL_POST_DIV_SRC, PLL->StorePostDivSrc); + RHDRegWrite(PLL, EXT2_PPLL_CNTL, PLL->StoreControl); + RHDRegMask(PLL, P2PLL_DISP_CLK_CNTL, PLL->StoreScalerPostDiv, 0x003F); + RHDRegMask(PLL, EXT2_SYM_PPLL_POST_DIV, PLL->StoreSymPostDiv, 0x007F); + RHDRegWrite(PLL, P2PLL_INT_SS_CNTL, PLL->StoreSpreadSpectrum); + + if (PLL->StoreGlitchReset) + RHDRegMask(PLL, P2PLL_CNTL, 0x00002000, 0x00002000); + else + RHDRegMask(PLL, P2PLL_CNTL, 0, 0x00002000); + } + + if (PLL->StoreCrtc1Owner) + R500PLLCRTCGrab(PLL, FALSE); + if (PLL->StoreCrtc2Owner) + R500PLLCRTCGrab(PLL, TRUE); + + if (PLL->StoreDCCGCLKOwner) + RHDRegWrite(PLL, DCCG_DISP_CLK_SRCSEL, PLL->StoreDCCGCLK); +} + +/* Some defaults for when we don't have this info */ +/* XTAL is visible on the cards */ +#define RHD_PLL_REFERENCE_DEFAULT 27000 +/* these required quite some testing */ +#define RHD_R500_PLL_INTERNAL_MIN_DEFAULT 648000 +#define RHD_RV620_PLL_INTERNAL_MIN_DEFAULT 702000 +/* Lowest value seen so far */ +#define RHD_PLL_INTERNAL_MAX_DEFAULT 1100000 +#define RHD_PLL_MIN_DEFAULT 16000 /* guess */ +#define RHD_PLL_MAX_DEFAULT 400000 /* 400Mhz modes... hrm */ + +enum pllComp { + PLL_NONE, + PLL_MIN, + PLL_MAX +}; + +/* + * + */ +#ifdef ATOM_BIOS +static Bool +getPLLValuesFromAtomBIOS(RHDPtr rhdPtr, + AtomBiosRequestID func, char *msg, CARD32 *val, enum pllComp comp) +{ + AtomBiosArgRec arg; + AtomBiosResult ret; + + if (rhdPtr->atomBIOS) { + ret = RHDAtomBiosFunc(rhdPtr->scrnIndex, rhdPtr->atomBIOS, + func, &arg); + if (ret == ATOM_SUCCESS) { + if (arg.val) { + switch (comp) { + case PLL_MAX: + if (arg.val < *val) + xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, + "Lower %s detected than the default: %lu %lu.\n" + "Please contact the authors ASAP.\n", msg, + (unsigned long)*val, (unsigned long)arg.val * 10); + break; + case PLL_MIN: + if (arg.val > *val) + xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, + "Higher %s detected than the default: %lu %lu.\n" + "Please contact the authors ASAP.\n", msg, + (unsigned long)*val, (unsigned long)arg.val * 10); + break; + default: + break; + } + *val = arg.val; + } + } + return TRUE; + } else + xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Failed to retrieve the %s" + " clock from ATOM.\n",msg); + return FALSE; +} +#endif + +/* + * + */ +void +RHDSetupLimits(RHDPtr rhdPtr, CARD32 *RefClock, + CARD32 *IntMin, CARD32 *IntMax, + CARD32 *PixMin, CARD32 *PixMax) +{ + /* Retrieve the internal PLL frequency limits*/ + *RefClock = RHD_PLL_REFERENCE_DEFAULT; + if (rhdPtr->ChipSet < RHD_RV620) + *IntMin = RHD_R500_PLL_INTERNAL_MIN_DEFAULT; + else + *IntMin = RHD_RV620_PLL_INTERNAL_MIN_DEFAULT; + + *IntMax = RHD_PLL_INTERNAL_MAX_DEFAULT; + + /* keep the defaults */ + *PixMin = RHD_PLL_MIN_DEFAULT; + *PixMax = RHD_PLL_MAX_DEFAULT; + +#ifdef ATOM_BIOS + getPLLValuesFromAtomBIOS(rhdPtr, GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, "minimum PLL output", + IntMin, PLL_MIN); + getPLLValuesFromAtomBIOS(rhdPtr, GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, "maximum PLL output", + IntMax, PLL_MAX); + getPLLValuesFromAtomBIOS(rhdPtr, GET_MAX_PIXEL_CLK, "Pixel Clock", + PixMax, PLL_MAX); + getPLLValuesFromAtomBIOS(rhdPtr, GET_REF_CLOCK, "reference clock", + RefClock, PLL_NONE); + if (*IntMax == 0) { + if (rhdPtr->ChipSet < RHD_RV620) + *IntMax = RHD_R500_PLL_INTERNAL_MIN_DEFAULT; + else + *IntMax = RHD_RV620_PLL_INTERNAL_MIN_DEFAULT; + + xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "AtomBIOS reports maximum VCO freq 0. " + "Using %lu instead\n",(unsigned long)*IntMax); + } +#endif +} + +/* + * + */ +Bool +RHDPLLsInit(RHDPtr rhdPtr) +{ + struct rhdPLL *PLL; + CARD32 RefClock, IntMin, IntMax, PixMin, PixMax; + + RHDFUNC(rhdPtr); + + if (RHDUseAtom(rhdPtr, NULL, atomUsagePLL)) + return FALSE; + + RHDSetupLimits(rhdPtr, &RefClock, &IntMin, &IntMax, &PixMin, &PixMax); + + /* PLL1 */ + PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1); + + PLL->scrnIndex = rhdPtr->scrnIndex; + PLL->Name = PLL_NAME_PLL1; + PLL->Id = PLL_ID_PLL1; + + PLL->RefClock = RefClock; + PLL->IntMin = IntMin; + PLL->IntMax = IntMax; + PLL->PixMin = PixMin; + PLL->PixMax = PixMax; + + PLL->Valid = NULL; + if (rhdPtr->ChipSet < RHD_RV620) { + PLL->Set = R500PLL1Set; + PLL->Power = R500PLL1Power; + PLL->Save = R500PLL1Save; + PLL->Restore = R500PLL1Restore; + } else { + PLL->Set = RV620PLL1Set; + PLL->Power = RV620PLL1Power; + PLL->Save = RV620PLL1Save; + PLL->Restore = RV620PLL1Restore; + } + + rhdPtr->PLLs[0] = PLL; + + /* PLL2 */ + PLL = (struct rhdPLL *) xnfcalloc(sizeof(struct rhdPLL), 1); + + PLL->scrnIndex = rhdPtr->scrnIndex; + PLL->Name = PLL_NAME_PLL2; + PLL->Id = PLL_ID_PLL2; + + PLL->RefClock = RefClock; + PLL->IntMin = IntMin; + PLL->IntMax = IntMax; + PLL->PixMin = PixMin; + PLL->PixMax = PixMax; + + PLL->Valid = NULL; + if (rhdPtr->ChipSet < RHD_RV620) { + PLL->Set = R500PLL2Set; + PLL->Power = R500PLL2Power; + PLL->Save = R500PLL2Save; + PLL->Restore = R500PLL2Restore; + } else { + PLL->Set = RV620PLL2Set; + PLL->Power = RV620PLL2Power; + PLL->Save = RV620PLL2Save; + PLL->Restore = RV620PLL2Restore; + } + + rhdPtr->PLLs[1] = PLL; + + return TRUE; +} + +/* + * + */ +ModeStatus +RHDPLLValid(struct rhdPLL *PLL, CARD32 Clock) +{ + RHDFUNC(PLL); + + if (Clock < PLL->PixMin) + return MODE_CLOCK_LOW; + if (Clock > PLL->PixMax) + return MODE_CLOCK_HIGH; + + if (PLL->Valid) + return PLL->Valid(PLL, Clock); + else + return MODE_OK; +} + + +/* + * Calculate the PLL parameters for a given dotclock. + * + * This calculation uses a linear approximation of an experimentally found + * curve that delimits reference versus feedback dividers on rv610. This curve + * can be shifted towards higher feedback divider through increasing the gain + * control, but the effect of this is rather limited. + * + * Since this upper limit still provides a wide enough range with enough + * granularity, we use it for all r5xx and r6xx devices. + */ +static Bool +PLLCalculate(struct rhdPLL *PLL, CARD32 PixelClock, + CARD16 *RefDivider, CARD16 *FBDivider, CARD8 *PostDivider) +{ +/* limited by the number of bits available */ +#define FB_DIV_LIMIT 2048 +#define REF_DIV_LIMIT 1024 +#define POST_DIV_LIMIT 128 + + CARD32 FBDiv, RefDiv, PostDiv, BestDiff = 0xFFFFFFFF; + float Ratio; + + Ratio = ((float) PixelClock) / ((float) PLL->RefClock); + + for (PostDiv = 2; PostDiv < POST_DIV_LIMIT; PostDiv++) { + CARD32 VCOOut = PixelClock * PostDiv; + + /* we are conservative and avoid the limits */ + if (VCOOut <= PLL->IntMin) + continue; + if (VCOOut >= PLL->IntMax) + break; + + for (RefDiv = 1; RefDiv <= REF_DIV_LIMIT; RefDiv++) { + CARD32 Diff; + + FBDiv = (CARD32) ((Ratio * PostDiv * RefDiv) + 0.5); + + if (FBDiv >= FB_DIV_LIMIT) + break; + if (FBDiv > (500 + (13 * RefDiv))) /* rv6x0 limit */ + break; + + Diff = abs( PixelClock - (FBDiv * PLL->RefClock) / (PostDiv * RefDiv) ); + + if (Diff < BestDiff) { + *FBDivider = FBDiv; + *RefDivider = RefDiv; + *PostDivider = PostDiv; + BestDiff = Diff; + } + + if (BestDiff == 0) + break; + } + if (BestDiff == 0) + break; + } + + if (BestDiff != 0xFFFFFFFF) { + RHDDebug(PLL->scrnIndex, "PLL Calculation: %dkHz = " + "(((%i / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n", + (int) PixelClock, (unsigned int) PLL->RefClock, *RefDivider, + *FBDivider, *PostDivider, (int) BestDiff); + return TRUE; + } else { /* Should never happen */ + xf86DrvMsg(PLL->scrnIndex, X_ERROR, + "%s: Failed to get a valid PLL setting for %dkHz\n", + __func__, (int) PixelClock); + return FALSE; + } +} + +/* + * + */ +void +RHDPLLSet(struct rhdPLL *PLL, CARD32 Clock) +{ + CARD16 RefDivider = 0, FBDivider = 0; + CARD8 PostDivider = 0; + + RHDDebug(PLL->scrnIndex, "%s: Setting %s to %dkHz\n", __func__, + PLL->Name, Clock); + + if (PLLCalculate(PLL, Clock, &RefDivider, &FBDivider, &PostDivider)) { + PLL->Set(PLL, Clock, RefDivider, FBDivider, PostDivider); + + PLL->CurrentClock = Clock; + PLL->Active = TRUE; + } else + xf86DrvMsg(PLL->scrnIndex, X_WARNING, + "%s: Not altering any settings.\n", __func__); +} + +/* + * + */ +void +RHDPLLPower(struct rhdPLL *PLL, int Power) +{ + RHDFUNC(PLL); + + if (PLL->Power) + PLL->Power(PLL, Power); +} + +/* + * + */ +void +RHDPLLsPowerAll(RHDPtr rhdPtr, int Power) +{ + struct rhdPLL *PLL; + + RHDFUNC(rhdPtr); + + PLL = rhdPtr->PLLs[0]; + if (PLL->Power) + PLL->Power(PLL, Power); + + PLL = rhdPtr->PLLs[1]; + if (PLL->Power) + PLL->Power(PLL, Power); +} + +/* + * + */ +void +RHDPLLsShutdownInactive(RHDPtr rhdPtr) +{ + struct rhdPLL *PLL; + + RHDFUNC(rhdPtr); + + PLL = rhdPtr->PLLs[0]; + if (PLL->Power && !PLL->Active) + PLL->Power(PLL, RHD_POWER_SHUTDOWN); + + PLL = rhdPtr->PLLs[1]; + if (PLL->Power && !PLL->Active) + PLL->Power(PLL, RHD_POWER_SHUTDOWN); +} + +/* + * + */ +void +RHDPLLsSave(RHDPtr rhdPtr) +{ + struct rhdPLL *PLL; + + RHDFUNC(rhdPtr); + + PLL = rhdPtr->PLLs[0]; + if (PLL->Save) + PLL->Save(PLL); + + PLL = rhdPtr->PLLs[1]; + if (PLL->Save) + PLL->Save(PLL); +} + +/* + * + */ +void +RHDPLLsRestore(RHDPtr rhdPtr) +{ + struct rhdPLL *PLL; + + RHDFUNC(rhdPtr); + + PLL = rhdPtr->PLLs[0]; + if (PLL->Restore) + PLL->Restore(PLL); + + PLL = rhdPtr->PLLs[1]; + if (PLL->Restore) + PLL->Restore(PLL); +} + +/* + * + */ +void +RHDPLLsDestroy(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + if (rhdPtr->PLLs[0] && rhdPtr->PLLs[0]->Private) + xfree(rhdPtr->PLLs[0]->Private); + xfree(rhdPtr->PLLs[0]); + if (rhdPtr->PLLs[1] && rhdPtr->PLLs[1]->Private) + xfree(rhdPtr->PLLs[1]->Private); + xfree(rhdPtr->PLLs[1]); +} diff --git a/programs/system/drivers/rhd/rhd_pll.h b/programs/system/drivers/rhd/rhd_pll.h new file mode 100644 index 000000000..8cd8f4ee5 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_pll.h @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_PLL_H +#define _RHD_PLL_H + +struct rhdPLL { + int scrnIndex; + +#define PLL_NAME_PLL1 "PLL 1" +#define PLL_NAME_PLL2 "PLL 2" + char *Name; + +/* also used as an index to rhdPtr->PLLs */ +#define PLL_ID_PLL1 0 +#define PLL_ID_PLL2 1 +#define PLL_ID_NONE -1 + int Id; + + CARD32 CurrentClock; + Bool Active; + + /* from defaults or from atom */ + CARD32 RefClock; + CARD32 IntMin; + CARD32 IntMax; + CARD32 PixMin; + CARD32 PixMax; + + ModeStatus (*Valid) (struct rhdPLL *PLL, CARD32 Clock); + void (*Set) (struct rhdPLL *PLL, int PixelClock, CARD16 ReferenceDivider, + CARD16 FeedbackDivider, CARD8 PostDivider); + void (*Power) (struct rhdPLL *PLL, int Power); + void (*Save) (struct rhdPLL *PLL); + void (*Restore) (struct rhdPLL *PLL); + + /* For save/restore: Move to a Private */ + Bool Stored; + + void *Private; + + Bool StoreActive; + Bool StoreCrtc1Owner; + Bool StoreCrtc2Owner; + CARD32 StoreRefDiv; + CARD32 StoreFBDiv; + CARD32 StorePostDiv; + CARD32 StoreControl; + CARD32 StoreSpreadSpectrum; + + /* RV620/RV635/RS780 */ + Bool StoreDCCGCLKOwner; + CARD32 StoreDCCGCLK; + CARD8 StoreScalerPostDiv; + CARD8 StoreSymPostDiv; + CARD32 StorePostDivSrc; + Bool StoreGlitchReset; +}; + +Bool RHDPLLsInit(RHDPtr rhdPtr); +ModeStatus RHDPLLValid(struct rhdPLL *PLL, CARD32 Clock); +void RHDPLLSet(struct rhdPLL *PLL, CARD32 Clock); +void RHDPLLPower(struct rhdPLL *PLL, int Power); +void RHDPLLsPowerAll(RHDPtr rhdPtr, int Power); +void RHDPLLsShutdownInactive(RHDPtr rhdPtr); +void RHDPLLsSave(RHDPtr rhdPtr); +void RHDPLLsRestore(RHDPtr rhdPtr); +void RHDPLLsDestroy(RHDPtr rhdPtr); + +void RHDSetupLimits(RHDPtr rhdPtr, CARD32 *RefClock, + CARD32 *IntMin, CARD32 *IntMax, + CARD32 *PixMin, CARD32 *PixMax); +Bool RHDAtomPLLsInit(RHDPtr rhdPtr); + +#endif /* _RHD_PLL_H */ diff --git a/programs/system/drivers/rhd/rhd_regs.h b/programs/system/drivers/rhd/rhd_regs.h new file mode 100644 index 000000000..da6799595 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_regs.h @@ -0,0 +1,1115 @@ +/* + * Copyright 2007, 2008 Luc Verhaegen + * Copyright 2007, 2008 Matthias Hopf + * Copyright 2007, 2008 Egbert Eich + * 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. + */ +#ifndef _RHD_REGS_H +# define _RHD_REGS_H + +enum { + CLOCK_CNTL_INDEX = 0x8, /* (RW) */ + CLOCK_CNTL_DATA = 0xC, /* (RW) */ + BUS_CNTL = 0x4C, /* (RW) */ + MC_IND_INDEX = 0x70, /* (RW) */ + MC_IND_DATA = 0x74, /* (RW) */ + CONFIG_CNTL = 0xE0, + /* RS690 ?? */ + RS60_MC_NB_MC_INDEX = 0x78, + RS60_MC_NB_MC_DATA = 0x7C, + RS69_MC_INDEX = 0xE8, + RS69_MC_DATA = 0xEC, + R5XX_CONFIG_MEMSIZE = 0x00F8, + + HDP_FB_LOCATION = 0x0134, + + SEPROM_CNTL1 = 0x1C0, /* (RW) */ + + AGP_BASE = 0x0170, + + GPIOPAD_MASK = 0x198, /* (RW) */ + GPIOPAD_A = 0x19C, /* (RW) */ + GPIOPAD_EN = 0x1A0, /* (RW) */ + VIPH_CONTROL = 0xC40, /* (RW) */ + + ROM_CNTL = 0x1600, + GENERAL_PWRMGT = 0x0618, + LOW_VID_LOWER_GPIO_CNTL = 0x0724, + MEDIUM_VID_LOWER_GPIO_CNTL = 0x0720, + HIGH_VID_LOWER_GPIO_CNTL = 0x071C, + CTXSW_VID_LOWER_GPIO_CNTL = 0x0718, + LOWER_GPIO_ENABLE = 0x0710, + + /* VGA registers */ + VGA_RENDER_CONTROL = 0x0300, + VGA_MODE_CONTROL = 0x0308, + VGA_MEMORY_BASE_ADDRESS = 0x0310, + VGA_HDP_CONTROL = 0x0328, + D1VGA_CONTROL = 0x0330, + D2VGA_CONTROL = 0x0338, + + EXT1_PPLL_REF_DIV_SRC = 0x0400, + EXT1_PPLL_REF_DIV = 0x0404, + EXT1_PPLL_UPDATE_LOCK = 0x0408, + EXT1_PPLL_UPDATE_CNTL = 0x040C, + EXT2_PPLL_REF_DIV_SRC = 0x0410, + EXT2_PPLL_REF_DIV = 0x0414, + EXT2_PPLL_UPDATE_LOCK = 0x0418, + EXT2_PPLL_UPDATE_CNTL = 0x041C, + + EXT1_PPLL_FB_DIV = 0x0430, + EXT2_PPLL_FB_DIV = 0x0434, + EXT1_PPLL_POST_DIV_SRC = 0x0438, + EXT1_PPLL_POST_DIV = 0x043C, + EXT2_PPLL_POST_DIV_SRC = 0x0440, + EXT2_PPLL_POST_DIV = 0x0444, + EXT1_PPLL_CNTL = 0x0448, + EXT2_PPLL_CNTL = 0x044C, + P1PLL_CNTL = 0x0450, + P2PLL_CNTL = 0x0454, + P1PLL_INT_SS_CNTL = 0x0458, + P2PLL_INT_SS_CNTL = 0x045C, + + P1PLL_DISP_CLK_CNTL = 0x0468, /* rv620+ */ + P2PLL_DISP_CLK_CNTL = 0x046C, /* rv620+ */ + EXT1_SYM_PPLL_POST_DIV = 0x0470, /* rv620+ */ + EXT2_SYM_PPLL_POST_DIV = 0x0474, /* rv620+ */ + + PCLK_CRTC1_CNTL = 0x0480, + PCLK_CRTC2_CNTL = 0x0484, + + /* these regs were reverse enginered, + * so the chance is high that the naming is wrong + * R6xx+ ??? */ + AUDIO_PLL1_MUL = 0x0514, + AUDIO_PLL1_DIV = 0x0518, + AUDIO_PLL2_MUL = 0x0524, + AUDIO_PLL2_DIV = 0x0528, + AUDIO_CLK_SRCSEL = 0x0534, + + DCCG_DISP_CLK_SRCSEL = 0x0538, /* rv620+ */ + + SRBM_STATUS = 0x0E50, + + AGP_STATUS = 0x0F5C, + + R7XX_MC_VM_FB_LOCATION = 0x2024, + + R6XX_MC_VM_FB_LOCATION = 0x2180, + R6XX_HDP_NONSURFACE_BASE = 0x2C04, + R6XX_CONFIG_MEMSIZE = 0x5428, + R6XX_CONFIG_FB_BASE = 0x542C, /* AKA CONFIG_F0_BASE */ + /* PCI config space */ + PCI_CONFIG_SPACE_BASE = 0x5000, + PCI_CAPABILITIES_PTR = 0x5034, + + /* CRTC1 registers */ + D1CRTC_H_TOTAL = 0x6000, + D1CRTC_H_BLANK_START_END = 0x6004, + D1CRTC_H_SYNC_A = 0x6008, + D1CRTC_H_SYNC_A_CNTL = 0x600C, + D1CRTC_H_SYNC_B = 0x6010, + D1CRTC_H_SYNC_B_CNTL = 0x6014, + + D1CRTC_V_TOTAL = 0x6020, + D1CRTC_V_BLANK_START_END = 0x6024, + D1CRTC_V_SYNC_A = 0x6028, + D1CRTC_V_SYNC_A_CNTL = 0x602C, + D1CRTC_V_SYNC_B = 0x6030, + D1CRTC_V_SYNC_B_CNTL = 0x6034, + + D1CRTC_CONTROL = 0x6080, + D1CRTC_BLANK_CONTROL = 0x6084, + D1CRTC_INTERLACE_CONTROL = 0x6088, + D1CRTC_BLACK_COLOR = 0x6098, + D1CRTC_STATUS = 0x609C, + D1CRTC_COUNT_CONTROL = 0x60B4, + + /* D1GRPH registers */ + D1GRPH_ENABLE = 0x6100, + D1GRPH_CONTROL = 0x6104, + D1GRPH_LUT_SEL = 0x6108, + D1GRPH_SWAP_CNTL = 0x610C, + D1GRPH_PRIMARY_SURFACE_ADDRESS = 0x6110, + D1GRPH_SECONDARY_SURFACE_ADDRESS = 0x6118, + D1GRPH_PITCH = 0x6120, + D1GRPH_SURFACE_OFFSET_X = 0x6124, + D1GRPH_SURFACE_OFFSET_Y = 0x6128, + D1GRPH_X_START = 0x612C, + D1GRPH_Y_START = 0x6130, + D1GRPH_X_END = 0x6134, + D1GRPH_Y_END = 0x6138, + D1GRPH_UPDATE = 0x6144, + + /* LUT */ + DC_LUT_RW_SELECT = 0x6480, + DC_LUT_RW_MODE = 0x6484, + DC_LUT_RW_INDEX = 0x6488, + DC_LUT_SEQ_COLOR = 0x648C, + DC_LUT_PWL_DATA = 0x6490, + DC_LUT_30_COLOR = 0x6494, + DC_LUT_READ_PIPE_SELECT = 0x6498, + DC_LUT_WRITE_EN_MASK = 0x649C, + DC_LUT_AUTOFILL = 0x64A0, + + /* LUTA */ + DC_LUTA_CONTROL = 0x64C0, + DC_LUTA_BLACK_OFFSET_BLUE = 0x64C4, + DC_LUTA_BLACK_OFFSET_GREEN = 0x64C8, + DC_LUTA_BLACK_OFFSET_RED = 0x64CC, + DC_LUTA_WHITE_OFFSET_BLUE = 0x64D0, + DC_LUTA_WHITE_OFFSET_GREEN = 0x64D4, + DC_LUTA_WHITE_OFFSET_RED = 0x64D8, + + /* D1CUR */ + D1CUR_CONTROL = 0x6400, + D1CUR_SURFACE_ADDRESS = 0x6408, + D1CUR_SIZE = 0x6410, + D1CUR_POSITION = 0x6414, + D1CUR_HOT_SPOT = 0x6418, + D1CUR_UPDATE = 0x6424, + + /* D1MODE */ + D1MODE_DESKTOP_HEIGHT = 0x652C, + D1MODE_VIEWPORT_START = 0x6580, + D1MODE_VIEWPORT_SIZE = 0x6584, + D1MODE_EXT_OVERSCAN_LEFT_RIGHT = 0x6588, + D1MODE_EXT_OVERSCAN_TOP_BOTTOM = 0x658C, + D1MODE_DATA_FORMAT = 0x6528, + + /* D1SCL */ + D1SCL_ENABLE = 0x6590, + D1SCL_TAP_CONTROL = 0x6594, + D1MODE_CENTER = 0x659C, /* guess */ + D1SCL_HVSCALE = 0x65A4, /* guess */ + D1SCL_HFILTER = 0x65B0, /* guess */ + D1SCL_VFILTER = 0x65C0, /* guess */ + D1SCL_UPDATE = 0x65CC, + D1SCL_DITHER = 0x65D4, /* guess */ + D1SCL_FLIP_CONTROL = 0x65D8, /* guess */ + + /* CRTC2 registers */ + D2CRTC_H_TOTAL = 0x6800, + D2CRTC_H_BLANK_START_END = 0x6804, + D2CRTC_H_SYNC_A = 0x6808, + D2CRTC_H_SYNC_A_CNTL = 0x680C, + D2CRTC_H_SYNC_B = 0x6810, + D2CRTC_H_SYNC_B_CNTL = 0x6814, + + D2CRTC_V_TOTAL = 0x6820, + D2CRTC_V_BLANK_START_END = 0x6824, + D2CRTC_V_SYNC_A = 0x6828, + D2CRTC_V_SYNC_A_CNTL = 0x682C, + D2CRTC_V_SYNC_B = 0x6830, + D2CRTC_V_SYNC_B_CNTL = 0x6834, + + D2CRTC_CONTROL = 0x6880, + D2CRTC_BLANK_CONTROL = 0x6884, + D2CRTC_BLACK_COLOR = 0x6898, + D2CRTC_INTERLACE_CONTROL = 0x6888, + D2CRTC_STATUS = 0x689C, + D2CRTC_COUNT_CONTROL = 0x68B4, + + /* D2GRPH registers */ + D2GRPH_ENABLE = 0x6900, + D2GRPH_CONTROL = 0x6904, + D2GRPH_LUT_SEL = 0x6908, + D2GRPH_SWAP_CNTL = 0x690C, + D2GRPH_PRIMARY_SURFACE_ADDRESS = 0x6910, + D2GRPH_PITCH = 0x6920, + D2GRPH_SURFACE_OFFSET_X = 0x6924, + D2GRPH_SURFACE_OFFSET_Y = 0x6928, + D2GRPH_X_START = 0x692C, + D2GRPH_Y_START = 0x6930, + D2GRPH_X_END = 0x6934, + D2GRPH_Y_END = 0x6938, + + /* LUTB */ + DC_LUTB_CONTROL = 0x6CC0, + DC_LUTB_BLACK_OFFSET_BLUE = 0x6CC4, + DC_LUTB_BLACK_OFFSET_GREEN = 0x6CC8, + DC_LUTB_BLACK_OFFSET_RED = 0x6CCC, + DC_LUTB_WHITE_OFFSET_BLUE = 0x6CD0, + DC_LUTB_WHITE_OFFSET_GREEN = 0x6CD4, + DC_LUTB_WHITE_OFFSET_RED = 0x6CD8, + + /* D2MODE */ + D2MODE_DESKTOP_HEIGHT = 0x6D2C, + D2MODE_VIEWPORT_START = 0x6D80, + D2MODE_VIEWPORT_SIZE = 0x6D84, + D2MODE_EXT_OVERSCAN_LEFT_RIGHT = 0x6D88, + D2MODE_EXT_OVERSCAN_TOP_BOTTOM = 0x6D8C, + D2MODE_DATA_FORMAT = 0x6D28, + + /* D2SCL */ + D2SCL_ENABLE = 0x6D90, + D2SCL_TAP_CONTROL = 0x6D94, + D2MODE_CENTER = 0x6D9C, /* guess */ + D2SCL_HVSCALE = 0x6DA4, /* guess */ + D2SCL_HFILTER = 0x6DB0, /* guess */ + D2SCL_VFILTER = 0x6DC0, /* guess */ + D2SCL_UPDATE = 0x6DCC, + D2SCL_DITHER = 0x6DD4, /* guess */ + D2SCL_FLIP_CONTROL = 0x6DD8, /* guess */ + + /* Audio, reverse enginered */ + AUDIO_ENABLE = 0x7300, /* RW */ + AUDIO_TIMING = 0x7344, /* RW */ + /* Audio params */ + AUDIO_VENDOR_ID = 0x7380, /* RW */ + AUDIO_REVISION_ID = 0x7384, /* RW */ + AUDIO_ROOT_NODE_COUNT = 0x7388, /* RW */ + AUDIO_NID1_NODE_COUNT = 0x738c, /* RW */ + AUDIO_NID1_TYPE = 0x7390, /* RW */ + AUDIO_SUPPORTED_SIZE_RATE = 0x7394, /* RW */ + AUDIO_SUPPORTED_CODEC = 0x7398, /* RW */ + AUDIO_SUPPORTED_POWER_STATES = 0x739c, /* RW */ + AUDIO_NID2_CAPS = 0x73a0, /* RW */ + AUDIO_NID3_CAPS = 0x73a4, /* RW */ + AUDIO_NID3_PIN_CAPS = 0x73a8, /* RW */ + /* Audio conn list */ + AUDIO_CONN_LIST_LEN = 0x73ac, /* RW */ + AUDIO_CONN_LIST = 0x73b0, /* RW */ + /* Audio verbs */ + AUDIO_RATE_BPS_CHANNEL = 0x73c0, /* RO */ + AUDIO_PLAYING = 0x73c4, /* RO */ + AUDIO_IMPLEMENTATION_ID = 0x73c8, /* RW */ + AUDIO_CONFIG_DEFAULT = 0x73cc, /* RW */ + AUDIO_PIN_SENSE = 0x73d0, /* RW */ + AUDIO_PIN_WIDGET_CNTL = 0x73d4, /* RO */ + AUDIO_STATUS_BITS = 0x73d8, /* RO */ + + /* HDMI */ + HDMI_TMDS = 0x7400, + HDMI_LVTMA = 0x7700, + HDMI_DIG = 0x7800, + + /* R500 DAC A */ + DACA_ENABLE = 0x7800, + DACA_SOURCE_SELECT = 0x7804, + DACA_SYNC_TRISTATE_CONTROL = 0x7820, + DACA_SYNC_SELECT = 0x7824, + DACA_AUTODETECT_CONTROL = 0x7828, + DACA_AUTODETECT_INT_CONTROL = 0x7838, + DACA_FORCE_OUTPUT_CNTL = 0x783C, + DACA_FORCE_DATA = 0x7840, + DACA_POWERDOWN = 0x7850, + DACA_CONTROL1 = 0x7854, + DACA_CONTROL2 = 0x7858, + DACA_COMPARATOR_ENABLE = 0x785C, + DACA_COMPARATOR_OUTPUT = 0x7860, + +/* TMDSA */ + TMDSA_CNTL = 0x7880, + TMDSA_SOURCE_SELECT = 0x7884, + TMDSA_COLOR_FORMAT = 0x7888, + TMDSA_FORCE_OUTPUT_CNTL = 0x788C, + TMDSA_BIT_DEPTH_CONTROL = 0x7894, + TMDSA_DCBALANCER_CONTROL = 0x78D0, + TMDSA_DATA_SYNCHRONIZATION_R500 = 0x78D8, + TMDSA_DATA_SYNCHRONIZATION_R600 = 0x78DC, + TMDSA_TRANSMITTER_ENABLE = 0x7904, + TMDSA_LOAD_DETECT = 0x7908, + TMDSA_MACRO_CONTROL = 0x790C, /* r5x0 and r600: 3 for pll and 1 for TX */ + TMDSA_PLL_ADJUST = 0x790C, /* rv6x0: pll only */ + TMDSA_TRANSMITTER_CONTROL = 0x7910, + TMDSA_TRANSMITTER_ADJUST = 0x7920, /* rv6x0: TX part of macro control */ + + /* DAC B */ + DACB_ENABLE = 0x7A00, + DACB_SOURCE_SELECT = 0x7A04, + DACB_SYNC_TRISTATE_CONTROL = 0x7A20, + DACB_SYNC_SELECT = 0x7A24, + DACB_AUTODETECT_CONTROL = 0x7A28, + DACB_AUTODETECT_INT_CONTROL = 0x7A38, + DACB_FORCE_OUTPUT_CNTL = 0x7A3C, + DACB_FORCE_DATA = 0x7A40, + DACB_POWERDOWN = 0x7A50, + DACB_CONTROL1 = 0x7A54, + DACB_CONTROL2 = 0x7A58, + DACB_COMPARATOR_ENABLE = 0x7A5C, + DACB_COMPARATOR_OUTPUT = 0x7A60, + + /* LVTMA */ + LVTMA_CNTL = 0x7A80, + LVTMA_SOURCE_SELECT = 0x7A84, + LVTMA_COLOR_FORMAT = 0x7A88, + LVTMA_FORCE_OUTPUT_CNTL = 0x7A8C, + LVTMA_BIT_DEPTH_CONTROL = 0x7A94, + LVTMA_DCBALANCER_CONTROL = 0x7AD0, + + /* no longer shared between both r5xx and r6xx */ + LVTMA_R500_DATA_SYNCHRONIZATION = 0x7AD8, + LVTMA_R500_PWRSEQ_REF_DIV = 0x7AE4, + LVTMA_R500_PWRSEQ_DELAY1 = 0x7AE8, + LVTMA_R500_PWRSEQ_DELAY2 = 0x7AEC, + LVTMA_R500_PWRSEQ_CNTL = 0x7AF0, + LVTMA_R500_PWRSEQ_STATE = 0x7AF4, + LVTMA_R500_BL_MOD_CNTL = 0x7AF8, + LVTMA_R500_LVDS_DATA_CNTL = 0x7AFC, + LVTMA_R500_MODE = 0x7B00, + LVTMA_R500_TRANSMITTER_ENABLE = 0x7B04, + LVTMA_R500_MACRO_CONTROL = 0x7B0C, + LVTMA_R500_TRANSMITTER_CONTROL = 0x7B10, + LVTMA_R500_REG_TEST_OUTPUT = 0x7B14, + + /* R600 adds an undocumented register at 0x7AD8, + * shifting all subsequent registers by exactly one. */ + LVTMA_R600_DATA_SYNCHRONIZATION = 0x7ADC, + LVTMA_R600_PWRSEQ_REF_DIV = 0x7AE8, + LVTMA_R600_PWRSEQ_DELAY1 = 0x7AEC, + LVTMA_R600_PWRSEQ_DELAY2 = 0x7AF0, + LVTMA_R600_PWRSEQ_CNTL = 0x7AF4, + LVTMA_R600_PWRSEQ_STATE = 0x7AF8, + LVTMA_R600_BL_MOD_CNTL = 0x7AFC, + LVTMA_R600_LVDS_DATA_CNTL = 0x7B00, + LVTMA_R600_MODE = 0x7B04, + LVTMA_R600_TRANSMITTER_ENABLE = 0x7B08, + LVTMA_R600_MACRO_CONTROL = 0x7B10, + LVTMA_R600_TRANSMITTER_CONTROL = 0x7B14, + LVTMA_R600_REG_TEST_OUTPUT = 0x7B18, + + LVTMA_TRANSMITTER_ADJUST = 0x7B24, /* RV630 */ + LVTMA_PREEMPHASIS_CONTROL = 0x7B28, /* RV630 */ + + /* I2C in separate enum */ + + /* HPD */ + DC_GPIO_HPD_MASK = 0x7E90, + DC_GPIO_HPD_A = 0x7E94, + DC_GPIO_HPD_EN = 0x7E98, + DC_GPIO_HPD_Y = 0x7E9C +}; + +enum CONFIG_CNTL_BITS { + RS69_CFG_ATI_REV_ID_SHIFT = 8, + RS69_CFG_ATI_REV_ID_MASK = 0xF << RS69_CFG_ATI_REV_ID_SHIFT +}; + +enum rv620Regs { + /* DAC common */ + RV620_DAC_COMPARATOR_MISC = 0x7da4, + RV620_DAC_COMPARATOR_OUTPUT = 0x7da8, + + /* RV620 DAC A */ + RV620_DACA_ENABLE = 0x7000, + RV620_DACA_SOURCE_SELECT = 0x7004, + RV620_DACA_SYNC_TRISTATE_CONTROL = 0x7020, + /* RV620_DACA_SYNC_SELECT = 0x7024, ?? */ + RV620_DACA_AUTODETECT_CONTROL = 0x7028, + RV620_DACA_AUTODETECT_STATUS = 0x7034, + RV620_DACA_AUTODETECT_INT_CONTROL = 0x7038, + RV620_DACA_FORCE_OUTPUT_CNTL = 0x703C, + RV620_DACA_FORCE_DATA = 0x7040, + RV620_DACA_POWERDOWN = 0x7050, + /* RV620_DACA_CONTROL1 moved */ + RV620_DACA_CONTROL2 = 0x7058, + RV620_DACA_COMPARATOR_ENABLE = 0x705C, + /* RV620_DACA_COMPARATOR_OUTPUT changed */ + RV620_DACA_BGADJ_SRC = 0x7ef0, + RV620_DACA_MACRO_CNTL = 0x7ef4, + RV620_DACA_AUTO_CALIB_CONTROL = 0x7ef8, + + /* DAC B */ + RV620_DACB_ENABLE = 0x7100, + RV620_DACB_SOURCE_SELECT = 0x7104, + RV620_DACB_SYNC_TRISTATE_CONTROL = 0x7120, + /* RV620_DACB_SYNC_SELECT = 0x7124, ?? */ + RV620_DACB_AUTODETECT_CONTROL = 0x7128, + RV620_DACB_AUTODETECT_STATUS = 0x7134, + RV620_DACB_AUTODETECT_INT_CONTROL = 0x7138, + RV620_DACB_FORCE_OUTPUT_CNTL = 0x713C, + RV620_DACB_FORCE_DATA = 0x7140, + RV620_DACB_POWERDOWN = 0x7150, + /* RV620_DACB_CONTROL1 moved */ + RV620_DACB_CONTROL2 = 0x7158, + RV620_DACB_COMPARATOR_ENABLE = 0x715C, + RV620_DACB_BGADJ_SRC = 0x7ef0, + RV620_DACB_MACRO_CNTL = 0x7ff4, + RV620_DACB_AUTO_CALIB_CONTROL = 0x7ef8, + /* DIG1 */ + RV620_DIG1_CNTL = 0x75A0, + RV620_DIG1_CLOCK_PATTERN = 0x75AC, + RV620_LVDS1_DATA_CNTL = 0x75BC, + RV620_TMDS1_CNTL = 0x75C0, + /* DIG2 */ + RV620_DIG2_CNTL = 0x79A0, + RV620_DIG2_CLOCK_PATTERN = 0x79AC, + RV620_LVDS2_DATA_CNTL = 0x79BC, + RV620_TMDS2_CNTL = 0x79C0, + + /* RV62x I2C */ + RV62_GENERIC_I2C_CONTROL = 0x7d80, /* (RW) */ + RV62_GENERIC_I2C_INTERRUPT_CONTROL = 0x7d84, /* (RW) */ + RV62_GENERIC_I2C_STATUS = 0x7d88, /* (RW) */ + RV62_GENERIC_I2C_SPEED = 0x7d8c, /* (RW) */ + RV62_GENERIC_I2C_SETUP = 0x7d90, /* (RW) */ + RV62_GENERIC_I2C_TRANSACTION = 0x7d94, /* (RW) */ + RV62_GENERIC_I2C_DATA = 0x7d98, /* (RW) */ + RV62_GENERIC_I2C_PIN_SELECTION = 0x7d9c, /* (RW) */ + RV62_DC_GPIO_DDC4_MASK = 0x7e20, /* (RW) */ + RV62_DC_GPIO_DDC1_MASK = 0x7e40, /* (RW) */ + RV62_DC_GPIO_DDC2_MASK = 0x7e50, /* (RW) */ + RV62_DC_GPIO_DDC3_MASK = 0x7e60, /* (RW) */ + + /* ?? */ + RV620_DCIO_LINK_STEER_CNTL = 0x7FA4, + + RV620_LVTMA_TRANSMITTER_CONTROL= 0x7F00, + RV620_LVTMA_TRANSMITTER_ENABLE = 0x7F04, + RV620_LVTMA_TRANSMITTER_ADJUST = 0x7F18, + RV620_LVTMA_PREEMPHASIS_CONTROL= 0x7F1C, + RV620_LVTMA_MACRO_CONTROL = 0x7F0C, + RV620_LVTMA_PWRSEQ_CNTL = 0x7F80, + RV620_LVTMA_PWRSEQ_STATE = 0x7f84, + RV620_LVTMA_PWRSEQ_REF_DIV = 0x7f88, + RV620_LVTMA_PWRSEQ_DELAY1 = 0x7f8C, + RV620_LVTMA_PWRSEQ_DELAY2 = 0x7f90, + RV620_LVTMA_BL_MOD_CNTL = 0x7F94, + RV620_LVTMA_DATA_SYNCHRONIZATION = 0x7F98, + RV620_FMT1_CONTROL = 0x6700, + RV620_FMT1_BIT_DEPTH_CONTROL= 0x6710, + RV620_FMT1_CLAMP_CNTL = 0x672C, + RV620_FMT2_CONTROL = 0x6F00, + RV620_FMT2_CNTL = 0x6F10, + RV620_FMT2_CLAMP_CNTL = 0x6F2C, + + RV620_EXT1_DIFF_POST_DIV_CNTL= 0x0420, + RV620_EXT2_DIFF_POST_DIV_CNTL= 0x0424, + RV620_DCCG_PCLK_DIGA_CNTL = 0x04b0, + RV620_DCCG_PCLK_DIGB_CNTL = 0x04b4, + RV620_DCCG_SYMCLK_CNTL = 0x04b8 +}; + +enum RV620_EXT1_DIFF_POST_DIV_CNTL_BITS { + RV62_EXT1_DIFF_POST_DIV_RESET = 1 << 0, + RV62_EXT1_DIFF_POST_DIV_SELECT = 1 << 4, + RV62_EXT1_DIFF_DRIVER_ENABLE = 1 << 8 +}; + +enum RV620_EXT2_DIFF_POST_DIV_CNTL_BITS { + RV62_EXT2_DIFF_POST_DIV_RESET = 1 << 0, + RV62_EXT2_DIFF_POST_DIV_SELECT = 1 << 4, + RV62_EXT2_DIFF_DRIVER_ENABLE = 1 << 8 +}; + +enum RV620_LVTMA_PWRSEQ_CNTL_BITS { + RV62_LVTMA_PWRSEQ_EN = 1 << 0, + RV62_LVTMA_PWRSEQ_DISABLE_SYNCEN_CONTROL_OF_TX_EN = 1 << 1, + RV62_LVTMA_PLL_ENABLE_PWRSEQ_MASK = 1 << 2, + RV62_LVTMA_PLL_RESET_PWRSEQ_MASK = 1 << 3, + RV62_LVTMA_PWRSEQ_TARGET_STATE = 1 << 4, + RV62_LVTMA_SYNCEN = 1 << 8, + RV62_LVTMA_SYNCEN_OVRD = 1 << 9, + RV62_LVTMA_SYNCEN_POL = 1 << 10, + RV62_LVTMA_DIGON = 1 << 16, + RV62_LVTMA_DIGON_OVRD = 1 << 17, + RV62_LVTMA_DIGON_POL = 1 << 18, + RV62_LVTMA_BLON = 1 << 24, + RV62_LVTMA_BLON_OVRD = 1 << 25, + RV62_LVTMA_BLON_POL = 1 << 26 +}; + +enum RV620_LVTMA_PWRSEQ_STATE_BITS { + RV62_LVTMA_PWRSEQ_STATE_SHIFT = 8 +}; + +enum RV620_LVTMA_PWRSEQ_STATE_VAL { + RV62_POWERUP_DONE = 4, + RV62_POWERDOWN_DONE = 9 +}; + +enum RV620_LVTMA_TRANSMITTER_CONTROL_BITS { + RV62_LVTMA_PLL_ENABLE = 1 << 0, + RV62_LVTMA_PLL_RESET = 1 << 1, + RV62_LVTMA_IDSCKSEL = 1 << 4, + RV62_LVTMA_BGSLEEP = 1 << 5, + RV62_LVTMA_IDCLK_SEL = 1 << 6, + RV62_LVTMA_TMCLK = 1 << 8, + RV62_LVTMA_TMCLK_FROM_PADS = 1 << 13, + RV62_LVTMA_TDCLK = 1 << 14, + RV62_LVTMA_TDCLK_FROM_PADS = 1 << 15, + RV62_LVTMA_BYPASS_PLL = 1 << 28, + RV62_LVTMA_USE_CLK_DATA = 1 << 29, + RV62_LVTMA_MODE = 1 << 30, + RV62_LVTMA_INPUT_TEST_CLK_SEL = 1 << 31 +}; + +enum RV620_DCCG_SYMCLK_CNTL { + RV62_SYMCLKA_SRC_SHIFT = 8, + RV62_SYMCLKB_SRC_SHIFT = 12 +}; + +enum RV620_DCCG_DIG_CNTL { + RV62_PCLK_DIGA_ON = 0x1 +}; + +enum RV620_DCIO_LINK_STEER_CNTL { + RV62_LINK_STEER_SWAP = 1 << 0, + RV62_LINK_STEER_PLLSEL_OVERWRITE_EN = 1 << 16, + RV62_LINK_STEER_PLLSELA = 1 << 17, + RV62_LINK_STEER_PLLSELB = 1 << 18 +}; + +enum R620_LVTMA_TRANSMITTER_ENABLE_BITS { + RV62_LVTMA_LNK0EN = 1 << 0, + RV62_LVTMA_LNK1EN = 1 << 1, + RV62_LVTMA_LNK2EN = 1 << 2, + RV62_LVTMA_LNK3EN = 1 << 3, + RV62_LVTMA_LNK4EN = 1 << 4, + RV62_LVTMA_LNK5EN = 1 << 5, + RV62_LVTMA_LNK6EN = 1 << 6, + RV62_LVTMA_LNK7EN = 1 << 7, + RV62_LVTMA_LNK8EN = 1 << 8, + RV62_LVTMA_LNK9EN = 1 << 9, + RV62_LVTMA_LNKL = RV62_LVTMA_LNK0EN | RV62_LVTMA_LNK1EN + | RV62_LVTMA_LNK2EN | RV62_LVTMA_LNK3EN, + RV62_LVTMA_LNKU = RV62_LVTMA_LNK4EN | RV62_LVTMA_LNK5EN + | RV62_LVTMA_LNK6EN | RV62_LVTMA_LNK7EN, + RV62_LVTMA_LNK_ALL = RV62_LVTMA_LNKL | RV62_LVTMA_LNKU + | RV62_LVTMA_LNK8EN | RV62_LVTMA_LNK9EN, + RV62_LVTMA_LNKEN_HPD_MASK = 1 << 16 +}; + +enum RV620_LVTMA_DATA_SYNCHRONIZATION { + RV62_LVTMA_DSYNSEL = (1 << 0), + RV62_LVTMA_PFREQCHG = (1 << 8) +}; + +enum RV620_LVTMA_PWRSEQ_REF_DIV_BITS { + LVTMA_PWRSEQ_REF_DI_SHIFT = 0, + LVTMA_BL_MOD_REF_DI_SHIFT = 16 +}; + +enum RV620_LVTMA_BL_MOD_CNTL_BITS { + LVTMA_BL_MOD_EN = 1 << 0, + LVTMA_BL_MOD_LEVEL_SHIFT = 8, + LVTMA_BL_MOD_RES_SHIFT = 16 +}; + +enum RV620_DIG_CNTL_BITS { + /* 0x75A0 */ + RV62_DIG_SWAP = (0x1 << 16), + RV62_DIG_DUAL_LINK_ENABLE = (0x1 << 12), + RV62_DIG_START = (0x1 << 6), + RV62_DIG_MODE = (0x7 << 8), + RV62_DIG_STEREOSYNC_SELECT = (1 << 2), + RV62_DIG_SOURCE_SELECT = (1 << 0) +}; + +enum RV620_DIG_LVDS_DATA_CNTL_BITS { + /* 0x75BC */ + RV62_LVDS_24BIT_ENABLE = (0x1 << 0), + RV62_LVDS_24BIT_FORMAT = (0x1 << 4) +}; + +enum RV620_TMDS_CNTL_BITS { + /* 0x75C0 */ + RV62_TMDS_PIXEL_ENCODING = (0x1 << 4), + RV62_TMDS_COLOR_FORMAT = (0x3 << 8) +}; + +enum RV620_FMT_BIT_DEPTH_CONTROL { + RV62_FMT_TRUNCATE_EN = 1 << 0, + RV62_FMT_TRUNCATE_DEPTH = 1 << 4, + RV62_FMT_SPATIAL_DITHER_EN = 1 << 8, + RV62_FMT_SPATIAL_DITHER_MODE = 1 << 9, + RV62_FMT_SPATIAL_DITHER_DEPTH = 1 << 12, + RV62_FMT_FRAME_RANDOM_ENABLE = 1 << 13, + RV62_FMT_RGB_RANDOM_ENABLE = 1 << 14, + RV62_FMT_HIGHPASS_RANDOM_ENABLE = 1 << 15, + RV62_FMT_TEMPORAL_DITHER_EN = 1 << 16, + RV62_FMT_TEMPORAL_DITHER_DEPTH = 1 << 20, + RV62_FMT_TEMPORAL_DITHER_OFFSET = 3 << 21, + RV62_FMT_TEMPORAL_LEVEL = 1 << 24, + RV62_FMT_TEMPORAL_DITHER_RESET = 1 << 25, + RV62_FMT_25FRC_SEL = 3 << 26, + RV62_FMT_50FRC_SEL = 3 << 28, + RV62_FMT_75FRC_SEL = 3 << 30 +}; + +enum RV620_FMT_CONTROL { + RV62_FMT_PIXEL_ENCODING = 1 << 16 +}; + +enum _r5xxMCRegs { + R5XX_MC_STATUS = 0x0000, + RV515_MC_FB_LOCATION = 0x0001, + R5XX_MC_FB_LOCATION = 0x0004, + RV515_MC_STATUS = 0x0008, + RV515_MC_MISC_LAT_TIMER = 0x0009 +}; + +enum _r5xxRegs { + /* I2C */ + R5_DC_I2C_STATUS1 = 0x7D30, /* (RW) */ + R5_DC_I2C_RESET = 0x7D34, /* (RW) */ + R5_DC_I2C_CONTROL1 = 0x7D38, /* (RW) */ + R5_DC_I2C_CONTROL2 = 0x7D3C, /* (RW) */ + R5_DC_I2C_CONTROL3 = 0x7D40, /* (RW) */ + R5_DC_I2C_DATA = 0x7D44, /* (RW) */ + R5_DC_I2C_INTERRUPT_CONTROL = 0x7D48, /* (RW) */ + R5_DC_I2C_ARBITRATION = 0x7D50, /* (RW) */ + + R5_DC_GPIO_DDC1_MASK = 0x7E40, /* (RW) */ + R5_DC_GPIO_DDC1_A = 0x7E44, /* (RW) */ + R5_DC_GPIO_DDC1_EN = 0x7E48, /* (RW) */ + R5_DC_GPIO_DDC2_MASK = 0x7E50, /* (RW) */ + R5_DC_GPIO_DDC2_A = 0x7E54, /* (RW) */ + R5_DC_GPIO_DDC2_EN = 0x7E58, /* (RW) */ + R5_DC_GPIO_DDC3_MASK = 0x7E60, /* (RW) */ + R5_DC_GPIO_DDC3_A = 0x7E64, /* (RW) */ + R5_DC_GPIO_DDC3_EN = 0x7E68 /* (RW) */ +}; + +enum _r5xxSPLLRegs { + SPLL_FUNC_CNTL = 0x0 /* (RW) */ +}; + +enum _r6xxRegs { + /* MCLK */ + R6_MCLK_PWRMGT_CNTL = 0x620, + /* I2C */ + R6_DC_I2C_CONTROL = 0x7D30, /* (RW) */ + R6_DC_I2C_ARBITRATION = 0x7D34, /* (RW) */ + R6_DC_I2C_INTERRUPT_CONTROL = 0x7D38, /* (RW) */ + R6_DC_I2C_SW_STATUS = 0x7d3c, /* (RW) */ + R6_DC_I2C_DDC1_SPEED = 0x7D4C, /* (RW) */ + R6_DC_I2C_DDC1_SETUP = 0x7D50, /* (RW) */ + R6_DC_I2C_DDC2_SPEED = 0x7D54, /* (RW) */ + R6_DC_I2C_DDC2_SETUP = 0x7D58, /* (RW) */ + R6_DC_I2C_DDC3_SPEED = 0x7D5C, /* (RW) */ + R6_DC_I2C_DDC3_SETUP = 0x7D60, /* (RW) */ + R6_DC_I2C_TRANSACTION0 = 0x7D64, /* (RW) */ + R6_DC_I2C_TRANSACTION1 = 0x7D68, /* (RW) */ + R6_DC_I2C_DATA = 0x7D74, /* (RW) */ + R6_DC_I2C_DDC4_SPEED = 0x7DB4, /* (RW) */ + R6_DC_I2C_DDC4_SETUP = 0x7DBC, /* (RW) */ + R6_DC_GPIO_DDC4_MASK = 0x7E00, /* (RW) */ + R6_DC_GPIO_DDC4_A = 0x7E04, /* (RW) */ + R6_DC_GPIO_DDC4_EN = 0x7E08, /* (RW) */ + R6_DC_GPIO_DDC1_MASK = 0x7E40, /* (RW) */ + R6_DC_GPIO_DDC1_A = 0x7E44, /* (RW) */ + R6_DC_GPIO_DDC1_EN = 0x7E48, /* (RW) */ + R6_DC_GPIO_DDC1_Y = 0x7E4C, /* (RW) */ + R6_DC_GPIO_DDC2_MASK = 0x7E50, /* (RW) */ + R6_DC_GPIO_DDC2_A = 0x7E54, /* (RW) */ + R6_DC_GPIO_DDC2_EN = 0x7E58, /* (RW) */ + R6_DC_GPIO_DDC2_Y = 0x7E5C, /* (RW) */ + R6_DC_GPIO_DDC3_MASK = 0x7E60, /* (RW) */ + R6_DC_GPIO_DDC3_A = 0x7E64, /* (RW) */ + R6_DC_GPIO_DDC3_EN = 0x7E68, /* (RW) */ + R6_DC_GPIO_DDC3_Y = 0x7E6C /* (RW) */ +}; + +enum R6_MCLK_PWRMGT_CNTL { + R6_MC_BUSY = (1 << 5) +}; + + +/* *_Q: questionbable */ +enum _rs69xRegs { + /* I2C */ + RS69_DC_I2C_CONTROL = 0x7D30, /* (RW) *//* */ + RS69_DC_I2C_UNKNOWN_2 = 0x7D34, /* (RW) */ + RS69_DC_I2C_INTERRUPT_CONTROL = 0x7D38, /* (RW) */ + RS69_DC_I2C_SW_STATUS = 0x7d3c, /* (RW) *//**/ + RS69_DC_I2C_UNKNOWN_1 = 0x7d40, + RS69_DC_I2C_DDC_SETUP_Q = 0x7D44, /* (RW) */ + RS69_DC_I2C_DATA = 0x7D58, /* (RW) *//**/ + RS69_DC_I2C_TRANSACTION0 = 0x7D48, /* (RW) *//**/ + RS69_DC_I2C_TRANSACTION1 = 0x7D4C, /* (RW) *//**/ + /* DDIA */ + RS69_DDIA_CNTL = 0x7200, + RS69_DDIA_SOURCE_SELECT = 0x7204, + RS69_DDIA_BIT_DEPTH_CONTROL = 0x7214, + RS69_DDIA_DCBALANCER_CONTROL = 0x7250, + RS69_DDIA_PATH_CONTROL = 0x7264, + RS69_DDIA_PCIE_LINK_CONTROL2 = 0x7278, + RS69_DDIA_PCIE_LINK_CONTROL3 = 0x727c, + RS69_DDIA_PCIE_PHY_CONTROL1 = 0x728c, + RS69_DDIA_PCIE_PHY_CONTROL2 = 0x7290 +}; + +enum RS69_DDIA_CNTL_BITS { + RS69_DDIA_ENABLE = 1 << 0, + RS69_DDIA_HDMI_EN = 1 << 2, + RS69_DDIA_ENABLE_HPD_MASK = 1 << 4, + RS69_DDIA_HPD_SELECT = 1 << 8, + RS69_DDIA_SYNC_PHASE = 1 << 12, + RS69_DDIA_PIXEL_ENCODING = 1 << 16, + RS69_DDIA_DUAL_LINK_ENABLE = 1 << 24, + RS69_DDIA_SWAP = 1 << 28 +}; + +enum RS69_DDIA_SOURCE_SELECT_BITS { + RS69_DDIA_SOURCE_SELECT_BIT = 1 << 0, + RS69_DDIA_SYNC_SELECT = 1 << 8, + RS69_DDIA_STEREOSYNC_SELECT = 1 << 16 +}; + +enum RS69_DDIA_LINK_CONTROL2_SHIFT { + RS69_DDIA_PCIE_OUTPUT_MUX_SEL0 = 0, + RS69_DDIA_PCIE_OUTPUT_MUX_SEL1 = 4, + RS69_DDIA_PCIE_OUTPUT_MUX_SEL2 = 8, + RS69_DDIA_PCIE_OUTPUT_MUX_SEL3 = 12 +}; + +enum RS69_DDIA_BIT_DEPTH_CONTROL_BITS { + RS69_DDIA_TRUNCATE_EN = 1 << 0, + RS69_DDIA_TRUNCATE_DEPTH = 1 << 4, + RS69_DDIA_SPATIAL_DITHER_EN = 1 << 8, + RS69_DDIA_SPATIAL_DITHER_DEPTH = 1 << 12, + RS69_DDIA_TEMPORAL_DITHER_EN = 1 << 16, + RS69_DDIA_TEMPORAL_DITHER_DEPTH = 1 << 20, + RS69_DDIA_TEMPORAL_LEVEL = 1 << 24, + RS69_DDIA_TEMPORAL_DITHER_RESET = 1 << 25 +}; + +enum RS69_DDIA_DCBALANCER_CONTROL_BITS { + RS69_DDIA_DCBALANCER_EN = 1 << 0, + RS69_DDIA_SYNC_DCBAL_EN_SHIFT = 4, + RS69_DDIA_SYNC_DCBAL_EN_MASK = 7 << RS69_DDIA_SYNC_DCBAL_EN_SHIFT, + RS69_DDIA_DCBALANCER_TEST_EN = 1 << 8, + RS69_DDIA_DCBALANCER_TEST_IN_SHIFT = 16, + RS69_DDIA_DCBALANCER_FORCE = 1 << 24 +}; + +enum RS69_DDIA_PATH_CONTROL_BITS { + RS69_DDIA_PATH_SELECT_SHIFT = 0, + RS69_DDIA_DDPII_DE_ALIGN_EN = 1 << 4, + RS69_DDIA_DDPII_TRAIN_EN = 1 << 8, + RS69_DDIA_DDPII_TRAIN_SELECT = 1 << 12, + RS69_DDIA_DDPII_SCRAMBLE_EN = 1 << 16, + RS69_DDIA_REPL_MODE_SELECT = 1 << 20, + RS69_DDIA_RB_30b_SWAP_EN = 1 << 24, + RS69_DDIA_PIXVLD_RESET = 1 << 28, + RS69_DDIA_REARRANGER_EN = 1 << 30 +}; + +enum RS69_DDIA_PCIE_LINK_CONTROL3_BITS { + RS69_DDIA_PCIE_MIRROR_EN = 1 << 0, + RS69_DDIA_PCIE_CFGDUALLINK = 1 << 4, + RS69_DDIA_PCIE_NCHG3EN = 1 << 8, + RS69_DDIA_PCIE_RX_PDNB_SHIFT = 12 +}; + +enum RS69_MC_INDEX_BITS { + RS69_MC_IND_ADDR = (0x1 << 0), + RS69_MC_IND_WR_EN = (0x1 << 9) +}; + +enum RS60_MC_NB_MC_INDEX_BITS { + RS60_NB_MC_IND_ADDR = (0x1 << 0), + RS60_NB_MC_IND_WR_EN = (0x1 << 8) +}; + +enum _rs690MCRegs { + RS69_K8_FB_LOCATION = 0x1E, + RS69_MC_MISC_UMA_CNTL = 0x5f, + RS69_MC_SYSTEM_STATUS = 0x90, /* (RW) */ + RS69_MCCFG_FB_LOCATION = 0x100, + RS69MCCFG_AGP_LOCATION = 0x101, + RS69_MC_INIT_MISC_LAT_TIMER = 0x104 +}; + +enum MC_MISC_LAT_TIMER_BITS { + MC_CPR_INIT_LAT_SHIFT = 0, + MC_VF_INIT_LAT = 4, + MC_DISP0R_INIT_LAT_SHIFT = 8, + MC_DISP1R_INIT_LAT_SHIFT = 12, + MC_FIXED_INIT_LAT_SHIFT = 16, + MC_E2R_INIT_LAT_SHIFT = 20, + SAME_PAGE_PRIO_SHIFT = 24, + MC_GLOBW_INIT_LAT_SHIFT = 28 +}; + +enum RS69_MC_MISC_UMA_CNTL_BITS { + RS69_K8_40BIT_ADDR_EXTENSION = (0x1 << 0), + RS69_GART_BYPASS = (0x1 << 8), + RS69_GFX_64BYTE_MODE = (0x1 << 9), + RS69_GFX_64BYTE_LAT = (0x1 << 10), + RS69_GTW_COHERENCY = (0x1 << 15), + RS69_READ_BUFFER_SIZE = (0x1 << 16), + RS69_HDR_ROUTE_TO_DSP = (0x1 << 24), + RS69_GTW_ROUTE_TO_DSP = (0x1 << 25), + RS69_DSP_ROUTE_TO_GFX = (0x1 << 26), + RS69_USE_HDPW_LAT_INIT = (0x1 << 27), + RS69_USE_GFXW_LAT_INIT = (0x1 << 28), + RS69_MCIFR_COHERENT = (0x1 << 29), + RS69_NON_SNOOP_AZR_AIC_BP = (0x1 << 30), + RS69_SIDE_PORT_PRESENT_R = (0x1 << 31) +}; + +enum _rs600MCRegs { + RS60_MC_SYSTEM_STATUS = 0x0, + RS60_NB_FB_LOCATION = 0xa +}; + +enum _rs780NBRegs { + RS78_NB_MC_IND_INDEX = 0x70, + RS78_NB_MC_IND_DATA = 0x74 +}; + +enum RS78_NB_IND_INDEX_BITS { + RS78_NB_MC_IND_INDEX_MASK = (0xffff << 0), + RS78_MC_IND_SEQ_RBS_0 = (0x1 << 16), + RS78_MC_IND_SEQ_RBS_1 = (0x1 << 17), + RS78_MC_IND_SEQ_RBS_2 = (0x1 << 18), + RS78_MC_IND_SEQ_RBS_3 = (0x1 << 19), + RS78_MC_IND_AIC_RBS = (0x1 << 20), + RS78_MC_IND_CITF_ARB0 = (0x1 << 21), + RS78_MC_IND_CITF_ARB1 = (0x1 << 22), + RS78_MC_IND_WR_EN = (0x1 << 23), + RS78_MC_IND_RD_INV = (0x1 << 24) +}; + +enum _rs780MCRegs { + RS78_MC_SYSTEM_STATUS = 0x0, + RS78_MC_FB_LOCATION = 0x10, + RS78_K8_FB_LOCATION = 0x11, + RS78_MC_MISC_UMA_CNTL = 0x12 +}; + +enum RS6X_MC_SYSTEM_STATUS_BITS { + RS6X_MC_SYSTEM_IDLE = (0x1 << 0), + RS6X_MC_SEQUENCER_IDLE = (0x1 << 1), + RS6X_MC_ARBITER_IDLE = (0x1 << 2), + RS6X_MC_SELECT_PM = (0x1 << 3), + RS6X_RESERVED4 = (0xf << 4), + RS6X_RESERVED8 = (0xf << 8), + RS6X_RESERVED12_SYSTEM_STATUS = (0xf << 12), + RS6X_MCA_INIT_EXECUTED = (0x1 << 16), + RS6X_MCA_IDLE = (0x1 << 17), + RS6X_MCA_SEQ_IDLE = (0x1 << 18), + RS6X_MCA_ARB_IDLE = (0x1 << 19), + RS6X_RESERVED20_SYSTEM_STATUS = (0xfff << 20) +}; + +enum RS78_MC_MISC_UMA_CNTL_BITS { + RS78_K8_40BIT_ADDR_EXTENSION = ( 0x1 << 0), + RS78_BANKGROUP_SEL = ( 0x1 << 8), + RS78_CNTL_SPARE = ( 0x1 << 15), + RS78_SIDE_PORT_PRESENT_R = ( 0x1 << 31) +}; + +enum R5XX_MC_STATUS_BITS { + R5XX_MEM_PWRUP_COMPL = (0x1 << 0), + R5XX_MC_IDLE = (0x1 << 1) +}; + +enum RV515_MC_STATUS_BITS { + RV515_MC_IDLE = (0x1 << 4) +}; + +enum RS78_MC_SYSTEM_STATUS_BITS { + RS78_MC_SYSTEM_IDLE = 1 << 0, + RS78_MC_SEQUENCER_IDLE = 1 << 1, + RS78_MC_ARBITER_IDLE = 1 << 2, + RS78_MC_SELECT_PM = 1 << 3, + RS78_MC_STATUS_15_4_SHIFT = 4, + RS78_MCA_INIT_EXECUTED = 1 << 16, + RS78_MCA_IDLE = 1 << 17, + RS78_MCA_SEQ_IDLE = 1 << 18, + RS78_MCA_ARB_IDLE = 1 << 19, + RS78_MC_STATUS_31_20_SHIFT = 20 +}; + +enum BUS_CNTL_BITS { + /* BUS_CNTL */ + BUS_DBL_RESYNC = (0x1 << 0), + BIOS_ROM_WRT_EN = (0x1 << 1), + BIOS_ROM_DIS = (0x1 << 2), + PMI_IO_DIS = (0x1 << 3), + PMI_MEM_DIS = (0x1 << 4), + PMI_BM_DIS = (0x1 << 5), + PMI_INT_DIS = (0x1 << 6) +}; + +enum SEPROM_SNTL1_BITS { + /* SEPROM_CNTL1 */ + WRITE_ENABLE = (0x1 << 0), + WRITE_DISABLE = (0x1 << 1), + READ_CONFIG = (0x1 << 2), + WRITE_CONFIG = (0x1 << 3), + READ_STATUS = (0x1 << 4), + SECT_TO_SRAM = (0x1 << 5), + READY_BUSY = (0x1 << 7), + SEPROM_BUSY = (0x1 << 8), + BCNT_OVER_WTE_EN = (0x1 << 9), + RB_MASKB = (0x1 << 10), + SOFT_RESET = (0x1 << 11), + STATE_IDLEb = (0x1 << 12), + SECTOR_ERASE = (0x1 << 13), + BYTE_CNT = (0xff << 16), + SCK_PRESCALE = (0xff << 24) +}; + +enum VIPH_CONTROL_BITS { + /* VIPH_CONTROL */ + VIPH_CLK_SEL = (0xff << 0), + VIPH_REG_RDY = (0x1 << 13), + VIPH_MAX_WAIT = (0xf << 16), + VIPH_DMA_MODE = (0x1 << 20), + VIPH_EN = (0x1 << 21), + VIPH_DV0_WID = (0x1 << 24), + VIPH_DV1_WID = (0x1 << 25), + VIPH_DV2_WID = (0x1 << 26), + VIPH_DV3_WID = (0x1 << 27), + VIPH_PWR_DOWN = (0x1 << 28), + VIPH_PWR_DOWN_AK = (0x1 << 28), + VIPH_VIPCLK_DIS = (0x1 << 29) +}; + +enum ROM_CNTL_BITS { + SCK_OVERWRITE = 1 << 1, + CLOCK_GATING_EN = 1 << 2, + CSB_ACTIVE_TO_SCK_SETUP_TIME_SHIFT = 8, + CSB_ACTIVE_TO_SCK_HOLD_TIME_SHIFT = 16, + SCK_PRESCALE_REFCLK_SHIFT = 24, + SCK_PRESCALE_CRYSTAL_CLK_SHIFT = 28 +}; + +enum GENERAL_PWRMGT_BITS { + GLOBAL_PWRMGT_EN = 1 << 0, + STATIC_PM_EN = 1 << 1, + MOBILE_SU = 1 << 2, + THERMAL_PROTECTION_DIS = 1 << 3, + THERMAL_PROTECTION_TYPE = 1 << 4, + ENABLE_GEN2PCIE = 1 << 5, + SW_GPIO_INDEX_SHIFT = 1 << 6, + LOW_VOLT_D2_ACPI = 1 << 8, + LOW_VOLT_D3_ACPI = 1 << 9, + VOLT_PWRMGT_EN = 1 << 10, + OPEN_DRAIN_PADS = 1 << 11, + AVP_SCLK_EN = 1 << 12, + IDCT_SCLK_EN = 1 << 13, + GPU_COUNTER_ACPI = 1 << 14, + GPU_COUNTER_CLK = 1 << 15, + BACKBIAS_PAD_EN = 1 << 16, + BACKBIAS_VALUE = 1 << 17, + BACKBIAS_DPM_CNTL = 1 << 18, + SPREAD_SPECTRUM_INDEX_SHIFT = 19, + DYN_SPREAD_SPECTRUM_EN = 1 << 2 +}; + +enum VGA_RENDER_CONTROL_BITS { + /* VGA_RENDER_CONTROL */ + VGA_BLINK_RATE = (0x1f << 0), + VGA_BLINK_MODE = (0x3 << 5), + VGA_CURSOR_BLINK_INVERT = (0x1 << 7), + VGA_EXTD_ADDR_COUNT_ENABLE = (0x1 << 8), + VGA_VSTATUS_CNTL = (0x3 << 16), + VGA_LOCK_8DOT = (0x1 << 24), + VGAREG_LINECMP_COMPATIBILITY_SEL = (0x1 << 25) +}; + +enum D1VGA_CONTROL_BITS { + /* D1VGA_CONTROL */ + D1VGA_MODE_ENABLE = (0x1 << 0), + D1VGA_TIMING_SELECT = (0x1 << 8), + D1VGA_SYNC_POLARITY_SELECT = (0x1 << 9), + D1VGA_OVERSCAN_TIMING_SELECT = (0x1 << 10), + D1VGA_OVERSCAN_COLOR_EN = (0x1 << 16), + D1VGA_ROTATE = (0x3 << 24) +}; + +enum D2VGA_CONTROL_BITS { + /* D2VGA_CONTROL */ + D2VGA_MODE_ENABLE = (0x1 << 0), + D2VGA_TIMING_SELECT = (0x1 << 8), + D2VGA_SYNC_POLARITY_SELECT = (0x1 << 9), + D2VGA_OVERSCAN_TIMING_SELECT = (0x1 << 10), + D2VGA_OVERSCAN_COLOR_EN = (0x1 << 16), + D2VGA_ROTATE = (0x3 << 24) +}; + +enum { + /* CLOCK_CNTL_INDEX */ + PLL_ADDR = (0x3f << 0), + PLL_WR_EN = (0x1 << 7), + PPLL_DIV_SEL = (0x3 << 8), + + /* CLOCK_CNTL_DATA */ +#define PLL_DATA 0xffffffff + + /* SPLL_FUNC_CNTL */ + SPLL_CHG_STATUS = (0x1 << 29), + SPLL_BYPASS_EN = (0x1 << 25), + + /* MC_IND_INDEX */ + MC_IND_ADDR = (0xffff << 0), + MC_IND_SEQ_RBS_0 = (0x1 << 16), + MC_IND_SEQ_RBS_1 = (0x1 << 17), + MC_IND_SEQ_RBS_2 = (0x1 << 18), + MC_IND_SEQ_RBS_3 = (0x1 << 19), + MC_IND_AIC_RBS = (0x1 << 20), + MC_IND_CITF_ARB0 = (0x1 << 21), + MC_IND_CITF_ARB1 = (0x1 << 22), + MC_IND_WR_EN = (0x1 << 23), + MC_IND_RD_INV = (0x1 << 24) +#define MC_IND_ALL (MC_IND_SEQ_RBS_0 | MC_IND_SEQ_RBS_1 \ + | MC_IND_SEQ_RBS_2 | MC_IND_SEQ_RBS_3 \ + | MC_IND_AIC_RBS | MC_IND_CITF_ARB0 | MC_IND_CITF_ARB1) + + /* MC_IND_DATA */ +#define MC_IND_DATA_BIT 0xffffffff +}; + +enum AGP_STATUS_BITS { + AGP_1X_MODE = 0x01, + AGP_2X_MODE = 0x02, + AGP_4X_MODE = 0x04, + AGP_FW_MODE = 0x10, + AGP_MODE_MASK = 0x17, + AGPv3_MODE = 0x08, + AGPv3_4X_MODE = 0x01, + AGPv3_8X_MODE = 0x02 +}; + +enum { + /* HDMI registers */ + HDMI_ENABLE = 0x00, + HDMI_CNTL = 0x08, + HDMI_UNKNOWN_0 = 0x0C, + HDMI_AUDIOCNTL = 0x10, + HDMI_VIDEOCNTL = 0x14, + HDMI_VERSION = 0x18, + HDMI_UNKNOWN_1 = 0x28, + HDMI_VIDEOINFOFRAME_0 = 0x54, + HDMI_VIDEOINFOFRAME_1 = 0x58, + HDMI_VIDEOINFOFRAME_2 = 0x5c, + HDMI_VIDEOINFOFRAME_3 = 0x60, + HDMI_32kHz_CTS = 0xac, + HDMI_32kHz_N = 0xb0, + HDMI_44_1kHz_CTS = 0xb4, + HDMI_44_1kHz_N = 0xb8, + HDMI_48kHz_CTS = 0xbc, + HDMI_48kHz_N = 0xc0, + HDMI_AUDIOINFOFRAME_0 = 0xcc, + HDMI_AUDIOINFOFRAME_1 = 0xd0, + HDMI_IEC60958_1 = 0xd4, + HDMI_IEC60958_2 = 0xd8, + HDMI_UNKNOWN_2 = 0xdc, + HDMI_AUDIO_DEBUG = 0xe0 +}; + +#endif /* _RHD_REGS_H */ diff --git a/programs/system/drivers/rhd/rhd_tmds.c b/programs/system/drivers/rhd/rhd_tmds.c new file mode 100644 index 000000000..c7377c4b6 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_tmds.c @@ -0,0 +1,548 @@ +/* + * Copyright 2007-2008 Luc Verhaegen + * Copyright 2007-2008 Matthias Hopf + * Copyright 2007-2008 Egbert Eich + * 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. + */ + +/* + * Deals with the Primary TMDS device (TMDSA) of R500s, R600s. + * Gets replaced by DDIA on RS690 and DIG/UNIPHY on RV620. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "xf86.h" + +/* for usleep */ +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#else +# include +#endif +#include "rhd.h" +#include "rhd_crtc.h" +#include "rhd_connector.h" +#include "rhd_output.h" +#include "rhd_regs.h" +#include "rhd_hdmi.h" + +#ifdef ATOM_BIOS +#include "rhd_atombios.h" +#endif + +struct rhdTMDSPrivate { + Bool RunsDualLink; + DisplayModePtr Mode; + Bool Coherent; + int PowerState; + + struct rhdHdmi *Hdmi; + + Bool Stored; + + CARD32 StoreControl; + CARD32 StoreSource; + CARD32 StoreFormat; + CARD32 StoreForce; + CARD32 StoreReduction; + CARD32 StoreDCBalancer; + CARD32 StoreDataSynchro; + CARD32 StoreTXEnable; + CARD32 StoreMacro; + CARD32 StoreTXControl; + CARD32 StoreTXAdjust; +}; + +/* + * We cannot sense for dual link here at all, plus, we need a bit more work + * for enabling the transmitter for sensing to happen on most R5xx cards. + * RV570 (0x7280) and R600 and above seem ok. + */ +static enum rhdSensedOutput +TMDSASense(struct rhdOutput *Output, struct rhdConnector *Connector) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + CARD32 Enable, Control, Detect; + enum rhdConnectorType Type = Connector->Type; + Bool ret; + + RHDFUNC(Output); + + if ((Type != RHD_CONNECTOR_DVI) && (Type != RHD_CONNECTOR_DVI_SINGLE)) { + xf86DrvMsg(Output->scrnIndex, X_WARNING, + "%s: connector type %d is not supported.\n", + __func__, Type); + return RHD_SENSED_NONE; + } + + Enable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE); + Control = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL); + Detect = RHDRegRead(Output, TMDSA_LOAD_DETECT); + + if (rhdPtr->ChipSet < RHD_R600) { + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00000003, 0x00000003); + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000003); + } + + RHDRegMask(Output, TMDSA_LOAD_DETECT, 0x00000001, 0x00000001); + usleep(1); + ret = RHDRegRead(Output, TMDSA_LOAD_DETECT) & 0x00000010; + + RHDRegMask(Output, TMDSA_LOAD_DETECT, Detect, 0x00000001); + + if (rhdPtr->ChipSet < RHD_R600) { + RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Enable); + RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Control); + } + + RHDDebug(Output->scrnIndex, "%s: %s\n", __func__, + ret ? "Attached" : "Disconnected"); + + if (ret) + return RHD_SENSED_DVI; + else + return RHD_SENSED_NONE; +} + +/* + * + */ +static ModeStatus +TMDSAModeValid(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDFUNC(Output); + + if (Mode->Flags & V_INTERLACE) + return MODE_NO_INTERLACE; + + if (Mode->Clock < 25000) + return MODE_CLOCK_LOW; + + if (Output->Connector->Type == RHD_CONNECTOR_DVI_SINGLE) { + if (Mode->Clock > 165000) + return MODE_CLOCK_HIGH; + } else if (Output->Connector->Type == RHD_CONNECTOR_DVI) { + if (Mode->Clock > 330000) /* could go higher still */ + return MODE_CLOCK_HIGH; + } + + return MODE_OK; +} + +/* + * This information is not provided in an atombios data table. + */ +static struct R5xxTMDSAMacro { + CARD16 Device; + CARD32 Macro; +} R5xxTMDSAMacro[] = { + { 0x7104, 0x00C00414 }, /* R520 */ + { 0x7142, 0x00A00415 }, /* RV515 */ + { 0x7145, 0x00A00416 }, /* M54 */ + { 0x7146, 0x00C0041F }, /* RV515 */ + { 0x7147, 0x00C00418 }, /* RV505 */ + { 0x7149, 0x00800416 }, /* M56 */ + { 0x7152, 0x00A00415 }, /* RV515 */ + { 0x7183, 0x00600412 }, /* RV530 */ + { 0x71C1, 0x00C0041F }, /* RV535 */ + { 0x71C2, 0x00A00416 }, /* RV530 */ + { 0x71C4, 0x00A00416 }, /* M56 */ + { 0x71C5, 0x00A00416 }, /* M56 */ + { 0x71C6, 0x00A00513 }, /* RV530 */ + { 0x71D2, 0x00A00513 }, /* RV530 */ + { 0x71D5, 0x00A00513 }, /* M66 */ + { 0x7249, 0x00A00513 }, /* R580 */ + { 0x724B, 0x00A00513 }, /* R580 */ + { 0x7280, 0x00C0041F }, /* RV570 */ + { 0x7288, 0x00C0041F }, /* RV570 */ + { 0x9400, 0x00910419 }, /* R600: */ + { 0, 0} /* End marker */ +}; + +static struct Rv6xxTMDSAMacro { + CARD16 Device; + CARD32 PLL; + CARD32 TX; +} Rv6xxTMDSAMacro[] = { + { 0x94C1, 0x00010416, 0x00010308 }, /* RV610 */ + { 0x94C3, 0x00010416, 0x00010308 }, /* RV610 */ + { 0x9501, 0x00010416, 0x00010308 }, /* RV670: != atombios */ + { 0x9505, 0x00010416, 0x00010308 }, /* RV670: != atombios */ + { 0x950F, 0x00010416, 0x00010308 }, /* R680 : != atombios */ + { 0x9581, 0x00030410, 0x00301044 }, /* M76 */ + { 0x9587, 0x00010416, 0x00010308 }, /* RV630 */ + { 0x9588, 0x00010416, 0x00010388 }, /* RV630 */ + { 0x9589, 0x00010416, 0x00010388 }, /* RV630 */ + { 0, 0, 0} /* End marker */ +}; + +static void +TMDSAVoltageControl(struct rhdOutput *Output) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + int i; + + if (rhdPtr->ChipSet < RHD_RV610) { + for (i = 0; R5xxTMDSAMacro[i].Device; i++) + if (R5xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) { + RHDRegWrite(Output, TMDSA_MACRO_CONTROL, R5xxTMDSAMacro[i].Macro); + return; + } + + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n", + __func__, rhdPtr->PciDeviceID); + xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_MACRO_CONTROL: 0x%08X\n", + (unsigned int) RHDRegRead(Output, TMDSA_MACRO_CONTROL)); + } else { + for (i = 0; Rv6xxTMDSAMacro[i].Device; i++) + if (Rv6xxTMDSAMacro[i].Device == rhdPtr->PciDeviceID) { + RHDRegWrite(Output, TMDSA_PLL_ADJUST, Rv6xxTMDSAMacro[i].PLL); + RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Rv6xxTMDSAMacro[i].TX); + return; + } + xf86DrvMsg(Output->scrnIndex, X_ERROR, "%s: unhandled chipset: 0x%04X.\n", + __func__, rhdPtr->PciDeviceID); + xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_PLL_ADJUST: 0x%08X\n", + (unsigned int) RHDRegRead(Output, TMDSA_PLL_ADJUST)); + xf86DrvMsg(Output->scrnIndex, X_INFO, "TMDSA_TRANSMITTER_ADJUST: 0x%08X\n", + (unsigned int) RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST)); + } +} + +/* + * + */ +static Bool +TMDSAPropertyControl(struct rhdOutput *Output, + enum rhdPropertyAction Action, enum rhdOutputProperty Property, union rhdPropertyData *val) +{ + struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private; + + RHDFUNC(Output); + switch (Action) { + case rhdPropertyCheck: + switch (Property) { + case RHD_OUTPUT_COHERENT: + return TRUE; + default: + return FALSE; + } + case rhdPropertyGet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + val->Bool = Private->Coherent; + return TRUE; + break; + default: + return FALSE; + } + break; + case rhdPropertySet: + switch (Property) { + case RHD_OUTPUT_COHERENT: + Private->Coherent = val->Bool; + Output->Mode(Output, Private->Mode); + Output->Power(Output, RHD_POWER_ON); + break; + default: + return FALSE; + } + break; + } + return TRUE; +} + +/* + * + */ +static void +TMDSASet(struct rhdOutput *Output, DisplayModePtr Mode) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private; + + RHDFUNC(Output); + + /* Clear out some HPD events first: this should be under driver control. */ + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x0000000C); + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00070000); + RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000010); + + /* Disable the transmitter */ + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001D1F); + + /* Disable bit reduction and reset temporal dither */ + RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x00010101); + if (rhdPtr->ChipSet < RHD_R600) { + RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x04000000, 0x04000000); + usleep(2); + RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x04000000); + } else { + RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0x02000000, 0x02000000); + usleep(2); + RHDRegMask(Output, TMDSA_BIT_DEPTH_CONTROL, 0, 0x02000000); + } + + /* reset phase on vsync and use RGB */ + RHDRegMask(Output, TMDSA_CNTL, 0x00001000, 0x00011000); + + /* Select CRTC, select syncA, no stereosync */ + RHDRegMask(Output, TMDSA_SOURCE_SELECT, Output->Crtc->Id, 0x00010101); + + /* Single link, for now */ + RHDRegWrite(Output, TMDSA_COLOR_FORMAT, 0); + + /* store this for TRANSMITTER_ENABLE in TMDSAPower */ + Private->Mode = Mode; + if (Mode->SynthClock > 165000) { + RHDRegMask(Output, TMDSA_CNTL, 0x01000000, 0x01000000); + Private->RunsDualLink = TRUE; /* for TRANSMITTER_ENABLE in TMDSAPower */ + } else { + RHDRegMask(Output, TMDSA_CNTL, 0, 0x01000000); + Private->RunsDualLink = FALSE; + } + + /* Disable force data */ + RHDRegMask(Output, TMDSA_FORCE_OUTPUT_CNTL, 0, 0x00000001); + + /* DC balancer enable */ + RHDRegMask(Output, TMDSA_DCBALANCER_CONTROL, 0x00000001, 0x00000001); + + TMDSAVoltageControl(Output); + + /* use IDCLK */ + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000010, 0x00000010); + + if (Private->Coherent) + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000000, 0x10000000); + else + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x10000000, 0x10000000); + + RHDHdmiSetMode(Private->Hdmi, Mode); +} + +/* + * + */ +static void +TMDSAPower(struct rhdOutput *Output, int Power) +{ + RHDPtr rhdPtr = RHDPTRI(Output); + struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private; + + RHDDebug(Output->scrnIndex, "%s(%s,%s)\n",__func__,Output->Name, + rhdPowerString[Power]); + + switch (Power) { + case RHD_POWER_ON: + if (Private->PowerState == RHD_POWER_SHUTDOWN + || Private->PowerState == RHD_POWER_UNKNOWN) { + RHDRegMask(Output, TMDSA_CNTL, 0x1, 0x00000001); + + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000001, 0x00000001); + usleep(20); + + /* reset transmitter PLL */ + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); + usleep(2); + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000002); + + usleep(30); + + /* restart data synchronisation */ + if (rhdPtr->ChipSet < RHD_R600) { + RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000001, 0x00000001); + usleep(2); + RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0x00000100, 0x00000100); + RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R500, 0, 0x00000001); + } else { + RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000001, 0x00000001); + usleep(2); + RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0x00000100, 0x00000100); + RHDRegMask(Output, TMDSA_DATA_SYNCHRONIZATION_R600, 0, 0x00000001); + } + } + + if (Private->RunsDualLink) { + /* bit 9 is not known by anything below RV610, but is ignored by + the hardware anyway */ + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x00001F1F, 0x00001F1F); + } else + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0x0000001F, 0x00001F1F); + + if(Output->Connector != NULL && RHDConnectorEnableHDMI(Output->Connector)) + RHDHdmiEnable(Private->Hdmi, TRUE); + else + RHDHdmiEnable(Private->Hdmi, FALSE); + Private->PowerState = RHD_POWER_ON; + return; + + case RHD_POWER_RESET: + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F); + /* if we do a RESET after a SHUTDOWN don't raise the power level, + * and similarly, don't raise from UNKNOWN state. */ + if (Private->PowerState == RHD_POWER_ON) + Private->PowerState = RHD_POWER_RESET; + return; + + case RHD_POWER_SHUTDOWN: + default: + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0x00000002, 0x00000002); + usleep(2); + RHDRegMask(Output, TMDSA_TRANSMITTER_CONTROL, 0, 0x00000001); + RHDRegMask(Output, TMDSA_TRANSMITTER_ENABLE, 0, 0x00001F1F); + RHDRegMask(Output, TMDSA_CNTL, 0, 0x00000001); + RHDHdmiEnable(Private->Hdmi, FALSE); + Private->PowerState = RHD_POWER_SHUTDOWN; + return; + } +} + +/* + * + */ +static void +TMDSASave(struct rhdOutput *Output) +{ + int ChipSet = RHDPTRI(Output)->ChipSet; + struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private; + + RHDFUNC(Output); + + Private->StoreControl = RHDRegRead(Output, TMDSA_CNTL); + Private->StoreSource = RHDRegRead(Output, TMDSA_SOURCE_SELECT); + Private->StoreFormat = RHDRegRead(Output, TMDSA_COLOR_FORMAT); + Private->StoreForce = RHDRegRead(Output, TMDSA_FORCE_OUTPUT_CNTL); + Private->StoreReduction = RHDRegRead(Output, TMDSA_BIT_DEPTH_CONTROL); + Private->StoreDCBalancer = RHDRegRead(Output, TMDSA_DCBALANCER_CONTROL); + + if (ChipSet < RHD_R600) + Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R500); + else + Private->StoreDataSynchro = RHDRegRead(Output, TMDSA_DATA_SYNCHRONIZATION_R600); + + Private->StoreTXEnable = RHDRegRead(Output, TMDSA_TRANSMITTER_ENABLE); + Private->StoreMacro = RHDRegRead(Output, TMDSA_MACRO_CONTROL); + Private->StoreTXControl = RHDRegRead(Output, TMDSA_TRANSMITTER_CONTROL); + + if (ChipSet >= RHD_RV610) + Private->StoreTXAdjust = RHDRegRead(Output, TMDSA_TRANSMITTER_ADJUST); + + RHDHdmiSave(Private->Hdmi); + + Private->Stored = TRUE; +} + +/* + * + */ +static void +TMDSARestore(struct rhdOutput *Output) +{ + int ChipSet = RHDPTRI(Output)->ChipSet; + struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private; + + RHDFUNC(Output); + + if (!Private->Stored) { + xf86DrvMsg(Output->scrnIndex, X_ERROR, + "%s: No registers stored.\n", __func__); + return; + } + + RHDRegWrite(Output, TMDSA_CNTL, Private->StoreControl); + RHDRegWrite(Output, TMDSA_SOURCE_SELECT, Private->StoreSource); + RHDRegWrite(Output, TMDSA_COLOR_FORMAT, Private->StoreFormat); + RHDRegWrite(Output, TMDSA_FORCE_OUTPUT_CNTL, Private->StoreForce); + RHDRegWrite(Output, TMDSA_BIT_DEPTH_CONTROL, Private->StoreReduction); + RHDRegWrite(Output, TMDSA_DCBALANCER_CONTROL, Private->StoreDCBalancer); + + if (ChipSet < RHD_R600) + RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R500, Private->StoreDataSynchro); + else + RHDRegWrite(Output, TMDSA_DATA_SYNCHRONIZATION_R600, Private->StoreDataSynchro); + + RHDRegWrite(Output, TMDSA_TRANSMITTER_ENABLE, Private->StoreTXEnable); + RHDRegWrite(Output, TMDSA_MACRO_CONTROL, Private->StoreMacro); + RHDRegWrite(Output, TMDSA_TRANSMITTER_CONTROL, Private->StoreTXControl); + + if (ChipSet >= RHD_RV610) + RHDRegWrite(Output, TMDSA_TRANSMITTER_ADJUST, Private->StoreTXAdjust); + + RHDHdmiRestore(Private->Hdmi); +} + +/* + * + */ +static void +TMDSADestroy(struct rhdOutput *Output) +{ + struct rhdTMDSPrivate *Private = (struct rhdTMDSPrivate *) Output->Private; + RHDFUNC(Output); + + if (!Private) + return; + + RHDHdmiDestroy(Private->Hdmi); + + xfree(Private); + Output->Private = NULL; +} + +/* + * + */ +struct rhdOutput * +RHDTMDSAInit(RHDPtr rhdPtr) +{ + struct rhdOutput *Output; + struct rhdTMDSPrivate *Private; + + RHDFUNC(rhdPtr); + + Output = xnfcalloc(sizeof(struct rhdOutput), 1); + + Output->scrnIndex = rhdPtr->scrnIndex; + Output->Name = "TMDS A"; + Output->Id = RHD_OUTPUT_TMDSA; + + Output->Sense = TMDSASense; + Output->ModeValid = TMDSAModeValid; + Output->Mode = TMDSASet; + Output->Power = TMDSAPower; + Output->Save = TMDSASave; + Output->Restore = TMDSARestore; + Output->Destroy = TMDSADestroy; + Output->Property = TMDSAPropertyControl; + + Private = xnfcalloc(sizeof(struct rhdTMDSPrivate), 1); + Private->RunsDualLink = FALSE; + Private->Coherent = FALSE; + Private->PowerState = RHD_POWER_UNKNOWN; + + Output->Private = Private; + + return Output; +} diff --git a/programs/system/drivers/rhd/rhd_vga.c b/programs/system/drivers/rhd/rhd_vga.c new file mode 100644 index 000000000..8faecc86b --- /dev/null +++ b/programs/system/drivers/rhd/rhd_vga.c @@ -0,0 +1,173 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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 + +#include "xf86.h" +#if HAVE_XF86_ANSIC_H +# include "xf86_ansic.h" +#endif + +#include "rhd.h" +#include "rhd_vga.h" +#include "rhd_regs.h" +#include "rhd_mc.h" + +/* + * + */ +void +RHDVGAInit(RHDPtr rhdPtr) +{ + static struct rhdVGA VGA; + + /* Check whether one of our VGA bits is set */ + if (!(_RHDRegRead(rhdPtr, VGA_RENDER_CONTROL) & 0x00030000) && + (_RHDRegRead(rhdPtr, VGA_HDP_CONTROL) & 0x00000010) && + !(_RHDRegRead(rhdPtr, D1VGA_CONTROL) & 0x00000001) && + !(_RHDRegRead(rhdPtr, D2VGA_CONTROL) & 0x00000001)) + return; + + DBG(dbgprintf("Detected VGA mode.\n")); + + VGA.Stored = FALSE; + rhdPtr->VGA = &VGA; +} + +#if 0 +/* + * + */ +void +RHDVGASave(RHDPtr rhdPtr) +{ + struct rhdVGA *VGA = &rhdPtr->VGA; + + VGA->Render_Control = _RHDRegRead(rhdPtr, VGA_RENDER_CONTROL); + VGA->Mode_Control = _RHDRegRead(rhdPtr, VGA_MODE_CONTROL); + VGA->HDP_Control = _RHDRegRead(rhdPtr, VGA_HDP_CONTROL); + VGA->D1_Control = _RHDRegRead(rhdPtr, D1VGA_CONTROL); + VGA->D2_Control = _RHDRegRead(rhdPtr, D2VGA_CONTROL); + + /* Store our VGA FB */ + VGA->FBOffset = + _RHDRegRead(rhdPtr, VGA_MEMORY_BASE_ADDRESS) - rhdPtr->FbIntAddress; + + /* Could be that the VGA internal address no longer is pointing to what + we know as our FB memory, in which case we should give up cleanly. */ + if (VGA->FBOffset < (unsigned) (rhdPtr->videoRam * 1024)) { + VGA->FBSize = 256 * 1024; + VGA->FB = calloc(VGA->FBSize, 1); + if (VGA->FB) + memcpy(VGA->FB, ((CARD8 *) rhdPtr->FbBase) + VGA->FBOffset, + VGA->FBSize); + else { + dbgprintf("%s: Failed to allocate" + " space for storing the VGA framebuffer.\n", __func__); + VGA->FBSize = 0; + VGA->FB = NULL; + } + } else { + dbgprintf("%s: VGA FB Offset (0x%08X) is " + "out of range of the Cards Internal FB Address (0x%08X)\n", + __func__, (int) RHDRegRead(rhdPtr, VGA_MEMORY_BASE_ADDRESS), + rhdPtr->FbIntAddress); + VGA->FBOffset = 0xFFFFFFFF; + VGA->FBSize = 0; + VGA->FB = NULL; + } + + VGA->Stored = TRUE; +} + +/* + * + */ +void +RHDVGARestore(RHDPtr rhdPtr) +{ + struct rhdVGA *VGA = rhdPtr->VGA; + + RHDFUNC(rhdPtr); + + if (!VGA) + return; /* We don't need to warn , this is intended use */ + + if (!VGA->Stored) { + dbgprintf("%s: trying to restore uninitialized values.\n", __func__); + return; + } + + if (VGA->FB) + memcpy(((CARD8 *) rhdPtr->FbBase) + VGA->FBOffset, + VGA->FB, VGA->FBSize); + + RHDRegWrite(rhdPtr, VGA_RENDER_CONTROL, VGA->Render_Control); + RHDRegWrite(rhdPtr, VGA_MODE_CONTROL, VGA->Mode_Control); + RHDRegWrite(rhdPtr, VGA_HDP_CONTROL, VGA->HDP_Control); + RHDRegWrite(rhdPtr, D1VGA_CONTROL, VGA->D1_Control); + RHDRegWrite(rhdPtr, D2VGA_CONTROL, VGA->D2_Control); +} +#endif +/* + * + */ +void +RHDVGADisable(RHDPtr rhdPtr) +{ + RHDFUNC(rhdPtr); + + _RHDRegMask(rhdPtr, VGA_RENDER_CONTROL, 0, 0x00030000); + _RHDRegMask(rhdPtr, VGA_MODE_CONTROL, 0, 0x00000030); + _RHDRegMask(rhdPtr, VGA_HDP_CONTROL, 0x00010010, 0x00010010); + _RHDRegMask(rhdPtr, D1VGA_CONTROL, 0, 0x00000001); + _RHDRegMask(rhdPtr, D2VGA_CONTROL, 0, 0x00000001); +} + +/* + * + */ +void +RHDVGADestroy(RHDPtr rhdPtr) +{ + struct rhdVGA *VGA = rhdPtr->VGA; + + RHDFUNC(rhdPtr); + + if (!VGA) + return; /* We don't need to warn , this is intended use */ + + if (VGA->FB) + free(VGA->FB); + rhdPtr->VGA=NULL; +} + + + + + + diff --git a/programs/system/drivers/rhd/rhd_vga.h b/programs/system/drivers/rhd/rhd_vga.h new file mode 100644 index 000000000..774537216 --- /dev/null +++ b/programs/system/drivers/rhd/rhd_vga.h @@ -0,0 +1,49 @@ +/* + * Copyright 2007 Luc Verhaegen + * Copyright 2007 Matthias Hopf + * Copyright 2007 Egbert Eich + * Copyright 2007 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. + */ + +#ifndef _RHD_VGA_H +#define _RHD_VGA_H + +struct rhdVGA { + Bool Stored; + + CARD32 FBBase; + CARD8 *FB; + int FBSize; /* most cases, 256kB */ + + CARD32 Render_Control; + CARD32 Mode_Control; + CARD32 HDP_Control; + CARD32 D1_Control; + CARD32 D2_Control; +}; + +void RHDVGAInit(RHDPtr rhdPtr); +void RHDVGASave(RHDPtr rhdPtr); +void RHDVGARestore(RHDPtr rhdPtr); +void RHDVGADisable(RHDPtr rhdPtr); +void RHDVGADestroy(RHDPtr rhdPtr); + +#endif /* _RHD_PLL_H */ diff --git a/programs/system/drivers/rhd/s_ceilf.asm b/programs/system/drivers/rhd/s_ceilf.asm new file mode 100644 index 000000000..1aba8133c --- /dev/null +++ b/programs/system/drivers/rhd/s_ceilf.asm @@ -0,0 +1,31 @@ +/* + * Written by J.T. Conklin . + * Public domain. + */ + + .text + + .global _ceilf + + +_ceilf: + flds 4(%esp) + subl $8,%esp + + fstcw 4(%esp) /* store fpu control word */ + + /* We use here %edx although only the low 1 bits are defined. + But none of the operations should care and they are faster + than the 16 bit operations. */ + movl $0x0800,%edx /* round towards +oo */ + orl 4(%esp),%edx + andl $0xfbff,%edx + movl %edx,(%esp) + fldcw (%esp) /* load modified control word */ + + frndint /* round */ + + fldcw 4(%esp) /* restore original control word */ + + addl $8,%esp + ret diff --git a/programs/system/drivers/rhd/stdio.h b/programs/system/drivers/rhd/stdio.h new file mode 100644 index 000000000..0f6e75628 --- /dev/null +++ b/programs/system/drivers/rhd/stdio.h @@ -0,0 +1,156 @@ +/* + * stdio.h - input/output definitions + * + * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. + * See the copyright notice in the ACK home directory, in the file "Copyright". + */ +/* $Header$ */ + +#ifndef _STDIO_H +#define _STDIO_H + +#ifndef _ANSI_H +//#include +#endif + +/* + * Focus point of all stdio activity. + */ +typedef struct __iobuf { + int _count; + int _fd; + int _flags; + int _bufsiz; + unsigned char *_buf; + unsigned char *_ptr; +} FILE; + +#define _IOFBF 0x000 +#define _IOREAD 0x001 +#define _IOWRITE 0x002 +#define _IONBF 0x004 +#define _IOMYBUF 0x008 +#define _IOEOF 0x010 +#define _IOERR 0x020 +#define _IOLBF 0x040 +#define _IOREADING 0x080 +#define _IOWRITING 0x100 +#define _IOAPPEND 0x200 +#define _IOFIFO 0x400 + +/* The following definitions are also in . They should not + * conflict. + */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define stdin (&__stdin) +#define stdout (&__stdout) +#define stderr (&__stderr) + +#define BUFSIZ 4096 +#define NULL ((void *)0) +#define EOF (-1) + +#define FOPEN_MAX 20 + +//#include +#define FILENAME_MAX DIRSIZ + +#define TMP_MAX 999 +#define L_tmpnam (sizeof("/tmp/") + FILENAME_MAX) +#define __STDIO_VA_LIST__ void * + +typedef long int fpos_t; + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; /* type returned by sizeof */ +#endif /* _SIZE_T */ + +extern FILE *__iotab[FOPEN_MAX]; +extern FILE __stdin, __stdout, __stderr; + +_PROTOTYPE( int remove, (const char *_filename) ); +_PROTOTYPE( int rename, (const char *_old, const char *_new) ); +_PROTOTYPE( FILE *tmpfile, (void) ); +_PROTOTYPE( char *tmpnam, (char *_s) ); +_PROTOTYPE( int fclose, (FILE *_stream) ); +_PROTOTYPE( int fflush, (FILE *_stream) ); +_PROTOTYPE( FILE *fopen, (const char *_filename, const char *_mode) ); +_PROTOTYPE( FILE *freopen, + (const char *_filename, const char *_mode, FILE *_stream) ); +_PROTOTYPE( void setbuf, (FILE *_stream, char *_buf) ); +_PROTOTYPE( int setvbuf, + (FILE *_stream, char *_buf, int _mode, size_t _size) ); +_PROTOTYPE( int fprintf, (FILE *_stream, const char *_format, ...) ); +_PROTOTYPE( int printf, (const char *_format, ...) ); +_PROTOTYPE( int sprintf, (char *_s, const char *_format, ...) ); +_PROTOTYPE( int vfprintf, + (FILE *_stream, const char *_format, char *_arg) ); +_PROTOTYPE( int vprintf, (const char *_format, char *_arg) ); +_PROTOTYPE( int vsprintf, (char *_s, const char *_format, char *_arg) ); +_PROTOTYPE( int fscanf, (FILE *_stream, const char *_format, ...) ); +_PROTOTYPE( int scanf, (const char *_format, ...) ); +_PROTOTYPE( int sscanf, (const char *_s, const char *_format, ...) ); +#define vfscanf _doscan +_PROTOTYPE( int vfscanf, (FILE *_stream, const char *_format, char *_arg)); +_PROTOTYPE( int vscanf, (const char *_format, char *_arg) ); +_PROTOTYPE( int vsscanf, (const char *_s, const char *_format, char *_arg)); +_PROTOTYPE( int fgetc, (FILE *_stream) ); +_PROTOTYPE( char *fgets, (char *_s, int _n, FILE *_stream) ); +_PROTOTYPE( int fputc, (int _c, FILE *_stream) ); +_PROTOTYPE( int fputs, (const char *_s, FILE *_stream) ); +_PROTOTYPE( int getc, (FILE *_stream) ); +_PROTOTYPE( int getchar, (void) ); +_PROTOTYPE( char *gets, (char *_s) ); +_PROTOTYPE( int putc, (int _c, FILE *_stream) ); +_PROTOTYPE( int putchar, (int _c) ); +_PROTOTYPE( int puts, (const char *_s) ); +_PROTOTYPE( int ungetc, (int _c, FILE *_stream) ); +_PROTOTYPE( size_t fread, + (void *_ptr, size_t _size, size_t _nmemb, FILE *_stream) ); +_PROTOTYPE( size_t fwrite, + (const void *_ptr, size_t _size, size_t _nmemb, FILE *_stream) ); +_PROTOTYPE( int fgetpos, (FILE *_stream, fpos_t *_pos) ); +_PROTOTYPE( int fseek, (FILE *_stream, long _offset, int _whence) ); +_PROTOTYPE( int fsetpos, (FILE *_stream, fpos_t *_pos) ); +_PROTOTYPE( long ftell, (FILE *_stream) ); +_PROTOTYPE( void rewind, (FILE *_stream) ); +_PROTOTYPE( void clearerr, (FILE *_stream) ); +_PROTOTYPE( int feof, (FILE *_stream) ); +_PROTOTYPE( int ferror, (FILE *_stream) ); +_PROTOTYPE( void perror, (const char *_s) ); +_PROTOTYPE( int __fillbuf, (FILE *_stream) ); +_PROTOTYPE( int __flushbuf, (int _c, FILE *_stream) ); + +#define getchar() getc(stdin) +#define putchar(c) putc(c,stdout) +#define getc(p) (--(p)->_count >= 0 ? (int) (*(p)->_ptr++) : \ + __fillbuf(p)) +#define putc(c, p) (--(p)->_count >= 0 ? \ + (int) (*(p)->_ptr++ = (c)) : \ + __flushbuf((c),(p))) + +#define feof(p) (((p)->_flags & _IOEOF) != 0) +#define ferror(p) (((p)->_flags & _IOERR) != 0) +#define clearerr(p) ((p)->_flags &= ~(_IOERR|_IOEOF)) + +#ifdef _POSIX_SOURCE +_PROTOTYPE( int fileno, (FILE *_stream) ); +_PROTOTYPE (FILE *fdopen, (int _fildes, const char *_types) ); +#define fileno(stream) ((stream)->_fd) +#define L_ctermid 255 /* required by POSIX */ +#define L_cuserid 255 /* required by POSIX */ +#endif + +#ifdef _MINIX +_PROTOTYPE(FILE *popen, (const char *_command, const char *_type)); +_PROTOTYPE(int pclose, (FILE *_stream)); +_PROTOTYPE(int snprintf, (char *_s, size_t _n, const char *_format, ...)); +_PROTOTYPE(int vsnprintf, (char *_s, size_t _n, const char *_format, + char *_arg) ); +#endif + +#endif /* _STDIO_H */ diff --git a/programs/system/drivers/rhd/string.c b/programs/system/drivers/rhd/string.c new file mode 100644 index 000000000..2b8904f6f --- /dev/null +++ b/programs/system/drivers/rhd/string.c @@ -0,0 +1,128 @@ +#include "common.h" + +char * strcat(char *s, const char *append) +{ + int d0, d1, d2, d3; + __asm__ __volatile__( + "repne\n\t" + "scasb\n\t" + "decl %1\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3) + : "0" (append),"1"(s),"2"(0),"3" (0xffffffff):"memory"); + return s; +} + +int +memcmp(const void *s1, const void *s2, size_t n) +{ + if (n != 0) + { + const unsigned char *p1 = s1, *p2 = s2; + + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); + } + return 0; +} + +void * memcpy(void * _dest, const void *_src, size_t _n) +{ +int d0, d1, d2; + __asm__ __volatile__( + "jcxz 1f\n\t" + "rep ; movsl\n\t" + "1:\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (_n/4), "q" (_n),"1" ((long)_dest),"2" ((long)_src) + : "memory"); + return (_dest); +} + +char * strcpy(char *to, const char *from) +{ +int d0, d1, d2; +__asm__ __volatile__( + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : "=&S" (d0), "=&D" (d1), "=&a" (d2) + :"0" (from),"1" (to) : "memory"); + return to; +} + +int strcmp(const char *s1, const char *s2) +{ +int d0, d1; +register int __res; +__asm__ __volatile__( + "1:\tlodsb\n\t" + "scasb\n\t" + "jne 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "jmp 3f\n" + "2:\tsbbl %%eax,%%eax\n\t" + "orb $1,%%al\n" + "3:" + :"=a" (__res), "=&S" (d0), "=&D" (d1) + :"1" (s1),"2" (s2)); +return __res; +} + +size_t strlen(const char *str) +{ +int d0; +register int __res; +__asm__ __volatile__( + "repne\n\t" + "scasb\n\t" + "notl %0\n\t" + "decl %0" + :"=c" (__res), "=&D" (d0) :"1" (str),"a" (0), "0" (0xffffffff)); +return __res; +} + +char * strdup(const char *_s) +{ + char *rv; + if (_s == 0) + return 0; + rv = (char *)malloc(strlen(_s) + 1); + if (rv == 0) + return 0; + strcpy(rv, _s); + return rv; +} + +char * strchr(const char *s, int c) +{ + int d0; + register char * __res; + __asm__ __volatile__( + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "je 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "movl $1,%1\n" + "2:\tmovl %1,%0\n\t" + "decl %0" + :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c)); + return __res; +} diff --git a/programs/system/drivers/rhd/stub.asm b/programs/system/drivers/rhd/stub.asm new file mode 100644 index 000000000..d4c62aad1 --- /dev/null +++ b/programs/system/drivers/rhd/stub.asm @@ -0,0 +1,22 @@ + format MZ + heap 0 + stack 800h + entry main:start + +segment main use16 + +start: + push cs + pop ds + + mov dx, msg + mov ah, 9 + int 21h ; DOS - PRINT STRING + ; DS:DX -> string terminated by "$" + mov ax, 4C01h + int 21h ; DOS - 2+ - QUIT WITH EXIT CODE (EXIT) + ; AL = exit code + + ; --------------------------------------------------------------------------- + msg db 'This is Kolibri OS device driver.',0Dh,0Ah,'$',0 + diff --git a/programs/system/drivers/rhd/vdif.h b/programs/system/drivers/rhd/vdif.h new file mode 100644 index 000000000..7a647031a --- /dev/null +++ b/programs/system/drivers/rhd/vdif.h @@ -0,0 +1,175 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/ddc/vdif.h,v 1.4tsi Exp $ */ + +#ifndef _VDIF_H +#define _VDIF_H + +#define VDIF_MONITOR_MONOCHROME 0 +#define VDIF_MONITOR_COLOR 1 +#define VDIF_VIDEO_TTL 0 +#define VDIF_VIDEO_ANALOG 1 +#define VDIF_VIDEO_ECL 2 +#define VDIF_VIDEO_DECL 3 +#define VDIF_VIDEO_OTHER 4 +#define VDIF_SYNC_SEPARATE 0 +#define VDIF_SYNC_C 1 +#define VDIF_SYNC_CP 2 +#define VDIF_SYNC_G 3 +#define VDIF_SYNC_GP 4 +#define VDIF_SYNC_OTHER 5 +#define VDIF_SCAN_NONINTERLACED 0 +#define VDIF_SCAN_INTERLACED 1 +#define VDIF_SCAN_OTHER 2 +#define VDIF_POLARITY_NEGATIVE 0 +#define VDIF_POLARITY_POSITIVE 1 + +#include "Xmd.h" + +#undef CARD32 +#define CARD32 unsigned int /* ... on all supported platforms */ + +typedef struct _VDIF { /* Monitor Description: */ + CARD8 VDIFId[4]; /* alway "VDIF" */ + CARD32 FileLength; /* lenght of the whole file */ + CARD32 Checksum; /* sum of all bytes in the file after*/ + /* this field */ + CARD16 VDIFVersion; /* structure version number */ + CARD16 VDIFRevision; /* structure revision number */ + CARD16 Date[3]; /* file date Year/Month/Day */ + CARD16 DateManufactured[3]; /* date Year/Month/Day */ + CARD32 FileRevision; /* file revision string */ + CARD32 Manufacturer; /* ASCII ID of the manufacturer */ + CARD32 ModelNumber; /* ASCII ID of the model */ + CARD32 MinVDIFIndex; /* ASCII ID of Minimum VDIF index */ + CARD32 Version; /* ASCII ID of the model version */ + CARD32 SerialNumber; /* ASCII ID of the serial number */ + CARD8 MonitorType; /* Monochrome or Color */ + CARD8 CRTSize; /* inches */ + CARD8 BorderRed; /* percent */ + CARD8 BorderGreen; /* percent */ + CARD8 BorderBlue; /* percent */ + CARD8 Reserved1; /* padding */ + CARD16 Reserved2; /* padding */ + CARD32 RedPhosphorDecay; /* microseconds */ + CARD32 GreenPhosphorDecay; /* microseconds */ + CARD32 BluePhosphorDecay; /* microseconds */ + CARD16 WhitePoint_x; /* WhitePoint in CIExyY (scale 1000) */ + CARD16 WhitePoint_y; + CARD16 WhitePoint_Y; + CARD16 RedChromaticity_x; /* Red chromaticity in x,y */ + CARD16 RedChromaticity_y; + CARD16 GreenChromaticity_x; /* Green chromaticity in x,y */ + CARD16 GreenChromaticity_y; + CARD16 BlueChromaticity_x; /* Blue chromaticity in x,y */ + CARD16 BlueChromaticity_y; + CARD16 RedGamma; /* Gamme curve exponent (scale 1000) */ + CARD16 GreenGamma; + CARD16 BlueGamma; + CARD32 NumberOperationalLimits; + CARD32 OffsetOperationalLimits; + CARD32 NumberOptions; /* optinal sections (gamma table) */ + CARD32 OffsetOptions; + CARD32 OffsetStringTable; +} xf86VdifRec, *xf86VdifPtr; + +typedef enum { /* Tags for section identification */ + VDIF_OPERATIONAL_LIMITS_TAG = 1, + VDIF_PREADJUSTED_TIMING_TAG, + VDIF_GAMMA_TABLE_TAG +} VDIFScnTag; + +typedef struct _VDIFScnHdr { /* Generic Section Header: */ + CARD32 ScnLength; /* lenght of section */ + CARD32 ScnTag; /* tag for section identification */ +} VDIFScnHdrRec, *VDIFScnHdrPtr; + +typedef struct _VDIFLimits { /* Operational Limits: */ + VDIFScnHdrRec Header; /* common section info */ + CARD16 MaxHorPixel; /* pixels */ + CARD16 MaxVerPixel; /* lines */ + CARD16 MaxHorActiveLength; /* millimeters */ + CARD16 MaxVerActiveHeight; /* millimeters */ + CARD8 VideoType; /* TTL / Analog / ECL / DECL */ + CARD8 SyncType; /* TTL / Analog / ECL / DECL */ + CARD8 SyncConfiguration; /* separate / composite / other */ + CARD8 Reserved1; /* padding */ + CARD16 Reserved2; /* padding */ + CARD16 TerminationResistance; /* */ + CARD16 WhiteLevel; /* millivolts */ + CARD16 BlackLevel; /* millivolts */ + CARD16 BlankLevel; /* millivolts */ + CARD16 SyncLevel; /* millivolts */ + CARD32 MaxPixelClock; /* kiloHertz */ + CARD32 MinHorFrequency; /* Hertz */ + CARD32 MaxHorFrequency; /* Hertz */ + CARD32 MinVerFrequency; /* milliHertz */ + CARD32 MaxVerFrequency; /* milliHertz */ + CARD16 MinHorRetrace; /* nanoseconds */ + CARD16 MinVerRetrace; /* microseconds */ + CARD32 NumberPreadjustedTimings; + CARD32 OffsetNextLimits; +} xf86VdifLimitsRec, *xf86VdifLimitsPtr; + +typedef struct _VDIFTiming { /* Preadjusted Timing: */ + VDIFScnHdrRec Header; /* common section info */ + CARD32 PreadjustedTimingName; /* SVGA/SVPMI mode number */ + CARD16 HorPixel; /* pixels */ + CARD16 VerPixel; /* lines */ + CARD16 HorAddrLength; /* millimeters */ + CARD16 VerAddrHeight; /* millimeters */ + CARD8 PixelWidthRatio; /* gives H:V */ + CARD8 PixelHeightRatio; + CARD8 Reserved1; /* padding */ + CARD8 ScanType; /* noninterlaced / interlaced / other*/ + CARD8 HorSyncPolarity; /* negative / positive */ + CARD8 VerSyncPolarity; /* negative / positive */ + CARD16 CharacterWidth; /* pixels */ + CARD32 PixelClock; /* kiloHertz */ + CARD32 HorFrequency; /* Hertz */ + CARD32 VerFrequency; /* milliHertz */ + CARD32 HorTotalTime; /* nanoseconds */ + CARD32 VerTotalTime; /* microseconds */ + CARD16 HorAddrTime; /* nanoseconds */ + CARD16 HorBlankStart; /* nanoseconds */ + CARD16 HorBlankTime; /* nanoseconds */ + CARD16 HorSyncStart; /* nanoseconds */ + CARD16 HorSyncTime; /* nanoseconds */ + CARD16 VerAddrTime; /* microseconds */ + CARD16 VerBlankStart; /* microseconds */ + CARD16 VerBlankTime; /* microseconds */ + CARD16 VerSyncStart; /* microseconds */ + CARD16 VerSyncTime; /* microseconds */ +} xf86VdifTimingRec, *xf86VdifTimingPtr; + +typedef struct _VDIFGamma { /* Gamma Table: */ + VDIFScnHdrRec Header; /* common section info */ + CARD16 GammaTableEntries; /* count of grays or RGB 3-tuples */ + CARD16 Unused1; +} xf86VdifGammaRec, *xf86VdifGammaPtr; + +/* access macros */ +#define VDIF_OPERATIONAL_LIMITS(vdif) \ +((xf86VdifLimitsPtr)((char*)(vdif) + (vdif)->OffsetOperationalLimits)) +#define VDIF_NEXT_OPERATIONAL_LIMITS(limits) limits = \ + ((xf86VdifLimitsPtr)((char*)(limits) + (limits)->OffsetNextLimits)) +#define VDIF_PREADJUSTED_TIMING(limits) \ +((xf86VdifTimingPtr)((char*)(limits) + (limits)->Header.ScnLength)) +#define VDIF_NEXT_PREADJUSTED_TIMING(timing) timing = \ + ((xf86VdifTimingPtr)((char*)(timing) + (timing)->Header.ScnLength)) +#define VDIF_OPTIONS(vdif) \ + ((VDIFScnHdrPtr)((char*)(vdif) + (vdif)->OffsetOptions)) +#define VDIF_NEXT_OPTIONS(options) options = \ + ((xf86VdifGammaPtr)((char*)(options) + (options)->Header.ScnLength)) +#define VDIF_STRING(vdif, string) \ + ((char*)((char*)vdif + vdif->OffsetStringTable + (string))) + +typedef struct _vdif { + xf86VdifPtr vdif; + xf86VdifLimitsPtr *limits; + xf86VdifTimingPtr *timings; + xf86VdifGammaPtr *gamma; + char * strings; +} xf86vdif, *xf86vdifPtr; + +#undef CARD32 + +#endif diff --git a/programs/system/drivers/rhd/vsprintf.c b/programs/system/drivers/rhd/vsprintf.c new file mode 100644 index 000000000..432eda83d --- /dev/null +++ b/programs/system/drivers/rhd/vsprintf.c @@ -0,0 +1,774 @@ +/* + * vsprintf - print formatted output without ellipsis on an array + */ +/* $Header$ */ + +//#include "stdio.h" +//#include + +typedef unsigned size_t; + +typedef struct +{ + char *_ptr; + unsigned _count; +}__str; + + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +typedef __builtin_va_list __gnuc_va_list; +typedef __gnuc_va_list va_list; + +#define arg(x) va_arg (ap, u32) + +#define io_testflag(p,x) ((p)->_flags & (x)) + +char *_i_compute(unsigned long val, int base, char *s, int nrdigits); +char *_f_print(va_list *ap, int flags, char *s, char c, int precision); +void __cleanup(void); + + +void *calloc( size_t num, size_t size ); +int memcmp(const void *s1, const void *s2, size_t n); +void * memcpy(void * _dest, const void *_src, size_t _n); +char * strcpy(char *to, const char *from); +char * strcat(char *s, const char *append); +int strcmp(const char *s1, const char *s2); +size_t strlen(const char *str); +char * strdup(const char *_s); +char * strchr(const char *s, int c); + + +#define FL_LJUST 0x0001 /* left-justify field */ +#define FL_SIGN 0x0002 /* sign in signed conversions */ +#define FL_SPACE 0x0004 /* space in signed conversions */ +#define FL_ALT 0x0008 /* alternate form */ +#define FL_ZEROFILL 0x0010 /* fill with zero's */ +#define FL_SHORT 0x0020 /* optional h */ +#define FL_LONG 0x0040 /* optional l */ +#define FL_LONGDOUBLE 0x0080 /* optional L */ +#define FL_WIDTHSPEC 0x0100 /* field width is specified */ +#define FL_PRECSPEC 0x0200 /* precision is specified */ +#define FL_SIGNEDCONV 0x0400 /* may contain a sign */ +#define FL_NOASSIGN 0x0800 /* do not assign (in scanf) */ +#define FL_NOMORE 0x1000 /* all flags collected */ + +#define _IOFBF 0x000 +#define _IOREAD 0x001 +#define _IOWRITE 0x002 +#define _IONBF 0x004 +#define _IOMYBUF 0x008 +#define _IOEOF 0x010 +#define _IOERR 0x020 +#define _IOLBF 0x040 +#define _IOREADING 0x080 +#define _IOWRITING 0x100 +#define _IOAPPEND 0x200 +#define _IOFIFO 0x400 + +#define SGL_MAX 254 /* standard definition */ +#define SGL_MIN 1 /* standard definition */ +#define DBL_MAX 2046 /* standard definition */ +#define DBL_MIN 1 /* standard definition */ +#define EXT_MAX 16383 /* standard minimum */ +#define EXT_MIN -16382 /* standard minimum */ +#include + +static char *cvt(); +#define NDIGITS 128 + +unsigned char __dj_ctype_toupper[] = { + 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; +#define toupper(c) (__dj_ctype_toupper[(int)(c)+1]) + +int (toupper)(int c) +{ + return toupper(c); +} + +char * +_ecvt(value, ndigit, decpt, sign) + double value; + int ndigit, *decpt, *sign; +{ + return cvt(value, ndigit, decpt, sign, 1); +} + +char * +_fcvt(value, ndigit, decpt, sign) + double value; + int ndigit, *decpt, *sign; +{ + return cvt(value, ndigit, decpt, sign, 0); +} + +static struct powers_of_10 { + double pval; + double rpval; + int exp; +} p10[] = { + 1.0e32, 1.0e-32, 32, + 1.0e16, 1.0e-16, 16, + 1.0e8, 1.0e-8, 8, + 1.0e4, 1.0e-4, 4, + 1.0e2, 1.0e-2, 2, + 1.0e1, 1.0e-1, 1, + 1.0e0, 1.0e0, 0 +}; + +static char * +cvt(value, ndigit, decpt, sign, ecvtflag) + double value; + int ndigit, *decpt, *sign; +{ + static char buf[NDIGITS+1]; + register char *p = buf; + register char *pe; + + if (ndigit < 0) ndigit = 0; + if (ndigit > NDIGITS) ndigit = NDIGITS; + pe = &buf[ndigit]; + buf[0] = '\0'; + + *sign = 0; + if (value < 0) { + *sign = 1; + value = -value; + } + + *decpt = 0; + if (value >= DBL_MAX) { + value = DBL_MAX; + } + if (value != 0.0) { + register struct powers_of_10 *pp = &p10[0]; + + if (value >= 10.0) do { + while (value >= pp->pval) { + value *= pp->rpval; + *decpt += pp->exp; + } + } while ((++pp)->exp > 0); + + pp = &p10[0]; + if (value < 1.0) do { + while (value * pp->pval < 10.0) { + value *= pp->pval; + *decpt -= pp->exp; + } + } while ((++pp)->exp > 0); + + (*decpt)++; /* because now value in [1.0, 10.0) */ + } + if (! ecvtflag) { + /* for fcvt() we need ndigit digits behind the dot */ + pe += *decpt; + if (pe > &buf[NDIGITS]) pe = &buf[NDIGITS]; + } + while (p <= pe) { + *p++ = (int)value + '0'; + value = 10.0 * (value - (int)value); + } + if (pe >= buf) { + p = pe; + *p += 5; /* round of at the end */ + while (*p > '9') { + *p = '0'; + if (p > buf) ++*--p; + else { + *p = '1'; + ++*decpt; + if (! ecvtflag) { + /* maybe add another digit at the end, + because the point was shifted right + */ + if (pe > buf) *pe = '0'; + pe++; + } + } + } + *pe = '\0'; + } + return buf; +} + + +int _fp_hook = 1; + +static char * +_pfloat(double r, register char *s, int n, int flags) +{ + register char *s1; + int sign, dp; + register int i; + + s1 = _fcvt(r, n, &dp, &sign); + if (sign) + *s++ = '-'; + else if (flags & FL_SIGN) + *s++ = '+'; + else if (flags & FL_SPACE) + *s++ = ' '; + + if (dp<=0) + *s++ = '0'; + for (i=dp; i>0; i--) + if (*s1) *s++ = *s1++; + else *s++ = '0'; + if (((i=n) > 0) || (flags & FL_ALT)) + *s++ = '.'; + while (++dp <= 0) { + if (--i<0) + break; + *s++ = '0'; + } + while (--i >= 0) + if (*s1) *s++ = *s1++; + else *s++ = '0'; + return s; +} + +static char * +_pscien(double r, register char *s, int n, int flags) +{ + int sign, dp; + register char *s1; + + s1 = _ecvt(r, n + 1, &dp, &sign); + if (sign) + *s++ = '-'; + else if (flags & FL_SIGN) + *s++ = '+'; + else if (flags & FL_SPACE) + *s++ = ' '; + + *s++ = *s1++; + if ((n > 0) || (flags & FL_ALT)) + *s++ = '.'; + while (--n >= 0) + if (*s1) *s++ = *s1++; + else *s++ = '0'; + *s++ = 'e'; + if ( r != 0 ) --dp ; + if ( dp<0 ) { + *s++ = '-' ; dp= -dp ; + } else { + *s++ = '+' ; + } + if (dp >= 100) { + *s++ = '0' + (dp / 100); + dp %= 100; + } + *s++ = '0' + (dp/10); + *s++ = '0' + (dp%10); + return s; +} + +#define NDIGINEXP(exp) (((exp) >= 100 || (exp) <= -100) ? 3 : 2) +#define LOW_EXP -4 +#define USE_EXP(exp, ndigits) (((exp) < LOW_EXP + 1) || (exp >= ndigits + 1)) + +static char * +_gcvt(double value, int ndigit, char *s, int flags) +{ + int sign, dp; + register char *s1, *s2; + register int i; + register int nndigit = ndigit; + + s1 = _ecvt(value, ndigit, &dp, &sign); + s2 = s; + if (sign) *s2++ = '-'; + else if (flags & FL_SIGN) + *s2++ = '+'; + else if (flags & FL_SPACE) + *s2++ = ' '; + + if (!(flags & FL_ALT)) + for (i = nndigit - 1; i > 0 && s1[i] == '0'; i--) + nndigit--; + + if (USE_EXP(dp,ndigit)) { + /* Use E format */ + dp--; + *s2++ = *s1++; + if ((nndigit > 1) || (flags & FL_ALT)) *s2++ = '.'; + while (--nndigit > 0) *s2++ = *s1++; + *s2++ = 'e'; + if (dp < 0) { + *s2++ = '-'; + dp = -dp; + } + else *s2++ = '+'; + s2 += NDIGINEXP(dp); + *s2 = 0; + for (i = NDIGINEXP(dp); i > 0; i--) { + *--s2 = dp % 10 + '0'; + dp /= 10; + } + return s; + } + /* Use f format */ + if (dp <= 0) { + if (*s1 != '0') { + /* otherwise the whole number is 0 */ + *s2++ = '0'; + *s2++ = '.'; + } + while (dp < 0) { + dp++; + *s2++ = '0'; + } + } + for (i = 1; i <= nndigit; i++) { + *s2++ = *s1++; + if (i == dp) *s2++ = '.'; + } + if (i <= dp) { + while (i++ <= dp) *s2++ = '0'; + *s2++ = '.'; + } + if ((s2[-1]=='.') && !(flags & FL_ALT)) s2--; + *s2 = '\0'; + return s; +} + +char * +_f_print(va_list *ap, int flags, char *s, char c, int precision) +{ + register char *old_s = s; + double ld_val; + + // if (flags & FL_LONGDOUBLE) ld_val = va_arg(*ap, double); +// else + ld_val = (double) va_arg(*ap, double); + + switch(c) { + case 'f': + s = _pfloat(ld_val, s, precision, flags); + break; + case 'e': + case 'E': + s = _pscien(ld_val, s, precision , flags); + break; + case 'g': + case 'G': + s = _gcvt(ld_val, precision, s, flags); + s += strlen(s); + break; + } + if ( c == 'E' || c == 'G') { + while (*old_s && *old_s != 'e') old_s++; + if (*old_s == 'e') *old_s = 'E'; + } + return s; +} + +//#endif /* NOFLOAT */ +/* $Header$ */ + +//#include +//#include "../ansi/ext_fmt.h" + +//void _str_ext_cvt(const char *s, char **ss, struct EXTEND *e); +//double _ext_dbl_cvt(struct EXTEND *e); + +//double +//strtod(const char *p, char **pp) +//{ +// struct EXTEND e; + +// _str_ext_cvt(p, pp, &e); +// return _ext_dbl_cvt(&e); +//} + +#define BUFSIZ 4096 +#define NULL ((void *)0) +#define EOF (-1) + + +/* gnum() is used to get the width and precision fields of a format. */ +static const char * +gnum(register const char *f, int *ip, va_list *app) +{ + register int i, c; + + if (*f == '*') { + *ip = va_arg((*app), int); + f++; + } else { + i = 0; + while ((c = *f - '0') >= 0 && c <= 9) { + i = i*10 + c; + f++; + } + *ip = i; + } + return f; +} + +#if _EM_WSIZE == _EM_PSIZE +#define set_pointer(flags) /* nothing */ +#elif _EM_LSIZE == _EM_PSIZE +#define set_pointer(flags) (flags |= FL_LONG) +#else +#error garbage pointer size +#define set_pointer(flags) /* compilation might continue */ +#endif + +/* print an ordinal number */ +static char * +o_print(va_list *ap, int flags, char *s, char c, int precision, int is_signed) +{ + long signed_val; + unsigned long unsigned_val; + char *old_s = s; + int base; + + switch (flags & (FL_SHORT | FL_LONG)) { + case FL_SHORT: + if (is_signed) { + signed_val = (short) va_arg(*ap, int); + } else { + unsigned_val = (unsigned short) va_arg(*ap, unsigned); + } + break; + case FL_LONG: + if (is_signed) { + signed_val = va_arg(*ap, long); + } else { + unsigned_val = va_arg(*ap, unsigned long); + } + break; + default: + if (is_signed) { + signed_val = va_arg(*ap, int); + } else { + unsigned_val = va_arg(*ap, unsigned int); + } + break; + } + + if (is_signed) { + if (signed_val < 0) { + *s++ = '-'; + signed_val = -signed_val; + } else if (flags & FL_SIGN) *s++ = '+'; + else if (flags & FL_SPACE) *s++ = ' '; + unsigned_val = signed_val; + } + if ((flags & FL_ALT) && (c == 'o')) *s++ = '0'; + if (!unsigned_val && c != 'p') { + if (!precision) + return s; + } else if (((flags & FL_ALT) && (c == 'x' || c == 'X')) + || c == 'p') { + *s++ = '0'; + *s++ = (c == 'X' ? 'X' : 'x'); + } + + switch (c) { + case 'b': base = 2; break; + case 'o': base = 8; break; + case 'd': + case 'i': + case 'u': base = 10; break; + case 'x': + case 'X': + case 'p': base = 16; break; + } + + s = _i_compute(unsigned_val, base, s, precision); + + if (c == 'X') + while (old_s != s) { + *old_s = toupper(*old_s); + old_s++; + } + + return s; +} + + +#define putc(c, p) (--(p)->_count >= 0 ? (int) (*(p)->_ptr++ = (c)) : EOF) + +int +_doprnt(register const char *fmt, va_list ap, __str *stream) +{ + register char *s; + register int j; + int i, c, width, precision, zfill, flags, between_fill; + int nrchars=0; + const char *oldfmt; + char *s1, buf[512]; + + while (c = *fmt++) + { + if (c != '%') + { + if (c == '\n') + { + if (putc('\r', stream) == EOF) + return nrchars ? -nrchars : -1; + nrchars++; + } + if (putc(c, stream) == EOF) + return nrchars ? -nrchars : -1; + nrchars++; + continue; + } + flags = 0; + do { + switch(*fmt) { + case '-': flags |= FL_LJUST; break; + case '+': flags |= FL_SIGN; break; + case ' ': flags |= FL_SPACE; break; + case '#': flags |= FL_ALT; break; + case '0': flags |= FL_ZEROFILL; break; + default: flags |= FL_NOMORE; continue; + } + fmt++; + } while(!(flags & FL_NOMORE)); + + oldfmt = fmt; + fmt = gnum(fmt, &width, &ap); + if (fmt != oldfmt) flags |= FL_WIDTHSPEC; + + if (*fmt == '.') { + fmt++; oldfmt = fmt; + fmt = gnum(fmt, &precision, &ap); + if (precision >= 0) flags |= FL_PRECSPEC; + } + + if ((flags & FL_WIDTHSPEC) && width < 0) { + width = -width; + flags |= FL_LJUST; + } + if (!(flags & FL_WIDTHSPEC)) width = 0; + + if (flags & FL_SIGN) flags &= ~FL_SPACE; + + if (flags & FL_LJUST) flags &= ~FL_ZEROFILL; + + + s = s1 = buf; + + switch (*fmt) { + case 'h': flags |= FL_SHORT; fmt++; break; + case 'l': flags |= FL_LONG; fmt++; break; + case 'L': flags |= FL_LONGDOUBLE; fmt++; break; + } + + switch (c = *fmt++) { + default: + if (c == '\n') { + if (putc('\r', stream) == EOF) + return nrchars ? -nrchars : -1; + nrchars++; + } + if (putc(c, stream) == EOF) + return nrchars ? -nrchars : -1; + nrchars++; + continue; + case 'n': + if (flags & FL_SHORT) + *va_arg(ap, short *) = (short) nrchars; + else if (flags & FL_LONG) + *va_arg(ap, long *) = (long) nrchars; + else + *va_arg(ap, int *) = (int) nrchars; + continue; + case 's': + s1 = va_arg(ap, char *); + if (s1 == NULL) + s1 = "(null)"; + s = s1; + while (precision || !(flags & FL_PRECSPEC)) { + if (*s == '\0') + break; + s++; + precision--; + } + break; + case 'p': + set_pointer(flags); + /* fallthrough */ + case 'b': + case 'o': + case 'u': + case 'x': + case 'X': + if (!(flags & FL_PRECSPEC)) precision = 1; + else if (c != 'p') flags &= ~FL_ZEROFILL; + s = o_print(&ap, flags, s, c, precision, 0); + break; + case 'd': + case 'i': + flags |= FL_SIGNEDCONV; + if (!(flags & FL_PRECSPEC)) precision = 1; + else flags &= ~FL_ZEROFILL; + s = o_print(&ap, flags, s, c, precision, 1); + break; + case 'c': + *s++ = va_arg(ap, int); + break; + + case 'G': + case 'g': + if ((flags & FL_PRECSPEC) && (precision == 0)) + precision = 1; + case 'f': + case 'E': + case 'e': + if (!(flags & FL_PRECSPEC)) + precision = 6; + + if (precision >= sizeof(buf)) + precision = sizeof(buf) - 1; + + flags |= FL_SIGNEDCONV; + s = _f_print(&ap, flags, s, c, precision); + break; + case 'r': + ap = va_arg(ap, va_list); + fmt = va_arg(ap, char *); + continue; + } + zfill = ' '; + if (flags & FL_ZEROFILL) zfill = '0'; + j = s - s1; + + /* between_fill is true under the following conditions: + * 1- the fill character is '0' + * and + * 2a- the number is of the form 0x... or 0X... + * or + * 2b- the number contains a sign or space + */ + between_fill = 0; + if ((flags & FL_ZEROFILL) + && (((c == 'x' || c == 'X') && (flags & FL_ALT) && j > 1) + || (c == 'p') + || ((flags & FL_SIGNEDCONV) + && ( *s1 == '+' || *s1 == '-' || *s1 == ' ')))) + between_fill++; + + if ((i = width - j) > 0) + if (!(flags & FL_LJUST)) { /* right justify */ + nrchars += i; + if (between_fill) { + if (flags & FL_SIGNEDCONV) { + j--; nrchars++; + if (putc(*s1++, stream) == EOF) + return nrchars ? -nrchars : -1; + } else { + j -= 2; nrchars += 2; + if ((putc(*s1++, stream) == EOF) + || (putc(*s1++, stream) == EOF)) + return nrchars ? -nrchars : -1; + } + } + do { + if (putc(zfill, stream) == EOF) + return nrchars ? -nrchars : -1; + } while (--i); + } + + nrchars += j; + while (--j >= 0) { + if (putc(*s1++, stream) == EOF) + return nrchars ? -nrchars : -1; + } + + if (i > 0) nrchars += i; + while (--i >= 0) + if (putc(zfill, stream) == EOF) + return nrchars ? -nrchars : -1; + } + return nrchars; +} + +int +vsnprintf(char *s, size_t n, const char *format, va_list arg) +{ + int retval; + __str tmp_stream; + + //tmp_stream._buf = (unsigned char *) s; + tmp_stream._ptr = (unsigned char *) s; + tmp_stream._count = n-1; + + retval = _doprnt(format, arg, &tmp_stream); + tmp_stream._count = 1; + putc('\0',&tmp_stream); + + return retval; +} + +int +vsprintf(char *s, const char *format, va_list arg) +{ + return vsnprintf(s, INT_MAX, format, arg); +} + + + + + + + + + + + + + + + + + + + + + + diff --git a/programs/system/drivers/rhd/xf86.h b/programs/system/drivers/rhd/xf86.h new file mode 100644 index 000000000..c3236ba9a --- /dev/null +++ b/programs/system/drivers/rhd/xf86.h @@ -0,0 +1,249 @@ + +//#define ATOM_BIOS 1 +//#define ATOM_BIOS_PARSER 1 + +#define OS_BASE 0x80000000 + +#include "xmd.h" + +#define NULL (void*)(0) + +#define FALSE 0 +#define TRUE 1 + +typedef void *pointer; + +typedef unsigned int Bool; + +typedef unsigned char u8_t; +typedef unsigned short u16_t; +typedef unsigned int u32_t; + +typedef unsigned int memType; +typedef unsigned int size_t; + +#define MAX_HSYNC 8 +#define MAX_VREFRESH 8 +#define INTERLACE_REFRESH_WEIGHT 1.5 +#define SYNC_TOLERANCE 0.01 /* 1 percent */ +#define CLOCK_TOLERANCE 2000 /* Clock matching tolerance (2MHz) */ + +typedef struct { float hi, lo; } range; + + +#define STDCALL __attribute__ ((stdcall)) __attribute__ ((dllimport)) +#define IMPORT __attribute__ ((dllimport)) + + +CARD32 STDCALL AllocKernelSpace(unsigned size)__asm__("AllocKernelSpace"); +void* STDCALL KernelAlloc(unsigned size)__asm__("KernelAlloc"); +int KernelFree(void *); + +CARD32 STDCALL MapIoMem(CARD32 Base,CARD32 size,CARD32 flags)__asm__("MapIoMem"); + +u8_t STDCALL PciRead8 (u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead8"); +u16_t STDCALL PciRead16(u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead16"); +u32_t STDCALL PciRead32(u32_t bus, u32_t devfn, u32_t reg)__asm__("PciRead32"); + +#define pciReadLong(tag, reg) \ + PciRead32(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg)) + +u32_t STDCALL PciWrite8 (u32_t bus, u32_t devfn, u32_t reg,u8_t val) __asm__("PciWrite8"); +u32_t STDCALL PciWrite16(u32_t bus, u32_t devfn, u32_t reg,u16_t val)__asm__("PciWrite16"); +u32_t STDCALL PciWrite32(u32_t bus, u32_t devfn, u32_t reg,u32_t val)__asm__("PciWrite32"); + +#define pciWriteLong(tag, reg, val) \ + PciWrite32(PCI_BUS_FROM_TAG(tag),PCI_DFN_FROM_TAG(tag),(reg),(val)) + +void usleep(u32_t delay); + +/////////////////////////////////////////////////////////////////////////////// + +void *malloc(size_t); +void *calloc( size_t num, size_t size ); +void *realloc(void*, size_t); +void free(void*); + + +#define xalloc malloc +#define xnfalloc malloc + +#define xcalloc calloc +#define xnfcalloc calloc + +#define xrealloc realloc + +#define xfree free + +/////////////////////////////////////////////////////////////////////////////// + +void* memset(void *s, int c, size_t n); +void* memcpy(void * dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); + +size_t strlen(const char *str); +char* strcpy(char *to, const char *from); +char* strcat(char *s, const char *append); +char* strdup(const char *s); +char* strchr(const char *s, int c); +int strcmp(const char *s1, const char *s2); + +#define xstrdup strdup + +/////////////////////////////////////////////////////////////////////////////// + +int snprintf(char *s, size_t n, const char *format, ...); +int printf(const char* format, ...); +int dbg_open(char *path); +int dbgprintf(const char* format, ...); + +/////////////////////////////////////////////////////////////////////////////// + +/* These are possible return values for xf86CheckMode() and ValidMode() */ +typedef enum { + MODE_OK = 0, /* Mode OK */ + MODE_HSYNC, /* hsync out of range */ + MODE_VSYNC, /* vsync out of range */ + MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ + MODE_BAD_WIDTH, /* requires an unsupported linepitch */ + MODE_NOMODE, /* no mode with a maching name */ + MODE_NO_INTERLACE, /* interlaced mode not supported */ + MODE_NO_DBLESCAN, /* doublescan mode not supported */ + MODE_NO_VSCAN, /* multiscan mode not supported */ + MODE_MEM, /* insufficient video memory */ + MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ + MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ + MODE_MEM_VIRT, /* insufficient video memory given virtual size */ + MODE_NOCLOCK, /* no fixed clock available */ + MODE_CLOCK_HIGH, /* clock required is too high */ + MODE_CLOCK_LOW, /* clock required is too low */ + MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ + MODE_BAD_HVALUE, /* horizontal timing was out of range */ + MODE_BAD_VVALUE, /* vertical timing was out of range */ + MODE_BAD_VSCAN, /* VScan value out of range */ + MODE_HSYNC_NARROW, /* horizontal sync too narrow */ + MODE_HSYNC_WIDE, /* horizontal sync too wide */ + MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ + MODE_HBLANK_WIDE, /* horizontal blanking too wide */ + MODE_VSYNC_NARROW, /* vertical sync too narrow */ + MODE_VSYNC_WIDE, /* vertical sync too wide */ + MODE_VBLANK_NARROW, /* vertical blanking too narrow */ + MODE_VBLANK_WIDE, /* vertical blanking too wide */ + MODE_PANEL, /* exceeds panel dimensions */ + MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ + MODE_ONE_WIDTH, /* only one width is supported */ + MODE_ONE_HEIGHT, /* only one height is supported */ + MODE_ONE_SIZE, /* only one resolution is supported */ + MODE_BAD = -2, /* unspecified reason */ + MODE_ERROR = -1 /* error condition */ +} ModeStatus; + +typedef enum { + V_PHSYNC = 0x0001, + V_NHSYNC = 0x0002, + V_PVSYNC = 0x0004, + V_NVSYNC = 0x0008, + V_INTERLACE = 0x0010, + V_DBLSCAN = 0x0020, + V_CSYNC = 0x0040, + V_PCSYNC = 0x0080, + V_NCSYNC = 0x0100, + V_HSKEW = 0x0200, /* hskew provided */ + V_BCAST = 0x0400, + V_PIXMUX = 0x1000, + V_DBLCLK = 0x2000, + V_CLKDIV2 = 0x4000 +} ModeFlags; + +# define M_T_DEFAULT 0x10 /* (VESA) default modes */ +# define M_T_USERDEF 0x20 /* One of the modes from the config file */ + + +/* Video mode */ +typedef struct _DisplayModeRec { + struct _DisplayModeRec * prev; + struct _DisplayModeRec * next; + char * name; /* identifier for the mode */ + ModeStatus status; + int type; + + /* These are the values that the user sees/provides */ + int Clock; /* pixel clock freq */ + int HDisplay; /* horizontal timing */ + int HSyncStart; + int HSyncEnd; + int HTotal; + int HSkew; + int VDisplay; /* vertical timing */ + int VSyncStart; + int VSyncEnd; + int VTotal; + int VScan; + int Flags; + + /* These are the values the hardware uses */ + int ClockIndex; + int SynthClock; /* Actual clock freq to + * be programmed */ + int CrtcHDisplay; + int CrtcHBlankStart; + int CrtcHSyncStart; + int CrtcHSyncEnd; + int CrtcHBlankEnd; + int CrtcHTotal; + int CrtcHSkew; + int CrtcVDisplay; + int CrtcVBlankStart; + int CrtcVSyncStart; + int CrtcVSyncEnd; + int CrtcVBlankEnd; + int CrtcVTotal; + Bool CrtcHAdjusted; + Bool CrtcVAdjusted; + int PrivSize; + CARD32* Private; + int PrivFlags; + + float HSync, VRefresh; +} DisplayModeRec, *DisplayModePtr; + +typedef struct +{ + unsigned short red, green, blue; +} LOCO; + + +static void __attribute__ ((always_inline)) +__clear (void * dst, unsigned len) +{ u32_t tmp; + asm __volatile__ + ( + "xor eax, eax \n\t" + "cld \n\t" + "rep stosb" + :"=c"(tmp),"=D"(tmp) + :"c"(len),"D"(dst) + :"memory","eax","cc" + ); +}; + +static int __attribute__ ((always_inline)) +abs (int i) +{ + return i < 0 ? -i : i; +}; + +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 + + + +#define max(x,y) (((y)>(x))?(y):(x)) +#define min(x,y) (((y)<(x))?(y):(x)) + + +#define M_T_BUILTIN 0x01 /* built-in mode */ + diff --git a/programs/system/drivers/rhd/xf86DDC.h b/programs/system/drivers/rhd/xf86DDC.h new file mode 100644 index 000000000..f75964ea7 --- /dev/null +++ b/programs/system/drivers/rhd/xf86DDC.h @@ -0,0 +1,60 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/ddc/xf86DDC.h,v 1.10 2000/06/07 22:03:09 tsi Exp $ */ + +/* xf86DDC.h + * + * This file contains all information to interpret a standard EDIC block + * transmitted by a display device via DDC (Display Data Channel). So far + * there is no information to deal with optional EDID blocks. + * DDC is a Trademark of VESA (Video Electronics Standard Association). + * + * Copyright 1998 by Egbert Eich + */ + + +#ifndef XF86_DDC_H +# define XF86_DDC_H + +#include "xf86i2c.h" +#include "vdif.h" + +//#include "xf86str.h" + +/* speed up / slow down */ +typedef enum { + DDC_SLOW, + DDC_FAST +} xf86ddcSpeed; + +typedef void (* DDC1SetSpeedProc)(RHDPtr, xf86ddcSpeed); + +extern xf86MonPtr xf86DoEDID_DDC1( + RHDPtr rhdPtr, + DDC1SetSpeedProc DDC1SetSpeed, + unsigned int (*DDC1Read)(RHDPtr) +); + +extern xf86MonPtr xf86DoEDID_DDC2(RHDPtr rhdPtr,I2CBusPtr pBus); + +extern xf86MonPtr xf86PrintEDID( + xf86MonPtr monPtr +); + +extern xf86MonPtr xf86InterpretEDID(int scrnIndex, Uchar *block); + +extern xf86vdifPtr xf86InterpretVdif( + CARD8 *c +); + +extern Bool xf86SetDDCproperties( + RHDPtr rhdPtr, + xf86MonPtr DDC +); + +extern void xf86print_vdif( + xf86vdifPtr v +); + + +#endif + + diff --git a/programs/system/drivers/rhd/xf86i2c.c b/programs/system/drivers/rhd/xf86i2c.c new file mode 100644 index 000000000..426eaa892 --- /dev/null +++ b/programs/system/drivers/rhd/xf86i2c.c @@ -0,0 +1,845 @@ +/* + * Copyright (C) 1998 Itai Nahshon, Michael Schimek + * + * The original code was derived from and inspired by + * the I2C driver from the Linux kernel. + * (c) 1998 Gerd Knorr + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.c,v 1.14 2003/05/05 21:18:41 tsi Exp $ */ + +#include "common.h" +#include "rhd.h" +#include "xf86i2c.h" + +#define I2C_TIMEOUT(x) /*(x)*/ /* Report timeouts */ +#define I2C_TRACE(x) /*(x)*/ /* Report progress */ + +/* Set which OSs have bad gettimeofday resolution. */ +#if defined(SVR4) && !defined(sun) +#define BAD_GETTIMEOFDAY_RESOLUTION +#endif + + +/* This is the default I2CUDelay function if not supplied by the driver. + * High level I2C interfaces implementing the bus protocol in hardware + * should supply this function too. + * + * Delay execution at least usec microseconds. + * All values 0 to 1e6 inclusive must be expected. + */ + +static int bogo_usec = 500; + +static void +I2CUDelay(I2CBusPtr b, int usec) +{ + volatile long i; + + if (usec > 0) + for (i = usec * bogo_usec; i > 0; i--) + /* (perhaps hw delay action) */; +} + +/* Most drivers will register just with GetBits/PutBits functions. + * The following functions implement a software I2C protocol + * by using the promitive functions given by the driver. + * ================================================================ + * + * It is assumed that there is just one master on the I2C bus, therefore + * there is no explicit test for conflits. + */ + +#define RISEFALLTIME 2 /* usec, actually 300 to 1000 ns according to the i2c specs */ + +/* Some devices will hold SCL low to slow down the bus or until + * ready for transmission. + * + * This condition will be noticed when the master tries to raise + * the SCL line. You can set the timeout to zero if the slave device + * does not support this clock synchronization. + */ + +static Bool +I2CRaiseSCL(I2CBusPtr b, int sda, int timeout) +{ + int i, scl; + + b->I2CPutBits(b, 1, sda); + b->I2CUDelay(b, b->RiseFallTime); + + for (i = timeout; i > 0; i -= b->RiseFallTime) { + b->I2CGetBits(b, &scl, &sda); + if (scl) break; + b->I2CUDelay(b, b->RiseFallTime); + } + + if (i <= 0) { +// I2C_TIMEOUT(ErrorF("[I2CRaiseSCL(<%s>, %d, %d) timeout]", b->BusName, sda, timeout)); + return FALSE; + } + + return TRUE; +} + +/* Send a start signal on the I2C bus. The start signal notifies + * devices that a new transaction is initiated by the bus master. + * + * The start signal is always followed by a slave address. + * Slave addresses are 8+ bits. The first 7 bits identify the + * device and the last bit signals if this is a read (1) or + * write (0) operation. + * + * There may be more than one start signal on one transaction. + * This happens for example on some devices that allow reading + * of registers. First send a start bit followed by the device + * address (with the last bit 0) and the register number. Then send + * a new start bit with the device address (with the last bit 1) + * and then read the value from the device. + * + * Note this is function does not implement a multiple master + * arbitration procedure. + */ + +static Bool +I2CStart(I2CBusPtr b, int timeout) +{ + if (!I2CRaiseSCL(b, 1, timeout)) + return FALSE; + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->HoldTime); + + // I2C_TRACE(ErrorF("\ni2c: <")); + + return TRUE; +} + +/* This is the default I2CStop function if not supplied by the driver. + * + * Signal devices on the I2C bus that a transaction on the + * bus has finished. There may be more than one start signal + * on a transaction but only one stop signal. + */ + +static void +I2CStop(I2CDevPtr d) +{ + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 0); + b->I2CUDelay(b, b->RiseFallTime); + + b->I2CPutBits(b, 1, 0); + b->I2CUDelay(b, b->HoldTime); + b->I2CPutBits(b, 1, 1); + b->I2CUDelay(b, b->HoldTime); + + I2C_TRACE(ErrorF(">\n")); +} + +/* Write/Read a single bit to/from a device. + * Return FALSE if a timeout occurs. + */ + +static Bool +I2CWriteBit(I2CBusPtr b, int sda, int timeout) +{ + Bool r; + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, sda, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CPutBits(b, 0, sda); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +static Bool +I2CReadBit(I2CBusPtr b, int *psda, int timeout) +{ + Bool r; + int scl; + + r = I2CRaiseSCL(b, 1, timeout); + b->I2CUDelay(b, b->HoldTime); + + b->I2CGetBits(b, &scl, psda); + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CPutByte function if not supplied by the driver. + * + * A single byte is sent to the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than BitTimeout usecs for each bit, + * or does not send an ACK bit (0) to acknowledge the transmission within + * AcknTimeout usecs, but a NACK (1) bit. + * + * AcknTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + */ + +static Bool +I2CPutByte(I2CDevPtr d, I2CByte data) +{ + Bool r; + int i, scl, sda; + I2CBusPtr b = d->pI2CBus; + + if (!I2CWriteBit(b, (data >> 7) & 1, d->ByteTimeout)) + return FALSE; + + for (i = 6; i >= 0; i--) + if (!I2CWriteBit(b, (data >> i) & 1, d->BitTimeout)) + return FALSE; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + r = I2CRaiseSCL(b, 1, b->HoldTime); + + if (r) + { + for (i = d->AcknTimeout; i > 0; i -= b->HoldTime) + { + b->I2CUDelay(b, b->HoldTime); + b->I2CGetBits(b, &scl, &sda); + if (sda == 0) break; + } + if (i <= 0) + { + // I2C_TIMEOUT(ErrorF("[I2CPutByte(<%s>, 0x%02x, %d, %d, %d) timeout]", + // b->BusName, data, d->BitTimeout, + // d->ByteTimeout, d->AcknTimeout)); + r = FALSE; + } + +// I2C_TRACE(ErrorF("W%02x%c ", (int) data, sda ? '-' : '+')); + } + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->HoldTime); + + return r; +} + +/* This is the default I2CGetByte function if not supplied by the driver. + * + * A single byte is read from the device. + * The function returns FALSE if a timeout occurs, you should send + * a stop condition afterwards to reset the bus. + * + * A timeout occurs, + * if the slave pulls SCL to slow down the bus more than ByteTimeout usecs, + * or slows down the bus for more than b->BitTimeout usecs for each bit. + * + * ByteTimeout must be at least b->HoldTime, the other timeouts can be + * zero according to the comment on I2CRaiseSCL. + * + * For the byte in a sequence the acknowledge bit NACK (1), + * otherwise ACK (0) will be sent. + */ + +static Bool +I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) +{ + int i, sda; + I2CBusPtr b = d->pI2CBus; + + b->I2CPutBits(b, 0, 1); + b->I2CUDelay(b, b->RiseFallTime); + + if (!I2CReadBit(b, &sda, d->ByteTimeout)) + return FALSE; + + *data = (sda > 0) << 7; + + for (i = 6; i >= 0; i--) + if (!I2CReadBit(b, &sda, d->BitTimeout)) + return FALSE; + else + *data |= (sda > 0) << i; + + if (!I2CWriteBit(b, last ? 1 : 0, d->BitTimeout)) + return FALSE; + +// I2C_TRACE(ErrorF("R%02x%c ", (int) *data, last ? '+' : '-')); + + return TRUE; +} + +/* This is the default I2CAddress function if not supplied by the driver. + * + * It creates the start condition, followed by the d->SlaveAddr. + * Higher level functions must call this routine rather than + * I2CStart/PutByte because a hardware I2C master may not be able + * to send a slave address without a start condition. + * + * The same timeouts apply as with I2CPutByte and additional a + * StartTimeout, similar to the ByteTimeout but for the start + * condition. + * + * In case of a timeout, the bus is left in a clean idle condition. + * I. e. you *must not* send a Stop. If this function succeeds, you *must*. + * + * The slave address format is 16 bit, with the legacy _8_bit_ slave address + * in the least significant byte. This is, the slave address must include the + * R/_W flag as least significant bit. + * + * The most significant byte of the address will be sent _after_ the LSB, + * but only if the LSB indicates: + * a) an 11 bit address, this is LSB = 1111 0xxx. + * b) a 'general call address', this is LSB = 0000 000x - see the I2C specs + * for more. + */ + +static Bool +I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) +{ + if (I2CStart(d->pI2CBus, d->StartTimeout)) { + if (I2CPutByte(d, addr & 0xFF)) { + if ((addr & 0xF8) != 0xF0 && + (addr & 0xFE) != 0x00) + return TRUE; + + if (I2CPutByte(d, (addr >> 8) & 0xFF)) + return TRUE; + } + + I2CStop(d); + } + + return FALSE; +} + +/* These are the hardware independent I2C helper functions. + * ======================================================== + */ + +/* Function for probing. Just send the slave address + * and return true if the device responds. The slave address + * must have the lsb set to reflect a read (1) or write (0) access. + * Don't expect a read- or write-only device will respond otherwise. + */ + +Bool +xf86I2CProbeAddress(I2CBusPtr b, I2CSlaveAddr addr) +{ + int r; + I2CDevRec d; + + d.DevName = "Probing"; + d.BitTimeout = b->BitTimeout; + d.ByteTimeout = b->ByteTimeout; + d.AcknTimeout = b->AcknTimeout; + d.StartTimeout = b->StartTimeout; + d.SlaveAddr = addr; + d.pI2CBus = b; + d.NextDev = NULL; + + r = b->I2CAddress(&d, addr); + + if (r) b->I2CStop(&d); + + return r; +} + +/* All functions below are related to devices and take the + * slave address and timeout values from an I2CDevRec. They + * return FALSE in case of an error (presumably a timeout). + */ + +/* General purpose read and write function. + * + * 1st, if nWrite > 0 + * Send a start condition + * Send the slave address (1 or 2 bytes) with write flag + * Write n bytes from WriteBuffer + * 2nd, if nRead > 0 + * Send a start condition [again] + * Send the slave address (1 or 2 bytes) with read flag + * Read n bytes to ReadBuffer + * 3rd, if a Start condition has been successfully sent, + * Send a Stop condition. + * + * The functions exits immediately when an error occures, + * not proceeding any data left. However, step 3 will + * be executed anyway to leave the bus in clean idle state. + */ + +static Bool +I2CWriteRead(I2CDevPtr d, + I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + Bool r = TRUE; + I2CBusPtr b = d->pI2CBus; + int s = 0; + + if (r && nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r) { + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + s++; + } + } + + if (r && nRead > 0) { + r = b->I2CAddress(d, d->SlaveAddr | 1); + if (r) { + for (; nRead > 0; ReadBuffer++, nRead--) + if (!(r = b->I2CGetByte(d, ReadBuffer, nRead == 1))) + break; + s++; + } + } + + if (s) b->I2CStop(d); + + return r; +} + +/* wrapper - for compatibility and convinience */ + +Bool +xf86I2CWriteRead(I2CDevPtr d, + I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + RHDFUNC(d); + + I2CBusPtr b = d->pI2CBus; + return b->I2CWriteRead(d,WriteBuffer,nWrite,ReadBuffer,nRead); +} + +/* Read a byte, the only readable register of a device. + */ + +Bool +xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, NULL, 0, pbyte, 1); +} + +/* Read a byte from one of the registers determined by its sub-address. + */ + +Bool +xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, 1); +} + +/* Read bytes from subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n) +{ + return xf86I2CWriteRead(d, &subaddr, 1, pbyte, n); +} + +/* Read a word (high byte, then low byte) from one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword) +{ + I2CByte rb[2]; + + if (!xf86I2CWriteRead(d, &subaddr, 1, rb, 2)) return FALSE; + + *pword = (rb[0] << 8) | rb[1]; + + return TRUE; +} + +/* Write a byte to one of the registers determined by its sub-address. + */ + +Bool +xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte) +{ + I2CByte wb[2]; + + wb[0] = subaddr; + wb[1] = byte; + + return xf86I2CWriteRead(d, wb, 2, NULL, 0); +} + +/* Write bytes to subsequent registers determined by the + * sub-address of the first register. + */ + +Bool +xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, + I2CByte *WriteBuffer, int nWrite) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + + if (nWrite > 0) { + r = b->I2CAddress(d, d->SlaveAddr & ~1); + if (r){ + if ((r = b->I2CPutByte(d, subaddr))) + for (; nWrite > 0; WriteBuffer++, nWrite--) + if (!(r = b->I2CPutByte(d, *WriteBuffer))) + break; + + b->I2CStop(d); + } + } + + return r; +} + +/* Write a word (high byte, then low byte) to one of the registers + * determined by its sub-address. + */ + +Bool +xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word) +{ + I2CByte wb[3]; + + wb[0] = subaddr; + wb[1] = word >> 8; + wb[2] = word & 0xFF; + + return xf86I2CWriteRead(d, wb, 3, NULL, 0); +} + +/* Write a vector of bytes to not adjacent registers. This vector is, + * 1st byte sub-address, 2nd byte value, 3rd byte sub-address asf. + * This function is intended to initialize devices. Note this function + * exits immediately when an error occurs, some registers may + * remain uninitialized. + */ + +Bool +xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues) +{ + I2CBusPtr b = d->pI2CBus; + Bool r = TRUE; + int s = 0; + + if (nValues > 0) { + for (; nValues > 0; nValues--, vec += 2) { + if (!(r = b->I2CAddress(d, d->SlaveAddr & ~1))) + break; + + s++; + + if (!(r = b->I2CPutByte(d, vec[0]))) + break; + + if (!(r = b->I2CPutByte(d, vec[1]))) + break; + } + + if (s > 0) b->I2CStop(d); + } + + return r; +} + +/* Administrative functions. + * ========================= + */ + +/* Allocates an I2CDevRec for you and initializes with propper defaults + * you may modify before calling xf86I2CDevInit. Your I2CDevRec must + * contain at least a SlaveAddr, and a pI2CBus pointer to the bus this + * device shall be linked to. + * + * See function I2CAddress for the slave address format. Always set + * the least significant bit, indicating a read or write access, to zero. + */ + +I2CDevPtr +xf86CreateI2CDevRec(void) +{ + return calloc(1, sizeof(I2CDevRec)); +} + +/* Unlink an I2C device. If you got the I2CDevRec from xf86CreateI2CDevRec + * you should set to free it. + */ + +void +xf86DestroyI2CDevRec(I2CDevPtr d, Bool unalloc) +{ + if (d) { + I2CDevPtr *p; + + /* Remove this from the list of active I2C devices. */ + + for (p = &d->pI2CBus->FirstDev; *p != NULL; p = &(*p)->NextDev) + if (*p == d) { + *p = (*p)->NextDev; + break; + } + + dbgprintf("I2C device \"%s:%s\" removed.\n", + d->pI2CBus->BusName, d->DevName); + + if (unalloc) free(d); + } +} + +/* I2C transmissions are related to an I2CDevRec you must link to a + * previously registered bus (see xf86I2CBusInit) before attempting + * to read and write data. You may call xf86I2CProbeAddress first to + * see if the device in question is present on this bus. + * + * xf86I2CDevInit will not allocate an I2CBusRec for you, instead you + * may enter a pointer to a statically allocated I2CDevRec or the (modified) + * result of xf86CreateI2CDevRec. + * + * If you don't specify timeouts for the device (n <= 0), it will inherit + * the bus-wide defaults. The function returns TRUE on success. + */ + +Bool +xf86I2CDevInit(I2CDevPtr d) +{ + I2CBusPtr b; + RHDFUNC(d); + + if (d == NULL || (b = d->pI2CBus) == NULL || + (d->SlaveAddr & 1) || xf86I2CFindDev(b, d->SlaveAddr) != NULL) + return FALSE; + + if (d->BitTimeout <= 0) d->BitTimeout = b->BitTimeout; + if (d->ByteTimeout <= 0) d->ByteTimeout = b->ByteTimeout; + if (d->AcknTimeout <= 0) d->AcknTimeout = b->AcknTimeout; + if (d->StartTimeout <= 0) d->StartTimeout = b->StartTimeout; + + d->NextDev = b->FirstDev; + b->FirstDev = d; + + dbgprintf("I2C device \"%s:%s\" registered at address 0x%x.\n", + b->BusName, d->DevName, d->SlaveAddr); + + return TRUE; +} + +I2CDevPtr +xf86I2CFindDev(I2CBusPtr b, I2CSlaveAddr addr) +{ + I2CDevPtr d; + + if (b) { + for (d = b->FirstDev; d != NULL; d = d->NextDev) + if (d->SlaveAddr == addr) + return d; + } + + return NULL; +} + +static I2CBusPtr I2CBusList; + +/* Allocates an I2CBusRec for you and initializes with propper defaults + * you may modify before calling xf86I2CBusInit. Your I2CBusRec must + * contain at least a BusName, a scrnIndex (or -1), and a complete set + * of either high or low level I2C function pointers. You may pass + * bus-wide timeouts, otherwise inplausible values will be replaced + * with safe defaults. + */ + +I2CBusPtr xf86CreateI2CBusRec(void) +{ + I2CBusPtr b; + + b = (I2CBusPtr) calloc(1, sizeof(I2CBusRec)); + + if (b != NULL) + { + b->scrnIndex = -1; + b->HoldTime = 5; /* 100 kHz bus */ + b->BitTimeout = 5; + b->ByteTimeout = 5; + b->AcknTimeout = 5; + b->StartTimeout = 5; + b->RiseFallTime = RISEFALLTIME; + } + return b; +} + +/* Unregister an I2C bus. If you got the I2CBusRec from xf86CreateI2CBusRec + * you should set to free it. If you set , the function + * xf86DestroyI2CDevRec will be called for all devices linked to the bus + * first, passing down the option. + */ + +void +xf86DestroyI2CBusRec(I2CBusPtr b, Bool unalloc, Bool devs_too) +{ + if (b) { + I2CBusPtr *p; + + /* Remove this from the list of active I2C buses */ + + for (p = &I2CBusList; *p != NULL; p = &(*p)->NextBus) + if (*p == b) { + *p = (*p)->NextBus; + break; + } + + if (b->FirstDev != NULL) { + if (devs_too) { + I2CDevPtr d; + + while ((d = b->FirstDev) != NULL) { + b->FirstDev = d->NextDev; + xf86DestroyI2CDevRec(d, unalloc); + } + } else { + if (unalloc) { + dbgprintf("i2c bug: Attempt to remove I2C bus \"%s\", " + "but device list is not empty.\n", + b->BusName); + return; + } + } + } + + dbgprintf("I2C bus \"%s\" removed.\n", b->BusName); + + if (unalloc) free(b); + } +} + +/* I2C masters have to register themselves using this function. + * It will not allocate an I2CBusRec for you, instead you may enter + * a pointer to a statically allocated I2CBusRec or the (modified) + * result of xf86CreateI2CBusRec. Returns TRUE on success. + * + * At this point there won't be any traffic on the I2C bus. + */ + +Bool xf86I2CBusInit(I2CBusPtr b) +{ + /* I2C buses must be identified by a unique scrnIndex + * and name. If scrnIndex is unspecified (a negative value), + * then the name must be unique throughout the server. + */ + + if (b->BusName == NULL || + xf86I2CFindBus(b->scrnIndex, b->BusName) != NULL) + return FALSE; + + /* If the high level functions are not + * supplied, use the generic functions. + * In this case we need the low-level + * function. + */ + if (b->I2CWriteRead == NULL) + { + b->I2CWriteRead=I2CWriteRead; + + if (b->I2CPutBits == NULL || + b->I2CGetBits == NULL) + { + if (b->I2CPutByte == NULL || + b->I2CGetByte == NULL || + b->I2CAddress == NULL || + b->I2CStart == NULL || + b->I2CStop == NULL) + return FALSE; + } + else + { + b->I2CPutByte = I2CPutByte; + b->I2CGetByte = I2CGetByte; + b->I2CAddress = I2CAddress; + b->I2CStop = I2CStop; + b->I2CStart = I2CStart; + } + } + + if (b->I2CUDelay == NULL) + b->I2CUDelay = I2CUDelay; + + if (b->HoldTime < 2) b->HoldTime = 5; + if (b->BitTimeout <= 0) b->BitTimeout = b->HoldTime; + if (b->ByteTimeout <= 0) b->ByteTimeout = b->HoldTime; + if (b->AcknTimeout <= 0) b->AcknTimeout = b->HoldTime; + if (b->StartTimeout <= 0) b->StartTimeout = b->HoldTime; + + /* Put new bus on list. */ + + b->NextBus = I2CBusList; + I2CBusList = b; + + dbgprintf("I2C bus \"%s\" initialized.\n",b->BusName); + + return TRUE; +} + +I2CBusPtr +xf86I2CFindBus(RHDPtr rhdPtr, char *name) +{ + I2CBusPtr p; + + if (name != NULL) + for (p = I2CBusList; p != NULL; p = p->NextBus) + if ((rhdPtr==(RHDPtr)-1) ||(p->scrnIndex == (int)rhdPtr)) + if (!strcmp(p->BusName, name)) + return p; + + return NULL; +} +/* + * Return an array of I2CBusPtr's related to a screen. The caller is + * responsible for freeing the array. + */ + +/* +int +xf86I2CGetScreenBuses(RHDPtr rhdPtr, I2CBusPtr **pppI2CBus) +{ + I2CBusPtr pI2CBus; + int n = 0; + + if (pppI2CBus) + *pppI2CBus = NULL; + + for (pI2CBus = I2CBusList; pI2CBus; pI2CBus = pI2CBus->NextBus) + { + if ((pI2CBus->rhdPtr >= 0) && (pI2CBus->rhdPtr != rhdPtr)) + continue; + + n++; + + if (!pppI2CBus) + continue; + + *pppI2CBus = xnfrealloc(*pppI2CBus, n * sizeof(I2CBusPtr)); + *pppI2CBus[n - 1] = pI2CBus; + } + return n; +} + +*/ diff --git a/programs/system/drivers/rhd/xf86i2c.h b/programs/system/drivers/rhd/xf86i2c.h new file mode 100644 index 000000000..2cb89ee91 --- /dev/null +++ b/programs/system/drivers/rhd/xf86i2c.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 1998 Itai Nahshon, Michael Schimek + */ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/i2c/xf86i2c.h,v 1.10 2003/07/16 01:38:47 dawes Exp $ */ +#ifndef _XF86I2C_H +#define _XF86I2C_H + +//#include "regionstr.h" + +typedef unsigned char I2CByte; +typedef unsigned short I2CSlaveAddr; + +typedef struct _I2CBusRec *I2CBusPtr; +typedef struct _I2CDevRec *I2CDevPtr; + +/* I2C masters have to register themselves */ + +typedef union _DevUnion { + pointer ptr; + long val; + unsigned long uval; +} DevUnion; + + + +typedef struct _I2CBusRec { + char * BusName; + int scrnIndex; + + void (*I2CUDelay) (I2CBusPtr b, int usec); + + void (*I2CPutBits)(I2CBusPtr b, int scl, int sda); + void (*I2CGetBits)(I2CBusPtr b, int *scl, int *sda); + + /* Look at the generic routines to see how these functions should behave. */ + + Bool (*I2CStart) (I2CBusPtr b, int timeout); + Bool (*I2CAddress)(I2CDevPtr d, I2CSlaveAddr); + void (*I2CStop) (I2CDevPtr d); + Bool (*I2CPutByte)(I2CDevPtr d, I2CByte data); + Bool (*I2CGetByte)(I2CDevPtr d, I2CByte *data, Bool); + + DevUnion DriverPrivate; + + int HoldTime; /* 1 / bus clock frequency, 5 or 2 usec */ + + int BitTimeout; /* usec */ + int ByteTimeout; /* usec */ + int AcknTimeout; /* usec */ + int StartTimeout; /* usec */ + int RiseFallTime; /* usec */ + + I2CDevPtr FirstDev; + I2CBusPtr NextBus; + Bool (*I2CWriteRead)(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead); +} I2CBusRec; + +I2CBusPtr xf86CreateI2CBusRec(void); +void xf86DestroyI2CBusRec(I2CBusPtr pI2CBus, Bool unalloc, Bool devs_too); +Bool xf86I2CBusInit(I2CBusPtr pI2CBus); +I2CBusPtr xf86I2CFindBus(RHDPtr rhdPtr, char *name); +int xf86I2CGetScreenBuses(RHDPtr rhdPtr, I2CBusPtr **pppI2CBus); + + +/* I2C slave devices */ + +typedef struct _I2CDevRec { + char * DevName; + + int BitTimeout; /* usec */ + int ByteTimeout; /* usec */ + int AcknTimeout; /* usec */ + int StartTimeout; /* usec */ + + I2CSlaveAddr SlaveAddr; + I2CBusPtr pI2CBus; + I2CDevPtr NextDev; + DevUnion DriverPrivate; +} I2CDevRec; + +I2CDevPtr xf86CreateI2CDevRec(void); +void xf86DestroyI2CDevRec(I2CDevPtr pI2CDev, Bool unalloc); +Bool xf86I2CDevInit(I2CDevPtr pI2CDev); +I2CDevPtr xf86I2CFindDev(I2CBusPtr, I2CSlaveAddr); + +/* See descriptions of these functions in xf86i2c.c */ + +Bool xf86I2CProbeAddress(I2CBusPtr pI2CBus, I2CSlaveAddr); +Bool xf86I2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead); +#define xf86I2CRead(d, rb, nr) xf86I2CWriteRead(d, NULL, 0, rb, nr) +Bool xf86I2CReadStatus(I2CDevPtr d, I2CByte *pbyte); +Bool xf86I2CReadByte(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte); +Bool xf86I2CReadBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *pbyte, int n); +Bool xf86I2CReadWord(I2CDevPtr d, I2CByte subaddr, unsigned short *pword); +#define xf86I2CWrite(d, wb, nw) xf86I2CWriteRead(d, wb, nw, NULL, 0) +Bool xf86I2CWriteByte(I2CDevPtr d, I2CByte subaddr, I2CByte byte); +Bool xf86I2CWriteBytes(I2CDevPtr d, I2CByte subaddr, I2CByte *WriteBuffer, int nWrite); +Bool xf86I2CWriteWord(I2CDevPtr d, I2CByte subaddr, unsigned short word); +Bool xf86I2CWriteVec(I2CDevPtr d, I2CByte *vec, int nValues); + +#endif /*_XF86I2C_H */