/* * Copyright 2007 Egbert Eich * Copyright 2007 Luc Verhaegen * Copyright 2007 Matthias Hopf * 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_clk_gating_setup(ScrnInfoPtr pScrn, Bool 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, Bool enable) { RADEONInfoPtr info = RADEONPTR(pScrn); ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION pwrmgt_data; AtomBiosArgRec data; unsigned char *space; /* disabling static power management causes hangs on some r4xx chips */ if (((info->ChipFamily == CHIP_FAMILY_R420) || (info->ChipFamily == CHIP_FAMILY_RV410)) && !enable) return ATOM_NOT_IMPLEMENTED; 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; } int atombios_set_engine_clock(ScrnInfoPtr pScrn, uint32_t engclock) { RADEONInfoPtr info = RADEONPTR(pScrn); SET_ENGINE_CLOCK_PS_ALLOCATION eng_clock_ps; AtomBiosArgRec data; unsigned char *space; RADEONWaitForIdleMMIO(pScrn); eng_clock_ps.ulTargetEngineClock = engclock; /* 10 khz */ /*ErrorF("Attempting to set engine clock to: %d\n", engclock);*/ data.exec.index = GetIndexIntoMasterTable(COMMAND, SetEngineClock); data.exec.dataSpace = (void *)&space; data.exec.pspace = &eng_clock_ps; if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { /* ErrorF("Set engine clock success\n"); */ return ATOM_SUCCESS; } /* ErrorF("Set engine clock failed\n"); */ return ATOM_NOT_IMPLEMENTED; } int atombios_set_memory_clock(ScrnInfoPtr pScrn, uint32_t memclock) { RADEONInfoPtr info = RADEONPTR(pScrn); SET_MEMORY_CLOCK_PS_ALLOCATION mem_clock_ps; AtomBiosArgRec data; unsigned char *space; if (info->IsIGP) return ATOM_SUCCESS; RADEONWaitForIdleMMIO(pScrn); mem_clock_ps.ulTargetMemoryClock = memclock; /* 10 khz */ /* ErrorF("Attempting to set mem clock to: %d\n", memclock); */ data.exec.index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock); data.exec.dataSpace = (void *)&space; data.exec.pspace = &mem_clock_ps; if (RHDAtomBiosFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { /* ErrorF("Set memory clock success\n"); */ return ATOM_SUCCESS; } /* ErrorF("Set memory clock failed\n"); */ 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_NONE, CONNECTOR_DIN, CONNECTOR_SCART, CONNECTOR_HDMI_TYPE_A, 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; } } /* 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_A) info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I; } /* ASUS HD 3450 board lists the DVI port as HDMI */ if ((info->Chipset == PCI_CHIP_RV620_95C5) && (PCI_SUB_VENDOR_ID(info->PciInfo) == 0x1043) && (PCI_SUB_DEVICE_ID(info->PciInfo) == 0x01e2)) { if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) info->BiosConnector[index].ConnectorType = CONNECTOR_DVI_I; } /* some BIOSes seem to report DAC on HDMI - usually this is a board with * HDMI + VGA reporting as HDMI */ if (info->BiosConnector[index].ConnectorType == CONNECTOR_HDMI_TYPE_A) { if (info->BiosConnector[index].devices & (ATOM_DEVICE_CRT_SUPPORT)) { info->BiosConnector[index].devices &= ~(ATOM_DEVICE_DFP_SUPPORT); info->BiosConnector[index].ConnectorType = CONNECTOR_VGA; info->BiosConnector[index].connector_object = 0; } } } 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 += le16_to_cpu(path->usSize); if (device_support & le16_to_cpu(path->usDeviceTag)) { uint8_t con_obj_id, con_obj_num, con_obj_type; con_obj_id = (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; con_obj_num = (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK) >> ENUM_ID_SHIFT; con_obj_type = (le16_to_cpu(path->usConnObjectId) & OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT; if ((le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV1_SUPPORT) || (le16_to_cpu(path->usDeviceTag) == ATOM_DEVICE_TV2_SUPPORT)) { if (!enable_tv) { info->BiosConnector[i].valid = FALSE; continue; } } /* don't support CV yet */ if (le16_to_cpu(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 = le16_to_cpu(path->usDeviceTag); info->BiosConnector[i].connector_object = le16_to_cpu(path->usConnObjectId); for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) { uint8_t enc_obj_id, enc_obj_num, enc_obj_type; enc_obj_id = (le16_to_cpu(path->usGraphicObjIds[j]) & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; enc_obj_num = (le16_to_cpu(path->usGraphicObjIds[j]) & ENUM_ID_MASK) >> ENUM_ID_SHIFT; enc_obj_type = (le16_to_cpu(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, le16_to_cpu(path->usDeviceTag))) return FALSE; } } /* look up gpio for ddc */ if ((le16_to_cpu(path->usDeviceTag) & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) == 0) { for (j = 0; j < con_obj->ucNumberOfObjects; j++) { if (le16_to_cpu(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) { 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); } void RADEONATOMGetIGPInfo(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); atomDataTablesPtr atomDataPtr; unsigned short size; uint8_t crev, frev; atomDataPtr = info->atomBIOS->atomDataPtr; if (!rhdAtomGetTableRevisionAndSize((ATOM_COMMON_TABLE_HEADER *)(atomDataPtr->IntegratedSystemInfo.base), &frev, &crev, &size)) return; switch (crev) { case 1: info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ulBootUpMemoryClock / 100.0; info->igp_system_mclk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usK8MemoryClock); info->igp_ht_link_clk = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->usFSBClock); info->igp_ht_link_width = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo->ucHTLinkWidth; break; case 2: info->igp_sideport_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpSidePortClock / 100.0; info->igp_system_mclk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulBootUpUMAClock / 100.0; info->igp_ht_link_clk = atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->ulHTLinkFreq / 100.0; info->igp_ht_link_width = le16_to_cpu(atomDataPtr->IntegratedSystemInfo.IntegratedSystemInfo_v2->usMinHTLinkWidth); break; } } 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 sometimes use non-standard gpio entries */ if ((i == ATOM_DEVICE_DFP2_INDEX) && (ci.sucI2cId.sbfAccess.bfI2C_LineMux == 2)) info->BiosConnector[i].ddc_i2c = RADEONLookupGPIOLineForDDC(pScrn, ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1); else if ((i == ATOM_DEVICE_DFP3_INDEX) && (ci.sucI2cId.sbfAccess.bfI2C_LineMux == 1)) 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; if (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) info->BiosConnector[i].ConnectorType = CONNECTOR_DVI_I; 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; if (info->BiosConnector[j].ConnectorType == CONNECTOR_DVI_D) info->BiosConnector[j].ConnectorType = CONNECTOR_DVI_I; info->BiosConnector[i].valid = FALSE; } else { info->BiosConnector[i].shared_ddc = TRUE; info->BiosConnector[j].shared_ddc = TRUE; } /* other possible combos? */ } } } } } 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 */