xenocara/driver/xf86-video-ati/src/radeon_atombios.c
matthieu f74c2dba55 update do xf86-video-ati 6.12.2
This has been in snapshots for weeks. ok oga@, todd@.
2009-08-25 18:51:44 +00:00

2689 lines
84 KiB
C

/*
* Copyright 2007 Egbert Eich <eich@novell.com>
* Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
* Copyright 2007 Matthias Hopf <mhopf@novell.com>
* 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 "xf86_OSproc.h"
#include "radeon.h"
#include "radeon_atombios.h"
#include "radeon_atomwrapper.h"
#include "radeon_probe.h"
#include "radeon_macros.h"
#include "ati_pciids_gen.h"
#include "xorg-server.h"
/* only for testing now */
#include "xf86DDC.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 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 rhdAtomCVGetTimings(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);*/
# ifdef ATOM_BIOS_PARSER
static AtomBiosResult rhdAtomExec(atomBiosHandlePtr handle,
AtomBiosRequestID unused, AtomBiosArgPtr data);
# endif
static AtomBiosResult
rhdAtomCompassionateDataQuery(atomBiosHandlePtr handle,
AtomBiosRequestID func, AtomBiosArgPtr data);
static void
RADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds);
enum msgDataFormat {
MSG_FORMAT_NONE,
MSG_FORMAT_HEX,
MSG_FORMAT_DEC
};
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_PANEL_MODE, rhdAtomLvdsGetTimings,
"AtomBIOS Get Panel Mode", MSG_FORMAT_NONE},
{ATOMBIOS_GET_PANEL_EDID, rhdAtomLvdsGetTimings,
"AtomBIOS Get Panel EDID", 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_FREQUENCY, rhdAtomTmdsInfoQuery,
"TMDS 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_DITHER, rhdAtomLvdsInfoQuery,
"LVDS Ditherc", 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_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_CRTC2_DAC_ADJ, rhdAtomCompassionateDataQuery,
"DAC2_CRTC2 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},
{ATOMBIOS_GET_CV_MODES, rhdAtomCVGetTimings,
"AtomBIOS Get CV Mode", MSG_FORMAT_NONE},
{FUNC_END, NULL,
NULL, MSG_FORMAT_NONE}
};
enum {
legacyBIOSLocation = 0xC0000,
legacyBIOSMax = 0x10000
};
#define DEBUGP(x) {x;}
#define LOG_DEBUG 7
# ifdef ATOM_BIOS_PARSER
# define LOG_CAIL LOG_DEBUG + 1
#if 0
static void
RHDDebug(int scrnIndex, const char *format, ...)
{
va_list ap;
va_start(ap, format);
xf86VDrvMsgVerb(scrnIndex, X_INFO, LOG_DEBUG, format, ap);
va_end(ap);
}
static void
RHDDebugCont(const char *format, ...)
{
va_list ap;
va_start(ap, format);
xf86VDrvMsgVerb(-1, X_NONE, LOG_DEBUG, format, ap);
va_end(ap);
}
#endif
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
static int
rhdAtomAnalyzeCommonHdr(ATOM_COMMON_TABLE_HEADER *hdr)
{
if (le16_to_cpu(hdr->usStructureSize) == 0xaa55)
return FALSE;
return TRUE;
}
static int
rhdAtomAnalyzeRomHdr(unsigned char *rombase,
ATOM_ROM_HEADER *hdr,
unsigned int *data_offset,
unsigned int *command_offset)
{
if (!rhdAtomAnalyzeCommonHdr(&hdr->sHeader)) {
return FALSE;
}
xf86DrvMsg(-1,X_NONE,"\tSubsystemVendorID: 0x%4.4x SubsystemID: 0x%4.4x\n",
le16_to_cpu(hdr->usSubsystemVendorID),le16_to_cpu(hdr->usSubsystemID));
xf86DrvMsg(-1,X_NONE,"\tIOBaseAddress: 0x%4.4x\n",le16_to_cpu(hdr->usIoBaseAddress));
xf86DrvMsgVerb(-1,X_NONE,3,"\tFilename: %s\n",rombase + le16_to_cpu(hdr->usConfigFilenameOffset));
xf86DrvMsgVerb(-1,X_NONE,3,"\tBIOS Bootup Message: %s\n",
rombase + le16_to_cpu(hdr->usBIOS_BootupMessageOffset));
*data_offset = le16_to_cpu(hdr->usMasterDataTableOffset);
*command_offset = le16_to_cpu(hdr->usMasterCommandTableOffset);
return TRUE;
}
static int
rhdAtomAnalyzeRomDataTable(unsigned char *base, uint16_t offset,
void *ptr,unsigned short *size)
{
ATOM_COMMON_TABLE_HEADER *table = (ATOM_COMMON_TABLE_HEADER *)
(base + le16_to_cpu(offset));
if (!*size || !rhdAtomAnalyzeCommonHdr(table)) {
if (*size) *size -= 2;
*(void **)ptr = NULL;
return FALSE;
}
*size -= 2;
*(void **)ptr = (void *)(table);
return TRUE;
}
Bool
rhdAtomGetTableRevisionAndSize(ATOM_COMMON_TABLE_HEADER *hdr,
uint8_t *contentRev,
uint8_t *formatRev,
unsigned short *size)
{
if (!hdr)
return FALSE;
if (contentRev) *contentRev = hdr->ucTableContentRevision;
if (formatRev) *formatRev = hdr->ucTableFormatRevision;
if (size) *size = (short)le16_to_cpu(hdr->usStructureSize)
- sizeof(ATOM_COMMON_TABLE_HEADER);
return TRUE;
}
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_VERS(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
rhdAtomGetDataTable(int scrnIndex,
unsigned char *base,
atomDataTables *atomDataPtr,
unsigned int *cmd_offset,
unsigned int BIOSImageSize)
{
unsigned int data_offset;
unsigned int atom_romhdr_off = le16_to_cpu(*(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, cmd_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__);
}
if (*cmd_offset + sizeof (ATOM_MASTER_COMMAND_TABLE) > BIOSImageSize) {
xf86DrvMsg(scrnIndex,X_ERROR,"%s: Atom command table outside of BIOS\n",
__func__);
}
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->scrnIndex, 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->scrnIndex, 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 & ~(uint32_t)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
Bool
rhdAtomASICInit(atomBiosHandlePtr handle)
{
ASIC_INIT_PS_ALLOCATION asicInit;
AtomBiosArgRec data;
RHDAtomBiosFunc(handle->scrnIndex, handle,
GET_DEFAULT_ENGINE_CLOCK,
&data);
asicInit.sASICInitClocks.ulDefaultEngineClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
RHDAtomBiosFunc(handle->scrnIndex, handle,
GET_DEFAULT_MEMORY_CLOCK,
&data);
asicInit.sASICInitClocks.ulDefaultMemoryClock = cpu_to_le32(data.val / 10);/*in 10 Khz*/
data.exec.dataSpace = NULL;
data.exec.index = 0x0;
data.exec.pspace = &asicInit;
xf86DrvMsg(handle->scrnIndex, X_INFO, "Calling ASIC Init\n");
if (RHDAtomBiosFunc(handle->scrnIndex, 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;
}
int
atombios_dyn_clk_setup(ScrnInfoPtr pScrn, int enable)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
DYNAMIC_CLOCK_GATING_PS_ALLOCATION dynclk_data;
AtomBiosArgRec data;
unsigned char *space;
dynclk_data.ucEnable = enable;
data.exec.index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
data.exec.dataSpace = (void *)&space;
data.exec.pspace = &dynclk_data;
if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
ErrorF("Dynamic clock gating %s success\n", enable? "enable" : "disable");
return ATOM_SUCCESS;
}
ErrorF("Dynamic clock gating %s failure\n", enable? "enable" : "disable");
return ATOM_NOT_IMPLEMENTED;
}
int
atombios_static_pwrmgt_setup(ScrnInfoPtr pScrn, int enable)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION pwrmgt_data;
AtomBiosArgRec data;
unsigned char *space;
pwrmgt_data.ucEnable = enable;
data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);
data.exec.dataSpace = (void *)&space;
data.exec.pspace = &pwrmgt_data;
if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) {
ErrorF("Static power management %s success\n", enable? "enable" : "disable");
return ATOM_SUCCESS;
}
ErrorF("Static power management %s failure\n", enable? "enable" : "disable");
return ATOM_NOT_IMPLEMENTED;
}
# endif
static AtomBiosResult
rhdAtomInit(atomBiosHandlePtr unused1, AtomBiosRequestID unused2,
AtomBiosArgPtr data)
{
int scrnIndex = data->val;
RADEONInfoPtr info = RADEONPTR(xf86Screens[scrnIndex]);
atomDataTablesPtr atomDataPtr;
unsigned int cmd_offset;
atomBiosHandlePtr handle = NULL;
unsigned int BIOSImageSize = 0;
data->atomhandle = NULL;
#ifdef XSERVER_LIBPCIACCESS
BIOSImageSize = info->PciInfo->rom_size > RADEON_VBIOS_SIZE ? info->PciInfo->rom_size : RADEON_VBIOS_SIZE;
#else
BIOSImageSize = RADEON_VBIOS_SIZE;
#endif
if (!(atomDataPtr = xcalloc(1, sizeof(atomDataTables)))) {
xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory for "
"ATOM BIOS data tabes\n");
goto error;
}
if (!rhdAtomGetDataTable(scrnIndex, info->VBIOS, atomDataPtr, &cmd_offset, BIOSImageSize))
goto error1;
if (!(handle = xcalloc(1, sizeof(atomBiosHandleRec)))) {
xf86DrvMsg(scrnIndex,X_ERROR,"Cannot allocate memory\n");
goto error1;
}
handle->BIOSBase = info->VBIOS;
handle->atomDataPtr = atomDataPtr;
handle->cmd_offset = cmd_offset;
handle->scrnIndex = scrnIndex;
#if XSERVER_LIBPCIACCESS
handle->device = info->PciInfo;
#else
handle->PciTag = info->PciTag;
#endif
handle->BIOSImageSize = BIOSImageSize;
data->atomhandle = handle;
return ATOM_SUCCESS;
error1:
xfree(atomDataPtr);
error:
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;
uint32_t *val = &data->val;
//RHDFUNC(handle);
atomDataPtr = handle->atomDataPtr;
switch (func) {
case GET_FW_FB_START:
if (atomDataPtr->VRAM_UsageByFirmware)
*val = le32_to_cpu(atomDataPtr->VRAM_UsageByFirmware
->asFirmwareVramReserveInfo[0].ulStartAddrUsedByFirmware);
else
return ATOM_NOT_IMPLEMENTED;
break;
case GET_FW_FB_SIZE:
if (atomDataPtr->VRAM_UsageByFirmware)
*val = le16_to_cpu(atomDataPtr->VRAM_UsageByFirmware
->asFirmwareVramReserveInfo[0].usFirmwareUseInKb);
else
return ATOM_NOT_IMPLEMENTED;
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
return ATOM_SUCCESS;
}
static AtomBiosResult
rhdAtomTmdsInfoQuery(atomBiosHandlePtr handle,
AtomBiosRequestID func, AtomBiosArgPtr data)
{
atomDataTablesPtr atomDataPtr;
uint32_t *val = &data->val;
int idx = *val;
atomDataPtr = handle->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->TMDS_Info),
NULL,NULL,NULL)) {
return ATOM_FAILED;
}
//RHDFUNC(handle);
switch (func) {
case ATOM_TMDS_FREQUENCY:
*val = le16_to_cpu(atomDataPtr->TMDS_Info->asMiscInfo[idx].usFrequency);
break;
case ATOM_TMDS_PLL_CHARGE_PUMP:
*val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_ChargePump;
break;
case ATOM_TMDS_PLL_DUTY_CYCLE:
*val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_DutyCycle;
break;
case ATOM_TMDS_PLL_VCO_GAIN:
*val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_VCO_Gain;
break;
case ATOM_TMDS_PLL_VOLTAGE_SWING:
*val = atomDataPtr->TMDS_Info->asMiscInfo[idx].ucPLL_VoltageSwing;
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
return ATOM_SUCCESS;
}
static DisplayModePtr
rhdAtomDTDTimings(atomBiosHandlePtr handle, ATOM_DTD_FORMAT *dtd)
{
DisplayModePtr mode;
#define NAME_LEN 16
char name[NAME_LEN];
//RHDFUNC(handle);
if (!dtd->usHActive || !dtd->usVActive)
return NULL;
if (!(mode = (DisplayModePtr)xcalloc(1,sizeof(DisplayModeRec))))
return NULL;
mode->CrtcHDisplay = mode->HDisplay = le16_to_cpu(dtd->usHActive);
mode->CrtcVDisplay = mode->VDisplay = le16_to_cpu(dtd->usVActive);
mode->CrtcHBlankStart = dtd->usHActive + dtd->ucHBorder;
mode->CrtcHBlankEnd = mode->CrtcHBlankStart + le16_to_cpu(dtd->usHBlanking_Time);
mode->CrtcHTotal = mode->HTotal = mode->CrtcHBlankEnd + dtd->ucHBorder;
mode->CrtcVBlankStart = dtd->usVActive + dtd->ucVBorder;
mode->CrtcVBlankEnd = mode->CrtcVBlankStart + le16_to_cpu(dtd->usVBlanking_Time);
mode->CrtcVTotal = mode->VTotal = mode->CrtcVBlankEnd + dtd->ucVBorder;
mode->CrtcHSyncStart = mode->HSyncStart = dtd->usHActive + le16_to_cpu(dtd->usHSyncOffset);
mode->CrtcHSyncEnd = mode->HSyncEnd = mode->HSyncStart + le16_to_cpu(dtd->usHSyncWidth);
mode->CrtcVSyncStart = mode->VSyncStart = dtd->usVActive + le16_to_cpu(dtd->usVSyncOffset);
mode->CrtcVSyncEnd = mode->VSyncEnd = mode->VSyncStart + le16_to_cpu(dtd->usVSyncWidth);
mode->SynthClock = mode->Clock = le16_to_cpu(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)));
if (dtd->susModeMiscInfo.sbfAccess.CompositeSync)
mode->Flags |= V_CSYNC;
if (dtd->susModeMiscInfo.sbfAccess.Interlace)
mode->Flags |= V_INTERLACE;
if (dtd->susModeMiscInfo.sbfAccess.DoubleClock)
mode->Flags |= V_DBLSCAN;
if (dtd->susModeMiscInfo.sbfAccess.VSyncPolarity)
mode->Flags |= V_NVSYNC;
if (dtd->susModeMiscInfo.sbfAccess.HSyncPolarity)
mode->Flags |= V_NHSYNC;
snprintf(name, NAME_LEN, "%dx%d",
mode->HDisplay, mode->VDisplay);
mode->name = xstrdup(name);
ErrorF("DTD Modeline: %s "
"%2.d %i (%i) %i %i (%i) %i %i (%i) %i %i (%i) %i flags: 0x%x\n",
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, mode->Flags);
return mode;
}
static unsigned char*
rhdAtomLvdsDDC(atomBiosHandlePtr handle, uint32_t 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);
xfree(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
rhdAtomCVGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data)
{
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
DisplayModePtr last = NULL;
DisplayModePtr new = NULL;
DisplayModePtr first = NULL;
int i;
data->modes = NULL;
atomDataPtr = handle->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->ComponentVideoInfo.base),
&frev,&crev,NULL)) {
return ATOM_FAILED;
}
switch (frev) {
case 1:
switch (func) {
case ATOMBIOS_GET_CV_MODES:
for (i = 0; i < MAX_SUPPORTED_CV_STANDARDS; i++) {
new = rhdAtomDTDTimings(handle,
&atomDataPtr->ComponentVideoInfo
.ComponentVideoInfo->aModeTimings[i]);
if (!new)
continue;
new->type |= M_T_DRIVER;
new->next = NULL;
new->prev = last;
if (last) last->next = new;
last = new;
if (!first) first = new;
}
if (last) {
last->next = NULL; //first;
first->prev = NULL; //last;
data->modes = first;
}
if (data->modes)
return ATOM_SUCCESS;
default:
return ATOM_FAILED;
}
case 2:
switch (func) {
case ATOMBIOS_GET_CV_MODES:
for (i = 0; i < MAX_SUPPORTED_CV_STANDARDS; i++) {
new = rhdAtomDTDTimings(handle,
&atomDataPtr->ComponentVideoInfo
.ComponentVideoInfo_v21->aModeTimings[i]);
if (!new)
continue;
new->type |= M_T_DRIVER;
new->next = NULL;
new->prev = last;
if (last) last->next = new;
last = new;
if (!first) first = new;
}
if (last) {
last->next = NULL; //first;
first->prev = NULL; //last;
data->modes = first;
}
if (data->modes)
return ATOM_SUCCESS;
return ATOM_FAILED;
default:
return ATOM_FAILED;
}
default:
return ATOM_NOT_IMPLEMENTED;
}
/*NOTREACHED*/
}
static AtomBiosResult
rhdAtomLvdsGetTimings(atomBiosHandlePtr handle, AtomBiosRequestID func,
AtomBiosArgPtr data)
{
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
unsigned long offset;
//RHDFUNC(handle);
atomDataPtr = handle->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
&frev,&crev,NULL)) {
return ATOM_FAILED;
}
switch (crev) {
case 1:
switch (func) {
case ATOMBIOS_GET_PANEL_MODE:
data->modes = rhdAtomDTDTimings(handle,
&atomDataPtr->LVDS_Info
.LVDS_Info->sLCDTiming);
if (data->modes)
return ATOM_SUCCESS;
default:
return ATOM_FAILED;
}
case 2:
switch (func) {
case ATOMBIOS_GET_PANEL_MODE:
data->modes = rhdAtomDTDTimings(handle,
&atomDataPtr->LVDS_Info
.LVDS_Info_v12->sLCDTiming);
if (data->modes)
return ATOM_SUCCESS;
return ATOM_FAILED;
case ATOMBIOS_GET_PANEL_EDID:
offset = (unsigned long)&atomDataPtr->LVDS_Info.base
- (unsigned long)handle->BIOSBase
+ le16_to_cpu(atomDataPtr->LVDS_Info
.LVDS_Info_v12->usExtInfoTableOffset);
data->EDIDBlock
= rhdAtomLvdsDDC(handle, offset,
(unsigned char *)
&atomDataPtr->LVDS_Info.base
+ le16_to_cpu(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;
uint8_t crev, frev;
uint32_t *val = &data->val;
//RHDFUNC(handle);
atomDataPtr = handle->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
&frev,&crev,NULL)) {
return ATOM_FAILED;
}
switch (crev) {
case 1:
switch (func) {
case ATOM_LVDS_SUPPORTED_REFRESH_RATE:
*val = le16_to_cpu(atomDataPtr->LVDS_Info
.LVDS_Info->usSupportedRefreshRate);
break;
case ATOM_LVDS_OFF_DELAY:
*val = le16_to_cpu(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_DITHER:
*val = atomDataPtr->LVDS_Info
.LVDS_Info->ucLVDS_Misc & 0x40;
break;
case ATOM_LVDS_DUALLINK:
*val = atomDataPtr->LVDS_Info
.LVDS_Info->ucLVDS_Misc & 0x01;
break;
case ATOM_LVDS_24BIT:
*val = atomDataPtr->LVDS_Info
.LVDS_Info->ucLVDS_Misc & 0x02;
break;
case ATOM_LVDS_GREYLVL:
*val = atomDataPtr->LVDS_Info
.LVDS_Info->ucLVDS_Misc & 0x0C;
break;
case ATOM_LVDS_FPDI:
*val = atomDataPtr->LVDS_Info
.LVDS_Info->ucLVDS_Misc * 0x10;
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
break;
case 2:
switch (func) {
case ATOM_LVDS_SUPPORTED_REFRESH_RATE:
*val = le16_to_cpu(atomDataPtr->LVDS_Info
.LVDS_Info_v12->usSupportedRefreshRate);
break;
case ATOM_LVDS_OFF_DELAY:
*val = le16_to_cpu(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_DITHER:
*val = atomDataPtr->LVDS_Info
.LVDS_Info_v12->ucLVDS_Misc & 0x40;
break;
case ATOM_LVDS_DUALLINK:
*val = atomDataPtr->LVDS_Info
.LVDS_Info_v12->ucLVDS_Misc & 0x01;
break;
case ATOM_LVDS_24BIT:
*val = atomDataPtr->LVDS_Info
.LVDS_Info_v12->ucLVDS_Misc & 0x02;
break;
case ATOM_LVDS_GREYLVL:
*val = atomDataPtr->LVDS_Info
.LVDS_Info_v12->ucLVDS_Misc & 0x0C;
break;
case ATOM_LVDS_FPDI:
*val = atomDataPtr->LVDS_Info
.LVDS_Info_v12->ucLVDS_Misc * 0x10;
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;
uint8_t crev, frev;
uint32_t *val = &data->val;
//RHDFUNC(handle);
atomDataPtr = handle->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->CompassionateData),
&frev,&crev,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_CRTC2_DAC_ADJ:
*val = atomDataPtr->CompassionateData->
ucDAC2_CRT2_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;
}
static AtomBiosResult
rhdAtomGPIOI2CInfoQuery(atomBiosHandlePtr handle,
AtomBiosRequestID func, AtomBiosArgPtr data)
{
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
uint32_t *val = &data->val;
unsigned short size;
//RHDFUNC(handle);
atomDataPtr = handle->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->GPIO_I2C_Info),
&frev,&crev,&size)) {
return ATOM_FAILED;
}
switch (func) {
case ATOM_GPIO_I2C_CLK_MASK:
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;
}
*val = le16_to_cpu(atomDataPtr->GPIO_I2C_Info->asGPIO_Info[*val]
.usClkMaskRegisterIndex);
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
return ATOM_SUCCESS;
}
static AtomBiosResult
rhdAtomFirmwareInfoQuery(atomBiosHandlePtr handle,
AtomBiosRequestID func, AtomBiosArgPtr data)
{
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
uint32_t *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 = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->ulDefaultEngineClock) * 10;
break;
case GET_DEFAULT_MEMORY_CLOCK:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->ulDefaultMemoryClock) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->ulMaxPixelClockPLL_Output) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->usMinPixelClockPLL_Output) * 10;
case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->usMaxPixelClockPLL_Input) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->usMinPixelClockPLL_Input) * 10;
break;
case GET_MAX_PIXEL_CLK:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->usMaxPixelClock) * 10;
break;
case GET_REF_CLOCK:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo->usReferenceClock) * 10;
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
case 2:
switch (func) {
case GET_DEFAULT_ENGINE_CLOCK:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->ulDefaultEngineClock) * 10;
break;
case GET_DEFAULT_MEMORY_CLOCK:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->ulDefaultMemoryClock) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->ulMaxPixelClockPLL_Output) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->usMinPixelClockPLL_Output) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->usMaxPixelClockPLL_Input) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->usMinPixelClockPLL_Input) * 10;
break;
case GET_MAX_PIXEL_CLK:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_2->usMaxPixelClock) * 10;
break;
case GET_REF_CLOCK:
*val = le16_to_cpu(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 = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->ulDefaultEngineClock) * 10;
break;
case GET_DEFAULT_MEMORY_CLOCK:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->ulDefaultMemoryClock) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->ulMaxPixelClockPLL_Output) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->usMinPixelClockPLL_Output) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->usMaxPixelClockPLL_Input) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->usMinPixelClockPLL_Input) * 10;
break;
case GET_MAX_PIXEL_CLK:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_3->usMaxPixelClock) * 10;
break;
case GET_REF_CLOCK:
*val = le16_to_cpu(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 = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->ulDefaultEngineClock) * 10;
break;
case GET_DEFAULT_MEMORY_CLOCK:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->ulDefaultMemoryClock) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->usMaxPixelClockPLL_Input) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_INPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->usMinPixelClockPLL_Input) * 10;
break;
case GET_MAX_PIXEL_CLOCK_PLL_OUTPUT:
*val = le32_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->ulMaxPixelClockPLL_Output) * 10;
break;
case GET_MIN_PIXEL_CLOCK_PLL_OUTPUT:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->usMinPixelClockPLL_Output) * 10;
break;
case GET_MAX_PIXEL_CLK:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->usMaxPixelClock) * 10;
break;
case GET_REF_CLOCK:
*val = le16_to_cpu(atomDataPtr->FirmwareInfo
.FirmwareInfo_V_1_4->usReferenceClock) * 10;
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
break;
default:
return ATOM_NOT_IMPLEMENTED;
}
return ATOM_SUCCESS;
}
const int object_connector_convert[] =
{ CONNECTOR_NONE,
CONNECTOR_DVI_I,
CONNECTOR_DVI_I,
CONNECTOR_DVI_D,
CONNECTOR_DVI_D,
CONNECTOR_VGA,
CONNECTOR_CTV,
CONNECTOR_STV,
CONNECTOR_NONE,
CONNECTOR_DIN,
CONNECTOR_SCART,
CONNECTOR_HDMI_TYPE_A,
CONNECTOR_HDMI_TYPE_B,
CONNECTOR_HDMI_TYPE_B,
CONNECTOR_LVDS,
CONNECTOR_DIN,
CONNECTOR_NONE,
CONNECTOR_NONE,
CONNECTOR_NONE,
CONNECTOR_DISPLAY_PORT,
};
xf86MonPtr radeon_atom_get_edid(xf86OutputPtr output)
{
RADEONOutputPrivatePtr radeon_output = output->driver_private;
RADEONInfoPtr info = RADEONPTR(output->scrn);
READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION edid_data;
AtomBiosArgRec data;
unsigned char *space;
int i2c_clock = 50;
int engine_clk = (int)info->sclk * 100;
int prescale;
unsigned char *edid;
xf86MonPtr mon = NULL;
if (!radeon_output->ddc_i2c.hw_capable)
return mon;
if (info->atomBIOS->fbBase)
edid = (unsigned char *)info->FB + info->atomBIOS->fbBase;
else if (info->atomBIOS->scratchBase)
edid = (unsigned char *)info->atomBIOS->scratchBase;
else
return mon;
memset(edid, 0, ATOM_EDID_RAW_DATASIZE);
if (info->ChipFamily == CHIP_FAMILY_R520)
prescale = (127 << 8) + (engine_clk * 10) / (4 * 127 * i2c_clock);
else if (info->ChipFamily < CHIP_FAMILY_R600)
prescale = (((engine_clk * 10)/(4 * 128 * 100) + 1) << 8) + 128;
else
prescale = (info->pll.reference_freq * 10) / i2c_clock;
edid_data.usPrescale = prescale;
edid_data.usVRAMAddress = 0;
edid_data.ucSlaveAddr = 0xa0;
edid_data.ucLineNumber = radeon_output->ddc_i2c.hw_line;
data.exec.index = GetIndexIntoMasterTable(COMMAND, ReadEDIDFromHWAssistedI2C);
data.exec.dataSpace = (void *)&space;
data.exec.pspace = &edid_data;
if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS)
ErrorF("Atom Get EDID success\n");
else
ErrorF("Atom Get EDID failed\n");
if (edid[1] == 0xff)
mon = xf86InterpretEDID(output->scrn->scrnIndex, edid);
return mon;
}
static RADEONI2CBusRec
RADEONLookupGPIOLineForDDC(ScrnInfoPtr pScrn, uint8_t id)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
atomDataTablesPtr atomDataPtr;
ATOM_GPIO_I2C_ASSIGMENT gpio;
RADEONI2CBusRec i2c;
uint8_t crev, frev;
memset(&i2c, 0, sizeof(RADEONI2CBusRec));
i2c.valid = FALSE;
atomDataPtr = info->atomBIOS->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
&(atomDataPtr->GPIO_I2C_Info->sHeader),
&crev,&frev,NULL)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No GPIO Info Table found!\n");
return i2c;
}
gpio = atomDataPtr->GPIO_I2C_Info->asGPIO_Info[id];
i2c.mask_clk_reg = le16_to_cpu(gpio.usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio.usDataMaskRegisterIndex) * 4;
i2c.put_clk_reg = le16_to_cpu(gpio.usClkEnRegisterIndex) * 4;
i2c.put_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4;
i2c.get_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4;
i2c.get_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4;
i2c.a_clk_reg = le16_to_cpu(gpio.usClkA_RegisterIndex) * 4;
i2c.a_data_reg = le16_to_cpu(gpio.usDataA_RegisterIndex) * 4;
i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift);
i2c.mask_data_mask = (1 << gpio.ucDataMaskShift);
i2c.put_clk_mask = (1 << gpio.ucClkEnShift);
i2c.put_data_mask = (1 << gpio.ucDataEnShift);
i2c.get_clk_mask = (1 << gpio.ucClkY_Shift);
i2c.get_data_mask = (1 << gpio.ucDataY_Shift);
i2c.a_clk_mask = (1 << gpio.ucClkA_Shift);
i2c.a_data_mask = (1 << gpio.ucDataA_Shift);
i2c.hw_line = gpio.sucI2cId.sbfAccess.bfI2C_LineMux;
i2c.hw_capable = gpio.sucI2cId.sbfAccess.bfHW_Capable;
i2c.valid = TRUE;
#if 0
ErrorF("id: %d\n", id);
ErrorF("hw capable: %d\n", gpio.sucI2cId.sbfAccess.bfHW_Capable);
ErrorF("hw engine id: %d\n", gpio.sucI2cId.sbfAccess.bfHW_EngineID);
ErrorF("line mux %d\n", gpio.sucI2cId.sbfAccess.bfI2C_LineMux);
ErrorF("mask_clk_reg: 0x%x\n", gpio.usClkMaskRegisterIndex * 4);
ErrorF("mask_data_reg: 0x%x\n", gpio.usDataMaskRegisterIndex * 4);
ErrorF("put_clk_reg: 0x%x\n", gpio.usClkEnRegisterIndex * 4);
ErrorF("put_data_reg: 0x%x\n", gpio.usDataEnRegisterIndex * 4);
ErrorF("get_clk_reg: 0x%x\n", gpio.usClkY_RegisterIndex * 4);
ErrorF("get_data_reg: 0x%x\n", gpio.usDataY_RegisterIndex * 4);
ErrorF("a_clk_reg: 0x%x\n", gpio.usClkA_RegisterIndex * 4);
ErrorF("a_data_reg: 0x%x\n", gpio.usDataA_RegisterIndex * 4);
ErrorF("mask_clk_mask: %d\n", gpio.ucClkMaskShift);
ErrorF("mask_data_mask: %d\n", gpio.ucDataMaskShift);
ErrorF("put_clk_mask: %d\n", gpio.ucClkEnShift);
ErrorF("put_data_mask: %d\n", gpio.ucDataEnShift);
ErrorF("get_clk_mask: %d\n", gpio.ucClkY_Shift);
ErrorF("get_data_mask: %d\n", gpio.ucDataY_Shift);
ErrorF("a_clk_mask: %d\n", gpio.ucClkA_Shift);
ErrorF("a_data_mask: %d\n", gpio.ucDataA_Shift);
#endif
return i2c;
}
static RADEONI2CBusRec
rhdAtomParseI2CRecord(ScrnInfoPtr pScrn, atomBiosHandlePtr handle,
ATOM_I2C_RECORD *Record, int i)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
info->BiosConnector[i].i2c_line_mux = Record->sucI2cId.bfI2C_LineMux;
return RADEONLookupGPIOLineForDDC(pScrn, Record->sucI2cId.bfI2C_LineMux);
}
static void RADEONApplyATOMQuirks(ScrnInfoPtr pScrn, int index)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
if ((info->Chipset == PCI_CHIP_RS690_791E) &&
(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x826d)) {
if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) &&
(info->BiosConnector[index].devices & ATOM_DEVICE_DFP3_SUPPORT)) {
info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
}
}
/* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
if ((info->Chipset == PCI_CHIP_RS600_7941) &&
(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x147b) &&
(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x2412)) {
if (info->BiosConnector[index].ConnectorType == CONNECTOR_DVI_I)
info->BiosConnector[index].valid = FALSE;
}
/* Falcon NW laptop lists vga ddc line for LVDS */
if ((info->Chipset == PCI_CHIP_RV410_5653) &&
(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1462) &&
(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0291)) {
if (info->BiosConnector[index].ConnectorType == CONNECTOR_LVDS) {
info->BiosConnector[index].ddc_i2c.valid = FALSE;
}
}
/* Funky macbooks */
if ((info->Chipset == PCI_CHIP_RV530_71C5) &&
(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x106b) &&
(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x0080)) {
if ((index == ATOM_DEVICE_CRT1_INDEX) ||
(index == ATOM_DEVICE_CRT2_INDEX) ||
(index == ATOM_DEVICE_DFP2_INDEX))
info->BiosConnector[index].valid = FALSE;
if (index == ATOM_DEVICE_DFP1_INDEX) {
info->BiosConnector[index].devices |= ATOM_DEVICE_CRT2_SUPPORT;
}
}
/* some BIOSes seem to report DAC on HDMI - they hurt me with their lies */
if ((info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) ||
(info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_B)) {
info->BiosConnector[index].devices &= ~(ATOM_DEVICE_CRT_SUPPORT);
}
/* ASUS HD 3600 XT board lists the DVI port as HDMI */
if ((info->Chipset == PCI_CHIP_RV635_9598) &&
(PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) &&
(PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01da)) {
if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_B)
info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_D;
}
}
uint32_t
radeon_get_device_index(uint32_t device_support)
{
uint32_t device_index = 0;
if (device_support == 0)
return 0;
while ((device_support & 1) == 0) {
device_support >>= 1;
device_index++;
}
return device_index;
}
radeon_encoder_ptr
radeon_get_encoder(xf86OutputPtr output)
{
RADEONOutputPrivatePtr radeon_output = output->driver_private;
RADEONInfoPtr info = RADEONPTR(output->scrn);
if (radeon_output->active_device)
return info->encoders[radeon_get_device_index(radeon_output->active_device)];
else
return NULL;
}
Bool
radeon_add_encoder(ScrnInfoPtr pScrn, uint32_t encoder_id, uint32_t device_support)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
uint32_t device_index = radeon_get_device_index(device_support);
int i;
if (device_support == 0) {
ErrorF("device support == 0\n");
return FALSE;
}
if (info->encoders[device_index] != NULL)
return TRUE;
else {
/* look for the encoder */
for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) {
if ((info->encoders[i] != NULL) && (info->encoders[i]->encoder_id == encoder_id)) {
info->encoders[device_index] = info->encoders[i];
switch (encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
if (info->encoders[device_index]->dev_priv == NULL) {
info->encoders[device_index]->dev_priv =
(radeon_lvds_ptr)xcalloc(1,sizeof(radeon_lvds_rec));
if (info->encoders[device_index]->dev_priv == NULL) {
ErrorF("xalloc failed\n");
return FALSE;
} else
RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
}
}
break;
}
return TRUE;
}
}
info->encoders[device_index] = (radeon_encoder_ptr)xcalloc(1,sizeof(radeon_encoder_rec));
if (info->encoders[device_index] != NULL) {
info->encoders[device_index]->encoder_id = encoder_id;
info->encoders[device_index]->devices = 0;
info->encoders[device_index]->dev_priv = NULL;
// add dev_priv stuff
switch (encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_LVDS:
info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)xcalloc(1,sizeof(radeon_lvds_rec));
if (info->encoders[device_index]->dev_priv == NULL) {
ErrorF("xalloc failed\n");
return FALSE;
} else {
if (info->IsAtomBios)
RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
else
RADEONGetLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DAC2:
if (!IS_AVIVO_VARIANT) {
info->encoders[device_index]->dev_priv = (radeon_tvdac_ptr)xcalloc(1,sizeof(radeon_tvdac_rec));
if (info->encoders[device_index]->dev_priv == NULL) {
ErrorF("xalloc failed\n");
return FALSE;
} else
RADEONGetTVDacAdjInfo(pScrn, (radeon_tvdac_ptr)info->encoders[device_index]->dev_priv);
}
break;
case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
if (!IS_AVIVO_VARIANT) {
info->encoders[device_index]->dev_priv = (radeon_tmds_ptr)xcalloc(1,sizeof(radeon_tmds_rec));
if (info->encoders[device_index]->dev_priv == NULL) {
ErrorF("xalloc failed\n");
return FALSE;
} else
RADEONGetTMDSInfo(pScrn, (radeon_tmds_ptr)info->encoders[device_index]->dev_priv);
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
if (!IS_AVIVO_VARIANT) {
info->encoders[device_index]->dev_priv = (radeon_dvo_ptr)xcalloc(1,sizeof(radeon_dvo_rec));
if (info->encoders[device_index]->dev_priv == NULL) {
ErrorF("xalloc failed\n");
return FALSE;
} else
RADEONGetExtTMDSInfo(pScrn, (radeon_dvo_ptr)info->encoders[device_index]->dev_priv);
}
break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
if (device_support & ATOM_DEVICE_LCD1_SUPPORT) {
info->encoders[device_index]->dev_priv = (radeon_lvds_ptr)xcalloc(1,sizeof(radeon_lvds_rec));
if (info->encoders[device_index]->dev_priv == NULL) {
ErrorF("xalloc failed\n");
return FALSE;
} else
RADEONGetATOMLVDSInfo(pScrn, (radeon_lvds_ptr)info->encoders[device_index]->dev_priv);
}
break;
}
return TRUE;
} else {
ErrorF("xalloc failed\n");
return FALSE;
}
}
}
Bool
RADEONGetATOMConnectorInfoFromBIOSObject (ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
uint8_t crev, frev;
unsigned short size;
atomDataTablesPtr atomDataPtr;
ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj = NULL;
int i, j, path_size, device_support;
Bool enable_tv = FALSE;
if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
enable_tv = TRUE;
atomDataPtr = info->atomBIOS->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->Object_Header), &crev, &frev, &size))
return FALSE;
if (crev < 2)
return FALSE;
path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
((char *)&atomDataPtr->Object_Header->sHeader +
le16_to_cpu(atomDataPtr->Object_Header->usDisplayPathTableOffset));
con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
((char *)&atomDataPtr->Object_Header->sHeader +
le16_to_cpu(atomDataPtr->Object_Header->usConnectorObjectTableOffset));
device_support = le16_to_cpu(atomDataPtr->Object_Header->usDeviceSupport);
path_size = 0;
for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
uint8_t *addr = (uint8_t *)path_obj->asDispPath;
ATOM_DISPLAY_OBJECT_PATH *path;
addr += path_size;
path = (ATOM_DISPLAY_OBJECT_PATH *)addr;
path_size += path->usSize;
if (device_support & path->usDeviceTag) {
uint8_t con_obj_id, con_obj_num, con_obj_type;
con_obj_id = (path->usConnObjectId & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
con_obj_num = (path->usConnObjectId & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
con_obj_type = (path->usConnObjectId & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
if ((path->usDeviceTag == ATOM_DEVICE_TV1_SUPPORT) ||
(path->usDeviceTag == ATOM_DEVICE_TV2_SUPPORT)) {
if (!enable_tv) {
info->BiosConnector[i].valid = FALSE;
continue;
}
}
/* don't support CV yet */
if (path->usDeviceTag == ATOM_DEVICE_CV_SUPPORT) {
info->BiosConnector[i].valid = FALSE;
continue;
}
if (info->IsIGP &&
(con_obj_id == CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
uint32_t slot_config, ct;
igp_obj = info->atomBIOS->atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2;
if (!igp_obj)
info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
else {
if (con_obj_num == 1)
slot_config = igp_obj->ulDDISlot1Config;
else
slot_config = igp_obj->ulDDISlot2Config;
ct = (slot_config >> 16) & 0xff;
info->BiosConnector[i].ConnectorType = object_connector_convert[ct];
info->BiosConnector[i].igp_lane_info = slot_config & 0xffff;
}
} else
info->BiosConnector[i].ConnectorType = object_connector_convert[con_obj_id];
if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
info->BiosConnector[i].valid = FALSE;
continue;
} else
info->BiosConnector[i].valid = TRUE;
info->BiosConnector[i].devices = path->usDeviceTag;
info->BiosConnector[i].connector_object = path->usConnObjectId;
for (j = 0; j < ((path->usSize - 8) / 2); j++) {
uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
enc_obj_id = (path->usGraphicObjIds[j] & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
enc_obj_num = (path->usGraphicObjIds[j] & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
enc_obj_type = (path->usGraphicObjIds[j] & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
if (enc_obj_num == 2)
info->BiosConnector[i].linkb = TRUE;
else
info->BiosConnector[i].linkb = FALSE;
if (!radeon_add_encoder(pScrn, enc_obj_id, path->usDeviceTag))
return FALSE;
}
}
/* look up gpio for ddc */
if ((path->usDeviceTag & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) {
for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
if (path->usConnObjectId == le16_to_cpu(con_obj->asObjects[j].usObjectID)) {
ATOM_COMMON_RECORD_HEADER *Record = (ATOM_COMMON_RECORD_HEADER *)
((char *)&atomDataPtr->Object_Header->sHeader
+ le16_to_cpu(con_obj->asObjects[j].usRecordOffset));
while (Record->ucRecordType > 0
&& Record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER ) {
/*ErrorF("record type %d\n", Record->ucRecordType);*/
switch (Record->ucRecordType) {
case ATOM_I2C_RECORD_TYPE:
info->BiosConnector[i].ddc_i2c =
rhdAtomParseI2CRecord(pScrn, info->atomBIOS,
(ATOM_I2C_RECORD *)Record, j);
break;
case ATOM_HPD_INT_RECORD_TYPE:
break;
case ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE:
break;
}
Record = (ATOM_COMMON_RECORD_HEADER*)
((char *)Record + Record->ucRecordSize);
}
break;
}
}
}
}
RADEONApplyATOMQuirks(pScrn, i);
}
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
if (info->BiosConnector[i].valid) {
/* shared connectors */
for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
if (info->BiosConnector[j].valid && (i != j) ) {
if (info->BiosConnector[i].connector_object == info->BiosConnector[j].connector_object) {
info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
info->BiosConnector[j].valid = FALSE;
}
}
}
/* shared ddc */
for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
if (info->BiosConnector[j].valid && (i != j) ) {
if (info->BiosConnector[i].i2c_line_mux == info->BiosConnector[j].i2c_line_mux) {
ErrorF("Shared DDC line: %d %d\n", i, j);
info->BiosConnector[i].shared_ddc = TRUE;
info->BiosConnector[j].shared_ddc = TRUE;
}
}
}
}
}
return TRUE;
}
static void
RADEONGetATOMLVDSInfo(ScrnInfoPtr pScrn, radeon_lvds_ptr lvds)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
radeon_native_mode_ptr native_mode = &lvds->native_mode;
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
atomDataPtr = info->atomBIOS->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->LVDS_Info.base),
&frev,&crev,NULL)) {
return;
}
switch (crev) {
case 1:
native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHActive);
native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVActive);
native_mode->DotClock = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usPixClk) * 10;
native_mode->HBlank = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHBlanking_Time);
native_mode->HOverPlus = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncOffset);
native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usHSyncWidth);
native_mode->VBlank = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVBlanking_Time);
native_mode->VOverPlus = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncOffset);
native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->sLCDTiming.usVSyncWidth);
lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info->usOffDelayInMs);
lvds->lvds_misc = atomDataPtr->LVDS_Info.LVDS_Info->ucLVDS_Misc;
lvds->lvds_ss_id = atomDataPtr->LVDS_Info.LVDS_Info->ucSS_Id;
break;
case 2:
native_mode->PanelXRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHActive);
native_mode->PanelYRes = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVActive);
native_mode->DotClock = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usPixClk) * 10;
native_mode->HBlank = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHBlanking_Time);
native_mode->HOverPlus = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncOffset);
native_mode->HSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usHSyncWidth);
native_mode->VBlank = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVBlanking_Time);
native_mode->VOverPlus = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncOffset);
native_mode->VSyncWidth = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->sLCDTiming.usVSyncWidth);
lvds->PanelPwrDly = le16_to_cpu(atomDataPtr->LVDS_Info.LVDS_Info_v12->usOffDelayInMs);
lvds->lvds_misc = atomDataPtr->LVDS_Info.LVDS_Info_v12->ucLVDS_Misc;
lvds->lvds_ss_id = atomDataPtr->LVDS_Info.LVDS_Info_v12->ucSS_Id;
break;
}
native_mode->Flags = 0;
if (lvds->PanelPwrDly > 2000 || lvds->PanelPwrDly < 0)
lvds->PanelPwrDly = 2000;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"LVDS Info:\n"
"XRes: %d, YRes: %d, DotClock: %d\n"
"HBlank: %d, HOverPlus: %d, HSyncWidth: %d\n"
"VBlank: %d, VOverPlus: %d, VSyncWidth: %d\n",
native_mode->PanelXRes, native_mode->PanelYRes, native_mode->DotClock,
native_mode->HBlank, native_mode->HOverPlus, native_mode->HSyncWidth,
native_mode->VBlank, native_mode->VOverPlus, native_mode->VSyncWidth);
}
Bool
RADEONGetATOMTVInfo(xf86OutputPtr output)
{
ScrnInfoPtr pScrn = output->scrn;
RADEONInfoPtr info = RADEONPTR(pScrn);
RADEONOutputPrivatePtr radeon_output = output->driver_private;
radeon_tvout_ptr tvout = &radeon_output->tvout;
ATOM_ANALOG_TV_INFO *tv_info;
tv_info = info->atomBIOS->atomDataPtr->AnalogTV_Info.AnalogTV_Info;
if (!tv_info)
return FALSE;
switch(tv_info->ucTV_BootUpDefaultStandard) {
case NTSCJ_SUPPORT:
tvout->default_tvStd = TV_STD_NTSC_J;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n");
break;
case PAL_SUPPORT:
tvout->default_tvStd = TV_STD_PAL;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n");
break;
case PALM_SUPPORT:
tvout->default_tvStd = TV_STD_PAL_M;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n");
break;
case PAL60_SUPPORT:
tvout->default_tvStd = TV_STD_PAL_60;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n");
break;
default:
case NTSC_SUPPORT:
tvout->default_tvStd = TV_STD_NTSC;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n");
break;
}
tvout->tvStd = tvout->default_tvStd;
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: ");
tvout->SupportedTVStds = tvout->default_tvStd;
if (tv_info->ucTV_SupportedStandard & NTSC_SUPPORT) {
ErrorF("NTSC ");
tvout->SupportedTVStds |= TV_STD_NTSC;
}
if (tv_info->ucTV_SupportedStandard & NTSCJ_SUPPORT) {
ErrorF("NTSC-J ");
tvout->SupportedTVStds |= TV_STD_NTSC_J;
}
if (tv_info->ucTV_SupportedStandard & PAL_SUPPORT) {
ErrorF("PAL ");
tvout->SupportedTVStds |= TV_STD_PAL;
}
if (tv_info->ucTV_SupportedStandard & PALM_SUPPORT) {
ErrorF("PAL-M ");
tvout->SupportedTVStds |= TV_STD_PAL_M;
}
if (tv_info->ucTV_SupportedStandard & PAL60_SUPPORT) {
ErrorF("PAL-60 ");
tvout->SupportedTVStds |= TV_STD_PAL_60;
}
ErrorF("\n");
if (tv_info->ucExt_TV_ASIC_ID) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown external TV ASIC\n");
return FALSE;
}
return TRUE;
}
Bool
RADEONATOMGetTVTimings(ScrnInfoPtr pScrn, int index, SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_timing, int32_t *pixel_clock)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
ATOM_ANALOG_TV_INFO *tv_info;
ATOM_ANALOG_TV_INFO_V1_2 *tv_info_v1_2;
ATOM_DTD_FORMAT *dtd_timings;
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
atomDataPtr = info->atomBIOS->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
(ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->AnalogTV_Info.base),
&crev,&frev,NULL)) {
return FALSE;
}
switch(crev) {
case 1:
tv_info = atomDataPtr->AnalogTV_Info.AnalogTV_Info;
if (index > MAX_SUPPORTED_TV_TIMING)
return FALSE;
crtc_timing->usH_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total);
crtc_timing->usH_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Disp);
crtc_timing->usH_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncStart);
crtc_timing->usH_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_SyncWidth);
crtc_timing->usV_Total = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Total);
crtc_timing->usV_Disp = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_Disp);
crtc_timing->usV_SyncStart = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncStart);
crtc_timing->usV_SyncWidth = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_V_SyncWidth);
crtc_timing->susModeMiscInfo = tv_info->aModeTimings[index].susModeMiscInfo;
crtc_timing->ucOverscanRight = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanRight);
crtc_timing->ucOverscanLeft = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanLeft);
crtc_timing->ucOverscanBottom = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanBottom);
crtc_timing->ucOverscanTop = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_OverscanTop);
*pixel_clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
if (index == 1) {
/* PAL timings appear to have wrong values for totals */
crtc_timing->usH_Total -= 1;
crtc_timing->usV_Total -= 1;
}
break;
case 2:
tv_info_v1_2 = atomDataPtr->AnalogTV_Info.AnalogTV_Info_v1_2;
if (index > MAX_SUPPORTED_TV_TIMING_V1_2)
return FALSE;
dtd_timings = &tv_info_v1_2->aModeTimings[index];
crtc_timing->usH_Total = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHBlanking_Time);
crtc_timing->usH_Disp = le16_to_cpu(dtd_timings->usHActive);
crtc_timing->usH_SyncStart = le16_to_cpu(dtd_timings->usHActive) + le16_to_cpu(dtd_timings->usHSyncOffset);
crtc_timing->usH_SyncWidth = le16_to_cpu(dtd_timings->usHSyncWidth);
crtc_timing->usV_Total = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVBlanking_Time);
crtc_timing->usV_Disp = le16_to_cpu(dtd_timings->usVActive);
crtc_timing->usV_SyncStart = le16_to_cpu(dtd_timings->usVActive) + le16_to_cpu(dtd_timings->usVSyncOffset);
crtc_timing->usV_SyncWidth = le16_to_cpu(dtd_timings->usVSyncWidth);
crtc_timing->susModeMiscInfo.usAccess = le16_to_cpu(dtd_timings->susModeMiscInfo.usAccess);
*pixel_clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
break;
}
return TRUE;
}
uint32_t
radeon_get_encoder_id_from_supported_device(ScrnInfoPtr pScrn, uint32_t supported_device, int dac)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
uint32_t ret = 0;
switch (supported_device) {
case ATOM_DEVICE_CRT1_SUPPORT:
case ATOM_DEVICE_TV1_SUPPORT:
case ATOM_DEVICE_TV2_SUPPORT:
case ATOM_DEVICE_CRT2_SUPPORT:
case ATOM_DEVICE_CV_SUPPORT:
switch (dac) {
// primary dac
case 1:
if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
(info->ChipFamily == CHIP_FAMILY_RS400) ||
(info->ChipFamily == CHIP_FAMILY_RS480))
ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
else if (IS_AVIVO_VARIANT)
ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
else
ret = ENCODER_OBJECT_ID_INTERNAL_DAC1;
break;
// secondary dac
case 2:
if (IS_AVIVO_VARIANT)
ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
else {
/*if (info->ChipFamily == CHIP_FAMILY_R200)
ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
else*/
ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
}
break;
// external dac
case 3:
if (IS_AVIVO_VARIANT)
ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
else
ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
break;
}
break;
case ATOM_DEVICE_LCD1_SUPPORT:
if (IS_AVIVO_VARIANT)
ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
else
ret = ENCODER_OBJECT_ID_INTERNAL_LVDS;
break;
case ATOM_DEVICE_DFP1_SUPPORT:
if ((info->ChipFamily == CHIP_FAMILY_RS300) ||
(info->ChipFamily == CHIP_FAMILY_RS400) ||
(info->ChipFamily == CHIP_FAMILY_RS480))
ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
else if (IS_AVIVO_VARIANT)
ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
else
ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1;
break;
case ATOM_DEVICE_LCD2_SUPPORT:
case ATOM_DEVICE_DFP2_SUPPORT:
if ((info->ChipFamily == CHIP_FAMILY_RS600) ||
(info->ChipFamily == CHIP_FAMILY_RS690) ||
(info->ChipFamily == CHIP_FAMILY_RS740))
ret = ENCODER_OBJECT_ID_INTERNAL_DDI;
else if (IS_AVIVO_VARIANT)
ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
else
ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
break;
case ATOM_DEVICE_DFP3_SUPPORT:
ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
break;
}
return ret;
}
Bool
RADEONGetATOMConnectorInfoFromBIOSConnectorTable (ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR (pScrn);
atomDataTablesPtr atomDataPtr;
uint8_t crev, frev;
int i, j;
Bool enable_tv = FALSE;
if (xf86ReturnOptValBool(info->Options, OPTION_ATOM_TVOUT, FALSE))
enable_tv = TRUE;
atomDataPtr = info->atomBIOS->atomDataPtr;
if (!rhdAtomGetTableRevisionAndSize(
&(atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->sHeader),
&crev,&frev,NULL)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n");
return FALSE;
}
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
ATOM_CONNECTOR_INFO_I2C ci
= atomDataPtr->SupportedDevicesInfo.SupportedDevicesInfo->asConnInfo[i];
if (!(le16_to_cpu(atomDataPtr->SupportedDevicesInfo
.SupportedDevicesInfo->usDeviceSupport) & (1 << i))) {
info->BiosConnector[i].valid = FALSE;
continue;
}
/* don't support CV yet */
if (i == ATOM_DEVICE_CV_INDEX) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping Component Video\n");
info->BiosConnector[i].valid = FALSE;
continue;
}
if (!enable_tv && (i == ATOM_DEVICE_TV1_INDEX)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Skipping TV-Out\n");
info->BiosConnector[i].valid = FALSE;
continue;
}
info->BiosConnector[i].valid = TRUE;
info->BiosConnector[i].load_detection = TRUE;
info->BiosConnector[i].shared_ddc = FALSE;
info->BiosConnector[i].output_id = ci.sucI2cId.sbfAccess.bfI2C_LineMux;
info->BiosConnector[i].devices = (1 << i);
info->BiosConnector[i].ConnectorType = ci.sucConnectorInfo.sbfAccess.bfConnectorType;
if (info->BiosConnector[i].ConnectorType == CONNECTOR_NONE) {
info->BiosConnector[i].valid = FALSE;
continue;
}
/* don't assign a gpio for tv */
if ((i == ATOM_DEVICE_TV1_INDEX) ||
(i == ATOM_DEVICE_TV2_INDEX) ||
(i == ATOM_DEVICE_CV_INDEX))
info->BiosConnector[i].ddc_i2c.valid = FALSE;
else if ((info->ChipFamily == CHIP_FAMILY_RS690) ||
(info->ChipFamily == CHIP_FAMILY_RS740)) {
/* IGP DFP ports use non-standard gpio entries */
if ((i == ATOM_DEVICE_DFP2_INDEX) || (i == ATOM_DEVICE_DFP3_INDEX))
info->BiosConnector[i].ddc_i2c =
RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1);
else
info->BiosConnector[i].ddc_i2c =
RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.sbfAccess.bfI2C_LineMux);
} else
info->BiosConnector[i].ddc_i2c =
RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.sbfAccess.bfI2C_LineMux);
if (!radeon_add_encoder(pScrn,
radeon_get_encoder_id_from_supported_device(pScrn, (1 << i),
ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC),
(1 << i)))
return FALSE;
/* Always set the connector type to VGA for CRT1/CRT2. if they are
* shared with a DVI port, we'll pick up the DVI connector below when we
* merge the outputs
*/
if ((i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX) &&
(info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I ||
info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D ||
info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A)) {
info->BiosConnector[i].ConnectorType = CONNECTOR_VGA;
}
if (crev > 1) {
ATOM_CONNECTOR_INC_SRC_BITMAP isb
= atomDataPtr->SupportedDevicesInfo
.SupportedDevicesInfo_HD->asIntSrcInfo[i];
switch (isb.ucIntSrcBitmap) {
case 0x4:
info->BiosConnector[i].hpd_mask = 0x00000001;
break;
case 0xa:
info->BiosConnector[i].hpd_mask = 0x00000100;
break;
default:
info->BiosConnector[i].hpd_mask = 0;
break;
}
} else
info->BiosConnector[i].hpd_mask = 0;
RADEONApplyATOMQuirks(pScrn, i);
}
/* CRTs/DFPs may share a port */
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
if (info->BiosConnector[i].valid) {
for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
if (info->BiosConnector[j].valid && (i != j) ) {
if (info->BiosConnector[i].output_id == info->BiosConnector[j].output_id) {
if (((i == ATOM_DEVICE_DFP1_INDEX) ||
(i == ATOM_DEVICE_DFP2_INDEX) ||
(i == ATOM_DEVICE_DFP3_INDEX)) &&
((j == ATOM_DEVICE_CRT1_INDEX) ||
(j == ATOM_DEVICE_CRT2_INDEX))) {
info->BiosConnector[i].devices |= info->BiosConnector[j].devices;
info->BiosConnector[j].valid = FALSE;
} else if (((j == ATOM_DEVICE_DFP1_INDEX) ||
(j == ATOM_DEVICE_DFP2_INDEX) ||
(j == ATOM_DEVICE_DFP3_INDEX)) &&
((i == ATOM_DEVICE_CRT1_INDEX) ||
(i == ATOM_DEVICE_CRT2_INDEX))) {
info->BiosConnector[j].devices |= info->BiosConnector[i].devices;
info->BiosConnector[i].valid = FALSE;
} else {
info->BiosConnector[i].shared_ddc = TRUE;
info->BiosConnector[j].shared_ddc = TRUE;
}
/* other possible combos? */
}
}
}
}
}
for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
if (info->encoders[i] != NULL) {
ErrorF("encoder: 0x%x\n", info->encoders[i]->encoder_id);
}
}
return TRUE;
}
# ifdef ATOM_BIOS_PARSER
static AtomBiosResult
rhdAtomExec (atomBiosHandlePtr handle,
AtomBiosRequestID unused, AtomBiosArgPtr data)
{
RADEONInfoPtr info = RADEONPTR (xf86Screens[handle->scrnIndex]);
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 (!info->FB) {
xf86DrvMsg(handle->scrnIndex, X_ERROR, "%s: "
"Cannot exec AtomBIOS: framebuffer not mapped\n",
__func__);
return ATOM_FAILED;
}
*dataSpace = (uint8_t*)info->FB + handle->fbBase;
} else
*dataSpace = (uint8_t*)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(int scrnIndex, atomBiosHandlePtr handle,
AtomBiosRequestID id, AtomBiosArgPtr data)
{
AtomBiosResult ret = ATOM_FAILED;
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 = scrnIndex;
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;
}
# ifdef ATOM_BIOS_PARSER
VOID*
CailAllocateMemory(VOID *CAIL,UINT16 size)
{
void *ret;
CAILFUNC(CAIL);
ret = malloc(size);
memset(ret, 0, size);
return ret;
}
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)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
UINT32 ret;
CAILFUNC(CAIL);
ret = INREG(idx << 2);
/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx << 2,ret));*/
return ret;
}
VOID
CailWriteATIRegister(VOID *CAIL, UINT32 idx, UINT32 data)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
unsigned char *RADEONMMIO = pRADEONEnt->MMIO;
CAILFUNC(CAIL);
OUTREG(idx << 2,data);
/*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx << 2,data));*/
}
UINT32
CailReadFBData(VOID* CAIL, UINT32 idx)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
RADEONInfoPtr info = RADEONPTR(pScrn);
UINT32 ret;
CAILFUNC(CAIL);
if (((atomBiosHandlePtr)CAIL)->fbBase) {
uint8_t *FBBase = (uint8_t*)info->FB;
ret = *((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx));
/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,ret));*/
} else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
ret = *(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx);
/*DEBUGP(ErrorF("%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);
/*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,data));*/
if (((atomBiosHandlePtr)CAIL)->fbBase) {
uint8_t *FBBase = (uint8_t*)
RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->FB;
*((uint32_t*)(FBBase + (((atomBiosHandlePtr)CAIL)->fbBase) + idx)) = data;
} else if (((atomBiosHandlePtr)CAIL)->scratchBase) {
*(uint32_t*)((uint8_t*)(((atomBiosHandlePtr)CAIL)->scratchBase) + idx) = data;
} else
xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,X_ERROR,
"%s: no fbbase set\n",__func__);
}
ULONG
CailReadMC(VOID *CAIL, ULONG Address)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
ULONG ret;
CAILFUNC(CAIL);
ret = INMC(pScrn, Address);
/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
return ret;
}
VOID
CailWriteMC(VOID *CAIL, ULONG Address, ULONG data)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
CAILFUNC(CAIL);
/*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,data));*/
OUTMC(pScrn, Address, data);
}
#ifdef XSERVER_LIBPCIACCESS
VOID
CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
{
pci_device_cfg_read(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
ret,idx << 2 , size >> 3, NULL);
}
VOID
CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
{
pci_device_cfg_write(RADEONPTR(xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex])->PciInfo,
src, idx << 2, size >> 3, NULL);
}
#else
VOID
CailReadPCIConfigData(VOID*CAIL, VOID* ret, UINT32 idx,UINT16 size)
{
PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
CAILFUNC(CAIL);
switch (size) {
case 8:
*(uint8_t*)ret = pciReadByte(tag,idx << 2);
break;
case 16:
*(uint16_t*)ret = pciReadWord(tag,idx << 2);
break;
case 32:
*(uint32_t*)ret = pciReadLong(tag,idx << 2);
break;
default:
xf86DrvMsg(((atomBiosHandlePtr)CAIL)->scrnIndex,
X_ERROR,"%s: Unsupported size: %i\n",
__func__,(int)size);
return;
break;
}
/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,idx,*(unsigned int*)ret));*/
}
VOID
CailWritePCIConfigData(VOID*CAIL,VOID*src,UINT32 idx,UINT16 size)
{
PCITAG tag = ((atomBiosHandlePtr)CAIL)->PciTag;
CAILFUNC(CAIL);
/*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,idx,(*(unsigned int*)src)));*/
switch (size) {
case 8:
pciWriteByte(tag,idx << 2,*(uint8_t*)src);
break;
case 16:
pciWriteWord(tag,idx << 2,*(uint16_t*)src);
break;
case 32:
pciWriteLong(tag,idx << 2,*(uint32_t*)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)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
ULONG ret;
CAILFUNC(CAIL);
ret = RADEONINPLL(pScrn, Address);
/*DEBUGP(ErrorF("%s(%x) = %x\n",__func__,Address,ret));*/
return ret;
}
VOID
CailWritePLL(VOID *CAIL, ULONG Address,ULONG Data)
{
ScrnInfoPtr pScrn = xf86Screens[((atomBiosHandlePtr)CAIL)->scrnIndex];
CAILFUNC(CAIL);
/*DEBUGP(ErrorF("%s(%x,%x)\n",__func__,Address,Data));*/
RADEONOUTPLL(pScrn, Address, Data);
}
void
atombios_get_command_table_version(atomBiosHandlePtr atomBIOS, int index, int *major, int *minor)
{
ATOM_MASTER_COMMAND_TABLE *cmd_table = (void *)(atomBIOS->BIOSBase + atomBIOS->cmd_offset);
ATOM_MASTER_LIST_OF_COMMAND_TABLES *table_start;
ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *table_hdr;
//unsigned short *ptr;
unsigned short offset;
table_start = &cmd_table->ListOfCommandTables;
offset = *(((unsigned short *)table_start) + index);
offset = le16_to_cpu(offset);
table_hdr = (ATOM_COMMON_ROM_COMMAND_TABLE_HEADER *)(atomBIOS->BIOSBase + offset);
*major = table_hdr->CommonHeader.ucTableFormatRevision;
*minor = table_hdr->CommonHeader.ucTableContentRevision;
}
UINT16 ATOM_BSWAP16(UINT16 x)
{
return bswap_16(x);
}
UINT32 ATOM_BSWAP32(UINT32 x)
{
return bswap_32(x);
}
#endif /* ATOM_BIOS */