diff options
author | Alex Deucher <alex@botch2.(none)> | 2007-11-06 18:47:00 -0500 |
---|---|---|
committer | Alex Deucher <alex@botch2.(none)> | 2007-11-06 18:47:00 -0500 |
commit | 0abfe3150ce3eed4db93ccc2975bd4622dfa54a7 (patch) | |
tree | 2e6682a06961ac04fd660c9601b1cc32c000f24a | |
parent | 20f01950e42babc308b4470df6a3c6628c932003 (diff) |
Add atombios files
-rw-r--r-- | src/atombios_crtc.c | 536 | ||||
-rw-r--r-- | src/atombios_output.c | 1188 |
2 files changed, 1724 insertions, 0 deletions
diff --git a/src/atombios_crtc.c b/src/atombios_crtc.c new file mode 100644 index 00000000..8c0f5c1a --- /dev/null +++ b/src/atombios_crtc.c @@ -0,0 +1,536 @@ +/* + * Copyright © 2007 Dave Airlie + * + */ +/* + * avivo crtc handling functions. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +/* DPMS */ +#define DPMS_SERVER +#include <X11/extensions/dpms.h> + +#include "radeon.h" +#include "radeon_reg.h" +#include "avivo_reg.h" +#include "radeon_macros.h" +#include "radeon_atombios.h" + + +AtomBiosResult +atombios_enable_crtc(atomBIOSHandlePtr atomBIOS, int crtc, int state) +{ + ENABLE_CRTC_PS_ALLOCATION crtc_data; + AtomBIOSArg data; + unsigned char *space; + + crtc_data.ucCRTC = crtc; + crtc_data.ucEnable = state; + + data.exec.index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &crtc_data; + + if (RHDAtomBIOSFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("%s CRTC %d success\n", state? "Enable":"Disable", crtc); + return ATOM_SUCCESS ; + } + + ErrorF("Enable CRTC failed\n"); + return ATOM_NOT_IMPLEMENTED; +} + +AtomBiosResult +atombios_blank_crtc(atomBIOSHandlePtr atomBIOS, int crtc, int state) +{ + BLANK_CRTC_PS_ALLOCATION crtc_data; + unsigned char *space; + AtomBIOSArg data; + + memset(&crtc_data, 0, sizeof(crtc_data)); + crtc_data.ucCRTC = crtc; + crtc_data.ucBlanking = state; + + data.exec.index = offsetof(ATOM_MASTER_LIST_OF_COMMAND_TABLES, BlankCRTC) / sizeof(unsigned short); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &crtc_data; + + if (RHDAtomBIOSFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("%s CRTC %d success\n", state? "Blank":"Unblank", crtc); + return ATOM_SUCCESS ; + } + + ErrorF("Blank CRTC failed\n"); + return ATOM_NOT_IMPLEMENTED; +} + +static void +atombios_crtc_enable(xf86CrtcPtr crtc, int enable) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + int scan_enable, cntl; + AtomBiosResult res; + atombios_enable_crtc(info->atomBIOS, radeon_crtc->crtc_id, enable); + + //TODOavivo_wait_idle(avivo); +} + +void +atombios_crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + switch (mode) { + case DPMSModeOn: + case DPMSModeStandby: + case DPMSModeSuspend: + atombios_enable_crtc(info->atomBIOS, radeon_crtc->crtc_id, 1); + atombios_blank_crtc(info->atomBIOS, radeon_crtc->crtc_id, 0); + break; + case DPMSModeOff: + atombios_blank_crtc(info->atomBIOS, radeon_crtc->crtc_id, 1); + atombios_enable_crtc(info->atomBIOS, radeon_crtc->crtc_id, 0); + break; + } +} + +static void +atombios_set_crtc_source(xf86CrtcPtr crtc) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + AtomBIOSArg data; + unsigned char *space; + SELECT_CRTC_SOURCE_PS_ALLOCATION crtc_src_param; + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + int major, minor; + + atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); + + ErrorF("select crtc source table is %d %d\n", major, minor); + + switch(major) { + case 1: { + switch(minor) { + case 0: + case 1: + default: + crtc_src_param.ucCRTC = radeon_crtc->crtc_id; + crtc_src_param.ucDevice = radeon_crtc->crtc_id? 0: 3; + break; + } + break; + } + default: + break; + } + + data.exec.index = index; + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &crtc_src_param; + + if (RHDAtomBIOSFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Set CRTC Source success\n"); + return; + } + + ErrorF("Set CRTC Source failed\n"); + return; +} + +static AtomBiosResult +atombios_set_crtc_timing(atomBIOSHandlePtr atomBIOS, SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *crtc_param) +{ + AtomBIOSArg data; + unsigned char *space; + + data.exec.index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = crtc_param; + + if (RHDAtomBIOSFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Set CRTC Timing success\n"); + return ATOM_SUCCESS ; + } + + ErrorF("Set CRTC Timing failed\n"); + return ATOM_NOT_IMPLEMENTED; +} + +#define USE_RADEONHD_CODE_FOR_PLL 1 +#if USE_RADEONHD_CODE_FOR_PLL + +struct rhdPLL { + int scrnIndex; + +/* also used as an index to rhdPtr->PLLs */ +#define PLL_ID_PLL1 0 +#define PLL_ID_PLL2 1 +#define PLL_ID_NONE -1 + int Id; + + CARD32 CurrentClock; + Bool Active; + + /* from defaults or from atom */ + CARD32 RefClock; + CARD32 InMin; + CARD32 InMax; + CARD32 OutMin; + CARD32 OutMax; + CARD32 PixMin; + CARD32 PixMax; +}; + +static struct rhdPLL mypll = { + 0, 0, 0, 0, + 27000, + 1000, 13500, + 600000, 1100000, + 16000, 400000 +}; +/* + * Calculate the PLL parameters for a given dotclock. + */ +static Bool +PLLCalculate(CARD32 PixelClock, + CARD16 *RefDivider, CARD16 *FBDivider, CARD8 *PostDivider) +{ +/* limited by the number of bits available */ +#define FB_DIV_LIMIT 1024 /* rv6x0 doesn't like 2048 */ +#define REF_DIV_LIMIT 1024 +#define POST_DIV_LIMIT 128 + struct rhdPLL *PLL = &mypll; + CARD32 FBDiv, RefDiv, PostDiv, BestDiff = 0xFFFFFFFF; + float Ratio; + + Ratio = ((float) PixelClock) / ((float) PLL->RefClock); + + for (PostDiv = 2; PostDiv < POST_DIV_LIMIT; PostDiv++) { + CARD32 VCOOut = PixelClock * PostDiv; + + /* we are conservative and avoid the limits */ + if (VCOOut <= PLL->OutMin) + continue; + if (VCOOut >= PLL->OutMax) + break; + + for (RefDiv = 1; RefDiv <= REF_DIV_LIMIT; RefDiv++) + { + CARD32 Diff; + + FBDiv = (CARD32) ((Ratio * PostDiv * RefDiv) + 0.5); + + if (FBDiv >= FB_DIV_LIMIT) + break; + + if (FBDiv > (500 + (13 * RefDiv))) /* rv6x0 limit */ + break; + + Diff = abs( PixelClock - (FBDiv * PLL->RefClock) / (PostDiv * RefDiv) ); + + if (Diff < BestDiff) { + *FBDivider = FBDiv; + *RefDivider = RefDiv; + *PostDivider = PostDiv; + BestDiff = Diff; + } + + if (BestDiff == 0) + break; + } + if (BestDiff == 0) + break; + } + + if (BestDiff != 0xFFFFFFFF) { + ErrorF("PLL Calculation: %dkHz = " + "(((0x%X / 0x%X) * 0x%X) / 0x%X) (%dkHz off)\n", + (int) PixelClock, (unsigned int) PLL->RefClock, *RefDivider, + *FBDivider, *PostDivider, (int) BestDiff); + xf86DrvMsg(PLL->scrnIndex, X_INFO, "PLL for %dkHz uses %dkHz internally.\n", + (int) PixelClock, + (int) (PLL->RefClock * *FBDivider) / *RefDivider); + return TRUE; + } else { /* Should never happen */ + xf86DrvMsg(PLL->scrnIndex, X_ERROR, + "%s: Failed to get a valid PLL setting for %dkHz\n", + __func__, (int) PixelClock); + return FALSE; + } +} +#else // avivo code + + +#endif + +void +atombios_crtc_set_pll(xf86CrtcPtr crtc, DisplayModePtr mode) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + double c; + int div1, div2, clock; + int sclock; + uint16_t ref_div, fb_div; + uint8_t post_div; + int mul; + int major, minor; + SET_PIXEL_CLOCK_PS_ALLOCATION spc_param; + void *ptr; + AtomBIOSArg data; + unsigned char *space; + RADEONSavePtr save = &info->ModeReg; + + PLLCalculate(mode->Clock, &ref_div, &fb_div, &post_div); + + xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, + "crtc(%d) Clock: mode %d, PLL %d\n", + radeon_crtc->crtc_id, mode->Clock, sclock); + xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, + "crtc(%d) PLL : refdiv %d, fbdiv 0x%X(%d), pdiv %d\n", + radeon_crtc->crtc_id, ref_div, fb_div, fb_div, post_div); + + xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, + "AGD: crtc(%d) PLL : refdiv %d, fbdiv 0x%X(%d), pdiv %d\n", + radeon_crtc->crtc_id, save->ppll_ref_div, save->feedback_div, save->feedback_div, save->post_div); + + if (1) { + fb_div = save->feedback_div; + post_div = save->post_div; + ref_div = save->ppll_ref_div; + } + + atombios_get_command_table_version(info->atomBIOS, index, &major, &minor); + + ErrorF("table is %d %d\n", major, minor); + switch(major) { + case 1: + switch(minor) { + case 1: + case 2: { + spc_param.sPCLKInput.usPixelClock = sclock / 10; + spc_param.sPCLKInput.usRefDiv = ref_div; + spc_param.sPCLKInput.usFbDiv = fb_div; + spc_param.sPCLKInput.ucPostDiv = post_div; + spc_param.sPCLKInput.ucPpll = radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1; + spc_param.sPCLKInput.ucCRTC = radeon_crtc->crtc_id; + spc_param.sPCLKInput.ucRefDivSrc = 1; + + ptr = &spc_param; + break; + } + default: + ErrorF("Unknown table version\n"); + exit(-1); + } + break; + default: + ErrorF("Unknown table version\n"); + exit(-1); + } + + data.exec.index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = ptr; + + if (RHDAtomBIOSFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Set CRTC PLL success\n"); + return; + } + + ErrorF("Set CRTC PLL failed\n"); + return; +} + + +void +atombios_crtc_mode_set(xf86CrtcPtr crtc, + DisplayModePtr mode, + DisplayModePtr adjusted_mode, + int x, int y) +{ + ScrnInfoPtr screen_info = crtc->scrn; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long fb_location = crtc->scrn->fbOffset + info->fbLocation; + int regval; + AtomBiosResult atom_res; + RADEONSavePtr restore = &info->ModeReg; + + SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing; + + memset(&crtc_timing, 0, sizeof(crtc_timing)); + + crtc_timing.ucCRTC = radeon_crtc->crtc_id; + crtc_timing.usH_Total = adjusted_mode->CrtcHTotal; + crtc_timing.usH_Disp = adjusted_mode->CrtcHDisplay; + crtc_timing.usH_SyncStart = adjusted_mode->CrtcHSyncStart; + crtc_timing.usH_SyncWidth = adjusted_mode->CrtcHSyncEnd - adjusted_mode->CrtcHSyncStart; + + crtc_timing.usV_Total = adjusted_mode->CrtcVTotal; + crtc_timing.usV_Disp = adjusted_mode->CrtcVDisplay; + crtc_timing.usV_SyncStart = adjusted_mode->CrtcVSyncStart; + crtc_timing.usV_SyncWidth = adjusted_mode->CrtcVSyncEnd - adjusted_mode->CrtcVSyncStart; + + if (adjusted_mode->Flags & V_NVSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY; + + if (adjusted_mode->Flags & V_NHSYNC) + crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY; + + ErrorF("Mode %dx%d - %d %d %d\n", adjusted_mode->CrtcHDisplay, adjusted_mode->CrtcVDisplay, + adjusted_mode->CrtcHTotal, adjusted_mode->CrtcVTotal, adjusted_mode->Flags); + + if (0) { + radeon_crtc->fb_width = adjusted_mode->CrtcHDisplay; + radeon_crtc->fb_height = screen_info->virtualY; + radeon_crtc->fb_pitch = adjusted_mode->CrtcHDisplay; + radeon_crtc->fb_length = radeon_crtc->fb_pitch * radeon_crtc->fb_height * 4; + switch (crtc->scrn->bitsPerPixel) { + case 15: + radeon_crtc->fb_format = AVIVO_CRTC_FORMAT_ARGB15; + break; + case 16: + radeon_crtc->fb_format = AVIVO_CRTC_FORMAT_ARGB16; + break; + case 24: + case 32: + radeon_crtc->fb_format = AVIVO_CRTC_FORMAT_ARGB32; + break; + default: + FatalError("Unsupported screen depth: %d\n", xf86GetDepth()); + } + if (info->tilingEnabled) { + radeon_crtc->fb_format |= AVIVO_CRTC_MACRO_ADDRESS_MODE; + } + /* setup fb format and location + */ + OUTREG(AVIVO_CRTC1_EXPANSION_SOURCE + radeon_crtc->crtc_offset, + (mode->HDisplay << 16) | mode->VDisplay); + + OUTREG(AVIVO_CRTC1_FB_LOCATION + radeon_crtc->crtc_offset, fb_location); + OUTREG(AVIVO_CRTC1_FB_END + radeon_crtc->crtc_offset, fb_location); + OUTREG(AVIVO_CRTC1_FB_FORMAT + radeon_crtc->crtc_offset, + radeon_crtc->fb_format); + + OUTREG(AVIVO_CRTC1_X_LENGTH + radeon_crtc->crtc_offset, + crtc->scrn->virtualX); + OUTREG(AVIVO_CRTC1_Y_LENGTH + radeon_crtc->crtc_offset, + crtc->scrn->virtualY); + OUTREG(AVIVO_CRTC1_PITCH + radeon_crtc->crtc_offset, + crtc->scrn->displayWidth); + + OUTREG(AVIVO_CRTC1_SCAN_ENABLE + radeon_crtc->crtc_offset, 1); + + } + + atombios_set_crtc_source(crtc); + + atombios_set_crtc_timing(info->atomBIOS, &crtc_timing); + + atombios_crtc_set_pll(crtc, adjusted_mode); + +} + + + +static void +atombios_setup_cursor(ScrnInfoPtr pScrn, int id, int enable) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + if (id == 0) { + OUTREG(AVIVO_CURSOR1_CNTL, 0); + + if (enable) { + OUTREG(AVIVO_CURSOR1_LOCATION, info->fbLocation + + info->cursor_offset); + OUTREG(AVIVO_CURSOR1_SIZE, ((info->cursor_width -1) << 16) | + (info->cursor_height-1)); + OUTREG(AVIVO_CURSOR1_CNTL, AVIVO_CURSOR_EN | + (AVIVO_CURSOR_FORMAT_ARGB << + AVIVO_CURSOR_FORMAT_SHIFT)); + } + } +} + +void +atombios_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + int crtc_id = radeon_crtc->crtc_id; + + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + OUTREG(AVIVO_CURSOR1_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); + radeon_crtc->cursor_x = x; + radeon_crtc->cursor_y = y; +} + + +void +atombios_crtc_show_cursor(xf86CrtcPtr crtc) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + +#ifdef XF86DRI + if (info->CPStarted && crtc->scrn->pScreen) DRILock(crtc->scrn->pScreen, 0); +#endif + + RADEON_SYNC(info, crtc->scrn); + + OUTREG(AVIVO_CURSOR1_CNTL + radeon_crtc->crtc_offset, + INREG(AVIVO_CURSOR1_CNTL + radeon_crtc->crtc_offset) + | AVIVO_CURSOR_EN); + atombios_setup_cursor(crtc->scrn, radeon_crtc->crtc_id, 1); + +#ifdef XF86DRI + if (info->CPStarted && crtc->scrn->pScreen) DRIUnlock(crtc->scrn->pScreen); +#endif +} + +void +atombios_crtc_hide_cursor(xf86CrtcPtr crtc) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(crtc->scrn); + unsigned char *RADEONMMIO = info->MMIO; + +#ifdef XF86DRI + if (info->CPStarted && crtc->scrn->pScreen) DRILock(crtc->scrn->pScreen, 0); +#endif + + RADEON_SYNC(info, crtc->scrn); + + OUTREG(AVIVO_CURSOR1_CNTL+ radeon_crtc->crtc_offset, + INREG(AVIVO_CURSOR1_CNTL + radeon_crtc->crtc_offset) + & ~(AVIVO_CURSOR_EN)); + atombios_setup_cursor(crtc->scrn, radeon_crtc->crtc_id, 0); + +#ifdef XF86DRI + if (info->CPStarted && crtc->scrn->pScreen) DRIUnlock(crtc->scrn->pScreen); +#endif +} + +static void +atombios_crtc_destroy(xf86CrtcPtr crtc) +{ + if (crtc->driver_private) + xfree(crtc->driver_private); +} diff --git a/src/atombios_output.c b/src/atombios_output.c new file mode 100644 index 00000000..18e6d3c2 --- /dev/null +++ b/src/atombios_output.c @@ -0,0 +1,1188 @@ +/* + * Copyright © 2007 Dave Airlie + */ +/* + * avivo output handling functions. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +/* DPMS */ +#define DPMS_SERVER +#include <X11/extensions/dpms.h> +#include <unistd.h> + +#include "radeon.h" +#include "radeon_reg.h" +#include "radeon_macros.h" +#include "radeon_atombios.h" + +static +Bool AVIVOI2CDoLock(ScrnInfoPtr pScrn, int lock_state); + +static AtomBiosResult atom_bios_display_device_control(atomBIOSHandlePtr atomBIOS, int device, Bool state) +{ + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION disp_data; + AtomBIOSArg data; + unsigned char *space; + AtomBiosResult ret; + + disp_data.ucAction = state; + data.exec.index = device; + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &disp_data; + + if (RHDAtomBIOSFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Output %d enable success\n", device); + return ATOM_SUCCESS; + } + + ErrorF("Output %d enable failed\n", device); + return ATOM_NOT_IMPLEMENTED; +} + +static void +atom_bios_enable_crt(atomBIOSHandlePtr atomBIOS, int dac, Bool state) +{ + int output; + if (dac == DAC_PRIMARY) + output = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + else + output = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + + atom_bios_display_device_control(atomBIOS, output, state); +} + +static int +atombios_output_dac_setup(xf86OutputPtr output, DisplayModePtr mode) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + DAC_ENCODER_CONTROL_PS_ALLOCATION disp_data; + AtomBIOSArg data; + unsigned char *space; + AtomBiosResult ret; + + disp_data.ucAction = 1; + disp_data.ucDacStandard = 1; + disp_data.usPixelClock = mode->Clock / 10; + if (radeon_output->DACType == DAC_PRIMARY) + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + else + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &disp_data; + + if (RHDAtomBIOSFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Output DAC %d enable success\n", radeon_output->DACType); + return ATOM_SUCCESS; + } + + ErrorF("Output DAC %d enable failed\n", radeon_output->DACType); + return ATOM_NOT_IMPLEMENTED; + + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, CRT1OutputControl), ATOM_TRANSMITTER_ACTION_INIT); + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, CRT1OutputControl), ATOM_TRANSMITTER_ACTION_SETUP); + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, CRT1OutputControl), ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT); + return ATOM_SUCCESS; + +} + + +static int +atombios_output_tmds1_setup(xf86OutputPtr output, DisplayModePtr mode) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + unsigned int tmp; + TMDS1_ENCODER_CONTROL_PS_ALLOCATION disp_data; + AtomBIOSArg data; + unsigned char *space; + AtomBiosResult ret; + + disp_data.ucAction = 1; + if (mode->Clock > 165000) + disp_data.ucMisc = 1; + else + disp_data.ucMisc = 0; + disp_data.usPixelClock = mode->Clock / 10; + data.exec.index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &disp_data; + + if (RHDAtomBIOSFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Output TMDS1 enable success\n"); + return ATOM_SUCCESS; + } + + ErrorF("Output TMDS1 enable failed\n"); + return ATOM_NOT_IMPLEMENTED; + + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, DFP1OutputControl), ATOM_TRANSMITTER_ACTION_INIT); + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, DFP1OutputControl), ATOM_TRANSMITTER_ACTION_SETUP); + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, DFP1OutputControl), ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT); + return ATOM_SUCCESS; +} + +static void +atombios_output_tmds2_setup(xf86OutputPtr output, DisplayModePtr mode) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned int tmp; + TMDS2_ENCODER_CONTROL_PS_ALLOCATION disp_data; + AtomBIOSArg data; + unsigned char *space; + AtomBiosResult ret; + + disp_data.ucAction = 1; + if (mode->Clock > 165000) + disp_data.ucMisc = 1; + else + disp_data.ucMisc = 0; + disp_data.usPixelClock = mode->Clock / 10; + data.exec.index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &disp_data; + + if (RHDAtomBIOSFunc(info->atomBIOS->scrnIndex, info->atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + ErrorF("Output TMDS2 enable success\n"); + return ATOM_SUCCESS; + } + + ErrorF("Output TMDS2 enable failed\n"); + return ATOM_NOT_IMPLEMENTED; +} + +static void +atombios_output_dac_dpms(xf86OutputPtr output, int mode) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + + switch(mode) { + case DPMSModeOn: + atom_bios_enable_crt(info->atomBIOS, radeon_output->DACType, ATOM_ENABLE); + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + atom_bios_enable_crt(info->atomBIOS, radeon_output->DACType, ATOM_DISABLE); + break; + } +} + +static void +atombios_output_tmds1_dpms(xf86OutputPtr output, int mode) +{ + RADEONOutputPrivatePtr avivo_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + + switch(mode) { + case DPMSModeOn: + /* TODO */ + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl), ATOM_ENABLE); + + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + /* TODO */ + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl), ATOM_DISABLE); + break; + } +} + +static void +atombios_output_tmds2_dpms(xf86OutputPtr output, int mode) +{ + RADEONOutputPrivatePtr avivo_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + + switch(mode) { + case DPMSModeOn: + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl), ATOM_ENABLE); + /* TODO */ + break; + case DPMSModeStandby: + case DPMSModeSuspend: + case DPMSModeOff: + atom_bios_display_device_control(info->atomBIOS, GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl), ATOM_DISABLE); + /* TODO */ + break; + } +} + +static void +atombios_output_lvds_dpms(xf86OutputPtr output, int mode) +{ + atombios_output_tmds2_dpms(output, mode); +} + +void +atombios_output_dpms(xf86OutputPtr output, int mode) +{ + RADEONOutputPrivatePtr avivo_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + int tmp, count; + +#if 1 + /* try to grab card lock or at least somethings that looks like a lock + * if it fails more than 5 times with 1000ms wait btw each try than we + * assume we can process. + */ + count = 0; + tmp = INREG(0x0028); + while((tmp & 0x100) && (count < 5)) { + tmp = INREG(0x0028); + count++; + usleep(1000); + } + if (count >= 5) { + xf86DrvMsg(output->scrn->scrnIndex, X_INFO, + "%s (WARNING) failed to grab card lock process anyway.\n", + __func__); + } + OUTREG(0x0028, tmp | 0x100); +#endif + + ErrorF("AGD: output dpms\n"); + + if (avivo_output->MonType == MT_LCD) { + atombios_output_tmds2_dpms(output, mode); + } else if (avivo_output->MonType == MT_DFP) { + ErrorF("AGD: tmds dpms\n"); + atombios_output_tmds1_dpms(output, mode); + } else if (avivo_output->MonType == MT_CRT) { + ErrorF("AGD: dac dpms\n"); + atombios_output_dac_dpms(output, mode); + } + +#if 1 + /* release card lock */ + tmp = INREG(0x0028); + OUTREG(0x0028, tmp & (~0x100)); +#endif +} + +static int +atombios_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + if (pMode->Flags & V_DBLSCAN) + return MODE_NO_DBLESCAN; + + if (pMode->Clock > 400000 || pMode->Clock < 25000) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +static Bool +atombios_output_mode_fixup(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +atombios_output_prepare(xf86OutputPtr output) +{ + output->funcs->dpms(output, DPMSModeOff); +} + + + +void +atombios_output_mode_set(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + if (radeon_output->MonType == MT_CRT) { + if (radeon_output->DACType == DAC_PRIMARY) { + ErrorF("AGD: atom dac setup\n"); + atombios_output_dac_setup(output, adjusted_mode); + } + } else if (radeon_output->MonType == MT_DFP) { + ErrorF("AGD: atom tmds setup\n"); + if (radeon_output->TMDSType == TMDS_INT) + atombios_output_tmds1_setup(output, adjusted_mode); + else + atombios_output_tmds2_setup(output, adjusted_mode); + } else if (radeon_output->MonType == MT_LCD) { + atombios_output_tmds2_setup(output, adjusted_mode); + } +} + +static void +atombios_output_commit(xf86OutputPtr output) +{ + output->funcs->dpms(output, DPMSModeOn); +} + +DisplayModePtr +atombios_output_get_modes(xf86OutputPtr output) +{ + RADEONOutputPrivatePtr atombios_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + xf86MonPtr edid_mon; + DisplayModePtr modes; + + modes = RADEONProbeOutputModes(output); + return modes; +} + +static void +atombios_output_destroy(xf86OutputPtr output) +{ + RADEONOutputPrivatePtr avivo_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (avivo_output == NULL) + return; + xf86DestroyI2CBusRec(avivo_output->pI2CBus, TRUE, TRUE); + xfree(avivo_output->name); + xfree(avivo_output); +} + + +Bool +atombios_output_lfp_mode_fixup(xf86OutputPtr output, + DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + RADEONInfoPtr info = RADEONPTR(output->scrn); + +#if 0 + if (avivo->lfp_fixed_mode) { + adjusted_mode->HDisplay = info->lfp_fixed_mode->HDisplay; + adjusted_mode->HSyncStart = info->lfp_fixed_mode->HSyncStart; + adjusted_mode->HSyncEnd = info->lfp_fixed_mode->HSyncEnd; + adjusted_mode->HTotal = info->lfp_fixed_mode->HTotal; + adjusted_mode->VDisplay = info->lfp_fixed_mode->VDisplay; + adjusted_mode->VSyncStart = info->lfp_fixed_mode->VSyncStart; + adjusted_mode->VSyncEnd = info->lfp_fixed_mode->VSyncEnd; + adjusted_mode->VTotal = info->lfp_fixed_mode->VTotal; + adjusted_mode->Clock = info->lfp_fixed_mode->Clock; + xf86SetModeCrtc(adjusted_mode, 0); + } +#endif + return TRUE; +} + +DisplayModePtr +atombios_output_lfp_get_modes(xf86OutputPtr output) +{ + ScrnInfoPtr screen_info = output->scrn; + RADEONInfoPtr info = RADEONPTR(output->scrn); + DisplayModePtr modes = NULL; + + modes = atombios_output_get_modes(output); + if (modes == NULL) { + /* DDC EDID failed try to get timing from BIOS */ + xf86DrvMsg(screen_info->scrnIndex, X_WARNING, + "Failed to get EDID over i2c for LFP try BIOS timings.\n"); + modes = atombios_bios_get_lfp_timing(screen_info); + } +#if 0 + if (modes) { + xf86DeleteMode(&info->lfp_fixed_mode, info->lfp_fixed_mode); + info->lfp_fixed_mode = xf86DuplicateMode(modes); + } +#endif + return modes; +} + + + +void +atombios_i2c_gpio0_get_bits(I2CBusPtr b, int *Clock, int *data) +{ + ScrnInfoPtr screen_info = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(screen_info); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long val; + + ErrorF("INREG %08x\n", INREG(b->DriverPrivate.uval)); + /* Get the result */ + val = INREG(b->DriverPrivate.uval + 0xC); + *Clock = (val & (1<<19)) != 0; + *data = (val & (1<<18)) != 0; +} + +void +atombios_i2c_gpio0_put_bits(I2CBusPtr b, int Clock, int data) +{ + ScrnInfoPtr screen_info = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(screen_info); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long val; + + val = 0; + val |= (Clock ? 0:(1<<19)); + val |= (data ? 0:(1<<18)); + OUTREG(b->DriverPrivate.uval + 0x8, val); + /* read back to improve reliability on some cards. */ + val = INREG(b->DriverPrivate.uval + 0x8); +} + +void +atombios_i2c_gpio123_get_bits(I2CBusPtr b, int *Clock, int *data) +{ + ScrnInfoPtr screen_info = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(screen_info); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long val; + + if (INREG(b->DriverPrivate.uval) == 0) + OUTREG(b->DriverPrivate.uval, (1<<0) | (1<<8)); + + /* Get the result */ + val = INREG(b->DriverPrivate.uval + 0xC); + *Clock = (val & (1<<0)) != 0; + *data = (val & (1<<8)) != 0; +} + +void +atombios_i2c_gpio123_put_bits(I2CBusPtr b, int Clock, int data) +{ + ScrnInfoPtr screen_info = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(screen_info); + unsigned char *RADEONMMIO = info->MMIO; + unsigned long val; + + val = 0; + val |= (Clock ? 0:(1<<0)); + val |= (data ? 0:(1<<8)); + OUTREG(b->DriverPrivate.uval + 0x8, val); + /* read back to improve reliability on some cards. */ + val = INREG(b->DriverPrivate.uval + 0x8); +} + +static xf86OutputStatus +atombios_output_detect(xf86OutputPtr output) +{ + RADEONOutputPrivatePtr avivo_output = output->driver_private; + ScrnInfoPtr screen_info = output->scrn; + RADEONInfoPtr info = RADEONPTR(output->scrn); + unsigned char *RADEONMMIO = info->MMIO; + AtomBiosResult ret; + uint32_t bios_0_scratch; + + return radeon_detect(output); +} + +static const xf86OutputFuncsRec atombios_output_dac_funcs = { + .dpms = atombios_output_dpms, + .save = NULL, + .restore = NULL, + .mode_valid = atombios_output_mode_valid, + .mode_fixup = atombios_output_mode_fixup, + .prepare = atombios_output_prepare, + .mode_set = atombios_output_mode_set, + .commit = atombios_output_commit, + .detect = atombios_output_detect, + .get_modes = atombios_output_get_modes, + .destroy = atombios_output_destroy +}; + +static const xf86OutputFuncsRec atombios_output_tmds_funcs = { + .dpms = atombios_output_dpms, + .save = NULL, + .restore = NULL, + .mode_valid = atombios_output_mode_valid, + .mode_fixup = atombios_output_mode_fixup, + .prepare = atombios_output_prepare, + .mode_set = atombios_output_mode_set, + .commit = atombios_output_commit, + .detect = atombios_output_detect, + .get_modes = atombios_output_get_modes, + .destroy = atombios_output_destroy +}; + +static const xf86OutputFuncsRec atombios_output_lfp_funcs = { + .dpms = atombios_output_dpms, + .save = NULL, + .restore = NULL, + .mode_valid = atombios_output_mode_valid, + .mode_fixup = atombios_output_lfp_mode_fixup, + .prepare = atombios_output_prepare, + .mode_set = atombios_output_mode_set, + .commit = atombios_output_commit, + .detect = atombios_output_detect, + .get_modes = atombios_output_get_modes, + .destroy = atombios_output_destroy +}; + +Bool +atombios_output_exist(ScrnInfoPtr screen_info, xf86ConnectorType type, + int number, unsigned long ddc_reg) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(screen_info); + int i; + + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + RADEONOutputPrivatePtr avivo_output = output->driver_private; + if (avivo_output->num == number && avivo_output->type == type) + return TRUE; + /* LVTMA is shared by LFP & DVI-I */ + if (avivo_output->type == XF86ConnectorLFP && number >= 1) + return TRUE; + if (type == XF86ConnectorLFP && avivo_output->num >= 1) { + avivo_output->type = type; + avivo_output->pI2CBus->DriverPrivate.uval = ddc_reg; + return TRUE; + } + } + return FALSE; +} + +#if 0 +Bool +avivo_output_init(ScrnInfoPtr screen_info, xf86ConnectorType type, + int number, unsigned long ddc_reg) +{ + xf86OutputPtr output = {0,}; + RADEONOutputPrivateRec *avivo_output; + int name_size; + + /* allocate & initialize private output structure */ + avivo_output = xcalloc(sizeof(RADEONOutputPrivateRec), 1); + if (avivo_output == NULL) + return FALSE; + name_size = snprintf(NULL, 0, "%s connector %d", + xf86ConnectorGetName(type), number); + avivo_output->name = xcalloc(name_size + 1, 1); + if (avivo_output->name == NULL) { + xfree(avivo_output); + xf86DrvMsg(screen_info->scrnIndex, X_ERROR, + "Failed to allocate memory for I2C bus name\n"); + return FALSE; + } + snprintf(avivo_output->name, name_size + 1, "%s connector %d", + xf86ConnectorGetName(type), number); + avivo_output->pI2CBus = xf86CreateI2CBusRec(); + if (!avivo_output->pI2CBus) { + xfree(avivo_output); + xf86DrvMsg(screen_info->scrnIndex, X_ERROR, + "Couldn't create I2C bus for %s connector %d\n", + xf86ConnectorGetName(type), number); + return FALSE; + } + avivo_output->pI2CBus->BusName = avivo_output->name; + avivo_output->pI2CBus->scrnIndex = screen_info->scrnIndex; + if (ddc_reg == AVIVO_GPIO_0) { + avivo_output->pI2CBus->I2CPutBits = atombios_i2c_gpio0_put_bits; + avivo_output->pI2CBus->I2CGetBits = atombios_i2c_gpio0_get_bits; + } else { + avivo_output->pI2CBus->I2CPutBits = avivo_i2c_gpio123_put_bits; + avivo_output->pI2CBus->I2CGetBits = avivo_i2c_gpio123_get_bits; + } + avivo_output->pI2CBus->AcknTimeout = 5; + avivo_output->pI2CBus->DriverPrivate.uval = ddc_reg; + if (!xf86I2CBusInit(avivo_output->pI2CBus)) { + xf86DrvMsg(screen_info->scrnIndex, X_ERROR, + "Couldn't initialise I2C bus for %s connector %d\n", + xf86ConnectorGetName(type), number); + return FALSE; + } + avivo_output->gpio = ddc_reg; + avivo_output->type = type; + avivo_output->num = number; + switch (avivo_output->type) { + case XF86ConnectorVGA: + avivo_output->setup = avivo_output_dac_setup; + avivo_output->dpms = avivo_output_dac_dpms; + output = xf86OutputCreate (screen_info, + &avivo_output_dac_funcs, + xf86ConnectorGetName(type)); + break; + case XF86ConnectorLFP: + avivo_output->setup = avivo_output_tmds2_setup; + avivo_output->dpms = avivo_output_lvds_dpms; + output = xf86OutputCreate (screen_info, + &avivo_output_lfp_funcs, + xf86ConnectorGetName(type)); + break; + case XF86ConnectorDVI_I: + case XF86ConnectorDVI_D: + case XF86ConnectorDVI_A: + if (!number) { + avivo_output->setup = avivo_output_tmds1_setup; + avivo_output->dpms = avivo_output_tmds1_dpms; + } else { + avivo_output->setup = avivo_output_tmds2_setup; + avivo_output->dpms = avivo_output_tmds2_dpms; + } + output = xf86OutputCreate (screen_info, + &avivo_output_tmds_funcs, + xf86ConnectorGetName(type)); + break; + default: + avivo_output->setup = NULL; + break; + } + + if (output == NULL) { + xf86DestroyI2CBusRec(avivo_output->pI2CBus, TRUE, TRUE); + xfree(avivo_output); + return FALSE; + } + output->driver_private = avivo_output; + output->interlaceAllowed = FALSE; + output->doubleScanAllowed = FALSE; + xf86DrvMsg(screen_info->scrnIndex, X_INFO, + "added %s connector %d (0x%04lX)\n", + xf86ConnectorGetName(type), number, ddc_reg); + + return TRUE; +} +#endif +extern void RADEONSetOutputType(ScrnInfoPtr pScrn, RADEONOutputPrivatePtr radeon_output); +extern void RADEONInitConnector(xf86OutputPtr output); +extern const char *OutputType[], *DDCTypeName[]; + + +static +Bool AVIVOI2CReset(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(AVIVO_I2C_STOP, 1); + INREG(AVIVO_I2C_STOP); + OUTREG(AVIVO_I2C_STOP, 0x0); + return TRUE; +} + +static +Bool AVIVOI2CDoLock(ScrnInfoPtr pScrn, int lock_state) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 temp; + int count=0; + + switch(lock_state) { + case 0: + temp = INREG(AVIVO_I2C_CNTL); + OUTREG(AVIVO_I2C_CNTL, temp | 0x100); + /* enable hdcp block */ + OUTREG(R520_PCLK_HDCP_CNTL, 0x0); + break; + case 1: + /* disable hdcp block */ + OUTREG(R520_PCLK_HDCP_CNTL, 0x1); + usleep(1); + OUTREG(AVIVO_I2C_CNTL, 0x1); + usleep(1); + temp = INREG(AVIVO_I2C_CNTL); + if (!(temp & 0x2)) { + ErrorF("Lock failed %08X\n", temp); + return FALSE; + } + break; + } + return TRUE; +} + +#if 0 +static Bool +AVIVOI2CSendData(I2CDevPtr d, int address, int nWrite, I2CByte *data) +{ + I2CBusPtr b = d->pI2CBus; + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 temp; + int count, i; + + OUTREG(AVIVO_I2C_STATUS, (AVIVO_I2C_STATUS_DONE | AVIVO_I2C_STATUS_NACK | AVIVO_I2C_STATUS_HALT)); + temp = INREG(AVIVO_I2C_START_CNTL); + temp |= R520_I2C_START | R520_I2C_STOP | R520_I2C_RX | R520_I2C_EN; + + temp &= ~R520_I2C_DDC_MASK; + + switch(b->DriverPrivate.uval) + { + case 0x7e40: + temp |= R520_I2C_DDC1; + break; + case 0x7e50: + default: + temp |= R520_I2C_DDC2; + break; + } + + OUTREG(AVIVO_I2C_START_CNTL, temp); + + temp = INREG(AVIVO_I2C_CONTROL2); + temp &= ~R520_I2C_DATA_COUNT_MASK; + temp |= 1 << R520_I2C_DATA_COUNT_SHIFT; + temp &= ~R520_I2C_ADDR_COUNT_MASK; + temp |= 1; + OUTREG(AVIVO_I2C_CONTROL2, temp); + + temp = INREG(AVIVO_I2C_CONTROL3); + OUTREG(AVIVO_I2C_CONTROL3, temp); + + OUTREG(AVIVO_I2C_DATA, address); + for (i=0; i<nWrite; i++) + OUTREG(AVIVO_I2C_DATA, data[i]); + + /* set to i2c tx mode */ + temp = INREG(AVIVO_I2C_START_CNTL); + temp &= ~R520_I2C_RX; + OUTREG(AVIVO_I2C_START_CNTL, temp); + + /* set go flag */ + OUTREG(AVIVO_I2C_STATUS, AVIVO_I2C_STATUS_GO); + + count = 0; + do { + temp = INREG(AVIVO_I2C_STATUS); + if (temp & AVIVO_I2C_STATUS_DONE) + break; + usleep(1); + count++; + } while(count<10); + + if (count == 10) + return FALSE; + OUTREG(AVIVO_I2C_STATUS, temp); + + return TRUE; +} +static Bool +AVIVOI2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, + I2CByte *ReadBuffer, int nRead) +{ + I2CBusPtr b = d->pI2CBus; + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 temp; + int i, count; + int sofar, thisread; + I2CByte offbuf[1]; + Bool ret; + + AVIVOI2CReset(pScrn); + + /* set the control1 flags */ + if (nWrite > 1) + { + ret = AVIVOI2CSendData(d, d->SlaveAddr, nWrite, WriteBuffer); + if (ret==FALSE) + return FALSE; + } + + if (nRead > 0 && nWrite == 1) + { + /* okay this is a standard read - the i2c hw can only do 15 bytes */ + sofar = 0; + do { + thisread = nRead - sofar; + if (thisread > 15) + thisread = 15; + + offbuf[0] = sofar; + ret = AVIVOI2CSendData(d, d->SlaveAddr, 1, offbuf); + if (ret==FALSE) + return FALSE; + + OUTREG(AVIVO_I2C_DATA, d->SlaveAddr | 0x1); + + temp = INREG(AVIVO_I2C_START_CNTL); + temp |= R520_I2C_RX; + OUTREG(AVIVO_I2C_START_CNTL, temp); + + temp = INREG(AVIVO_I2C_CONTROL2); + temp &= ~R520_I2C_DATA_COUNT_MASK; + temp |= thisread << R520_I2C_DATA_COUNT_SHIFT; + temp &= ~R520_I2C_ADDR_COUNT_MASK; + temp |= 1; + OUTREG(AVIVO_I2C_CONTROL2, temp); + + OUTREG(AVIVO_I2C_STATUS, AVIVO_I2C_STATUS_GO); + count = 0; + do { + temp = INREG(AVIVO_I2C_STATUS); + if (temp & AVIVO_I2C_STATUS_DONE) + break; + usleep(1); + count++; + } while(count<100); + if (count == 100) + return FALSE; + + OUTREG(AVIVO_I2C_STATUS, temp); + + for (i=0; i<thisread; i++) + { + temp = INREG(AVIVO_I2C_DATA); + ReadBuffer[sofar+i] = (I2CByte)(temp & 0xff); + } + sofar += thisread; + } while(sofar < nRead); + } + return TRUE; +} + + +Bool atombios_i2c_init(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + I2CBusPtr pI2CBus; + + pI2CBus = xf86CreateI2CBusRec(); + if (!pI2CBus) + return FALSE; + + pI2CBus->BusName = name; + pI2CBus->scrnIndex = pScrn->scrnIndex; + pI2CBus->I2CWriteRead = AVIVOI2CWriteRead; + pI2CBus->DriverPrivate.uval = i2c_reg; + + ErrorF("uval is %04X\n", i2c_reg); + if (!xf86I2CBusInit(pI2CBus)) + return FALSE; + + *bus_ptr = pI2CBus; + return TRUE; +} + +#else +Bool +atom_bios_i2c_init(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg, char *name) +{ + I2CBusPtr pI2CBus; + + pI2CBus = xf86CreateI2CBusRec(); + if (!pI2CBus) return FALSE; + + pI2CBus->BusName = name; + pI2CBus->scrnIndex = pScrn->scrnIndex; + if (i2c_reg == AVIVO_GPIO_0) { + pI2CBus->I2CPutBits = atombios_i2c_gpio0_put_bits; + pI2CBus->I2CGetBits = atombios_i2c_gpio0_get_bits; + } else { + pI2CBus->I2CPutBits = atombios_i2c_gpio123_put_bits; + pI2CBus->I2CGetBits = atombios_i2c_gpio123_get_bits; + } + pI2CBus->AcknTimeout = 5; + pI2CBus->DriverPrivate.uval = i2c_reg; + + if (!xf86I2CBusInit(pI2CBus)) return FALSE; + + *bus_ptr = pI2CBus; + return TRUE; +} +#endif + +void atombios_init_connector(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int DDCReg = 0; + char* name = (char*) DDCTypeName[radeon_output->DDCType]; + + if (radeon_output->gpio) { + radeon_output->DDCReg = radeon_output->gpio; + if (IS_AVIVO_VARIANT) + atom_bios_i2c_init(pScrn, &radeon_output->pI2CBus, radeon_output->gpio, output->name); + else + RADEONI2CInit(pScrn, &radeon_output->pI2CBus, radeon_output->DDCReg, name); + } + + if (radeon_output->type == OUTPUT_LVDS) { + RADEONGetLVDSInfo(output); + } + + if (radeon_output->type == OUTPUT_DVI) { + // RADEONGetTMDSInfo(output); + } + + if (radeon_output->type == OUTPUT_STV || + radeon_output->type == OUTPUT_CTV) { + // RADEONGetTVInfo(output); + } + + if (radeon_output->DACType == DAC_TVDAC) { + radeon_output->tv_on = FALSE; + // RADEONGetTVDacAdjInfo(output); + } + +} + +Bool atombios_setup_outputs(ScrnInfoPtr pScrn, int num_vga, int num_dvi) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + xf86OutputPtr output; + int i; + + for (i = 0 ; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + if (info->BiosConnector[i].valid) { + RADEONOutputPrivatePtr radeon_output = xnfcalloc(sizeof(RADEONOutputPrivateRec), 1); + if (!radeon_output) { + return FALSE; + } + radeon_output->MonType = MT_UNKNOWN; + radeon_output->ConnectorType = info->BiosConnector[i].ConnectorType; + radeon_output->DDCType = info->BiosConnector[i].DDCType; + radeon_output->gpio = info->BiosConnector[i].gpio; + if (info->IsAtomBios) { + if (radeon_output->ConnectorType == CONNECTOR_DVI_D_ATOM) + radeon_output->DACType = DAC_NONE; + else + radeon_output->DACType = info->BiosConnector[i].DACType; + + if (radeon_output->ConnectorType == CONNECTOR_VGA_ATOM) + radeon_output->TMDSType = TMDS_NONE; + else + radeon_output->TMDSType = info->BiosConnector[i].TMDSType; + } else { + if (radeon_output->ConnectorType == CONNECTOR_DVI_D) + radeon_output->DACType = DAC_NONE; + else + radeon_output->DACType = info->BiosConnector[i].DACType; + + if (radeon_output->ConnectorType == CONNECTOR_CRT) + radeon_output->TMDSType = TMDS_NONE; + else + radeon_output->TMDSType = info->BiosConnector[i].TMDSType; + } + RADEONSetOutputType(pScrn, radeon_output); + fprintf(stderr,"output type is %d\n", radeon_output->type); + if (info->IsAtomBios) { + if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D_ATOM) || + (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I_ATOM) || + (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_A_ATOM)) { + if (num_dvi > 1) { + output = xf86OutputCreate(pScrn, &atombios_output_tmds_funcs, "DVI-1"); + num_dvi--; + } else { + output = xf86OutputCreate(pScrn, &atombios_output_tmds_funcs, "DVI-0"); + } + } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_VGA_ATOM) { + if (num_vga > 1) { + output = xf86OutputCreate(pScrn, &atombios_output_dac_funcs, "VGA-1"); + num_vga--; + } else { + output = xf86OutputCreate(pScrn, &atombios_output_dac_funcs, "VGA-0"); + } + } else if (info->BiosConnector[i].ConnectorType != CONNECTOR_STV) + output = xf86OutputCreate(pScrn, &atombios_output_lfp_funcs, OutputType[radeon_output->type]); + } else { + if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) || + (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I)) { + if (num_dvi > 1) { + output = xf86OutputCreate(pScrn, &atombios_output_tmds_funcs, "DVI-1"); + num_dvi--; + } else { + output = xf86OutputCreate(pScrn, &atombios_output_tmds_funcs, "DVI-0"); + } + } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_CRT) { + if (num_vga > 1) { + output = xf86OutputCreate(pScrn, &atombios_output_dac_funcs, "VGA-1"); + num_vga--; + } else { + output = xf86OutputCreate(pScrn, &atombios_output_dac_funcs, "VGA-0"); + } + } else + output = xf86OutputCreate(pScrn, &atombios_output_lfp_funcs, OutputType[radeon_output->type]); + } + + if (!output) { + return FALSE; + } + output->driver_private = radeon_output; + output->possible_crtcs = 1; + /* crtc2 can drive LVDS, it just doesn't have RMX */ + if (radeon_output->type != OUTPUT_LVDS) + output->possible_crtcs |= 2; + + /* we can clone the DACs, and probably TV-out, + but I'm not sure it's worth the trouble */ + output->possible_clones = 0; + + atombios_init_connector(output); + } + } + return TRUE; +} + +static AtomBiosResult +atom_bios_dac_load_detect(atomBIOSHandlePtr atomBIOS, int dac) +{ + DAC_LOAD_DETECTION_PS_ALLOCATION dac_data; + AtomBIOSArg data; + unsigned char *space; + + dac_data.sDacload.usDeviceID = 0; + dac_data.sDacload.ucDacType = 0; + dac_data.sDacload.ucMisc = 0; + + data.exec.index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + data.exec.dataSpace = (void *)&space; + data.exec.pspace = &dac_data; + + if (RHDAtomBIOSFunc(atomBIOS->scrnIndex, atomBIOS, ATOMBIOS_EXEC, &data) == ATOM_SUCCESS) { + + ErrorF("Dac detection success\n"); + return ATOM_SUCCESS ; + } + + ErrorF("DAC detection failed\n"); + return ATOM_NOT_IMPLEMENTED; +} + +static RADEONMonitorType atombios_dac_detect(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONMonitorType MonType = MT_NONE; + AtomBiosResult ret; + uint32_t bios_0_scratch; + + ret = atom_bios_dac_load_detect(info->atomBIOS, radeon_output->DACType); + if (ret == ATOM_SUCCESS) { + ErrorF("DAC connect %08X\n", INREG(0x10)); + bios_0_scratch = INREG(RADEON_BIOS_0_SCRATCH); + + if (radeon_output->DACType == DAC_PRIMARY) { + if (bios_0_scratch & ATOM_S0_CRT1_COLOR) + MonType = MT_CRT; + } else { + if (bios_0_scratch & ATOM_S0_CRT2_COLOR) + MonType = MT_CRT; + } + } + return MonType; +} + +static RADEONMonitorType atombios_port_check_nonddc(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONMonitorType MonType = MT_NONE; + uint32_t bios_0_scratch; + int ret; + if (radeon_output->type == OUTPUT_LVDS) { + MonType = MT_LCD; + } +#if 0 + else if (radeon_output->type == OUTPUT_DVI) { + if (radeon_output->TMDSType == TMDS_INT) { + if (INREG(RADEON_FP_GEN_CNTL) & RADEON_FP_DETECT_SENSE) + MonType = MT_DFP; + } else if (radeon_output->TMDSType == TMDS_EXT) { + if (INREG(RADEON_FP2_GEN_CNTL) & RADEON_FP2_DETECT_SENSE) + MonType = MT_DFP; + } + } +#endif + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected Monitor Type: %d\n", MonType); + + return MonType; + +} + + +static RADEONMonitorType +atombios_display_ddc_connected(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long DDCReg; + RADEONMonitorType MonType = MT_NONE; + xf86MonPtr* MonInfo = &output->MonInfo; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONDDCType DDCType = radeon_output->DDCType; + int i, j; + + if (!IS_AVIVO_VARIANT) { + ErrorF("AGD: DDCConnected\n"); + return RADEONDisplayDDCConnected(pScrn, output); + } + + AVIVOI2CDoLock(output->scrn, 1); + *MonInfo = xf86OutputGetEDID(output, radeon_output->pI2CBus); + AVIVOI2CDoLock(output->scrn, 0); + if (*MonInfo) { + if ((info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_LVDS_ATOM) || + (!info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_PROPRIETARY)) { + MonType = MT_LCD; + } else if ((info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_D_ATOM) || + (!info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_D)) { + MonType = MT_DFP; + } else if (radeon_output->type == OUTPUT_DVI && + ((*MonInfo)->rawData[0x14] & 0x80)) { /* if it's digital and DVI */ + MonType = MT_DFP; + } else { + MonType = MT_CRT; + } + } else MonType = MT_NONE; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DDC Type: %d[%04x], Detected Monitor Type: %d\n", DDCType, radeon_output->gpio, MonType); + + return MonType; +} + +extern const char *ConnectorTypeNameATOM[]; +extern const char *ConnectorTypeName[]; + +void atombios_connector_find_monitor(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + ErrorF("AGD: atom connector find monitor\n"); + + if (radeon_output->MonType == MT_UNKNOWN) { + radeon_output->MonType = atombios_display_ddc_connected(pScrn, output); + if (!radeon_output->MonType) { + ErrorF("AGD: No DDC\n"); + if (radeon_output->type == OUTPUT_LVDS || radeon_output->type == OUTPUT_DVI) + radeon_output->MonType = atombios_port_check_nonddc(pScrn, output); +#if 0 + if (!radeon_output->MonType) { + if (radeon_output->DACType == DAC_PRIMARY) { + radeon_output->MonType = atombios_dac_detect(pScrn, output); + } else if (radeon_output->DACType == DAC_TVDAC) { + radeon_output->MonType = atombios_dac_detect(pScrn, output); + } + } +#endif + if (!radeon_output->MonType) { + radeon_output->MonType = MT_NONE; + } + } + } + /* update panel info for RMX */ + // if (radeon_output->MonType == MT_LCD || radeon_output->MonType == MT_DFP) + // RADEONUpdatePanelSize(output); + + if (output->MonInfo) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID data from the display on connector: %s ----------------------\n", + info->IsAtomBios ? + ConnectorTypeNameATOM[radeon_output->ConnectorType]: + ConnectorTypeName[radeon_output->ConnectorType] + ); + xf86PrintEDID( output->MonInfo ); + } +} |