diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/local_xf86Rename.h | 23 | ||||
-rw-r--r-- | src/radeon.h | 271 | ||||
-rw-r--r-- | src/radeon_bios.c | 1000 | ||||
-rw-r--r-- | src/radeon_crtc.c | 1323 | ||||
-rw-r--r-- | src/radeon_cursor.c | 302 | ||||
-rw-r--r-- | src/radeon_display.c | 1700 | ||||
-rw-r--r-- | src/radeon_dri.c | 8 | ||||
-rw-r--r-- | src/radeon_driver.c | 3272 | ||||
-rw-r--r-- | src/radeon_mergedfb.c | 2118 | ||||
-rw-r--r-- | src/radeon_mergedfb.h | 121 | ||||
-rw-r--r-- | src/radeon_modes.c | 691 | ||||
-rw-r--r-- | src/radeon_output.c | 2569 | ||||
-rw-r--r-- | src/radeon_probe.h | 119 | ||||
-rw-r--r-- | src/radeon_reg.h | 160 | ||||
-rw-r--r-- | src/radeon_tv.c | 759 | ||||
-rw-r--r-- | src/radeon_tv.h | 56 | ||||
-rw-r--r-- | src/radeon_version.h | 2 | ||||
-rw-r--r-- | src/radeon_video.c | 169 |
19 files changed, 7413 insertions, 7257 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 84642f7..709b98c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,10 +77,11 @@ radeon_drv_la_LTLIBRARIES = radeon_drv.la radeon_drv_la_LDFLAGS = -module -avoid-version radeon_drv_ladir = @moduledir@/drivers radeon_drv_la_SOURCES = \ - radeon_accel.c radeon_mergedfb.c radeon_cursor.c radeon_dga.c \ + radeon_accel.c radeon_cursor.c radeon_dga.c \ radeon_driver.c radeon_video.c radeon_bios.c radeon_mm_i2c.c \ radeon_vip.c radeon_misc.c radeon_probe.c radeon_display.c \ - radeon_modes.c $(RADEON_DRI_SRCS) $(RADEON_EXA_SOURCES) + radeon_crtc.c radeon_output.c radeon_modes.c radeon_tv.c \ + $(RADEON_DRI_SRCS) $(RADEON_EXA_SOURCES) theatre_detect_drv_la_LTLIBRARIES = theatre_detect_drv.la theatre_detect_drv_la_LDFLAGS = -module -avoid-version @@ -175,12 +176,12 @@ EXTRA_DIST = \ radeon_exa_funcs.c \ radeon.h \ radeon_macros.h \ - radeon_mergedfb.h \ radeon_probe.h \ radeon_reg.h \ radeon_sarea.h \ radeon_version.h \ radeon_video.h \ + radeon_tv.h \ theatre200.h \ theatre_detect.h \ theatre.h \ diff --git a/src/local_xf86Rename.h b/src/local_xf86Rename.h new file mode 100644 index 0000000..5102170 --- /dev/null +++ b/src/local_xf86Rename.h @@ -0,0 +1,23 @@ +/* + * Copyright © 2006 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#define XF86NAME(x) radeon_##x diff --git a/src/radeon.h b/src/radeon.h index b19b017..aee4c3e 100644 --- a/src/radeon.h +++ b/src/radeon.h @@ -65,6 +65,8 @@ #include "xf86xv.h" #include "radeon_probe.h" +#include "radeon_tv.h" + /* DRI support */ #ifdef XF86DRI #define _XF86DRI_SERVER_ @@ -77,6 +79,9 @@ #endif #endif +#include "xf86Crtc.h" +#include "X11/Xatom.h" + /* Render support */ #ifdef RENDER #include "picturestr.h" @@ -115,21 +120,9 @@ typedef enum { OPTION_ACCEL_DFS, #endif #endif - OPTION_PANEL_OFF, OPTION_DDC_MODE, - OPTION_MONITOR_LAYOUT, OPTION_IGNORE_EDID, OPTION_FBDEV, - OPTION_MERGEDFB, - OPTION_CRT2HSYNC, - OPTION_CRT2VREFRESH, - OPTION_CRT2POS, - OPTION_METAMODES, - OPTION_MERGEDDPI, - OPTION_RADEONXINERAMA, - OPTION_CRT2ISSCRN0, - OPTION_MERGEDFBNONRECT, - OPTION_MERGEDFBMOUSER, OPTION_DISP_PRIORITY, OPTION_PANEL_SIZE, OPTION_MIN_DOTCLOCK, @@ -157,34 +150,10 @@ typedef enum { OPTION_LVDS_PROBE_PLL, OPTION_ACCELMETHOD, OPTION_CONSTANTDPI, - OPTION_REVERSE_DISPLAY, + OPTION_CONNECTORTABLE, OPTION_DRI } RADEONOpts; -/* ------- mergedfb support ------------- */ - /* Psuedo Xinerama support */ -#define NEED_REPLIES /* ? */ -#define EXTENSION_PROC_ARGS void * -#include "extnsionst.h" /* required */ -#include <X11/extensions/panoramiXproto.h> /* required */ -#define RADEON_XINERAMA_MAJOR_VERSION 1 -#define RADEON_XINERAMA_MINOR_VERSION 1 - - -/* Relative merge position */ -typedef enum { - radeonLeftOf, - radeonRightOf, - radeonAbove, - radeonBelow, - radeonClone -} RADEONScrn2Rel; - -typedef struct _region { - int x0,x1,y0,y1; -} region; - -/* ------------------------------------- */ #define RADEON_IDLE_RETRY 16 /* Fall out of idle loops after this count */ #define RADEON_TIMEOUT 2000000 /* Fall out of wait loops after this count */ @@ -199,12 +168,26 @@ typedef struct _region { #define RADEON_LOGLEVEL_DEBUG 4 +/* for Xv, outputs */ +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) /* Other macros */ #define RADEON_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define RADEON_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1)) #define RADEONPTR(pScrn) ((RADEONInfoPtr)(pScrn)->driverPrivate) +typedef struct { + int revision; + CARD16 rr1_offset; + CARD16 rr2_offset; + CARD16 dyn_clk_offset; + CARD16 pll_offset; + CARD16 mem_config_offset; + CARD16 mem_reset_offset; + CARD16 short_mem_offset; + CARD16 rr3_offset; + CARD16 rr4_offset; +} RADEONBIOSInitTable; typedef struct { /* Common registers */ @@ -253,10 +236,11 @@ typedef struct { CARD32 disp_merge_cntl; CARD32 grph_buffer_cntl; CARD32 crtc_more_cntl; + CARD32 crtc_tile_x0_y0; /* CRTC2 registers */ CARD32 crtc2_gen_cntl; - + CARD32 dac_macro_cntl; CARD32 dac2_cntl; CARD32 disp_output_cntl; CARD32 disp_tv_out_cntl; @@ -270,6 +254,8 @@ typedef struct { CARD32 crtc2_offset; CARD32 crtc2_offset_cntl; CARD32 crtc2_pitch; + CARD32 crtc2_tile_x0_y0; + /* Flat panel registers */ CARD32 fp_crtc_h_total_disp; CARD32 fp_crtc_v_total_disp; @@ -297,7 +283,7 @@ typedef struct { unsigned ppll_ref_div; unsigned ppll_div_3; CARD32 htotal_cntl; - CARD32 vclk_cntl; + CARD32 vclk_ecp_cntl; /* Computed values for PLL2 */ CARD32 dot_clock_freq_2; @@ -316,12 +302,54 @@ typedef struct { CARD32 palette[256]; CARD32 palette2[256]; - CARD32 tv_dac_cntl; - CARD32 rs480_unk_e30; CARD32 rs480_unk_e34; CARD32 rs480_unk_e38; CARD32 rs480_unk_e3c; + + /* TV out registers */ + CARD32 tv_master_cntl; + CARD32 tv_htotal; + CARD32 tv_hsize; + CARD32 tv_hdisp; + CARD32 tv_hstart; + CARD32 tv_vtotal; + CARD32 tv_vdisp; + CARD32 tv_timing_cntl; + CARD32 tv_vscaler_cntl1; + CARD32 tv_vscaler_cntl2; + CARD32 tv_sync_size; + CARD32 tv_vrestart; + CARD32 tv_hrestart; + CARD32 tv_frestart; + CARD32 tv_ftotal; + CARD32 tv_clock_sel_cntl; + CARD32 tv_clkout_cntl; + CARD32 tv_data_delay_a; + CARD32 tv_data_delay_b; + CARD32 tv_dac_cntl; + CARD32 tv_pll_cntl; + CARD32 tv_pll_fine_cntl; + CARD32 tv_modulator_cntl1; + CARD32 tv_modulator_cntl2; + CARD32 tv_frame_lock_cntl; + CARD32 tv_pre_dac_mux_cntl; + CARD32 tv_rgb_cntl; + CARD32 tv_y_saw_tooth_cntl; + CARD32 tv_y_rise_cntl; + CARD32 tv_y_fall_cntl; + CARD32 tv_uv_adr; + CARD32 tv_upsamp_and_gain_cntl; + CARD32 tv_gain_limit_settings; + CARD32 tv_linear_gain_settings; + CARD32 tv_crc_cntl; + CARD32 tv_sync_cntl; + CARD32 gpiopad_a; + CARD32 pll_test_cntl; + + CARD16 h_code_timing[MAX_H_CODE_TIMING_LEN]; + CARD16 v_code_timing[MAX_V_CODE_TIMING_LEN]; + } RADEONSaveRec, *RADEONSavePtr; typedef struct { @@ -397,11 +425,6 @@ typedef enum { } RADEONCardType; typedef struct { - CARD32 freq; - CARD32 value; -}RADEONTMDSPll; - -typedef struct { EntityInfoPtr pEnt; pciVideoPtr PciInfo; PCITAG PciTag; @@ -433,19 +456,10 @@ typedef struct { unsigned long FbMapSize; /* Size of frame buffer, in bytes */ unsigned long FbSecureSize; /* Size of secured fb area at end of framebuffer */ - int Flags; /* Saved copy of mode flags */ - - /* VE/M6 support */ - RADEONMonitorType DisplayType; /* Monitor connected on */ - RADEONDDCType DDCType; - RADEONConnectorType ConnectorType; Bool IsMobility; /* Mobile chips for laptops */ Bool IsIGP; /* IGP chips */ Bool HasSingleDAC; /* only TVDAC on chip */ - Bool IsSecondary; /* Second Screen */ - Bool IsPrimary; /* Primary Screen */ - Bool IsSwitching; /* Flag for switching mode */ Bool OverlayOnCRTC2; Bool ddc_mode; /* Validate mode by matching exactly * the modes supported in DDC data @@ -453,16 +467,6 @@ typedef struct { Bool R300CGWorkaround; /* EDID or BIOS values for FPs */ - int PanelXRes; - int PanelYRes; - int HOverPlus; - int HSyncWidth; - int HBlank; - int VOverPlus; - int VSyncWidth; - int VBlank; - int PanelPwrDly; - int DotClock; int RefDivider; int FeedbackDivider; int PostDivider; @@ -471,11 +475,9 @@ typedef struct { Bool ddc_bios; Bool ddc1; Bool ddc2; - I2CBusPtr pI2CBus; - CARD32 DDCReg; RADEONPLLRec pll; - RADEONTMDSPll tmds_pll[4]; + int RamWidth; float sclk; /* in MHz */ float mclk; /* in MHz */ @@ -770,42 +772,10 @@ typedef struct { /* X itself has the 3D context */ Bool XInited3D; - /* merged fb stuff, also covers clone modes */ - Bool MergedFB; - RADEONScrn2Rel CRT2Position; - char * CRT2HSync; - char * CRT2VRefresh; - char * MetaModes; - ScrnInfoPtr CRT2pScrn; - DisplayModePtr CRT1Modes; - DisplayModePtr CRT1CurrentMode; - int CRT1frameX0; - int CRT1frameY0; - int CRT1frameX1; - int CRT1frameY1; - RADEONMonitorType MergeType; - RADEONDDCType MergeDDCType; - void (*PointerMoved)(int index, int x, int y); - /* pseudo xinerama support for mergedfb */ - int maxCRT1_X1, maxCRT1_X2, maxCRT1_Y1, maxCRT1_Y2; - int maxCRT2_X1, maxCRT2_X2, maxCRT2_Y1, maxCRT2_Y2; - int maxClone_X1, maxClone_X2, maxClone_Y1, maxClone_Y2; - Bool UseRADEONXinerama; - Bool CRT2IsScrn0; - ExtensionEntry *XineramaExtEntry; - int RADEONXineramaVX, RADEONXineramaVY; - Bool AtLeastOneNonClone; - int MergedFBXDPI, MergedFBYDPI; - Bool NoVirtual; - int CRT1XOffs, CRT1YOffs, CRT2XOffs, CRT2YOffs; - int MBXNR1XMAX, MBXNR1YMAX, MBXNR2XMAX, MBXNR2YMAX; - Bool NonRect, HaveNonRect, HaveOffsRegions, MouseRestrictions; - region NonRectDead, OffDead1, OffDead2; + DisplayModePtr currentMode, savedCurrentMode; int constantDPI; /* -1 = auto, 0 = off, 1 = on */ int RADEONDPIVX, RADEONDPIVY; - RADEONScrn2Rel MergedDPISRel; - int RADEONMergedDPIVX, RADEONMergedDPIVY, RADEONMergedDPIRot; /* special handlings for DELL triple-head server */ Bool IsDellServer; @@ -818,6 +788,18 @@ typedef struct { CARD32 tv_dac_adj; Bool want_vblank_interrupts; + RADEONBIOSConnector BiosConnector[RADEON_MAX_BIOS_CONNECTOR]; + RADEONBIOSInitTable BiosTable; + + /* save crtc state for console restore */ + Bool crtc_on; + Bool crtc2_on; + + Bool InternalTVOut; + + Rotation rotation; + void (*PointerMoved)(int, int, int); + CreateScreenResourcesProcPtr CreateScreenResources; } RADEONInfoRec, *RADEONInfoPtr; #define RADEONWaitForFifo(pScrn, entries) \ @@ -836,7 +818,7 @@ extern void RADEONWaitForIdleCP(ScrnInfoPtr pScrn); #endif extern void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, - int clone); + Bool clone); extern void RADEONEngineReset(ScrnInfoPtr pScrn); extern void RADEONEngineFlush(ScrnInfoPtr pScrn); @@ -890,20 +872,49 @@ extern void RADEONPllErrataAfterData(RADEONInfoPtr info); extern Bool RADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10); extern Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn); extern Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn); -extern Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn); -extern Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn); -extern Bool RADEONGetHardCodedEDIDFromBIOS (ScrnInfoPtr pScrn); - +extern Bool RADEONGetLVDSInfoFromBIOS (xf86OutputPtr output); +extern Bool RADEONGetTMDSInfoFromBIOS (xf86OutputPtr output); +extern Bool RADEONGetTVInfoFromBIOS (xf86OutputPtr output); +extern Bool RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output); + +extern void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreDACRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreFP2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreLVDSRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreRMXRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore); +extern void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore); + +extern void RADEONInitMemMapRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr save, + RADEONInfoPtr info); extern void RADEONInitDispBandwidth(ScrnInfoPtr pScrn); extern Bool RADEONI2cInit(ScrnInfoPtr pScrn); extern void RADEONSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag); -extern void RADEONSetupConnectors(ScrnInfoPtr pScrn); -extern Bool RADEONMapControllers(ScrnInfoPtr pScrn); -extern void RADEONEnableDisplay(ScrnInfoPtr pScrn, RADEONConnector* pPort, BOOL bEnable); +extern Bool RADEONSetupConnectors(ScrnInfoPtr pScrn); +extern void RADEONPrintPortMap(ScrnInfoPtr pScrn); +extern void RADEONEnableDisplay(xf86OutputPtr pPort, BOOL bEnable); extern void RADEONDisableDisplays(ScrnInfoPtr pScrn); extern void RADEONGetPanelInfo(ScrnInfoPtr pScrn); -extern void RADEONGetTVDacAdjInfo(ScrnInfoPtr pScrn); -extern void RADEONBlank(ScrnInfoPtr pScrn, Bool Blank); +extern void RADEONGetTVDacAdjInfo(xf86OutputPtr output); +extern void RADEONUnblank(ScrnInfoPtr pScrn); +extern void RADEONUnblank(ScrnInfoPtr pScrn); +extern void RADEONBlank(ScrnInfoPtr pScrn); extern void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags); @@ -912,9 +923,43 @@ extern Bool RADEONAllocateConnectors(ScrnInfoPtr pScrn); extern int RADEONValidateMergeModes(ScrnInfoPtr pScrn); extern int RADEONValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName, RADEONMonitorType DisplayType, int crtc2); -extern int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName); +extern int RADEONValidateFPModes(xf86OutputPtr output, char **ppModeName, DisplayModePtr *modeList); extern void RADEONSetPitch (ScrnInfoPtr pScrn); - +extern void RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode); + +DisplayModePtr +RADEONProbeOutputModes(xf86OutputPtr output); +extern Bool RADEONInit2(ScrnInfoPtr pScrn, DisplayModePtr crtc1, + DisplayModePtr crtc2, int crtc_mask, + RADEONSavePtr save, RADEONMonitorType montype); + +void +radeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y); +void +radeon_crtc_show_cursor (xf86CrtcPtr crtc); +void +radeon_crtc_hide_cursor (xf86CrtcPtr crtc); +void +radeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y); +void +radeon_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg); +void +radeon_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image); +void +RADEONEnableOutputs(ScrnInfoPtr pScrn, int crtc_num); +void +RADEONChooseOverlayCRTC(ScrnInfoPtr pScrn, BoxPtr dstBox); + +extern void RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output); +extern void RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output); +extern void RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output); +extern void RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output); +extern void RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary); #ifdef XF86DRI #ifdef USE_XAA diff --git a/src/radeon_bios.c b/src/radeon_bios.c index fefa6ff..9d8946f 100644 --- a/src/radeon_bios.c +++ b/src/radeon_bios.c @@ -44,13 +44,12 @@ int RADEONBIOSApplyConnectorQuirks(ScrnInfoPtr pScrn, int connector_found) { RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); /* quirk for compaq nx6125 - the bios lies about the VGA DDC */ if (info->PciInfo->subsysVendor == PCI_VENDOR_HP) { if (info->PciInfo->subsysCard == 0x308b) { - if (pRADEONEnt->PortInfo[1]->DDCType == DDC_CRT2) - pRADEONEnt->PortInfo[1]->DDCType = DDC_MONID; + if (info->BiosConnector[1].DDCType == DDC_CRT2) + info->BiosConnector[1].DDCType = DDC_MONID; } } return connector_found; @@ -142,11 +141,191 @@ Bool RADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) return TRUE; } +static Bool RADEONGetATOMConnectorInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + int offset, i, tmp, tmp0, crtc, portinfo, gpio; + + if (!info->VBIOS) return FALSE; + + offset = RADEON_BIOS16(info->MasterDataStart + 22); + + if (offset) { + tmp = RADEON_BIOS16(offset + 4); + for (i = 0; i < 8; i++) { + if (tmp & (1 << i)) { + info->BiosConnector[i].valid = TRUE; + portinfo = RADEON_BIOS16(offset + 6 + i * 2); + info->BiosConnector[i].DACType = (portinfo & 0xf) - 1; + info->BiosConnector[i].ConnectorType = (portinfo >> 4) & 0xf; + crtc = (portinfo >> 8) & 0xf; + tmp0 = RADEON_BIOS16(info->MasterDataStart + 24); + gpio = RADEON_BIOS16(tmp0 + 4 + 27 * crtc) * 4; + switch(gpio) { + case RADEON_GPIO_MONID: + info->BiosConnector[i].DDCType = DDC_MONID; + break; + case RADEON_GPIO_DVI_DDC: + info->BiosConnector[i].DDCType = DDC_DVI; + break; + case RADEON_GPIO_VGA_DDC: + info->BiosConnector[i].DDCType = DDC_VGA; + break; + case RADEON_GPIO_CRT2_DDC: + info->BiosConnector[i].DDCType = DDC_CRT2; + break; + case RADEON_LCD_GPIO_MASK: + info->BiosConnector[i].DDCType = DDC_LCD; + break; + default: + info->BiosConnector[i].DDCType = DDC_NONE_DETECTED; + break; + } + + if (i == 3) + info->BiosConnector[i].TMDSType = TMDS_INT; + else if (i == 7) + info->BiosConnector[i].TMDSType = TMDS_EXT; + else + info->BiosConnector[i].TMDSType = TMDS_UNKNOWN; + + } else { + info->BiosConnector[i].valid = FALSE; + } + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n"); + return FALSE; + } + + /* DVI-I ports have 2 entries: one for analog, one for digital. combine them */ + if (info->BiosConnector[0].valid && info->BiosConnector[7].valid) { + info->BiosConnector[7].DACType = info->BiosConnector[0].DACType; + info->BiosConnector[0].valid = FALSE; + } + + if (info->BiosConnector[4].valid && info->BiosConnector[3].valid) { + info->BiosConnector[3].DACType = info->BiosConnector[4].DACType; + info->BiosConnector[4].valid = FALSE; + } + + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n"); + for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + if (info->BiosConnector[i].valid) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + i, info->BiosConnector[i].DDCType, info->BiosConnector[i].DACType, + info->BiosConnector[i].TMDSType, info->BiosConnector[i].ConnectorType); + } + } + + return TRUE; +} + +static Bool RADEONGetLegacyConnectorInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + int offset, i, entry, tmp, tmp0, tmp1; + + if (!info->VBIOS) return FALSE; + + offset = RADEON_BIOS16(info->ROMHeaderStart + 0x50); + if (offset) { + for (i = 0; i < 4; i++) { + entry = offset + 2 + i*2; + + if (!RADEON_BIOS16(entry)) { + break; + } + info->BiosConnector[i].valid = TRUE; + tmp = RADEON_BIOS16(entry); + info->BiosConnector[i].ConnectorType = (tmp >> 12) & 0xf; + info->BiosConnector[i].DDCType = (tmp >> 8) & 0xf; + info->BiosConnector[i].DACType = tmp & 0x1; + info->BiosConnector[i].TMDSType = tmp & 0x10; + + } + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n"); + return FALSE; + } + + /* check LVDS table */ + if (info->IsMobility) { + offset = RADEON_BIOS16(info->ROMHeaderStart + 0x40); + if (offset) { + info->BiosConnector[4].valid = TRUE; + info->BiosConnector[4].ConnectorType = CONNECTOR_PROPRIETARY; + info->BiosConnector[4].DACType = DAC_NONE; + info->BiosConnector[4].TMDSType = TMDS_NONE; + + tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42); + if (tmp) { + tmp0 = RADEON_BIOS16(tmp + 0x15); + if (tmp0) { + tmp1 = RADEON_BIOS8(tmp0+2) & 0x07; + if (tmp1) { + info->BiosConnector[4].DDCType = tmp1; + if (info->BiosConnector[4].DDCType > DDC_LCD) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Unknown DDCType %d found\n", + info->BiosConnector[4].DDCType); + info->BiosConnector[4].DDCType = DDC_NONE_DETECTED; + } + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n"); + } + } + } else { + info->BiosConnector[4].DDCType = DDC_NONE_DETECTED; + } + } + } + + /* check TV table */ + if (info->InternalTVOut) { + offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32); + if (offset) { + if (RADEON_BIOS8(offset + 6) == 'T') { + info->BiosConnector[5].valid = TRUE; + /* assume s-video for now */ + info->BiosConnector[5].ConnectorType = CONNECTOR_STV; + info->BiosConnector[5].DACType = DAC_TVDAC; + info->BiosConnector[5].TMDSType = TMDS_NONE; + info->BiosConnector[5].DDCType = DDC_NONE_DETECTED; + } + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n"); + for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + if (info->BiosConnector[i].valid) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + i, info->BiosConnector[i].DDCType, info->BiosConnector[i].DACType, + info->BiosConnector[i].TMDSType, info->BiosConnector[i].ConnectorType); + } + } + + return TRUE; +} + +Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + + if(!info->VBIOS) return FALSE; + + if (info->IsAtomBios) + return RADEONGetATOMConnectorInfoFromBIOS(pScrn); + else + return RADEONGetLegacyConnectorInfoFromBIOS(pScrn); +} + +#if 0 Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR (pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); int i = 0, j, tmp, tmp0=0, tmp1=0; + RADEONBIOSConnector tempConnector; if(!info->VBIOS) return FALSE; @@ -164,49 +343,49 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) /* sharing same port with id[0] */ if (((portinfo>>8) & 0xf) == id[0]) { if (i == 3) - pRADEONEnt->PortInfo[0]->TMDSType = TMDS_INT; + info->BiosConnector[0].TMDSType = TMDS_INT; else if (i == 7) - pRADEONEnt->PortInfo[0]->TMDSType = TMDS_EXT; + info->BiosConnector[0].TMDSType = TMDS_EXT; - if (pRADEONEnt->PortInfo[0]->DACType == DAC_UNKNOWN) - pRADEONEnt->PortInfo[0]->DACType = (portinfo & 0xf) - 1; + if (info->BiosConnector[0].DACType == DAC_UNKNOWN) + info->BiosConnector[0].DACType = (portinfo & 0xf) - 1; continue; } } id[crtc] = (portinfo>>8) & 0xf; - pRADEONEnt->PortInfo[crtc]->DACType = (portinfo & 0xf) - 1; - pRADEONEnt->PortInfo[crtc]->ConnectorType = (portinfo>>4) & 0xf; + info->BiosConnector[crtc].DACType = (portinfo & 0xf) - 1; + info->BiosConnector[crtc].ConnectorType = (portinfo>>4) & 0xf; if (i == 3) - pRADEONEnt->PortInfo[crtc]->TMDSType = TMDS_INT; + info->BiosConnector[crtc].TMDSType = TMDS_INT; else if (i == 7) - pRADEONEnt->PortInfo[crtc]->TMDSType = TMDS_EXT; + info->BiosConnector[crtc].TMDSType = TMDS_EXT; if((tmp0 = RADEON_BIOS16 (info->MasterDataStart + 24)) && id[crtc]) { switch (RADEON_BIOS16 (tmp0 + 4 + 27 * id[crtc]) * 4) { case RADEON_GPIO_MONID: - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_MONID; + info->BiosConnector[crtc].DDCType = DDC_MONID; break; case RADEON_GPIO_DVI_DDC: - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_DVI; + info->BiosConnector[crtc].DDCType = DDC_DVI; break; case RADEON_GPIO_VGA_DDC: - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_VGA; + info->BiosConnector[crtc].DDCType = DDC_VGA; break; case RADEON_GPIO_CRT2_DDC: - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_CRT2; + info->BiosConnector[crtc].DDCType = DDC_CRT2; break; case RADEON_LCD_GPIO_MASK: - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_LCD; + info->BiosConnector[crtc].DDCType = DDC_LCD; break; default: - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_NONE_DETECTED; + info->BiosConnector[crtc].DDCType = DDC_NONE_DETECTED; break; } } else { - pRADEONEnt->PortInfo[crtc]->DDCType = DDC_NONE_DETECTED; + info->BiosConnector[crtc].DDCType = DDC_NONE_DETECTED; } crtc++; } else { @@ -216,22 +395,28 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) for (j=0; j<2; j++) { if (((portinfo>>8) & 0xf) == id[j]) { if (i == 3) - pRADEONEnt->PortInfo[j]->TMDSType = TMDS_INT; + info->BiosConnector[j].TMDSType = TMDS_INT; else if (i == 7) - pRADEONEnt->PortInfo[j]->TMDSType = TMDS_EXT; + info->BiosConnector[j].TMDSType = TMDS_EXT; - if (pRADEONEnt->PortInfo[j]->DACType == DAC_UNKNOWN) - pRADEONEnt->PortInfo[j]->DACType = (portinfo & 0xf) - 1; + if (info->BiosConnector[j].DACType == DAC_UNKNOWN) + info->BiosConnector[j].DACType = (portinfo & 0xf) - 1; } } } } } + /* R4xx seem to get the connector table backwards */ + tempConnector = info->BiosConnector[0]; + info->BiosConnector[0] = info->BiosConnector[1]; + info->BiosConnector[1] = tempConnector; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Bios Connector table: \n"); for (i=0; i<2; i++) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", - i, pRADEONEnt->PortInfo[i]->DDCType, pRADEONEnt->PortInfo[i]->DACType, - pRADEONEnt->PortInfo[i]->TMDSType, pRADEONEnt->PortInfo[i]->ConnectorType); + i, info->BiosConnector[i].DDCType, info->BiosConnector[i].DACType, + info->BiosConnector[i].TMDSType, info->BiosConnector[i].ConnectorType); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n"); @@ -258,25 +443,27 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) tmp0 = RADEON_BIOS16(tmp + i*2); if (((tmp0 >> 12) & 0x0f) == 0) continue; /* no connector */ if (connector_found > 0) { - if (pRADEONEnt->PortInfo[tmp1]->DDCType == ((tmp0 >> 8) & 0x0f)) + if (info->BiosConnector[tmp1].DDCType == ((tmp0 >> 8) & 0x0f)) continue; /* same connector */ } /* internal DDC_DVI port will get assigned to PortInfo[0], or if there is no DDC_DVI (like in some IGPs). */ tmp1 = ((((tmp0 >> 8) & 0xf) == DDC_DVI) || (tmp1 == 1)) ? 0 : 1; /* determine port info index */ - pRADEONEnt->PortInfo[tmp1]->DDCType = (tmp0 >> 8) & 0x0f; - if (pRADEONEnt->PortInfo[tmp1]->DDCType > DDC_CRT2) pRADEONEnt->PortInfo[tmp1]->DDCType = DDC_NONE_DETECTED; - pRADEONEnt->PortInfo[tmp1]->DACType = (tmp0 & 0x01) ? DAC_TVDAC : DAC_PRIMARY; - pRADEONEnt->PortInfo[tmp1]->ConnectorType = (tmp0 >> 12) & 0x0f; - if (pRADEONEnt->PortInfo[tmp1]->ConnectorType > CONNECTOR_UNSUPPORTED) pRADEONEnt->PortInfo[tmp1]->ConnectorType = CONNECTOR_UNSUPPORTED; - pRADEONEnt->PortInfo[tmp1]->TMDSType = ((tmp0 >> 4) & 0x01) ? TMDS_EXT : TMDS_INT; + info->BiosConnector[tmp1].DDCType = (tmp0 >> 8) & 0x0f; + if (info->BiosConnector[tmp1].DDCType > DDC_CRT2) + info->BiosConnector[tmp1].DDCType = DDC_NONE_DETECTED; + info->BiosConnector[tmp1].DACType = (tmp0 & 0x01) ? DAC_TVDAC : DAC_PRIMARY; + info->BiosConnector[tmp1].ConnectorType = (tmp0 >> 12) & 0x0f; + if (info->BiosConnector[tmp1].ConnectorType > CONNECTOR_UNSUPPORTED) + info->BiosConnector[tmp1].ConnectorType = CONNECTOR_UNSUPPORTED; + info->BiosConnector[tmp1].TMDSType = ((tmp0 >> 4) & 0x01) ? TMDS_EXT : TMDS_INT; /* some sanity checks */ - if (((pRADEONEnt->PortInfo[tmp1]->ConnectorType != CONNECTOR_DVI_D) && - (pRADEONEnt->PortInfo[tmp1]->ConnectorType != CONNECTOR_DVI_I)) && - pRADEONEnt->PortInfo[tmp1]->TMDSType == TMDS_INT) - pRADEONEnt->PortInfo[tmp1]->TMDSType = TMDS_UNKNOWN; + if (((info->BiosConnector[tmp1].ConnectorType != CONNECTOR_DVI_D) && + (info->BiosConnector[tmp1].ConnectorType != CONNECTOR_DVI_I)) && + info->BiosConnector[tmp1].TMDSType == TMDS_INT) + info->BiosConnector[tmp1].TMDSType = TMDS_UNKNOWN; connector_found += (tmp1 + 1); } @@ -286,46 +473,27 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) } if (info->IsMobility) { - /* For the cases where only one VGA connector is found, - we assume LVDS is not listed in the connector table, - add it in here as the first port. - */ - if ((connector_found < 3) && (pRADEONEnt->PortInfo[tmp1]->ConnectorType == CONNECTOR_CRT)) { - if (connector_found == 1) { - memcpy (&pRADEONEnt->PortInfo[1], &pRADEONEnt->PortInfo[0], - sizeof (pRADEONEnt->PortInfo[0])); - } - pRADEONEnt->PortInfo[0]->DACType = DAC_TVDAC; - pRADEONEnt->PortInfo[0]->TMDSType = TMDS_UNKNOWN; - pRADEONEnt->PortInfo[0]->DDCType = DDC_NONE_DETECTED; - pRADEONEnt->PortInfo[0]->ConnectorType = CONNECTOR_PROPRIETARY; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS port is not in connector table, added in.\n"); - if (connector_found == 0) connector_found = 1; - else connector_found = 3; - } - if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42))) { if ((tmp0 = RADEON_BIOS16(tmp + 0x15))) { if ((tmp1 = RADEON_BIOS8(tmp0+2) & 0x07)) { - pRADEONEnt->PortInfo[0]->DDCType = tmp1; - if (pRADEONEnt->PortInfo[0]->DDCType > DDC_LCD) { + info->BiosConnector[0].DDCType = tmp1; + if (info->BiosConnector[0].DDCType > DDC_LCD) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDCType %d found\n", - pRADEONEnt->PortInfo[0]->DDCType); - pRADEONEnt->PortInfo[0]->DDCType = DDC_NONE_DETECTED; + info->BiosConnector[0].DDCType); + info->BiosConnector[0].DDCType = DDC_NONE_DETECTED; } xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n"); } } } } else if (connector_found == 2) { - memcpy (&pRADEONEnt->PortInfo[0], &pRADEONEnt->PortInfo[1], - sizeof (pRADEONEnt->PortInfo[0])); - pRADEONEnt->PortInfo[1]->DACType = DAC_UNKNOWN; - pRADEONEnt->PortInfo[1]->TMDSType = TMDS_UNKNOWN; - pRADEONEnt->PortInfo[1]->DDCType = DDC_NONE_DETECTED; - pRADEONEnt->PortInfo[1]->ConnectorType = CONNECTOR_NONE; + memcpy (&info->BiosConnector[0], &info->BiosConnector[1], + sizeof (info->BiosConnector[0])); + info->BiosConnector[1].DACType = DAC_UNKNOWN; + info->BiosConnector[1].TMDSType = TMDS_UNKNOWN; + info->BiosConnector[1].DDCType = DDC_NONE_DETECTED; + info->BiosConnector[1].ConnectorType = CONNECTOR_NONE; connector_found = 1; } @@ -334,23 +502,23 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) if (connector_found == 0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No connector found in Connector Info Table.\n"); } else { - xf86DrvMsg(0, X_INFO, "Connector0: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", - pRADEONEnt->PortInfo[0]->DDCType, pRADEONEnt->PortInfo[0]->DACType, - pRADEONEnt->PortInfo[0]->TMDSType, pRADEONEnt->PortInfo[0]->ConnectorType); + xf86DrvMsg(0, X_INFO, "Bios Connector0: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + info->BiosConnector[0].DDCType, info->BiosConnector[0].DACType, + info->BiosConnector[0].TMDSType, info->BiosConnector[0].ConnectorType); } if (connector_found == 3) { - xf86DrvMsg(0, X_INFO, "Connector1: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", - pRADEONEnt->PortInfo[1]->DDCType, pRADEONEnt->PortInfo[1]->DACType, - pRADEONEnt->PortInfo[1]->TMDSType, pRADEONEnt->PortInfo[1]->ConnectorType); + xf86DrvMsg(0, X_INFO, "Bios Connector1: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", + info->BiosConnector[1].DDCType, info->BiosConnector[1].DACType, + info->BiosConnector[1].TMDSType, info->BiosConnector[1].ConnectorType); } #if 0 /* External TMDS Table, not used now */ if ((tmp0 = RADEON_BIOS16(info->ROMHeaderStart + 0x58))) { - //pRADEONEnt->PortInfo[1]->DDCType = (RADEON_BIOS8(tmp0 + 7) & 0x07); - //pRADEONEnt->PortInfo[1]->ConnectorType = CONNECTOR_DVI_I; - //pRADEONEnt->PortInfo[1]->TMDSType = TMDS_EXT; + //info->BiosConnector[1].DDCType = (RADEON_BIOS8(tmp0 + 7) & 0x07); + //info->BiosConnector[1].ConnectorType = CONNECTOR_DVI_I; + //info->BiosConnector[1].TMDSType = TMDS_EXT; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "External TMDS found.\n"); } else { @@ -362,6 +530,100 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn) } return TRUE; } +#endif + +Bool RADEONGetTVInfoFromBIOS (xf86OutputPtr output) { + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int offset, refclk, stds; + + if (!info->VBIOS) return FALSE; + + if (info->IsAtomBios) { + /* no idea where TV table is on ATOM bios */ + return FALSE; + } else { + offset = RADEON_BIOS16(info->ROMHeaderStart + 0x32); + if (offset) { + if (RADEON_BIOS8(offset + 6) == 'T') { + switch (RADEON_BIOS8(offset + 7) & 0xf) { + case 1: + radeon_output->default_tvStd = TV_STD_NTSC; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC\n"); + break; + case 2: + radeon_output->default_tvStd = TV_STD_PAL; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL\n"); + break; + case 3: + radeon_output->default_tvStd = TV_STD_PAL_M; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-M\n"); + break; + case 4: + radeon_output->default_tvStd = TV_STD_PAL_60; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: PAL-60\n"); + break; + case 5: + radeon_output->default_tvStd = TV_STD_NTSC_J; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: NTSC-J\n"); + break; + case 6: + radeon_output->default_tvStd = TV_STD_SCART_PAL; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Default TV standard: SCART-PAL\n"); + break; + default: + radeon_output->default_tvStd = TV_STD_NTSC; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Unknown TV standard; defaulting to NTSC\n"); + break; + } + radeon_output->tvStd = radeon_output->default_tvStd; + + refclk = (RADEON_BIOS8(offset + 9) >> 2) & 0x3; + if (refclk == 0) + radeon_output->TVRefClk = 29.498928713; /* MHz */ + else if (refclk == 1) + radeon_output->TVRefClk = 28.636360000; + else if (refclk == 2) + radeon_output->TVRefClk = 14.318180000; + else if (refclk == 3) + radeon_output->TVRefClk = 27.000000000; + + radeon_output->SupportedTVStds = radeon_output->default_tvStd; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TV standards supported by chip: "); + stds = RADEON_BIOS8(offset + 10) & 0x1f; + if (stds & TV_STD_NTSC) { + radeon_output->SupportedTVStds |= TV_STD_NTSC; + ErrorF("NTSC "); + } + if (stds & TV_STD_PAL) { + radeon_output->SupportedTVStds |= TV_STD_PAL; + ErrorF("PAL "); + } + if (stds & TV_STD_PAL_M) { + radeon_output->SupportedTVStds |= TV_STD_PAL_M; + ErrorF("PAL-M "); + } + if (stds & TV_STD_PAL_60) { + radeon_output->SupportedTVStds |= TV_STD_PAL_60; + ErrorF("PAL-60 "); + } + if (stds & TV_STD_NTSC_J) { + radeon_output->SupportedTVStds |= TV_STD_NTSC_J; + ErrorF("NTSC-J "); + } + if (stds & TV_STD_SCART_PAL) { + radeon_output->SupportedTVStds |= TV_STD_SCART_PAL; + ErrorF("SCART-PAL"); + } + ErrorF("\n"); + + return TRUE; + } else + return FALSE; + } + } +} /* Read PLL parameters from BIOS block. Default to typical values if there is no BIOS. */ @@ -411,9 +673,11 @@ Bool RADEONGetClockInfoFromBIOS (ScrnInfoPtr pScrn) return TRUE; } -Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn) +Bool RADEONGetLVDSInfoFromBIOS (xf86OutputPtr output) { - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; unsigned long tmp, i; if (!info->VBIOS) return FALSE; @@ -421,29 +685,29 @@ Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn) if (info->IsAtomBios) { if((tmp = RADEON_BIOS16 (info->MasterDataStart + 16))) { - info->PanelXRes = RADEON_BIOS16(tmp+6); - info->PanelYRes = RADEON_BIOS16(tmp+10); - info->DotClock = RADEON_BIOS16(tmp+4)*10; - info->HBlank = RADEON_BIOS16(tmp+8); - info->HOverPlus = RADEON_BIOS16(tmp+14); - info->HSyncWidth = RADEON_BIOS16(tmp+16); - info->VBlank = RADEON_BIOS16(tmp+12); - info->VOverPlus = RADEON_BIOS16(tmp+18); - info->VSyncWidth = RADEON_BIOS16(tmp+20); - info->PanelPwrDly = RADEON_BIOS16(tmp+40); - - if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0) - info->PanelPwrDly = 2000; - - info->Flags = 0; + radeon_output->PanelXRes = RADEON_BIOS16(tmp+6); + radeon_output->PanelYRes = RADEON_BIOS16(tmp+10); + radeon_output->DotClock = RADEON_BIOS16(tmp+4)*10; + radeon_output->HBlank = RADEON_BIOS16(tmp+8); + radeon_output->HOverPlus = RADEON_BIOS16(tmp+14); + radeon_output->HSyncWidth = RADEON_BIOS16(tmp+16); + radeon_output->VBlank = RADEON_BIOS16(tmp+12); + radeon_output->VOverPlus = RADEON_BIOS16(tmp+18); + radeon_output->VSyncWidth = RADEON_BIOS16(tmp+20); + radeon_output->PanelPwrDly = RADEON_BIOS16(tmp+40); + + if (radeon_output->PanelPwrDly > 2000 || radeon_output->PanelPwrDly < 0) + radeon_output->PanelPwrDly = 2000; + + radeon_output->Flags = 0; 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", - info->PanelXRes, info->PanelYRes, info->DotClock, - info->HBlank,info->HOverPlus, info->HSyncWidth, - info->VBlank, info->VOverPlus, info->VSyncWidth); + radeon_output->PanelXRes, radeon_output->PanelYRes, radeon_output->DotClock, + radeon_output->HBlank, radeon_output->HOverPlus, radeon_output->HSyncWidth, + radeon_output->VBlank, radeon_output->VOverPlus, radeon_output->VSyncWidth); } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No LVDS Info Table found in BIOS!\n"); @@ -468,14 +732,14 @@ Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel ID string: %s\n", stmp); - info->PanelXRes = RADEON_BIOS16(tmp+25); - info->PanelYRes = RADEON_BIOS16(tmp+27); + radeon_output->PanelXRes = RADEON_BIOS16(tmp+25); + radeon_output->PanelYRes = RADEON_BIOS16(tmp+27); xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n", - info->PanelXRes, info->PanelYRes); + radeon_output->PanelXRes, radeon_output->PanelYRes); - info->PanelPwrDly = RADEON_BIOS16(tmp+44); - if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0) - info->PanelPwrDly = 2000; + radeon_output->PanelPwrDly = RADEON_BIOS16(tmp+44); + if (radeon_output->PanelPwrDly > 2000 || radeon_output->PanelPwrDly < 0) + radeon_output->PanelPwrDly = 2000; /* some panels only work well with certain divider combinations. */ @@ -496,20 +760,20 @@ Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn) for (i = 0; i < 32; i++) { tmp0 = RADEON_BIOS16(tmp+64+i*2); if (tmp0 == 0) break; - if ((RADEON_BIOS16(tmp0) == info->PanelXRes) && - (RADEON_BIOS16(tmp0+2) == info->PanelYRes)) { - info->HBlank = (RADEON_BIOS16(tmp0+17) - + if ((RADEON_BIOS16(tmp0) == radeon_output->PanelXRes) && + (RADEON_BIOS16(tmp0+2) == radeon_output->PanelYRes)) { + radeon_output->HBlank = (RADEON_BIOS16(tmp0+17) - RADEON_BIOS16(tmp0+19)) * 8; - info->HOverPlus = (RADEON_BIOS16(tmp0+21) - + radeon_output->HOverPlus = (RADEON_BIOS16(tmp0+21) - RADEON_BIOS16(tmp0+19) - 1) * 8; - info->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8; - info->VBlank = (RADEON_BIOS16(tmp0+24) - + radeon_output->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8; + radeon_output->VBlank = (RADEON_BIOS16(tmp0+24) - RADEON_BIOS16(tmp0+26)); - info->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) - + radeon_output->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) - RADEON_BIOS16(tmp0+26)); - info->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11); - info->DotClock = RADEON_BIOS16(tmp0+9) * 10; - info->Flags = 0; + radeon_output->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11); + radeon_output->DotClock = RADEON_BIOS16(tmp0+9) * 10; + radeon_output->Flags = 0; } } } @@ -517,9 +781,11 @@ Bool RADEONGetLVDSInfoFromBIOS (ScrnInfoPtr pScrn) return TRUE; } -Bool RADEONGetHardCodedEDIDFromBIOS (ScrnInfoPtr pScrn) +Bool RADEONGetHardCodedEDIDFromBIOS (xf86OutputPtr output) { - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; unsigned long tmp; char EDID[256]; @@ -535,24 +801,26 @@ Bool RADEONGetHardCodedEDIDFromBIOS (ScrnInfoPtr pScrn) memcpy(EDID, (char*)(info->VBIOS + tmp), 256); - info->DotClock = (*(CARD16*)(EDID+54)) * 10; - info->PanelXRes = (*(CARD8*)(EDID+56)) + ((*(CARD8*)(EDID+58))>>4)*256; - info->HBlank = (*(CARD8*)(EDID+57)) + ((*(CARD8*)(EDID+58)) & 0xf)*256; - info->HOverPlus = (*(CARD8*)(EDID+62)) + ((*(CARD8*)(EDID+65)>>6)*256); - info->HSyncWidth = (*(CARD8*)(EDID+63)) + (((*(CARD8*)(EDID+65)>>4) & 3)*256); - info->PanelYRes = (*(CARD8*)(EDID+59)) + ((*(CARD8*)(EDID+61))>>4)*256; - info->VBlank = ((*(CARD8*)(EDID+60)) + ((*(CARD8*)(EDID+61)) & 0xf)*256); - info->VOverPlus = (((*(CARD8*)(EDID+64))>>4) + (((*(CARD8*)(EDID+65)>>2) & 3)*16)); - info->VSyncWidth = (((*(CARD8*)(EDID+64)) & 0xf) + ((*(CARD8*)(EDID+65)) & 3)*256); - info->Flags = V_NHSYNC | V_NVSYNC; /**(CARD8*)(EDID+71);*/ + radeon_output->DotClock = (*(CARD16*)(EDID+54)) * 10; + radeon_output->PanelXRes = (*(CARD8*)(EDID+56)) + ((*(CARD8*)(EDID+58))>>4)*256; + radeon_output->HBlank = (*(CARD8*)(EDID+57)) + ((*(CARD8*)(EDID+58)) & 0xf)*256; + radeon_output->HOverPlus = (*(CARD8*)(EDID+62)) + ((*(CARD8*)(EDID+65)>>6)*256); + radeon_output->HSyncWidth = (*(CARD8*)(EDID+63)) + (((*(CARD8*)(EDID+65)>>4) & 3)*256); + radeon_output->PanelYRes = (*(CARD8*)(EDID+59)) + ((*(CARD8*)(EDID+61))>>4)*256; + radeon_output->VBlank = ((*(CARD8*)(EDID+60)) + ((*(CARD8*)(EDID+61)) & 0xf)*256); + radeon_output->VOverPlus = (((*(CARD8*)(EDID+64))>>4) + (((*(CARD8*)(EDID+65)>>2) & 3)*16)); + radeon_output->VSyncWidth = (((*(CARD8*)(EDID+64)) & 0xf) + ((*(CARD8*)(EDID+65)) & 3)*256); + radeon_output->Flags = V_NHSYNC | V_NVSYNC; /**(CARD8*)(EDID+71);*/ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Hardcoded EDID data will be used for TMDS panel\n"); } return TRUE; } -Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) +Bool RADEONGetTMDSInfoFromBIOS (xf86OutputPtr output) { - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; CARD32 tmp, maxfreq; int i, n; @@ -564,18 +832,18 @@ Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) maxfreq = RADEON_BIOS16(tmp+4); for (i=0; i<4; i++) { - info->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*6+6); + radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*6+6); /* This assumes each field in TMDS_PLL has 6 bit as in R300/R420 */ - info->tmds_pll[i].value = ((RADEON_BIOS8(tmp+i*6+8) & 0x3f) | + radeon_output->tmds_pll[i].value = ((RADEON_BIOS8(tmp+i*6+8) & 0x3f) | ((RADEON_BIOS8(tmp+i*6+10) & 0x3f)<<6) | ((RADEON_BIOS8(tmp+i*6+9) & 0xf)<<12) | ((RADEON_BIOS8(tmp+i*6+11) & 0xf)<<16)); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "TMDS PLL from BIOS: %ld %lx\n", - info->tmds_pll[i].freq, info->tmds_pll[i].value); + radeon_output->tmds_pll[i].freq, radeon_output->tmds_pll[i].value); - if (maxfreq == info->tmds_pll[i].freq) { - info->tmds_pll[i].freq = 0xffffffff; + if (maxfreq == radeon_output->tmds_pll[i].freq) { + radeon_output->tmds_pll[i].freq = 0xffffffff; break; } } @@ -591,8 +859,8 @@ Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) n = RADEON_BIOS8(tmp + 5) + 1; if (n > 4) n = 4; for (i=0; i<n; i++) { - info->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08); - info->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10); + radeon_output->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08); + radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10); } return TRUE; } else if (RADEON_BIOS8(tmp) == 4) { @@ -600,8 +868,8 @@ Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) n = RADEON_BIOS8(tmp + 5) + 1; if (n > 4) n = 4; for (i=0; i<n; i++) { - info->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); - info->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); + radeon_output->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); + radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); if (i == 0) stride += 10; else stride += 6; } @@ -616,8 +884,8 @@ Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) n = RADEON_BIOS8(tmp + 5) + 1; if (n > 4) n = 4; for (i=0; i<n; i++) { - info->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); - info->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); + radeon_output->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08); + radeon_output->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10); if (i == 0) stride += 10; else stride += 6; } @@ -628,3 +896,465 @@ Bool RADEONGetTMDSInfoFromBIOS (ScrnInfoPtr pScrn) } return FALSE; } + +/* support for init from bios tables + * + * Based heavily on the netbsd radeonfb driver + * Written by Garrett D'Amore + * Copyright (c) 2006 Itronix Inc. + * + */ + +/* bios table defines */ + +#define RADEON_TABLE_ENTRY_FLAG_MASK 0xe000 +#define RADEON_TABLE_ENTRY_INDEX_MASK 0x1fff +#define RADEON_TABLE_ENTRY_COMMAND_MASK 0x00ff + +#define RADEON_TABLE_FLAG_WRITE_INDEXED 0x0000 +#define RADEON_TABLE_FLAG_WRITE_DIRECT 0x2000 +#define RADEON_TABLE_FLAG_MASK_INDEXED 0x4000 +#define RADEON_TABLE_FLAG_MASK_DIRECT 0x6000 +#define RADEON_TABLE_FLAG_DELAY 0x8000 +#define RADEON_TABLE_FLAG_SCOMMAND 0xa000 + +#define RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK 0x03 +#define RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE 0x08 + +#define RADEON_PLL_FLAG_MASK 0xc0 +#define RADEON_PLL_INDEX_MASK 0x3f + +#define RADEON_PLL_FLAG_WRITE 0x00 +#define RADEON_PLL_FLAG_MASK_BYTE 0x40 +#define RADEON_PLL_FLAG_WAIT 0x80 + +#define RADEON_PLL_WAIT_150MKS 1 +#define RADEON_PLL_WAIT_5MS 2 +#define RADEON_PLL_WAIT_MC_BUSY_MASK 3 +#define RADEON_PLL_WAIT_DLL_READY_MASK 4 +#define RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24 5 + +static CARD16 +RADEONValidateBIOSOffset(ScrnInfoPtr pScrn, CARD16 offset) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + CARD8 revision = RADEON_BIOS8(offset - 1); + + if (revision > 0x10) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Bad revision %d for BIOS table\n", revision); + return 0; + } + + if (offset < 0x60) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Bad offset 0x%x for BIOS Table\n", offset); + return 0; + } + + return offset; +} + +Bool +RADEONGetBIOSInitTableOffsets(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + CARD8 val; + + if (!info->VBIOS) { + return FALSE; + } else { + if (info->IsAtomBios) { + return FALSE; + } else { + info->BiosTable.revision = RADEON_BIOS8(info->ROMHeaderStart + 4); + info->BiosTable.rr1_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x0c); + if (info->BiosTable.rr1_offset) { + info->BiosTable.rr1_offset = + RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr1_offset); + } + if (info->BiosTable.revision > 0x09) + return TRUE; + info->BiosTable.rr2_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x4e); + if (info->BiosTable.rr2_offset) { + info->BiosTable.rr2_offset = + RADEONValidateBIOSOffset(pScrn, info->BiosTable.rr2_offset); + } + info->BiosTable.dyn_clk_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x52); + if (info->BiosTable.dyn_clk_offset) { + info->BiosTable.dyn_clk_offset = + RADEONValidateBIOSOffset(pScrn, info->BiosTable.dyn_clk_offset); + } + info->BiosTable.pll_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x46); + if (info->BiosTable.pll_offset) { + info->BiosTable.pll_offset = + RADEONValidateBIOSOffset(pScrn, info->BiosTable.pll_offset); + } + info->BiosTable.mem_config_offset = RADEON_BIOS16(info->ROMHeaderStart + 0x48); + if (info->BiosTable.mem_config_offset) { + info->BiosTable.mem_config_offset = + RADEONValidateBIOSOffset(pScrn, info->BiosTable.mem_config_offset); + } + if (info->BiosTable.mem_config_offset) { + info->BiosTable.mem_reset_offset = info->BiosTable.mem_config_offset; + if (info->BiosTable.mem_reset_offset) { + while (RADEON_BIOS8(info->BiosTable.mem_reset_offset)) + info->BiosTable.mem_reset_offset++; + info->BiosTable.mem_reset_offset++; + info->BiosTable.mem_reset_offset += 2; + } + } + if (info->BiosTable.mem_config_offset) { + info->BiosTable.short_mem_offset = info->BiosTable.mem_config_offset; + if ((info->BiosTable.short_mem_offset != 0) && + (RADEON_BIOS8(info->BiosTable.short_mem_offset - 2) <= 64)) + info->BiosTable.short_mem_offset += + RADEON_BIOS8(info->BiosTable.short_mem_offset - 3); + } + if (info->BiosTable.rr2_offset) { + info->BiosTable.rr3_offset = info->BiosTable.rr2_offset; + if (info->BiosTable.rr3_offset) { + while ((val = RADEON_BIOS8(info->BiosTable.rr3_offset + 1)) != 0) { + if (val & 0x40) + info->BiosTable.rr3_offset += 10; + else if (val & 0x80) + info->BiosTable.rr3_offset += 4; + else + info->BiosTable.rr3_offset += 6; + } + info->BiosTable.rr3_offset += 2; + } + } + + if (info->BiosTable.rr3_offset) { + info->BiosTable.rr4_offset = info->BiosTable.rr3_offset; + if (info->BiosTable.rr4_offset) { + while ((val = RADEON_BIOS8(info->BiosTable.rr4_offset + 1)) != 0) { + if (val & 0x40) + info->BiosTable.rr4_offset += 10; + else if (val & 0x80) + info->BiosTable.rr4_offset += 4; + else + info->BiosTable.rr4_offset += 6; + } + info->BiosTable.rr4_offset += 2; + } + } + + if (info->BiosTable.rr3_offset + 1 == info->BiosTable.pll_offset) { + info->BiosTable.rr3_offset = 0; + info->BiosTable.rr4_offset = 0; + } + + return TRUE; + + } + } +} + +static void +RADEONRestoreBIOSRegBlock(ScrnInfoPtr pScrn, CARD16 table_offset) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD16 offset = table_offset; + CARD16 value, flag, index, count; + CARD32 andmask, ormask, val, channel_complete_mask; + CARD8 command; + + if (offset == 0) + return; + + while ((value = RADEON_BIOS16(offset)) != 0) { + flag = value & RADEON_TABLE_ENTRY_FLAG_MASK; + index = value & RADEON_TABLE_ENTRY_INDEX_MASK; + command = value & RADEON_TABLE_ENTRY_COMMAND_MASK; + + offset += 2; + + switch (flag) { + case RADEON_TABLE_FLAG_WRITE_INDEXED: + val = RADEON_BIOS32(offset); + ErrorF("WRITE INDEXED: 0x%x 0x%x\n", + index, val); + OUTREG(RADEON_MM_INDEX, index); + OUTREG(RADEON_MM_DATA, val); + offset += 4; + break; + + case RADEON_TABLE_FLAG_WRITE_DIRECT: + val = RADEON_BIOS32(offset); + ErrorF("WRITE DIRECT: 0x%x 0x%x\n", index, val); + OUTREG(index, val); + offset += 4; + break; + + case RADEON_TABLE_FLAG_MASK_INDEXED: + andmask = RADEON_BIOS32(offset); + offset += 4; + ormask = RADEON_BIOS32(offset); + offset += 4; + ErrorF("MASK INDEXED: 0x%x 0x%x 0x%x\n", + index, andmask, ormask); + OUTREG(RADEON_MM_INDEX, index); + val = INREG(RADEON_MM_DATA); + val = (val & andmask) | ormask; + OUTREG(RADEON_MM_DATA, val); + break; + + case RADEON_TABLE_FLAG_MASK_DIRECT: + andmask = RADEON_BIOS32(offset); + offset += 4; + ormask = RADEON_BIOS32(offset); + offset += 4; + ErrorF("MASK DIRECT: 0x%x 0x%x 0x%x\n", + index, andmask, ormask); + val = INREG(index); + val = (val & andmask) | ormask; + OUTREG(index, val); + break; + + case RADEON_TABLE_FLAG_DELAY: + count = RADEON_BIOS16(offset); + ErrorF("delay: %d\n", count); + usleep(count); + offset += 2; + break; + + case RADEON_TABLE_FLAG_SCOMMAND: + ErrorF("SCOMMAND 0x%x\n", command); + switch (command) { + case RADEON_TABLE_SCOMMAND_WAIT_MC_BUSY_MASK: + count = RADEON_BIOS16(offset); + ErrorF("SCOMMAND_WAIT_MC_BUSY_MASK %d\n", count); + while (count--) { + if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) & + RADEON_MC_BUSY)) + break; + } + break; + + case RADEON_TABLE_SCOMMAND_WAIT_MEM_PWRUP_COMPLETE: + count = RADEON_BIOS16(offset); + ErrorF("SCOMMAND_WAIT_MEM_PWRUP_COMPLETE %d\n", count); + /* may need to take into account how many memory channels + * each card has + */ + if (IS_R300_VARIANT) + channel_complete_mask = R300_MEM_PWRUP_COMPLETE; + else + channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE; + while (count--) { + /* XXX: may need indexed access */ + if ((INREG(RADEON_MEM_STR_CNTL) & + channel_complete_mask) == + channel_complete_mask) + break; + } + break; + + } + offset += 2; + break; + } + } +} + +static void +RADEONRestoreBIOSMemBlock(ScrnInfoPtr pScrn, CARD16 table_offset) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD16 offset = table_offset; + CARD16 count; + CARD32 ormask, val, channel_complete_mask; + CARD8 index; + + if (offset == 0) + return; + + while ((index = RADEON_BIOS8(offset)) != 0xff) { + offset++; + if (index == 0x0f) { + count = 20000; + ErrorF("MEM_WAIT_MEM_PWRUP_COMPLETE %d\n", count); + /* may need to take into account how many memory channels + * each card has + */ + if (IS_R300_VARIANT) + channel_complete_mask = R300_MEM_PWRUP_COMPLETE; + else + channel_complete_mask = RADEON_MEM_PWRUP_COMPLETE; + while (count--) { + /* XXX: may need indexed access */ + if ((INREG(RADEON_MEM_STR_CNTL) & + channel_complete_mask) == + channel_complete_mask) + break; + } + } else { + ormask = RADEON_BIOS16(offset); + offset += 2; + + ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n", + RADEON_SDRAM_MODE_MASK, ormask); + + /* can this use direct access? */ + OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG); + val = INREG(RADEON_MM_DATA); + val = (val & RADEON_SDRAM_MODE_MASK) | ormask; + OUTREG(RADEON_MM_DATA, val); + + ormask = (CARD32)index << 24; + + ErrorF("INDEX RADEON_MEM_SDRAM_MODE_REG %x %x\n", + RADEON_B3MEM_RESET_MASK, ormask); + + /* can this use direct access? */ + OUTREG(RADEON_MM_INDEX, RADEON_MEM_SDRAM_MODE_REG); + val = INREG(RADEON_MM_DATA); + val = (val & RADEON_B3MEM_RESET_MASK) | ormask; + OUTREG(RADEON_MM_DATA, val); + } + } +} + +static void +RADEONRestoreBIOSPllBlock(ScrnInfoPtr pScrn, CARD16 table_offset) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD16 offset = table_offset; + CARD8 index, shift; + CARD32 andmask, ormask, val, clk_pwrmgt_cntl; + CARD16 count; + + if (offset == 0) + return; + + while ((index = RADEON_BIOS8(offset)) != 0) { + offset++; + + switch (index & RADEON_PLL_FLAG_MASK) { + case RADEON_PLL_FLAG_WAIT: + switch (index & RADEON_PLL_INDEX_MASK) { + case RADEON_PLL_WAIT_150MKS: + ErrorF("delay: 150 us\n"); + usleep(150); + break; + case RADEON_PLL_WAIT_5MS: + ErrorF("delay: 5 ms\n"); + usleep(5000); + break; + + case RADEON_PLL_WAIT_MC_BUSY_MASK: + count = 1000; + ErrorF("PLL_WAIT_MC_BUSY_MASK %d\n", count); + while (count--) { + if (!(INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) & + RADEON_MC_BUSY)) + break; + } + break; + + case RADEON_PLL_WAIT_DLL_READY_MASK: + count = 1000; + ErrorF("PLL_WAIT_DLL_READY_MASK %d\n", count); + while (count--) { + if (INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL) & + RADEON_DLL_READY) + break; + } + break; + + case RADEON_PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24: + ErrorF("PLL_WAIT_CHK_SET_CLK_PWRMGT_CNTL24\n"); + clk_pwrmgt_cntl = INPLL(pScrn, RADEON_CLK_PWRMGT_CNTL); + if (clk_pwrmgt_cntl & RADEON_CG_NO1_DEBUG_0) { + val = INPLL(pScrn, RADEON_MCLK_CNTL); + /* is this right? */ + val = (val & 0xFFFF0000) | 0x1111; /* seems like we should clear these... */ + OUTPLL(pScrn, RADEON_MCLK_CNTL, val); + usleep(10000); + OUTPLL(pScrn, RADEON_CLK_PWRMGT_CNTL, + clk_pwrmgt_cntl & ~RADEON_CG_NO1_DEBUG_0); + usleep(10000); + } + break; + } + break; + + case RADEON_PLL_FLAG_MASK_BYTE: + shift = RADEON_BIOS8(offset) * 8; + offset++; + + andmask = + (((CARD32)RADEON_BIOS8(offset)) << shift) | + ~((CARD32)0xff << shift); + offset++; + + ormask = ((CARD32)RADEON_BIOS8(offset)) << shift; + offset++; + + ErrorF("PLL_MASK_BYTE 0x%x 0x%x 0x%x 0x%x\n", + index, shift, andmask, ormask); + val = INPLL(pScrn, index); + val = (val & andmask) | ormask; + OUTPLL(pScrn, index, val); + break; + + case RADEON_PLL_FLAG_WRITE: + val = RADEON_BIOS32(offset); + ErrorF("PLL_WRITE 0x%x 0x%x\n", index, val); + OUTPLL(pScrn, index, val); + offset += 4; + break; + } + } +} + +Bool +RADEONPostCardFromBIOSTables(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + + if (!info->VBIOS) { + return FALSE; + } else { + if (info->IsAtomBios) { + return FALSE; + } else { + if (info->BiosTable.rr1_offset) { + ErrorF("rr1 restore, 0x%x\n", info->BiosTable.rr1_offset); + RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr1_offset); + } + if (info->BiosTable.revision < 0x09) { + if (info->BiosTable.pll_offset) { + ErrorF("pll restore, 0x%x\n", info->BiosTable.pll_offset); + RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.pll_offset); + } + if (info->BiosTable.rr2_offset) { + ErrorF("rr2 restore, 0x%x\n", info->BiosTable.rr2_offset); + RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr2_offset); + } + if (info->BiosTable.rr4_offset) { + ErrorF("rr4 restore, 0x%x\n", info->BiosTable.rr4_offset); + RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr4_offset); + } + if (info->BiosTable.mem_reset_offset) { + ErrorF("mem reset restore, 0x%x\n", info->BiosTable.mem_reset_offset); + RADEONRestoreBIOSMemBlock(pScrn, info->BiosTable.mem_reset_offset); + } + if (info->BiosTable.rr3_offset) { + ErrorF("rr3 restore, 0x%x\n", info->BiosTable.rr3_offset); + RADEONRestoreBIOSRegBlock(pScrn, info->BiosTable.rr3_offset); + } + if (info->BiosTable.dyn_clk_offset) { + ErrorF("dyn_clk restore, 0x%x\n", info->BiosTable.dyn_clk_offset); + RADEONRestoreBIOSPllBlock(pScrn, info->BiosTable.dyn_clk_offset); + } + } + } + } + return TRUE; +} diff --git a/src/radeon_crtc.c b/src/radeon_crtc.c new file mode 100644 index 0000000..8e71330 --- /dev/null +++ b/src/radeon_crtc.c @@ -0,0 +1,1323 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdio.h> + +/* X and server generic header files */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "fbdevhw.h" +#include "vgaHW.h" +#include "xf86Modes.h" + +/* Driver data structures */ +#include "radeon.h" +#include "radeon_reg.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_version.h" + +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "radeon_dri.h" +#include "radeon_sarea.h" +#include "sarea.h" +#endif + +void radeon_crtc_load_lut(xf86CrtcPtr crtc); + +static void +radeon_crtc_dpms(xf86CrtcPtr crtc, int mode) +{ + int mask; + ScrnInfoPtr pScrn = crtc->scrn; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + mask = radeon_crtc->crtc_id ? (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_REQ_EN_B) : (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_VSYNC_DIS); + + + switch(mode) { + case DPMSModeOn: + if (radeon_crtc->crtc_id) { + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~mask); + } else { + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); + OUTREGP(RADEON_CRTC_EXT_CNTL, 0, ~mask); + } + break; + case DPMSModeStandby: + if (radeon_crtc->crtc_id) { + OUTREGP(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), ~mask); + } else { + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); + OUTREGP(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS), ~mask); + } + break; + case DPMSModeSuspend: + if (radeon_crtc->crtc_id) { + OUTREGP(RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), ~mask); + } else { + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B); + OUTREGP(RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS), ~mask); + } + break; + case DPMSModeOff: + if (radeon_crtc->crtc_id) { + OUTREGP(RADEON_CRTC2_GEN_CNTL, mask, ~mask); + } else { + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~RADEON_CRTC_DISP_REQ_EN_B); + OUTREGP(RADEON_CRTC_EXT_CNTL, mask, ~mask); + } + break; + } + + if (mode != DPMSModeOff) + radeon_crtc_load_lut(crtc); +} + +static Bool +radeon_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +static void +radeon_crtc_mode_prepare(xf86CrtcPtr crtc) +{ + radeon_crtc_dpms(crtc, DPMSModeOff); +} + +/* Define common registers for requested video mode */ +static void +RADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info) +{ + save->ovr_clr = 0; + save->ovr_wid_left_right = 0; + save->ovr_wid_top_bottom = 0; + save->ov0_scale_cntl = 0; + save->subpic_cntl = 0; + save->viph_control = 0; + save->i2c_cntl_1 = 0; + save->rbbm_soft_reset = 0; + save->cap0_trig_cntl = 0; + save->cap1_trig_cntl = 0; + save->bus_cntl = info->BusCntl; + /* + * If bursts are enabled, turn on discards + * Radeon doesn't have write bursts + */ + if (save->bus_cntl & (RADEON_BUS_READ_BURST)) + save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN; +} + +static void +RADEONInitSurfaceCntl(xf86CrtcPtr crtc, RADEONSavePtr save) +{ + ScrnInfoPtr pScrn = crtc->scrn; + + save->surface_cntl = 0; + +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* We must set both apertures as they can be both used to map the entire + * video memory. -BenH. + */ + switch (pScrn->bitsPerPixel) { + case 16: + save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP; + save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP; + break; + + case 32: + save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP; + save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP; + break; + } +#endif + +} + +static Bool +RADEONInitCrtcBase(xf86CrtcPtr crtc, RADEONSavePtr save, + int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + int Base; +#ifdef XF86DRI + RADEONSAREAPrivPtr pSAREAPriv; + XF86DRISAREAPtr pSAREA; +#endif + + save->crtc_offset = pScrn->fbOffset; +#ifdef XF86DRI + if (info->allowPageFlip) + save->crtc_offset_cntl = RADEON_CRTC_OFFSET_FLIP_CNTL; + else +#endif + save->crtc_offset_cntl = 0; + + if (info->tilingEnabled) { + if (IS_R300_VARIANT) + save->crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + save->crtc_offset_cntl |= RADEON_CRTC_TILE_EN; + } + else { + if (IS_R300_VARIANT) + save->crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + save->crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; + } + + Base = pScrn->fbOffset; + + if (info->tilingEnabled) { + if (IS_R300_VARIANT) { + /* On r300/r400 when tiling is enabled crtc_offset is set to the address of + * the surface. the x/y offsets are handled by the X_Y tile reg for each crtc + * Makes tiling MUCH easier. + */ + save->crtc_tile_x0_y0 = x | (y << 16); + Base &= ~0x7ff; + } else { + /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the + drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes + flickering when scrolling vertically in a virtual screen, possibly because crtc will + pick up the new offset value at the end of each scanline, but the new offset_cntl value + only after a vsync. We'd probably need to wait (in drm) for vsync and only then update + OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */ + /*save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL) & ~0xf;*/ +#if 0 + /* try to get rid of flickering when scrolling at least for 2d */ +#ifdef XF86DRI + if (!info->have3DWindows) +#endif + save->crtc_offset_cntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL; +#endif + + int byteshift = info->CurrentLayout.bitsPerPixel >> 4; + /* crtc uses 256(bytes)x8 "half-tile" start addresses? */ + int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11; + Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + save->crtc_offset_cntl = save->crtc_offset_cntl | (y % 16); + } + } + else { + int offset = y * info->CurrentLayout.displayWidth + x; + switch (info->CurrentLayout.pixel_code) { + case 15: + case 16: offset *= 2; break; + case 24: offset *= 3; break; + case 32: offset *= 4; break; + } + Base += offset; + } + + Base &= ~7; /* 3 lower bits are always 0 */ + + +#ifdef XF86DRI + if (info->directRenderingInited) { + /* note cannot use pScrn->pScreen since this is unitialized when called from + RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */ + /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for + *** pageflipping! + ***/ + pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]); + /* can't get at sarea in a semi-sane way? */ + pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec)); + + pSAREA->frame.x = (Base / info->CurrentLayout.pixel_bytes) + % info->CurrentLayout.displayWidth; + pSAREA->frame.y = (Base / info->CurrentLayout.pixel_bytes) + / info->CurrentLayout.displayWidth; + pSAREA->frame.width = pScrn->frameX1 - x + 1; + pSAREA->frame.height = pScrn->frameY1 - y + 1; + + if (pSAREAPriv->pfCurrentPage == 1) { + Base += info->backOffset - info->frontOffset; + } + } +#endif + save->crtc_offset = Base; + + return TRUE; + +} + +/* Define CRTC registers for requested video mode */ +static Bool +RADEONInitCrtcRegisters(xf86CrtcPtr crtc, RADEONSavePtr save, + DisplayModePtr mode) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + int format; + int hsync_start; + int hsync_wid; + int vsync_wid; + + switch (info->CurrentLayout.pixel_code) { + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported pixel depth (%d)\n", + info->CurrentLayout.bitsPerPixel); + return FALSE; + } + + save->bios_4_scratch = info->SavedReg.bios_4_scratch; + save->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN + | RADEON_CRTC_EN + | (format << 8) + | ((mode->Flags & V_DBLSCAN) + ? RADEON_CRTC_DBL_SCAN_EN + : 0) + | ((mode->Flags & V_CSYNC) + ? RADEON_CRTC_CSYNC_EN + : 0) + | ((mode->Flags & V_INTERLACE) + ? RADEON_CRTC_INTERLACE_EN + : 0)); + + save->crtc_ext_cntl |= (RADEON_XCRT_CNT_EN| + RADEON_CRTC_VSYNC_DIS | + RADEON_CRTC_HSYNC_DIS | + RADEON_CRTC_DISPLAY_DIS); + + save->disp_merge_cntl = info->SavedReg.disp_merge_cntl; + save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; + + save->crtc_more_cntl = 0; + if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200)) { + /* This is to workaround the asic bug for RMX, some versions + of BIOS dosen't have this register initialized correctly. + */ + save->crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; + } + + save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff) + | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) + << 16)); + + hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; + if (!hsync_wid) hsync_wid = 1; + if (hsync_wid > 0x3f) hsync_wid = 0x3f; + hsync_start = mode->CrtcHSyncStart - 8; + + save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) + | (hsync_wid << 16) + | ((mode->Flags & V_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + /* This works for double scan mode. */ + save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay - 1) << 16)); + + vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + if (!vsync_wid) vsync_wid = 1; + if (vsync_wid > 0x1f) vsync_wid = 0x1f; + + save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + | (vsync_wid << 16) + | ((mode->Flags & V_NVSYNC) + ? RADEON_CRTC_V_SYNC_POL + : 0)); + + save->crtc_pitch = (((pScrn->displayWidth * pScrn->bitsPerPixel) + + ((pScrn->bitsPerPixel * 8) -1)) / + (pScrn->bitsPerPixel * 8)); + save->crtc_pitch |= save->crtc_pitch << 16; + + save->fp_h_sync_strt_wid = save->crtc_h_sync_strt_wid; + save->fp_v_sync_strt_wid = save->crtc_v_sync_strt_wid; + save->fp_crtc_h_total_disp = save->crtc_h_total_disp; + save->fp_crtc_v_total_disp = save->crtc_v_total_disp; + + if (info->IsDellServer) { + save->dac2_cntl = info->SavedReg.dac2_cntl; + save->tv_dac_cntl = info->SavedReg.tv_dac_cntl; + save->crtc2_gen_cntl = info->SavedReg.crtc2_gen_cntl; + save->disp_hw_debug = info->SavedReg.disp_hw_debug; + + save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; + save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; + + /* For CRT on DAC2, don't turn it on if BIOS didn't + enable it, even it's detected. + */ + save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + save->tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); + save->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); + } + + return TRUE; +} + +static Bool +RADEONInitCrtc2Base(xf86CrtcPtr crtc, RADEONSavePtr save, + int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + int Base; +#ifdef XF86DRI + RADEONSAREAPrivPtr pSAREAPriv; + XF86DRISAREAPtr pSAREA; +#endif + + /* It seems all fancy options apart from pflip can be safely disabled + */ + save->crtc2_offset = pScrn->fbOffset; +#ifdef XF86DRI + if (info->allowPageFlip) + save->crtc2_offset_cntl = RADEON_CRTC_OFFSET_FLIP_CNTL; + else +#endif + save->crtc2_offset_cntl = 0; + + if (info->tilingEnabled) { + if (IS_R300_VARIANT) + save->crtc2_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + save->crtc2_offset_cntl |= RADEON_CRTC_TILE_EN; + } + else { + if (IS_R300_VARIANT) + save->crtc2_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | + R300_CRTC_MICRO_TILE_BUFFER_DIS | + R300_CRTC_MACRO_TILE_EN); + else + save->crtc2_offset_cntl &= ~RADEON_CRTC_TILE_EN; + } + + Base = pScrn->fbOffset; + + if (info->tilingEnabled) { + if (IS_R300_VARIANT) { + /* On r300/r400 when tiling is enabled crtc_offset is set to the address of + * the surface. the x/y offsets are handled by the X_Y tile reg for each crtc + * Makes tiling MUCH easier. + */ + save->crtc2_tile_x0_y0 = x | (y << 16); + Base &= ~0x7ff; + } else { + /* note we cannot really simply use the info->ModeReg.crtc_offset_cntl value, since the + drm might have set FLIP_CNTL since we wrote that. Unfortunately FLIP_CNTL causes + flickering when scrolling vertically in a virtual screen, possibly because crtc will + pick up the new offset value at the end of each scanline, but the new offset_cntl value + only after a vsync. We'd probably need to wait (in drm) for vsync and only then update + OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */ + /*save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL) & ~0xf;*/ +#if 0 + /* try to get rid of flickering when scrolling at least for 2d */ +#ifdef XF86DRI + if (!info->have3DWindows) +#endif + save->crtc2_offset_cntl &= ~RADEON_CRTC_OFFSET_FLIP_CNTL; +#endif + + int byteshift = info->CurrentLayout.bitsPerPixel >> 4; + /* crtc uses 256(bytes)x8 "half-tile" start addresses? */ + int tile_addr = (((y >> 3) * info->CurrentLayout.displayWidth + x) >> (8 - byteshift)) << 11; + Base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8); + save->crtc2_offset_cntl = save->crtc_offset_cntl | (y % 16); + } + } + else { + int offset = y * info->CurrentLayout.displayWidth + x; + switch (info->CurrentLayout.pixel_code) { + case 15: + case 16: offset *= 2; break; + case 24: offset *= 3; break; + case 32: offset *= 4; break; + } + Base += offset; + } + + Base &= ~7; /* 3 lower bits are always 0 */ + +#ifdef XF86DRI + if (info->directRenderingInited) { + /* note cannot use pScrn->pScreen since this is unitialized when called from + RADEONScreenInit, and we need to call from there to get mergedfb + pageflip working */ + /*** NOTE: r3/4xx will need sarea and drm pageflip updates to handle the xytile regs for + *** pageflipping! + ***/ + pSAREAPriv = DRIGetSAREAPrivate(screenInfo.screens[pScrn->scrnIndex]); + /* can't get at sarea in a semi-sane way? */ + pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec)); + + pSAREAPriv->crtc2_base = Base; + + if (pSAREAPriv->pfCurrentPage == 1) { + Base += info->backOffset - info->frontOffset; + } + } +#endif + save->crtc2_offset = Base; + + return TRUE; +} + +/* Define CRTC2 registers for requested video mode */ +static Bool +RADEONInitCrtc2Registers(xf86CrtcPtr crtc, RADEONSavePtr save, + DisplayModePtr mode) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + int format; + int hsync_start; + int hsync_wid; + int vsync_wid; + + switch (info->CurrentLayout.pixel_code) { + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Unsupported pixel depth (%d)\n", + info->CurrentLayout.bitsPerPixel); + return FALSE; + } + + save->crtc2_h_total_disp = + ((((mode->CrtcHTotal / 8) - 1) & 0x3ff) + | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 16)); + + hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; + if (!hsync_wid) hsync_wid = 1; + if (hsync_wid > 0x3f) hsync_wid = 0x3f; + hsync_start = mode->CrtcHSyncStart - 8; + + save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff) + | (hsync_wid << 16) + | ((mode->Flags & V_NHSYNC) + ? RADEON_CRTC_H_SYNC_POL + : 0)); + + /* This works for double scan mode. */ + save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) + | ((mode->CrtcVDisplay - 1) << 16)); + + vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; + if (!vsync_wid) vsync_wid = 1; + if (vsync_wid > 0x1f) vsync_wid = 0x1f; + + save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) + | (vsync_wid << 16) + | ((mode->Flags & V_NVSYNC) + ? RADEON_CRTC2_V_SYNC_POL + : 0)); + + save->crtc2_pitch = ((info->CurrentLayout.displayWidth * pScrn->bitsPerPixel) + + ((pScrn->bitsPerPixel * 8) -1)) / (pScrn->bitsPerPixel * 8); + save->crtc2_pitch |= save->crtc2_pitch << 16; + + /* check to see if TV DAC is enabled for another crtc and keep it enabled */ + if (save->crtc2_gen_cntl & RADEON_CRTC2_CRT2_ON) + save->crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON; + else + save->crtc2_gen_cntl = 0; + + save->crtc2_gen_cntl |= (RADEON_CRTC2_EN + | (format << 8) + | RADEON_CRTC2_VSYNC_DIS + | RADEON_CRTC2_HSYNC_DIS + | RADEON_CRTC2_DISP_DIS + | ((mode->Flags & V_DBLSCAN) + ? RADEON_CRTC2_DBL_SCAN_EN + : 0) + | ((mode->Flags & V_CSYNC) + ? RADEON_CRTC2_CSYNC_EN + : 0) + | ((mode->Flags & V_INTERLACE) + ? RADEON_CRTC2_INTERLACE_EN + : 0)); + + save->disp2_merge_cntl = info->SavedReg.disp2_merge_cntl; + save->disp2_merge_cntl &= ~(RADEON_DISP2_RGB_OFFSET_EN); + + save->fp_h2_sync_strt_wid = save->crtc2_h_sync_strt_wid; + save->fp_v2_sync_strt_wid = save->crtc2_v_sync_strt_wid; + + if (info->ChipFamily == CHIP_FAMILY_RS400) { + save->rs480_unk_e30 = 0x105DC1CC; /* because I'm worth it */ + save->rs480_unk_e34 = 0x2749D000; /* AMD really should */ + save->rs480_unk_e38 = 0x29ca71dc; /* release docs */ + save->rs480_unk_e3c = 0x28FBC3AC; /* this is so a trade secret */ + } + + return TRUE; +} + + +/* Compute n/d with rounding */ +static int RADEONDiv(int n, int d) +{ + return (n + (d / 2)) / d; +} + +/* Define PLL registers for requested video mode */ +static void +RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info, + RADEONSavePtr save, RADEONPLLPtr pll, + double dot_clock) +{ + unsigned long freq = dot_clock * 100; + + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 16, 5 }, /* VCLK_SRC/16 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (info->UseBiosDividers) { + save->ppll_ref_div = info->RefDivider; + save->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); + save->htotal_cntl = 0; + return; + } + + if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; + if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + save->pll_output_freq = post_div->divider * freq; + + if (save->pll_output_freq >= pll->min_pll_freq + && save->pll_output_freq <= pll->max_pll_freq) break; + } + + if (!post_div->divider) { + save->pll_output_freq = freq; + post_div = &post_divs[0]; + } + + save->dot_clock_freq = freq; + save->feedback_div = RADEONDiv(pll->reference_div + * save->pll_output_freq, + pll->reference_freq); + save->post_div = post_div->divider; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "dc=%ld, of=%ld, fd=%d, pd=%d\n", + save->dot_clock_freq, + save->pll_output_freq, + save->feedback_div, + save->post_div); + + save->ppll_ref_div = pll->reference_div; + save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16)); + save->htotal_cntl = 0; + + save->vclk_ecp_cntl = (info->SavedReg.vclk_ecp_cntl & + ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; + +} + +/* Define PLL2 registers for requested video mode */ +static void +RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, + RADEONPLLPtr pll, double dot_clock, + int no_odd_postdiv) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long freq = dot_clock * 100; + + struct { + int divider; + int bitvalue; + } *post_div, post_divs[] = { + /* From RAGE 128 VR/RAGE 128 GL Register + * Reference Manual (Technical Reference + * Manual P/N RRG-G04100-C Rev. 0.04), page + * 3-17 (PLL_DIV_[3:0]). + */ + { 1, 0 }, /* VCLK_SRC */ + { 2, 1 }, /* VCLK_SRC/2 */ + { 4, 2 }, /* VCLK_SRC/4 */ + { 8, 3 }, /* VCLK_SRC/8 */ + { 3, 4 }, /* VCLK_SRC/3 */ + { 6, 6 }, /* VCLK_SRC/6 */ + { 12, 7 }, /* VCLK_SRC/12 */ + { 0, 0 } + }; + + if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; + if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; + + for (post_div = &post_divs[0]; post_div->divider; ++post_div) { + /* Odd post divider value don't work properly on the second digital + * output + */ + if (no_odd_postdiv && (post_div->divider & 1)) + continue; + save->pll_output_freq_2 = post_div->divider * freq; + if (save->pll_output_freq_2 >= pll->min_pll_freq + && save->pll_output_freq_2 <= pll->max_pll_freq) break; + } + + if (!post_div->divider) { + save->pll_output_freq_2 = freq; + post_div = &post_divs[0]; + } + + save->dot_clock_freq_2 = freq; + save->feedback_div_2 = RADEONDiv(pll->reference_div + * save->pll_output_freq_2, + pll->reference_freq); + save->post_div_2 = post_div->divider; + + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "dc=%ld, of=%ld, fd=%d, pd=%d\n", + save->dot_clock_freq_2, + save->pll_output_freq_2, + save->feedback_div_2, + save->post_div_2); + + save->p2pll_ref_div = pll->reference_div; + save->p2pll_div_0 = (save->feedback_div_2 | + (post_div->bitvalue << 16)); + save->htotal_cntl2 = 0; + + save->pixclks_cntl = ((info->SavedReg.pixclks_cntl & + ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | + RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); + +} + +static void +radeon_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, + DisplayModePtr adjusted_mode, int x, int y) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + xf86OutputPtr output; + RADEONOutputPrivatePtr radeon_output; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONMonitorType montype = MT_NONE; + Bool tilingOld = info->tilingEnabled; + int i = 0; + double dot_clock = 0; + + + if (info->allowColorTiling) { + info->tilingEnabled = (adjusted_mode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; +#ifdef XF86DRI + if (info->directRenderingEnabled && (info->tilingEnabled != tilingOld)) { + RADEONSAREAPrivPtr pSAREAPriv; + if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_SWITCH_TILING, (info->tilingEnabled ? 1 : 0)) < 0) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "[drm] failed changing tiling status\n"); + pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + info->tilingEnabled = pSAREAPriv->tiling_enabled ? TRUE : FALSE; + } +#endif + } + + for (i = 0; i < xf86_config->num_output; i++) { + output = xf86_config->output[i]; + radeon_output = output->driver_private; + + if (output->crtc == crtc) { + montype = radeon_output->MonType; + } + } + + ErrorF("init memmap\n"); + RADEONInitMemMapRegisters(pScrn, &info->ModeReg, info); + ErrorF("init common\n"); + RADEONInitCommonRegisters(&info->ModeReg, info); + + RADEONInitSurfaceCntl(crtc, &info->ModeReg); + + switch (radeon_crtc->crtc_id) { + case 0: + ErrorF("init crtc1\n"); + RADEONInitCrtcRegisters(crtc, &info->ModeReg, adjusted_mode); + RADEONInitCrtcBase(crtc, &info->ModeReg, x, y); + dot_clock = adjusted_mode->Clock / 1000.0; + if (dot_clock) { + ErrorF("init pll1\n"); + RADEONInitPLLRegisters(pScrn, info, &info->ModeReg, &info->pll, dot_clock); + } else { + info->ModeReg.ppll_ref_div = info->SavedReg.ppll_ref_div; + info->ModeReg.ppll_div_3 = info->SavedReg.ppll_div_3; + info->ModeReg.htotal_cntl = info->SavedReg.htotal_cntl; + } + break; + case 1: + ErrorF("init crtc2\n"); + RADEONInitCrtc2Registers(crtc, &info->ModeReg, adjusted_mode); + RADEONInitCrtc2Base(crtc, &info->ModeReg, x, y); + dot_clock = adjusted_mode->Clock / 1000.0; + if (dot_clock) { + ErrorF("init pll2\n"); + RADEONInitPLL2Registers(pScrn, &info->ModeReg, &info->pll, dot_clock, montype != MT_CRT); + } + break; + } + + if (montype == MT_STV || montype == MT_CTV) { + switch (radeon_crtc->crtc_id) { + case 0: + RADEONAdjustCrtcRegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output); + RADEONAdjustPLLRegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output); + break; + case 1: + RADEONAdjustCrtc2RegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output); + RADEONAdjustPLL2RegistersForTV(pScrn, &info->ModeReg, adjusted_mode, output); + break; + } + } + + ErrorF("restore memmap\n"); + RADEONRestoreMemMapRegisters(pScrn, &info->ModeReg); + ErrorF("restore common\n"); + RADEONRestoreCommonRegisters(pScrn, &info->ModeReg); + + switch (radeon_crtc->crtc_id) { + case 0: + ErrorF("restore crtc1\n"); + RADEONRestoreCrtcRegisters(pScrn, &info->ModeReg); + ErrorF("restore pll1\n"); + RADEONRestorePLLRegisters(pScrn, &info->ModeReg); + break; + case 1: + ErrorF("restore crtc2\n"); + RADEONRestoreCrtc2Registers(pScrn, &info->ModeReg); + ErrorF("restore pll2\n"); + RADEONRestorePLL2Registers(pScrn, &info->ModeReg); + break; + } + + /* pixclks_cntl handles tv-out clock routing */ + if (montype == MT_STV || montype == MT_CTV) + RADEONRestorePLL2Registers(pScrn, &info->ModeReg); + + if (info->DispPriority) + RADEONInitDispBandwidth(pScrn); + + if (info->tilingEnabled != tilingOld) { + /* need to redraw front buffer, I guess this can be considered a hack ? */ + xf86EnableDisableFBAccess(pScrn->scrnIndex, FALSE); + RADEONChangeSurfaces(pScrn); + xf86EnableDisableFBAccess(pScrn->scrnIndex, TRUE); + /* xf86SetRootClip would do, but can't access that here */ + } + + /* reset ecp_div for Xv */ + info->ecp_div = -1; + +} + +static void +radeon_crtc_mode_commit(xf86CrtcPtr crtc) +{ + radeon_crtc_dpms(crtc, DPMSModeOn); +} + +void radeon_crtc_load_lut(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int i; + + if (!crtc->enabled) + return; + + PAL_SELECT(radeon_crtc->crtc_id); + + if (pScrn->depth == 15) { + for (i = 0; i < 32; i++) { + OUTPAL(i * 8, radeon_crtc->lut_r[i], radeon_crtc->lut_g[i], radeon_crtc->lut_b[i]); + } + } else if (pScrn->depth == 16) { + for (i = 0; i < 64; i++) { + OUTPAL(i * 4, radeon_crtc->lut_r[i], radeon_crtc->lut_g[i], radeon_crtc->lut_b[i]); + } + } else { + for (i = 0; i < 256; i++) { + OUTPAL(i, radeon_crtc->lut_r[i], radeon_crtc->lut_g[i], radeon_crtc->lut_b[i]); + } + } + +} + + +static void +radeon_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, + CARD16 *blue, int size) +{ + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + ScrnInfoPtr pScrn = crtc->scrn; + int i; + + if (pScrn->depth == 16) { + for (i = 0; i < 64; i++) { + radeon_crtc->lut_r[i] = red[i/2] >> 8; + radeon_crtc->lut_g[i] = green[i] >> 8; + radeon_crtc->lut_b[i] = blue[i/2] >> 8; + } + } else { + for (i = 0; i < 256; i++) { + radeon_crtc->lut_r[i] = red[i] >> 8; + radeon_crtc->lut_g[i] = green[i] >> 8; + radeon_crtc->lut_b[i] = blue[i] >> 8; + } + } + + radeon_crtc_load_lut(crtc); +} + +static Bool +radeon_crtc_lock(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + +#ifdef XF86DRI + if (info->CPStarted && pScrn->pScreen) { + DRILock(pScrn->pScreen, 0); + if (info->accelOn) + RADEON_SYNC(info, pScrn); + return TRUE; + } +#endif + if (info->accelOn) + RADEON_SYNC(info, pScrn); + + return FALSE; + +} + +static void +radeon_crtc_unlock(xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + +#ifdef XF86DRI + if (info->CPStarted && pScrn->pScreen) DRIUnlock(pScrn->pScreen); +#endif + + if (info->accelOn) + RADEON_SYNC(info, pScrn); +} + +#ifdef USE_XAA +/** + * Allocates memory from the XF86 linear allocator, but also purges + * memory if possible to cause the allocation to succeed. + */ +static FBLinearPtr +radeon_xf86AllocateOffscreenLinear(ScreenPtr pScreen, int length, + int granularity, + MoveLinearCallbackProcPtr moveCB, + RemoveLinearCallbackProcPtr removeCB, + pointer privData) +{ + FBLinearPtr linear; + int max_size; + + linear = xf86AllocateOffscreenLinear(pScreen, length, granularity, moveCB, + removeCB, privData); + if (linear != NULL) + return linear; + + /* The above allocation didn't succeed, so purge unlocked stuff and try + * again. + */ + xf86QueryLargestOffscreenLinear(pScreen, &max_size, granularity, + PRIORITY_EXTREME); + + if (max_size < length) + return NULL; + + xf86PurgeUnlockedOffscreenAreas(pScreen); + + linear = xf86AllocateOffscreenLinear(pScreen, length, granularity, moveCB, + removeCB, privData); + + return linear; +} +#endif + +/** + * Allocates memory for a locked-in-framebuffer shadow of the given + * width and height for this CRTC's rotated shadow framebuffer. + */ + +static void * +radeon_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + ScreenPtr pScreen = pScrn->pScreen; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + unsigned long rotate_pitch; + unsigned long rotate_offset; + int align = 4096, size; + int cpp = pScrn->bitsPerPixel / 8; + + rotate_pitch = pScrn->displayWidth * cpp; + size = rotate_pitch * height; + +#ifdef USE_EXA + /* We could get close to what we want here by just creating a pixmap like + * normal, but we have to lock it down in framebuffer, and there is no + * setter for offscreen area locking in EXA currently. So, we just + * allocate offscreen memory and fake up a pixmap header for it. + */ + if (info->useEXA) { + assert(radeon_crtc->rotate_mem_exa == NULL); + + radeon_crtc->rotate_mem_exa = exaOffscreenAlloc(pScreen, size, align, + TRUE, NULL, NULL); + if (radeon_crtc->rotate_mem_exa == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow memory for rotated CRTC\n"); + return NULL; + } + rotate_offset = radeon_crtc->rotate_mem_exa->offset; + } +#endif /* USE_EXA */ +#ifdef USE_XAA + if (!info->useEXA) { + /* The XFree86 linear allocator operates in units of screen pixels, + * sadly. + */ + size = (size + cpp - 1) / cpp; + align = (align + cpp - 1) / cpp; + + assert(radeon_crtc->rotate_mem_xaa == NULL); + + radeon_crtc->rotate_mem_xaa = + radeon_xf86AllocateOffscreenLinear(pScreen, size, align, + NULL, NULL, NULL); + if (radeon_crtc->rotate_mem_xaa == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow memory for rotated CRTC\n"); + return NULL; + } +#ifdef XF86DRI + rotate_offset = info->frontOffset + + radeon_crtc->rotate_mem_xaa->offset * cpp; +#endif + } +#endif /* USE_XAA */ + + return info->FB + rotate_offset; +} + +/** + * Creates a pixmap for this CRTC's rotated shadow framebuffer. + */ +static PixmapPtr +radeon_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + unsigned long rotate_pitch; + PixmapPtr rotate_pixmap; + int cpp = pScrn->bitsPerPixel / 8; + + if (!data) + data = radeon_crtc_shadow_allocate(crtc, width, height); + + rotate_pitch = pScrn->displayWidth * cpp; + + rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen, + width, height, + pScrn->depth, + pScrn->bitsPerPixel, + rotate_pitch, + data); + + if (rotate_pixmap == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't allocate shadow pixmap for rotated CRTC\n"); + } + + return rotate_pixmap; +} + +static void +radeon_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + + if (rotate_pixmap) + FreeScratchPixmapHeader(rotate_pixmap); + + if (data) { +#ifdef USE_EXA + if (info->useEXA && radeon_crtc->rotate_mem_exa != NULL) { + exaOffscreenFree(pScrn->pScreen, radeon_crtc->rotate_mem_exa); + radeon_crtc->rotate_mem_exa = NULL; + } +#endif /* USE_EXA */ +#ifdef USE_XAA + if (!info->useEXA) { + xf86FreeOffscreenLinear(radeon_crtc->rotate_mem_xaa); + radeon_crtc->rotate_mem_xaa = NULL; + } +#endif /* USE_XAA */ + } +} + +static const xf86CrtcFuncsRec radeon_crtc_funcs = { + .dpms = radeon_crtc_dpms, + .save = NULL, /* XXX */ + .restore = NULL, /* XXX */ + .mode_fixup = radeon_crtc_mode_fixup, + .prepare = radeon_crtc_mode_prepare, + .mode_set = radeon_crtc_mode_set, + .commit = radeon_crtc_mode_commit, + .gamma_set = radeon_crtc_gamma_set, + .lock = radeon_crtc_lock, + .unlock = radeon_crtc_unlock, + .shadow_create = radeon_crtc_shadow_create, + .shadow_allocate = radeon_crtc_shadow_allocate, + .shadow_destroy = radeon_crtc_shadow_destroy, + .set_cursor_colors = radeon_crtc_set_cursor_colors, + .set_cursor_position = radeon_crtc_set_cursor_position, + .show_cursor = radeon_crtc_show_cursor, + .hide_cursor = radeon_crtc_hide_cursor, + .load_cursor_argb = radeon_crtc_load_cursor_argb, + .destroy = NULL, /* XXX */ +}; + +Bool RADEONAllocateControllers(ScrnInfoPtr pScrn) +{ + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + + if (pRADEONEnt->Controller[0]) + return TRUE; + + pRADEONEnt->pCrtc[0] = xf86CrtcCreate(pScrn, &radeon_crtc_funcs); + if (!pRADEONEnt->pCrtc[0]) + return FALSE; + + pRADEONEnt->Controller[0] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); + if (!pRADEONEnt->Controller[0]) + return FALSE; + + pRADEONEnt->pCrtc[0]->driver_private = pRADEONEnt->Controller[0]; + pRADEONEnt->Controller[0]->crtc_id = 0; + + if (!pRADEONEnt->HasCRTC2) + return TRUE; + + pRADEONEnt->pCrtc[1] = xf86CrtcCreate(pScrn, &radeon_crtc_funcs); + if (!pRADEONEnt->pCrtc[1]) + return FALSE; + + pRADEONEnt->Controller[1] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); + if (!pRADEONEnt->Controller[1]) + { + xfree(pRADEONEnt->Controller[0]); + return FALSE; + } + + pRADEONEnt->pCrtc[1]->driver_private = pRADEONEnt->Controller[1]; + pRADEONEnt->Controller[1]->crtc_id = 1; + return TRUE; +} + +/** + * In the current world order, there are lists of modes per output, which may + * or may not include the mode that was asked to be set by XFree86's mode + * selection. Find the closest one, in the following preference order: + * + * - Equality + * - Closer in size to the requested mode, but no larger + * - Closer in refresh rate to the requested mode. + */ +DisplayModePtr +RADEONCrtcFindClosestMode(xf86CrtcPtr crtc, DisplayModePtr pMode) +{ + ScrnInfoPtr pScrn = crtc->scrn; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + DisplayModePtr pBest = NULL, pScan = NULL; + int i; + + /* Assume that there's only one output connected to the given CRTC. */ + for (i = 0; i < xf86_config->num_output; i++) + { + xf86OutputPtr output = xf86_config->output[i]; + if (output->crtc == crtc && output->probed_modes != NULL) + { + pScan = output->probed_modes; + break; + } + } + + /* If the pipe doesn't have any detected modes, just let the system try to + * spam the desired mode in. + */ + if (pScan == NULL) { + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No crtc mode list for crtc %d," + "continuing with desired mode\n", radeon_crtc->crtc_id); + return pMode; + } + + for (; pScan != NULL; pScan = pScan->next) { + assert(pScan->VRefresh != 0.0); + + /* If there's an exact match, we're done. */ + if (xf86ModesEqual(pScan, pMode)) { + pBest = pMode; + break; + } + + /* Reject if it's larger than the desired mode. */ + if (pScan->HDisplay > pMode->HDisplay || + pScan->VDisplay > pMode->VDisplay) + { + continue; + } + + if (pBest == NULL) { + pBest = pScan; + continue; + } + + /* Find if it's closer to the right size than the current best + * option. + */ + if ((pScan->HDisplay > pBest->HDisplay && + pScan->VDisplay >= pBest->VDisplay) || + (pScan->HDisplay >= pBest->HDisplay && + pScan->VDisplay > pBest->VDisplay)) + { + pBest = pScan; + continue; + } + + /* Find if it's still closer to the right refresh than the current + * best resolution. + */ + if (pScan->HDisplay == pBest->HDisplay && + pScan->VDisplay == pBest->VDisplay && + (fabs(pScan->VRefresh - pMode->VRefresh) < + fabs(pBest->VRefresh - pMode->VRefresh))) { + pBest = pScan; + } + } + + if (pBest == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No suitable mode found to program for the pipe.\n" + " continuing with desired mode %dx%d@%.1f\n", + pMode->HDisplay, pMode->VDisplay, pMode->VRefresh); + } else if (!xf86ModesEqual(pBest, pMode)) { + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + int crtc = radeon_crtc->crtc_id; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Choosing pipe %d's mode %dx%d@%.1f instead of xf86 " + "mode %dx%d@%.1f\n", crtc, + pBest->HDisplay, pBest->VDisplay, pBest->VRefresh, + pMode->HDisplay, pMode->VDisplay, pMode->VRefresh); + pMode = pBest; + } + return pMode; +} + +void +RADEONChooseOverlayCRTC(ScrnInfoPtr pScrn, BoxPtr dstBox) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + RADEONInfoPtr info = RADEONPTR(pScrn); + int c; + int crtc_num = 0; + + for (c = 0; c < xf86_config->num_crtc; c++) + { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + + if (!crtc->enabled) + continue; + + if ((dstBox->x1 >= crtc->x) && (dstBox->y1 >= crtc->y)) + crtc_num = c; + } + + if (crtc_num == 1) + info->OverlayOnCRTC2 = TRUE; + else + info->OverlayOnCRTC2 = FALSE; +} + diff --git a/src/radeon_cursor.c b/src/radeon_cursor.c index ec80dd8..f19f2bc 100644 --- a/src/radeon_cursor.c +++ b/src/radeon_cursor.c @@ -31,7 +31,7 @@ #endif #define RADEONCTRACE(x) -/* #define RADEONCTRACE(x) RADEONTRACE(x) */ +/*#define RADEONCTRACE(x) RADEONTRACE(x) */ /* * Authors: @@ -55,19 +55,10 @@ #include "radeon_version.h" #include "radeon_reg.h" #include "radeon_macros.h" -#include "radeon_mergedfb.h" /* X and server generic header files */ #include "xf86.h" -/* Mono ARGB cursor colours (premultiplied). */ -static CARD32 mono_cursor_color[] = { - 0x00000000, /* White, fully transparent. */ - 0x00000000, /* Black, fully transparent. */ - 0xffffffff, /* White, fully opaque. */ - 0xff000000, /* Black, fully opaque. */ -}; - #define CURSOR_WIDTH 64 #define CURSOR_HEIGHT 64 @@ -98,232 +89,144 @@ static CARD32 mono_cursor_color[] = { #endif - -/* Set cursor foreground and background colors */ -static void RADEONSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg) +void +radeon_crtc_show_cursor (xf86CrtcPtr crtc) { - RADEONInfoPtr info = RADEONPTR(pScrn); - CARD32 *pixels = (CARD32 *)(pointer)(info->FB + info->cursor_offset + pScrn->fbOffset); - int pixel, i; - CURSOR_SWAPPING_DECL_MMIO - - RADEONCTRACE(("RADEONSetCursorColors\n")); - -#ifdef ARGB_CURSOR - /* Don't recolour cursors set with SetCursorARGB. */ - if (info->cursor_argb) - return; -#endif + ScrnInfoPtr pScrn = crtc->scrn; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + int crtc_id = radeon_crtc->crtc_id; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; - fg |= 0xff000000; - bg |= 0xff000000; + if (crtc_id == 0) + OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN | 2 << 20, + ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); + else if (crtc_id == 1) + OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN | 2 << 20, + ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_CUR_MODE_MASK)); +} - /* Don't recolour the image if we don't have to. */ - if (fg == info->cursor_fg && bg == info->cursor_bg) - return; +void +radeon_crtc_hide_cursor (xf86CrtcPtr crtc) +{ + ScrnInfoPtr pScrn = crtc->scrn; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + int crtc_id = radeon_crtc->crtc_id; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; - CURSOR_SWAPPING_START(); + if (crtc_id == 0) + OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); + else if (crtc_id == 1) + OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); - /* Note: We assume that the pixels are either fully opaque or fully - * transparent, so we won't premultiply them, and we can just - * check for non-zero pixel values; those are either fg or bg - */ - for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++) - if ((pixel = *pixels)) - *pixels = (pixel == info->cursor_fg) ? fg : bg; - CURSOR_SWAPPING_END(); - info->cursor_fg = fg; - info->cursor_bg = bg; } - -/* Set cursor position to (x,y) with offset into cursor bitmap at - * (xorigin,yorigin) - */ -static void RADEONSetCursorPosition(ScrnInfoPtr pScrn, int x, int y) +void +radeon_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) { + ScrnInfoPtr pScrn = crtc->scrn; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + int crtc_id = radeon_crtc->crtc_id; RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - xf86CursorInfoPtr cursor = info->cursor; - int xorigin = 0; - int yorigin = 0; - int total_y = pScrn->frameY1 - pScrn->frameY0; - int stride = 256; - - if(info->MergedFB) { - RADEONCTRACE(("RADEONSetCursorPositionMerged\n")); - RADEONSetCursorPositionMerged(pScrn, x, y); - return; - } - - RADEONCTRACE(("RADEONSetCursorPosition\n")); + int xorigin = 0, yorigin = 0; + int stride = 256; + DisplayModePtr mode = &crtc->mode; if (x < 0) xorigin = -x+1; if (y < 0) yorigin = -y+1; - if (y > total_y) y = total_y; - if (info->Flags & V_DBLSCAN) y *= 2; - if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; - if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; + if (xorigin >= CURSOR_WIDTH) xorigin = CURSOR_WIDTH - 1; + if (yorigin >= CURSOR_HEIGHT) yorigin = CURSOR_HEIGHT - 1; - if (!info->IsSecondary) { + if (mode->Flags & V_INTERLACE) + y /= 2; + else if (mode->Flags & V_DBLSCAN) + y *= 2; + + if (crtc_id == 0) { OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK | (xorigin << 16) | yorigin)); OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK | ((xorigin ? 0 : x) << 16) | (yorigin ? 0 : y))); - RADEONCTRACE(("cursor_offset: 0x%x, yorigin: %d, stride: %d\n", - info->cursor_offset + pScrn->fbOffset, yorigin, stride)); + RADEONCTRACE(("cursor_offset: 0x%x, yorigin: %d, stride: %d, temp %08X\n", + info->cursor_offset + pScrn->fbOffset, yorigin, stride, temp)); OUTREG(RADEON_CUR_OFFSET, info->cursor_offset + pScrn->fbOffset + yorigin * stride); - } else { + } else if (crtc_id == 1) { OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK | (xorigin << 16) | yorigin)); OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK - | ((xorigin ? 0 : x) << 16) - | (yorigin ? 0 : y))); + | ((xorigin ? 0 : x) << 16) + | (yorigin ? 0 : y))); + RADEONCTRACE(("cursor_offset2: 0x%x, yorigin: %d, stride: %d, temp %08X\n", + info->cursor_offset + pScrn->fbOffset, yorigin, stride, temp)); OUTREG(RADEON_CUR2_OFFSET, - info->cursor_offset + pScrn->fbOffset + yorigin * stride); + info->cursor_offset + pScrn->fbOffset + yorigin * stride); } } -/* Copy cursor image from `image' to video memory. RADEONSetCursorPosition - * will be called after this, so we can ignore xorigin and yorigin. - */ -static void RADEONLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image) +void +radeon_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) { - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - CARD8 *s = (CARD8 *)(pointer)image; - CARD32 *d = (CARD32 *)(pointer)(info->FB + info->cursor_offset + pScrn->fbOffset); - CARD8 chunk; - CARD32 i, j; + ScrnInfoPtr pScrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD32 *pixels = (CARD32 *)(pointer)(info->FB + info->cursor_offset + pScrn->fbOffset); + int pixel, i; + CURSOR_SWAPPING_DECL_MMIO - RADEONCTRACE(("RADEONLoadCursorImage (at %x)\n", info->cursor_offset)); + RADEONCTRACE(("RADEONSetCursorColors\n")); #ifdef ARGB_CURSOR - info->cursor_argb = FALSE; + /* Don't recolour cursors set with SetCursorARGB. */ + if (info->cursor_argb) + return; #endif - /* - * Convert the bitmap to ARGB32. - * - * HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 always places - * source in the low bit of the pair and mask in the high bit, - * and MSBFirst machines set HARDWARE_CURSOR_BIT_ORDER_MSBFIRST - * (which actually bit swaps the image) to make the bits LSBFirst - */ - CURSOR_SWAPPING_START(); - -#define ARGB_PER_CHUNK (8 * sizeof (chunk) / 2) - for (i = 0; i < (CURSOR_WIDTH * CURSOR_HEIGHT / ARGB_PER_CHUNK); i++) { - chunk = *s++; - for (j = 0; j < ARGB_PER_CHUNK; j++, chunk >>= 2) - *d++ = mono_cursor_color[chunk & 3]; - } - - CURSOR_SWAPPING_END(); - - info->cursor_bg = mono_cursor_color[2]; - info->cursor_fg = mono_cursor_color[3]; -} - -/* Hide hardware cursor. */ -static void RADEONHideCursor(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - RADEONCTRACE(("RADEONHideCursor\n")); - - RADEON_SYNC(info, pScrn); - - if (info->IsSecondary || info->MergedFB) - OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); - - if (!info->IsSecondary) - OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); -} - -/* Show hardware cursor. */ -static void RADEONShowCursor(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - RADEONCTRACE(("RADEONShowCursor\n")); - - RADEON_SYNC(info, pScrn); + fg |= 0xff000000; + bg |= 0xff000000; - if (info->IsSecondary || info->MergedFB) - OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN | 2 << 20, - ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_CUR_MODE_MASK)); + /* Don't recolour the image if we don't have to. */ + if (fg == info->cursor_fg && bg == info->cursor_bg) + return; - if (!info->IsSecondary) - OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN | 2 << 20, - ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK)); -} + CURSOR_SWAPPING_START(); -/* Determine if hardware cursor is in use. */ -static Bool RADEONUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs) -{ - ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; - RADEONInfoPtr info = RADEONPTR(pScrn); + /* Note: We assume that the pixels are either fully opaque or fully + * transparent, so we won't premultiply them, and we can just + * check for non-zero pixel values; those are either fg or bg + */ + for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++) + if ((pixel = *pixels)) + *pixels = (pixel == info->cursor_fg) ? fg : bg; - return info->cursor ? TRUE : FALSE; + CURSOR_SWAPPING_END(); + info->cursor_fg = fg; + info->cursor_bg = bg; } #ifdef ARGB_CURSOR -#include "cursorstr.h" -static Bool RADEONUseHWCursorARGB (ScreenPtr pScreen, CursorPtr pCurs) -{ - if (RADEONUseHWCursor(pScreen, pCurs) && - pCurs->bits->height <= CURSOR_HEIGHT && pCurs->bits->width <= CURSOR_WIDTH) - return TRUE; - return FALSE; -} - -static void RADEONLoadCursorARGB (ScrnInfoPtr pScrn, CursorPtr pCurs) +void +radeon_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) { + ScrnInfoPtr pScrn = crtc->scrn; RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 *d = (CARD32 *)(pointer)(info->FB + info->cursor_offset + pScrn->fbOffset); - int x, y, w, h; - CARD32 *image = pCurs->bits->argb; - CARD32 *i; RADEONCTRACE(("RADEONLoadCursorARGB\n")); -#ifdef ARGB_CURSOR info->cursor_argb = TRUE; -#endif CURSOR_SWAPPING_START(); - w = pCurs->bits->width; - if (w > CURSOR_WIDTH) - w = CURSOR_WIDTH; - h = pCurs->bits->height; - if (h > CURSOR_HEIGHT) - h = CURSOR_HEIGHT; - for (y = 0; y < h; y++) - { - i = image; - image += pCurs->bits->width; - for (x = 0; x < w; x++) - *d++ = *i++; - /* pad to the right with transparent */ - for (; x < CURSOR_WIDTH; x++) - *d++ = 0; - } - /* pad below with transparent */ - for (; y < CURSOR_HEIGHT; y++) - for (x = 0; x < CURSOR_WIDTH; x++) - *d++ = 0; + memcpy (d, image, CURSOR_HEIGHT * CURSOR_WIDTH * 4); CURSOR_SWAPPING_END (); } @@ -336,39 +239,12 @@ Bool RADEONCursorInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; RADEONInfoPtr info = RADEONPTR(pScrn); - xf86CursorInfoPtr cursor; int width; int width_bytes; int height; int size_bytes; - if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE; - cursor->MaxWidth = CURSOR_WIDTH; - cursor->MaxHeight = CURSOR_HEIGHT; - cursor->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP - | HARDWARE_CURSOR_AND_SOURCE_WITH_MASK -#if X_BYTE_ORDER == X_BIG_ENDIAN - /* this is a lie -- - * HARDWARE_CURSOR_BIT_ORDER_MSBFIRST - * actually inverts the bit order, so - * this switches to LSBFIRST - */ - | HARDWARE_CURSOR_BIT_ORDER_MSBFIRST -#endif - | HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1); - - cursor->SetCursorColors = RADEONSetCursorColors; - cursor->SetCursorPosition = RADEONSetCursorPosition; - cursor->LoadCursorImage = RADEONLoadCursorImage; - cursor->HideCursor = RADEONHideCursor; - cursor->ShowCursor = RADEONShowCursor; - cursor->UseHWCursor = RADEONUseHWCursor; - -#ifdef ARGB_CURSOR - cursor->UseHWCursorARGB = RADEONUseHWCursorARGB; - cursor->LoadCursorARGB = RADEONLoadCursorARGB; -#endif size_bytes = CURSOR_WIDTH * 4 * CURSOR_HEIGHT; width = pScrn->displayWidth; width_bytes = width * (pScrn->bitsPerPixel / 8); @@ -398,5 +274,17 @@ Bool RADEONCursorInit(ScreenPtr pScreen) } #endif - return xf86InitCursor(pScreen, cursor); + return xf86_cursors_init (pScreen, CURSOR_WIDTH, CURSOR_HEIGHT, + (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | +#if X_BYTE_ORDER == X_BIG_ENDIAN + /* this is a lie -- + * HARDWARE_CURSOR_BIT_ORDER_MSBFIRST + * actually inverts the bit order, so + * this switches to LSBFIRST + */ + HARDWARE_CURSOR_BIT_ORDER_MSBFIRST | +#endif + HARDWARE_CURSOR_AND_SOURCE_WITH_MASK | + HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 | + HARDWARE_CURSOR_ARGB)); } diff --git a/src/radeon_display.c b/src/radeon_display.c index 02f5960..e76ffa4 100644 --- a/src/radeon_display.c +++ b/src/radeon_display.c @@ -38,6 +38,7 @@ #include "xf86_OSproc.h" #include "fbdevhw.h" #include "vgaHW.h" +#include "xf86Modes.h" /* Driver data structures */ #include "radeon.h" @@ -45,98 +46,9 @@ #include "radeon_macros.h" #include "radeon_probe.h" #include "radeon_version.h" -#include "radeon_mergedfb.h" extern int getRADEONEntityIndex(void); -const char *MonTypeName[7] = { - "AUTO", - "NONE", - "CRT", - "LVDS", - "TMDS", - "CTV", - "STV" -}; - -const RADEONMonitorType MonTypeID[7] = { - MT_UNKNOWN, /* this is just a dummy value for AUTO DETECTION */ - MT_NONE, /* NONE -> NONE */ - MT_CRT, /* CRT -> CRT */ - MT_LCD, /* Laptop LCDs are driven via LVDS port */ - MT_DFP, /* DFPs are driven via TMDS */ - MT_CTV, /* CTV -> CTV */ - MT_STV, /* STV -> STV */ -}; - -const char *TMDSTypeName[3] = { - "NONE", - "Internal", - "External" -}; - -const char *DDCTypeName[6] = { - "NONE", - "MONID", - "DVI_DDC", - "VGA_DDC", - "CRT2_DDC", - "LCD_DDC" -}; - -const char *DACTypeName[3] = { - "Unknown", - "Primary", - "TVDAC/ExtDAC", -}; - -const char *ConnectorTypeName[8] = { - "None", - "Proprietary", - "VGA", - "DVI-I", - "DVI-D", - "CTV", - "STV", - "Unsupported" -}; - -const char *ConnectorTypeNameATOM[10] = { - "None", - "VGA", - "DVI-I", - "DVI-D", - "DVI-A", - "STV", - "CTV", - "LVDS", - "Digital", - "Unsupported" -}; - - -static const RADEONTMDSPll default_tmds_pll[CHIP_FAMILY_LAST][4] = -{ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_UNKNOW*/ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_LEGACY*/ - {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RADEON*/ - {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV100*/ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS100*/ - {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV200*/ - {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS200*/ - {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R200*/ - {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV250*/ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS300*/ - {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}}, /*CHIP_FAMILY_RV280*/ - {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R300*/ - {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R350*/ - {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV350*/ - {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV380*/ - {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R420*/ - {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV410*/ /* FIXME: just values from r420 used... */ - {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS400*/ /* FIXME: just values from rv380 used... */ -}; - static const CARD32 default_tvdac_adj [CHIP_FAMILY_LAST] = { 0x00000000, /* unknown */ @@ -159,65 +71,6 @@ static const CARD32 default_tvdac_adj [CHIP_FAMILY_LAST] = 0x00780000, /* rs400 */ /* FIXME: just values from rv380 used... */ }; -static void RADEONI2CGetBits(I2CBusPtr b, int *Clock, int *data) -{ - ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned long val; - unsigned char *RADEONMMIO = info->MMIO; - - /* Get the result */ - - if (info->DDCReg == RADEON_LCD_GPIO_MASK) { - val = INREG(info->DDCReg+4); - *Clock = (val & (1<<13)) != 0; - *data = (val & (1<<12)) != 0; - } else { - val = INREG(info->DDCReg); - *Clock = (val & RADEON_GPIO_Y_1) != 0; - *data = (val & RADEON_GPIO_Y_0) != 0; - } -} - -static void RADEONI2CPutBits(I2CBusPtr b, int Clock, int data) -{ - ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned long val; - unsigned char *RADEONMMIO = info->MMIO; - - if (info->DDCReg == RADEON_LCD_GPIO_MASK) { - val = INREG(info->DDCReg) & (CARD32)~((1<<12) | (1<<13)); - val |= (Clock ? 0:(1<<13)); - val |= (data ? 0:(1<<12)); - OUTREG(info->DDCReg, val); - } else { - val = INREG(info->DDCReg) & (CARD32)~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1); - val |= (Clock ? 0:RADEON_GPIO_EN_1); - val |= (data ? 0:RADEON_GPIO_EN_0); - OUTREG(info->DDCReg, val); - } - /* read back to improve reliability on some cards. */ - val = INREG(info->DDCReg); -} - -Bool RADEONI2cInit(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - info->pI2CBus = xf86CreateI2CBusRec(); - if (!info->pI2CBus) return FALSE; - - info->pI2CBus->BusName = "DDC"; - info->pI2CBus->scrnIndex = pScrn->scrnIndex; - info->pI2CBus->I2CPutBits = RADEONI2CPutBits; - info->pI2CBus->I2CGetBits = RADEONI2CGetBits; - info->pI2CBus->AcknTimeout = 5; - - if (!xf86I2CBusInit(info->pI2CBus)) return FALSE; - return TRUE; -} - void RADEONSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag) { MonPtr mon = pScrn->monitor; @@ -306,1127 +159,18 @@ void RADEONSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag) } } -static RADEONMonitorType -RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - int bConnected = 0; - - /* the monitor either wasn't connected or it is a non-DDC CRT. - * try to probe it - */ - if(IsCrtDac) { - unsigned long ulOrigVCLK_ECP_CNTL; - unsigned long ulOrigDAC_CNTL; - unsigned long ulOrigDAC_MACRO_CNTL; - unsigned long ulOrigDAC_EXT_CNTL; - unsigned long ulOrigCRTC_EXT_CNTL; - unsigned long ulData; - unsigned long ulMask; - - ulOrigVCLK_ECP_CNTL = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); - - ulData = ulOrigVCLK_ECP_CNTL; - ulData &= ~(RADEON_PIXCLK_ALWAYS_ONb - | RADEON_PIXCLK_DAC_ALWAYS_ONb); - ulMask = ~(RADEON_PIXCLK_ALWAYS_ONb - |RADEON_PIXCLK_DAC_ALWAYS_ONb); - OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); - - ulOrigCRTC_EXT_CNTL = INREG(RADEON_CRTC_EXT_CNTL); - ulData = ulOrigCRTC_EXT_CNTL; - ulData |= RADEON_CRTC_CRT_ON; - OUTREG(RADEON_CRTC_EXT_CNTL, ulData); - - ulOrigDAC_EXT_CNTL = INREG(RADEON_DAC_EXT_CNTL); - ulData = ulOrigDAC_EXT_CNTL; - ulData &= ~RADEON_DAC_FORCE_DATA_MASK; - ulData |= (RADEON_DAC_FORCE_BLANK_OFF_EN - |RADEON_DAC_FORCE_DATA_EN - |RADEON_DAC_FORCE_DATA_SEL_MASK); - if ((info->ChipFamily == CHIP_FAMILY_RV250) || - (info->ChipFamily == CHIP_FAMILY_RV280)) - ulData |= (0x01b6 << RADEON_DAC_FORCE_DATA_SHIFT); - else - ulData |= (0x01ac << RADEON_DAC_FORCE_DATA_SHIFT); - - OUTREG(RADEON_DAC_EXT_CNTL, ulData); - - /* turn on power so testing can go through */ - ulOrigDAC_CNTL = INREG(RADEON_DAC_CNTL); - ulOrigDAC_CNTL &= ~RADEON_DAC_PDWN; - OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL); - - ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL); - ulOrigDAC_MACRO_CNTL &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | - RADEON_DAC_PDWN_B); - OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL); - - /* Enable comparators and set DAC range to PS2 (VGA) output level */ - ulData = ulOrigDAC_CNTL; - ulData |= RADEON_DAC_CMP_EN; - ulData &= ~RADEON_DAC_RANGE_CNTL_MASK; - ulData |= 0x2; - OUTREG(RADEON_DAC_CNTL, ulData); - - /* Settle down */ - usleep(10000); - - /* Read comparators */ - ulData = INREG(RADEON_DAC_CNTL); - bConnected = (RADEON_DAC_CMP_OUTPUT & ulData)?1:0; - - /* Restore things */ - ulData = ulOrigVCLK_ECP_CNTL; - ulMask = 0xFFFFFFFFL; - OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); - - OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL ); - OUTREG(RADEON_DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL ); - OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL); - - if (!bConnected) { - /* Power DAC down if CRT is not connected */ - ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL); - ulOrigDAC_MACRO_CNTL |= (RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | - RADEON_DAC_PDWN_B); - OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL); - - ulData = INREG(RADEON_DAC_CNTL); - ulData |= RADEON_DAC_PDWN; - OUTREG(RADEON_DAC_CNTL, ulData); - } - } else { /* TV DAC */ - - /* This doesn't seem to work reliably (maybe worse on some OEM cards), - for now we always return false. If one wants to connected a - non-DDC monitor on the DVI port when CRT port is also connected, - he will need to explicitly tell the driver in the config file - with Option MonitorLayout. - */ - bConnected = FALSE; - -#if 0 - if (info->ChipFamily == CHIP_FAMILY_R200) { - unsigned long ulOrigGPIO_MONID; - unsigned long ulOrigFP2_GEN_CNTL; - unsigned long ulOrigDISP_OUTPUT_CNTL; - unsigned long ulOrigCRTC2_GEN_CNTL; - unsigned long ulOrigDISP_LIN_TRANS_GRPH_A; - unsigned long ulOrigDISP_LIN_TRANS_GRPH_B; - unsigned long ulOrigDISP_LIN_TRANS_GRPH_C; - unsigned long ulOrigDISP_LIN_TRANS_GRPH_D; - unsigned long ulOrigDISP_LIN_TRANS_GRPH_E; - unsigned long ulOrigDISP_LIN_TRANS_GRPH_F; - unsigned long ulOrigCRTC2_H_TOTAL_DISP; - unsigned long ulOrigCRTC2_V_TOTAL_DISP; - unsigned long ulOrigCRTC2_H_SYNC_STRT_WID; - unsigned long ulOrigCRTC2_V_SYNC_STRT_WID; - unsigned long ulData, i; - - ulOrigGPIO_MONID = INREG(RADEON_GPIO_MONID); - ulOrigFP2_GEN_CNTL = INREG(RADEON_FP2_GEN_CNTL); - ulOrigDISP_OUTPUT_CNTL = INREG(RADEON_DISP_OUTPUT_CNTL); - ulOrigCRTC2_GEN_CNTL = INREG(RADEON_CRTC2_GEN_CNTL); - ulOrigDISP_LIN_TRANS_GRPH_A = INREG(RADEON_DISP_LIN_TRANS_GRPH_A); - ulOrigDISP_LIN_TRANS_GRPH_B = INREG(RADEON_DISP_LIN_TRANS_GRPH_B); - ulOrigDISP_LIN_TRANS_GRPH_C = INREG(RADEON_DISP_LIN_TRANS_GRPH_C); - ulOrigDISP_LIN_TRANS_GRPH_D = INREG(RADEON_DISP_LIN_TRANS_GRPH_D); - ulOrigDISP_LIN_TRANS_GRPH_E = INREG(RADEON_DISP_LIN_TRANS_GRPH_E); - ulOrigDISP_LIN_TRANS_GRPH_F = INREG(RADEON_DISP_LIN_TRANS_GRPH_F); - - ulOrigCRTC2_H_TOTAL_DISP = INREG(RADEON_CRTC2_H_TOTAL_DISP); - ulOrigCRTC2_V_TOTAL_DISP = INREG(RADEON_CRTC2_V_TOTAL_DISP); - ulOrigCRTC2_H_SYNC_STRT_WID = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); - ulOrigCRTC2_V_SYNC_STRT_WID = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); - - ulData = INREG(RADEON_GPIO_MONID); - ulData &= ~RADEON_GPIO_A_0; - OUTREG(RADEON_GPIO_MONID, ulData); - - OUTREG(RADEON_FP2_GEN_CNTL, 0x0a000c0c); - - OUTREG(RADEON_DISP_OUTPUT_CNTL, 0x00000012); - - OUTREG(RADEON_CRTC2_GEN_CNTL, 0x06000000); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); - OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); - OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); - OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); - OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); - - for (i = 0; i < 200; i++) { - ulData = INREG(RADEON_GPIO_MONID); - bConnected = (ulData & RADEON_GPIO_Y_0)?1:0; - if (!bConnected) break; - - usleep(1000); - } - - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, ulOrigDISP_LIN_TRANS_GRPH_A); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, ulOrigDISP_LIN_TRANS_GRPH_B); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, ulOrigDISP_LIN_TRANS_GRPH_C); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, ulOrigDISP_LIN_TRANS_GRPH_D); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, ulOrigDISP_LIN_TRANS_GRPH_E); - OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, ulOrigDISP_LIN_TRANS_GRPH_F); - OUTREG(RADEON_CRTC2_H_TOTAL_DISP, ulOrigCRTC2_H_TOTAL_DISP); - OUTREG(RADEON_CRTC2_V_TOTAL_DISP, ulOrigCRTC2_V_TOTAL_DISP); - OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, ulOrigCRTC2_H_SYNC_STRT_WID); - OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, ulOrigCRTC2_V_SYNC_STRT_WID); - OUTREG(RADEON_CRTC2_GEN_CNTL, ulOrigCRTC2_GEN_CNTL); - OUTREG(RADEON_DISP_OUTPUT_CNTL, ulOrigDISP_OUTPUT_CNTL); - OUTREG(RADEON_FP2_GEN_CNTL, ulOrigFP2_GEN_CNTL); - OUTREG(RADEON_GPIO_MONID, ulOrigGPIO_MONID); - } else { - unsigned long ulOrigPIXCLKSDATA; - unsigned long ulOrigTV_MASTER_CNTL; - unsigned long ulOrigTV_DAC_CNTL; - unsigned long ulOrigTV_PRE_DAC_MUX_CNTL; - unsigned long ulOrigDAC_CNTL2; - unsigned long ulData; - unsigned long ulMask; - - ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL); - - ulData = ulOrigPIXCLKSDATA; - ulData &= ~(RADEON_PIX2CLK_ALWAYS_ONb - | RADEON_PIX2CLK_DAC_ALWAYS_ONb); - ulMask = ~(RADEON_PIX2CLK_ALWAYS_ONb - | RADEON_PIX2CLK_DAC_ALWAYS_ONb); - OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); - - ulOrigTV_MASTER_CNTL = INREG(RADEON_TV_MASTER_CNTL); - ulData = ulOrigTV_MASTER_CNTL; - ulData &= ~RADEON_TVCLK_ALWAYS_ONb; - OUTREG(RADEON_TV_MASTER_CNTL, ulData); - - ulOrigDAC_CNTL2 = INREG(RADEON_DAC_CNTL2); - ulData = ulOrigDAC_CNTL2; - ulData &= ~RADEON_DAC2_DAC2_CLK_SEL; - OUTREG(RADEON_DAC_CNTL2, ulData); - - ulOrigTV_DAC_CNTL = INREG(RADEON_TV_DAC_CNTL); - - ulData = 0x00880213; - OUTREG(RADEON_TV_DAC_CNTL, ulData); - - ulOrigTV_PRE_DAC_MUX_CNTL = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); - - ulData = (RADEON_Y_RED_EN - | RADEON_C_GRN_EN - | RADEON_CMP_BLU_EN - | RADEON_RED_MX_FORCE_DAC_DATA - | RADEON_GRN_MX_FORCE_DAC_DATA - | RADEON_BLU_MX_FORCE_DAC_DATA); - if (IS_R300_VARIANT) - ulData |= 0x180 << RADEON_TV_FORCE_DAC_DATA_SHIFT; - else - ulData |= 0x1f5 << RADEON_TV_FORCE_DAC_DATA_SHIFT; - OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulData); - - usleep(10000); - - ulData = INREG(RADEON_TV_DAC_CNTL); - bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0; - - ulData = ulOrigPIXCLKSDATA; - ulMask = 0xFFFFFFFFL; - OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); - - OUTREG(RADEON_TV_MASTER_CNTL, ulOrigTV_MASTER_CNTL); - OUTREG(RADEON_DAC_CNTL2, ulOrigDAC_CNTL2); - OUTREG(RADEON_TV_DAC_CNTL, ulOrigTV_DAC_CNTL); - OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulOrigTV_PRE_DAC_MUX_CNTL); - } -#endif - } - - return(bConnected ? MT_CRT : MT_NONE); -} - - -static RADEONMonitorType RADEONDisplayDDCConnected(ScrnInfoPtr pScrn, RADEONDDCType DDCType, RADEONConnector* port) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - unsigned long DDCReg; - RADEONMonitorType MonType = MT_NONE; - xf86MonPtr* MonInfo = &port->MonInfo; - int i, j; - - DDCReg = info->DDCReg; - switch(DDCType) - { - case DDC_MONID: - info->DDCReg = RADEON_GPIO_MONID; - break; - case DDC_DVI: - info->DDCReg = RADEON_GPIO_DVI_DDC; - break; - case DDC_VGA: - info->DDCReg = RADEON_GPIO_VGA_DDC; - break; - case DDC_CRT2: - info->DDCReg = RADEON_GPIO_CRT2_DDC; - break; - case DDC_LCD: - info->DDCReg = RADEON_LCD_GPIO_MASK; - break; - default: - info->DDCReg = DDCReg; - return MT_NONE; - } - - /* Read and output monitor info using DDC2 over I2C bus */ - if (info->pI2CBus && info->ddc2 && (info->DDCReg != RADEON_LCD_GPIO_MASK)) { - OUTREG(info->DDCReg, INREG(info->DDCReg) & - (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1)); - - /* For some old monitors (like Compaq Presario FP500), we need - * following process to initialize/stop DDC - */ - OUTREG(info->DDCReg, INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1)); - for (j = 0; j < 3; j++) { - OUTREG(info->DDCReg, - INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0)); - usleep(13000); - - OUTREG(info->DDCReg, - INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1)); - for (i = 0; i < 10; i++) { - usleep(15000); - if (INREG(info->DDCReg) & RADEON_GPIO_Y_1) - break; - } - if (i == 10) continue; - - usleep(15000); - - OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0); - usleep(15000); - - OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1); - usleep(15000); - OUTREG(info->DDCReg, - INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0)); - usleep(15000); - *MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, info->pI2CBus); - - OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1); - OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0); - usleep(15000); - OUTREG(info->DDCReg, - INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1)); - for (i = 0; i < 5; i++) { - usleep(15000); - if (INREG(info->DDCReg) & RADEON_GPIO_Y_1) - break; - } - usleep(15000); - OUTREG(info->DDCReg, - INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0)); - usleep(15000); - - OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1); - OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0); - usleep(15000); - if(*MonInfo) break; - } - } else if (info->pI2CBus && info->ddc2 && info->DDCReg == RADEON_LCD_GPIO_MASK) { - *MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, info->pI2CBus); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DDC2/I2C is not properly initialized\n"); - MonType = MT_NONE; - } - - OUTREG(info->DDCReg, INREG(info->DDCReg) & - ~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1)); - - if (*MonInfo) { - if ((*MonInfo)->rawData[0x14] & 0x80) { - /* Note some laptops have a DVI output that uses internal TMDS, - * when its DVI is enabled by hotkey, LVDS panel is not used. - * In this case, the laptop is configured as DVI+VGA as a normal - * desktop card. - * Also for laptop, when X starts with lid closed (no DVI connection) - * both LDVS and TMDS are disable, we still need to treat it as a LVDS panel. - */ - if (port->TMDSType == TMDS_EXT) MonType = MT_DFP; - else { - if ((INREG(RADEON_FP_GEN_CNTL) & RADEON_FP_EN_TMDS) || !info->IsMobility) - MonType = MT_DFP; - else - MonType = MT_LCD; - } - } else MonType = MT_CRT; - } else MonType = MT_NONE; - - info->DDCReg = DDCReg; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "DDC Type: %d, Detected Type: %d\n", DDCType, MonType); - - return MonType; -} - -static void RADEONGetPanelInfoFromReg (ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - CARD32 fp_vert_stretch = INREG(RADEON_FP_VERT_STRETCH); - CARD32 fp_horz_stretch = INREG(RADEON_FP_HORZ_STRETCH); - - info->PanelPwrDly = 200; - if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) { - info->PanelYRes = ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >> - RADEON_VERT_PANEL_SHIFT) + 1; - } else { - info->PanelYRes = (INREG(RADEON_CRTC_V_TOTAL_DISP)>>16) + 1; - } - if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE) { - info->PanelXRes = (((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >> - RADEON_HORZ_PANEL_SHIFT) + 1) * 8; - } else { - info->PanelXRes = ((INREG(RADEON_CRTC_H_TOTAL_DISP)>>16) + 1) * 8; - } - - if ((info->PanelXRes < 640) || (info->PanelYRes < 480)) { - info->PanelXRes = 640; - info->PanelYRes = 480; - } - - if (xf86ReturnOptValBool(info->Options, OPTION_LVDS_PROBE_PLL, TRUE)) { - CARD32 ppll_div_sel, ppll_val; - - ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; - RADEONPllErrataAfterIndex(info); - ppll_val = INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel); - if ((ppll_val & 0x000707ff) == 0x1bb) - goto noprobe; - info->FeedbackDivider = ppll_val & 0x7ff; - info->PostDivider = (ppll_val >> 16) & 0x7; - info->RefDivider = info->pll.reference_div; - info->UseBiosDividers = TRUE; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Existing panel PLL dividers will be used.\n"); - } - noprobe: - - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Panel size %dx%d is derived, this may not be correct.\n" - "If not, use PanelSize option to overwrite this setting\n", - info->PanelXRes, info->PanelYRes); -} - - -/* BIOS may not have right panel size, we search through all supported - * DDC modes looking for the maximum panel size. - */ -static void RADEONUpdatePanelSize(ScrnInfoPtr pScrn) +void RADEONGetTVDacAdjInfo(xf86OutputPtr output) { - int j; - RADEONInfoPtr info = RADEONPTR (pScrn); - xf86MonPtr ddc = pScrn->monitor->DDC; - DisplayModePtr p; - - if ((info->UseBiosDividers && info->DotClock != 0) || (ddc == NULL)) - return; - - /* Go thru detailed timing table first */ - for (j = 0; j < 4; j++) { - if (ddc->det_mon[j].type == 0) { - struct detailed_timings *d_timings = - &ddc->det_mon[j].section.d_timings; - int match = 0; - - /* If we didn't get a panel clock or guessed one, try to match the - * mode with the panel size. We do that because we _need_ a panel - * clock, or ValidateFPModes will fail, even when UseBiosDividers - * is set. - */ - if (info->DotClock == 0 && - info->PanelXRes == d_timings->h_active && - info->PanelYRes == d_timings->v_active) - match = 1; - - /* If we don't have a BIOS provided panel data with fixed dividers, - * check for a larger panel size - */ - if (info->PanelXRes < d_timings->h_active && - info->PanelYRes < d_timings->v_active && - !info->UseBiosDividers) - match = 1; - - if (match) { - info->PanelXRes = d_timings->h_active; - info->PanelYRes = d_timings->v_active; - info->DotClock = d_timings->clock / 1000; - info->HOverPlus = d_timings->h_sync_off; - info->HSyncWidth = d_timings->h_sync_width; - info->HBlank = d_timings->h_blanking; - info->VOverPlus = d_timings->v_sync_off; - info->VSyncWidth = d_timings->v_sync_width; - info->VBlank = d_timings->v_blanking; - info->Flags = (d_timings->interlaced ? V_INTERLACE : 0); - switch (d_timings->misc) { - case 0: info->Flags |= V_NHSYNC | V_NVSYNC; break; - case 1: info->Flags |= V_PHSYNC | V_NVSYNC; break; - case 2: info->Flags |= V_NHSYNC | V_PVSYNC; break; - case 3: info->Flags |= V_PHSYNC | V_PVSYNC; break; - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n", - info->PanelXRes, info->PanelYRes); - } - } - } - - if (info->UseBiosDividers && info->DotClock != 0) - return; - - /* Search thru standard VESA modes from EDID */ - for (j = 0; j < 8; j++) { - if ((info->PanelXRes < ddc->timings2[j].hsize) && - (info->PanelYRes < ddc->timings2[j].vsize)) { - for (p = pScrn->monitor->Modes; p; p = p->next) { - if ((ddc->timings2[j].hsize == p->HDisplay) && - (ddc->timings2[j].vsize == p->VDisplay)) { - float refresh = - (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; - - if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { - /* Is this good enough? */ - info->PanelXRes = ddc->timings2[j].hsize; - info->PanelYRes = ddc->timings2[j].vsize; - info->HBlank = p->HTotal - p->HDisplay; - info->HOverPlus = p->HSyncStart - p->HDisplay; - info->HSyncWidth = p->HSyncEnd - p->HSyncStart; - info->VBlank = p->VTotal - p->VDisplay; - info->VOverPlus = p->VSyncStart - p->VDisplay; - info->VSyncWidth = p->VSyncEnd - p->VSyncStart; - info->DotClock = p->Clock; - info->Flags = p->Flags; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n", - info->PanelXRes, info->PanelYRes); - } - } - } - } - } -} - -static Bool RADEONGetLVDSInfo (ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - if (!RADEONGetLVDSInfoFromBIOS(pScrn)) - RADEONGetPanelInfoFromReg(pScrn); - - /* The panel size we collected from BIOS may not be the - * maximum size supported by the panel. If not, we update - * it now. These will be used if no matching mode can be - * found from EDID data. - */ - RADEONUpdatePanelSize(pScrn); - - if (info->DotClock == 0) { - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - DisplayModePtr tmp_mode = NULL; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "No valid timing info from BIOS.\n"); - /* No timing information for the native mode, - use whatever specified in the Modeline. - If no Modeline specified, we'll just pick - the VESA mode at 60Hz refresh rate which - is likely to be the best for a flat panel. - */ - tmp_mode = pScrn->monitor->Modes; - while(tmp_mode) { - if ((tmp_mode->HDisplay == info->PanelXRes) && - (tmp_mode->VDisplay == info->PanelYRes)) { - - float refresh = - (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal; - if ((abs(60.0 - refresh) < 1.0) || - (tmp_mode->type == 0)) { - info->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay; - info->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay; - info->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart; - info->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay; - info->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay; - info->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart; - info->DotClock = tmp_mode->Clock; - info->Flags = 0; - break; - } - } - - tmp_mode = tmp_mode->next; - - if (tmp_mode == pScrn->monitor->Modes) - break; - } - if ((info->DotClock == 0) && !pRADEONEnt->PortInfo[0]->MonInfo) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Panel size is not correctly detected.\n" - "Please try to use PanelSize option for correct settings.\n"); - return FALSE; - } - } - - return TRUE; -} - -static void RADEONGetTMDSInfo(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - int i; - - for (i=0; i<4; i++) { - info->tmds_pll[i].value = 0; - info->tmds_pll[i].freq = 0; - } - - if (RADEONGetTMDSInfoFromBIOS(pScrn)) return; - - for (i=0; i<4; i++) { - info->tmds_pll[i].value = default_tmds_pll[info->ChipFamily][i].value; - info->tmds_pll[i].freq = default_tmds_pll[info->ChipFamily][i].freq; - } -} - -void RADEONGetPanelInfo (ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - char* s; - - if((s = xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) { - info->PanelPwrDly = 200; - if (sscanf (s, "%dx%d", &info->PanelXRes, &info->PanelYRes) != 2) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid PanelSize option: %s\n", s); - RADEONGetPanelInfoFromReg(pScrn); - } - } else { - - if(info->DisplayType == MT_LCD) { - RADEONGetLVDSInfo(pScrn); - if (info->MergeType == MT_DFP) { - RADEONGetTMDSInfo(pScrn); - } - } else if ((info->DisplayType == MT_DFP) || (info->MergeType == MT_DFP)) { - RADEONGetTMDSInfo(pScrn); - if (!pScrn->monitor->DDC) - RADEONGetHardCodedEDIDFromBIOS(pScrn); - else if (!info->IsSecondary) - RADEONUpdatePanelSize(pScrn); - } - } -} - -void RADEONGetTVDacAdjInfo(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; /* Todo: get this setting from BIOS */ - info->tv_dac_adj = default_tvdac_adj[info->ChipFamily]; + radeon_output->tv_dac_adj = default_tvdac_adj[info->ChipFamily]; if (info->IsMobility) { /* some mobility chips may different */ if (info->ChipFamily == CHIP_FAMILY_RV250) - info->tv_dac_adj = 0x00880000; - } -} - -static void -RADEONConnectorReverse(RADEONEntPtr pRADEONEnt) -{ - RADEONConnector *connector; - - connector = pRADEONEnt->PortInfo[0]; - pRADEONEnt->PortInfo[0] = pRADEONEnt->PortInfo[1]; - pRADEONEnt->PortInfo[1] = connector; -} - -/* - * initialise the static data sos we don't have to re-do at randr change */ -void RADEONSetupConnectors(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - const char *s; - Bool ignore_edid = FALSE; - int i = 0, second = 0, max_mt = 5; - - /* We first get the information about all connectors from BIOS. - * This is how the card is phyiscally wired up. - * The information should be correct even on a OEM card. - * If not, we may have problem -- need to use MonitorLayout option. - */ - for (i = 0; i < 2; i++) { - pRADEONEnt->PortInfo[i]->MonType = MT_UNKNOWN; - pRADEONEnt->PortInfo[i]->MonInfo = NULL; - pRADEONEnt->PortInfo[i]->DDCType = DDC_NONE_DETECTED; - pRADEONEnt->PortInfo[i]->DACType = DAC_UNKNOWN; - pRADEONEnt->PortInfo[i]->TMDSType = TMDS_UNKNOWN; - pRADEONEnt->PortInfo[i]->ConnectorType = CONNECTOR_NONE; - } - pRADEONEnt->Controller[0]->IsUsed = FALSE; - pRADEONEnt->Controller[1]->IsUsed = FALSE; - pRADEONEnt->Controller[0]->IsActive = FALSE; - pRADEONEnt->Controller[1]->IsActive = FALSE; - - if (!RADEONGetConnectorInfoFromBIOS(pScrn) || - ((pRADEONEnt->PortInfo[0]->DDCType == 0) && - (pRADEONEnt->PortInfo[1]->DDCType == 0))) { - /* Below is the most common setting, but may not be true */ - pRADEONEnt->PortInfo[0]->MonType = MT_UNKNOWN; - pRADEONEnt->PortInfo[0]->MonInfo = NULL; - pRADEONEnt->PortInfo[0]->DDCType = DDC_DVI; - pRADEONEnt->PortInfo[0]->DACType = DAC_TVDAC; - pRADEONEnt->PortInfo[0]->TMDSType = TMDS_INT; - pRADEONEnt->PortInfo[0]->ConnectorType = CONNECTOR_DVI_I; - - pRADEONEnt->PortInfo[1]->MonType = MT_UNKNOWN; - pRADEONEnt->PortInfo[1]->MonInfo = NULL; - pRADEONEnt->PortInfo[1]->DDCType = DDC_VGA; - pRADEONEnt->PortInfo[1]->DACType = DAC_PRIMARY; - pRADEONEnt->PortInfo[1]->TMDSType = TMDS_EXT; - pRADEONEnt->PortInfo[1]->ConnectorType = CONNECTOR_CRT; - - - /* Some cards have the DDC lines swapped and we have no way to - * detect it yet (Mac cards) - */ - if (xf86ReturnOptValBool(info->Options, OPTION_REVERSE_DDC, FALSE)) { - pRADEONEnt->PortInfo[0]->DDCType = DDC_VGA; - pRADEONEnt->PortInfo[1]->DDCType = DDC_DVI; - } - } - - /* always make TMDS_INT port first*/ - if (pRADEONEnt->PortInfo[1]->TMDSType == TMDS_INT) - RADEONConnectorReverse(pRADEONEnt); - else if ((pRADEONEnt->PortInfo[0]->TMDSType != TMDS_INT && - pRADEONEnt->PortInfo[1]->TMDSType != TMDS_INT)) { - /* no TMDS_INT port, make primary DAC port first */ - /* On my Inspiron 8600 both internal and external ports are - marked DAC_PRIMARY in BIOS. So be extra careful - only - swap when the first port is not DAC_PRIMARY */ - if ((!(pRADEONEnt->PortInfo[0]->ConnectorType == CONNECTOR_PROPRIETARY)) && (pRADEONEnt->PortInfo[1]->DACType == DAC_PRIMARY) && - (pRADEONEnt->PortInfo[0]->DACType != DAC_PRIMARY)) { - RADEONConnectorReverse(pRADEONEnt); - } - } - - if (info->HasSingleDAC) { - /* For RS300/RS350/RS400 chips, there is no primary DAC. Force VGA port to use TVDAC*/ - if (pRADEONEnt->PortInfo[0]->ConnectorType == CONNECTOR_CRT) { - pRADEONEnt->PortInfo[0]->DACType = DAC_TVDAC; - pRADEONEnt->PortInfo[1]->DACType = DAC_PRIMARY; - } else { - pRADEONEnt->PortInfo[1]->DACType = DAC_TVDAC; - pRADEONEnt->PortInfo[0]->DACType = DAC_PRIMARY; - } - } else if (!pRADEONEnt->HasCRTC2) { - pRADEONEnt->PortInfo[0]->DACType = DAC_PRIMARY; - } - - /* IgnoreEDID option is different from the NoDDCxx options used by DDC module - * When IgnoreEDID is used, monitor detection will still use DDC - * detection, but all EDID data will not be used in mode validation. - * You can use this option when you have a DDC monitor but want specify your own - * monitor timing parameters by using HSync, VRefresh and Modeline, - */ - if (xf86GetOptValBool(info->Options, OPTION_IGNORE_EDID, &ignore_edid)) { - if (ignore_edid) - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, - "IgnoreEDID is specified, EDID data will be ignored\n"); - } - - /* - * MonitorLayout option takes a string for two monitors connected in following format: - * Option "MonitorLayout" "primary-port-display, secondary-port-display" - * primary and secondary port displays can have one of following: - * NONE, CRT, LVDS, TMDS - * With this option, driver will bring up monitors as specified, - * not using auto-detection routines to probe monitors. - * - * This option can be used when the false monitor detection occurs. - * - * This option can also be used to disable one connected display. - * For example, if you have a laptop connected to an external CRT - * and you want to disable the internal LCD panel, you can specify - * Option "MonitorLayout" "NONE, CRT" - * - * This option can also used to disable Clone mode. One there is only - * one monitor is specified, clone mode will be turned off automatically - * even you have two monitors connected. - * - * Another usage of this option is you want to config the server - * to start up with a certain monitor arrangement even one monitor - * is not plugged in when server starts. - * For example, you can config your laptop with - * Option "MonitorLayout" "LVDS, CRT" - * Option "CloneHSync" "40-150" - * Option "CloneVRefresh" "60-120" - * With these options, you can connect in your CRT monitor later - * after the X server has started. - */ - if ((s = xf86GetOptValString(info->Options, OPTION_MONITOR_LAYOUT))) { - char s1[5], s2[5]; - i = 0; - /* When using user specified monitor types, we will not do DDC detection - * - */ - do { - switch(*s) { - case ',': - s1[i] = '\0'; - i = 0; - second = 1; - break; - case ' ': - case '\t': - case '\n': - case '\r': - break; - default: - if (second) - s2[i] = *s; - else - s1[i] = *s; - i++; - break; - } - if (i > 4) i = 4; - } while(*s++); - s2[i] = '\0'; - - for (i = 0; i < max_mt; i++) - { - if (strcmp(s1, MonTypeName[i]) == 0) - { - pRADEONEnt->PortInfo[0]->MonType = MonTypeID[i]; - break; - } - } - if (i == max_mt) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Invalid Monitor type specified for 1st port \n"); - - for (i = 0; i < max_mt; i++) - { - if (strcmp(s2, MonTypeName[i]) == 0) - { - pRADEONEnt->PortInfo[1]->MonType = MonTypeID[i]; - break; - } - - } - if (i == max_mt) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Invalid Monitor type specified for 2nd port \n"); - - if (i == max_mt) - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Invalid Monitor type specified for 2nd port \n"); - - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, - "MonitorLayout Option: \n\tMonitor1--Type %s, Monitor2--Type %s\n\n", s1, s2); -#if 0 - if (pRADEONEnt->PortInfo[1]->MonType == MT_CRT) { - pRADEONEnt->PortInfo[1]->DACType = DAC_PRIMARY; - pRADEONEnt->PortInfo[1]->TMDSType = TMDS_UNKNOWN; - pRADEONEnt->PortInfo[1]->DDCType = DDC_VGA; - pRADEONEnt->PortInfo[1]->ConnectorType = CONNECTOR_CRT; - pRADEONEnt->PortInfo[0]->DACType = DAC_TVDAC; - pRADEONEnt->PortInfo[0]->TMDSType = TMDS_UNKNOWN; - pRADEONEnt->PortInfo[0]->DDCType = DDC_NONE_DETECTED; - pRADEONEnt->PortInfo[0]->ConnectorType = pRADEONEnt->PortInfo[0]->MonType+1; - pRADEONEnt->PortInfo[0]->MonInfo = NULL; - } -#endif - - /* some thinkpads and powerbooks use lvds and internal tmds - * at the same time. --AGD - */ - if ((pRADEONEnt->PortInfo[0]->MonType == MT_LCD) && - (pRADEONEnt->PortInfo[1]->MonType == MT_DFP)) { - pRADEONEnt->PortInfo[1]->DDCType = DDC_DVI; - pRADEONEnt->PortInfo[0]->DDCType = DDC_MONID; - pRADEONEnt->PortInfo[1]->TMDSType = TMDS_INT; - pRADEONEnt->PortInfo[1]->ConnectorType = CONNECTOR_DVI_I; - pRADEONEnt->PortInfo[0]->TMDSType = TMDS_UNKNOWN; - } - - } -} - -static RADEONMonitorType RADEONPortCheckNonDDC(ScrnInfoPtr pScrn, int connector) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - - if (info->IsMobility) { - switch(connector) { - case 0: - /* non-DDC laptop panel connected on primary */ - if (INREG(RADEON_BIOS_4_SCRATCH) & 4) - return MT_LCD; - break; - case 1: - /* non-DDC TMDS panel connected through DVO */ - if (INREG(RADEON_FP2_GEN_CNTL) & RADEON_FP2_ON) - return MT_DFP; - break; - default: - break; - } + radeon_output->tv_dac_adj = 0x00880000; } - return MT_NONE; -} - -/* Primary Head (DVI or Laptop Int. panel)*/ -/* A ddc capable display connected on DVI port */ -/* Secondary Head (mostly VGA, can be DVI on some OEM boards)*/ -void RADEONConnectorFindMonitor(ScrnInfoPtr pScrn, int connector) -{ - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONConnector *pPort = pRADEONEnt->PortInfo[connector]; - - if (pPort->MonType == MT_UNKNOWN) { - if ((pPort->MonType = RADEONDisplayDDCConnected(pScrn, - pPort->DDCType, - pPort))); - else if((pPort->MonType = RADEONPortCheckNonDDC(pScrn, connector))); - else - pPort->MonType = RADEONCrtIsPhysicallyConnected(pScrn, !(pPort->DACType)); - } -} - -static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn) -{ - - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - const char *s; - Bool ignore_edid = FALSE; - - /* IgnoreEDID option is different from the NoDDCxx options used by DDC module - * When IgnoreEDID is used, monitor detection will still use DDC - * detection, but all EDID data will not be used in mode validation. - * You can use this option when you have a DDC monitor but want specify your own - * monitor timing parameters by using HSync, VRefresh and Modeline, - */ - if (xf86GetOptValBool(info->Options, OPTION_IGNORE_EDID, &ignore_edid)) { - if (ignore_edid) - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, - "IgnoreEDID is specified, EDID data will be ignored\n"); - } - - if ((s = xf86GetOptValString(info->Options, OPTION_MONITOR_LAYOUT))) { - if (!ignore_edid) { - if ((pRADEONEnt->PortInfo[0]->MonType > MT_NONE) && - (pRADEONEnt->PortInfo[0]->MonType < MT_STV)) - RADEONDisplayDDCConnected(pScrn, pRADEONEnt->PortInfo[0]->DDCType, - pRADEONEnt->PortInfo[0]); - if ((pRADEONEnt->PortInfo[1]->MonType > MT_NONE) && - (pRADEONEnt->PortInfo[1]->MonType < MT_STV)) - RADEONDisplayDDCConnected(pScrn, pRADEONEnt->PortInfo[1]->DDCType, - pRADEONEnt->PortInfo[1]); - } - } - else { - /* force monitor redetection */ - pRADEONEnt->PortInfo[0]->MonType = MT_UNKNOWN; - pRADEONEnt->PortInfo[1]->MonType = MT_UNKNOWN; - } - - - if (pRADEONEnt->PortInfo[0]->MonType == MT_UNKNOWN || pRADEONEnt->PortInfo[1]->MonType == MT_UNKNOWN) { - - if ((!pRADEONEnt->HasCRTC2) && (pRADEONEnt->PortInfo[0]->MonType == MT_UNKNOWN)) { - if((pRADEONEnt->PortInfo[0]->MonType = RADEONDisplayDDCConnected(pScrn, DDC_DVI, - pRADEONEnt->PortInfo[0]))); - else if((pRADEONEnt->PortInfo[0]->MonType = RADEONDisplayDDCConnected(pScrn, DDC_VGA, - pRADEONEnt->PortInfo[0]))); - else if((pRADEONEnt->PortInfo[0]->MonType = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, - pRADEONEnt->PortInfo[0]))); - else - pRADEONEnt->PortInfo[0]->MonType = MT_CRT; - - if (!ignore_edid) { - if (pRADEONEnt->PortInfo[0]->MonInfo) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n"); - xf86PrintEDID(pRADEONEnt->PortInfo[0]->MonInfo ); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n"); - } - } - - pRADEONEnt->PortInfo[1]->MonType = MT_NONE; - pRADEONEnt->PortInfo[1]->MonInfo = NULL; - pRADEONEnt->PortInfo[1]->DDCType = DDC_NONE_DETECTED; - pRADEONEnt->PortInfo[1]->DACType = DAC_UNKNOWN; - pRADEONEnt->PortInfo[1]->TMDSType = TMDS_UNKNOWN; - pRADEONEnt->PortInfo[1]->ConnectorType = CONNECTOR_NONE; - - return; - } - - RADEONConnectorFindMonitor(pScrn, 0); - RADEONConnectorFindMonitor(pScrn, 1); - - } - - if(ignore_edid) { - pRADEONEnt->PortInfo[0]->MonInfo = NULL; - pRADEONEnt->PortInfo[1]->MonInfo = NULL; - } else { - if (pRADEONEnt->PortInfo[0]->MonInfo) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID data from the display on 1st port ----------------------\n"); - xf86PrintEDID( pRADEONEnt->PortInfo[0]->MonInfo ); - } - - if (pRADEONEnt->PortInfo[1]->MonInfo) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID data from the display on 2nd port -----------------------\n"); - xf86PrintEDID( pRADEONEnt->PortInfo[1]->MonInfo ); - } - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\n"); - - return; -} - -Bool RADEONMapControllers(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - Bool head_reversed = FALSE; - - info->MergeType = MT_NONE; - - if (!info->IsSecondary) { - RADEONQueryConnectedDisplays(pScrn); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Port1:\n Monitor -- %s\n Connector -- %s\n DAC Type -- %s\n TMDS Type -- %s\n DDC Type -- %s\n", - MonTypeName[pRADEONEnt->PortInfo[0]->MonType+1], - info->IsAtomBios ? - ConnectorTypeNameATOM[pRADEONEnt->PortInfo[0]->ConnectorType]: - ConnectorTypeName[pRADEONEnt->PortInfo[0]->ConnectorType], - DACTypeName[pRADEONEnt->PortInfo[0]->DACType+1], - TMDSTypeName[pRADEONEnt->PortInfo[0]->TMDSType+1], - DDCTypeName[pRADEONEnt->PortInfo[0]->DDCType]); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Port2:\n Monitor -- %s\n Connector -- %s\n DAC Type -- %s\n TMDS Type -- %s\n DDC Type -- %s\n", - MonTypeName[pRADEONEnt->PortInfo[1]->MonType+1], - info->IsAtomBios ? - ConnectorTypeNameATOM[pRADEONEnt->PortInfo[1]->ConnectorType]: - ConnectorTypeName[pRADEONEnt->PortInfo[1]->ConnectorType], - DACTypeName[pRADEONEnt->PortInfo[1]->DACType+1], - TMDSTypeName[pRADEONEnt->PortInfo[1]->TMDSType+1], - DDCTypeName[pRADEONEnt->PortInfo[1]->DDCType]); - - /* no display detected on primary port*/ - if (pRADEONEnt->PortInfo[0]->MonType == MT_NONE) { - if (pRADEONEnt->PortInfo[1]->MonType != MT_NONE) { - /* Only one detected on secondary, let it to be primary */ - if (!head_reversed) - RADEONConnectorReverse(pRADEONEnt); - head_reversed = TRUE; - } else { - /* None detected, Default to a CRT connected */ - pRADEONEnt->PortInfo[0]->MonType = MT_CRT; - } - } - - if ((pRADEONEnt->PortInfo[0]->MonType == MT_LCD) && - (pRADEONEnt->PortInfo[1]->MonType == MT_CRT)) { - if (!(INREG(RADEON_LVDS_GEN_CNTL) & RADEON_LVDS_ON)) { - /* LCD is switched off, don't turn it on, otherwise it may casue lockup due to SS issue. */ - if (!head_reversed) - RADEONConnectorReverse(pRADEONEnt); - head_reversed = TRUE; - pRADEONEnt->PortInfo[0]->MonType = MT_NONE; - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "LCD is switched off, only CRT will be used\n"); - } - } - - if ((pRADEONEnt->PortInfo[0]->MonType != MT_NONE) && - (pRADEONEnt->PortInfo[1]->MonType != MT_NONE)) { - if (xf86ReturnOptValBool(info->Options, OPTION_REVERSE_DISPLAY, FALSE)) { - if (info->IsMobility) { - /* Don't reverse display for mobility chips, as only CRTC1 path has RMX which - will be required by many LCD panels - */ - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Reverse Display cannot be used for mobility chip\n"); - } else { - if (!head_reversed) - RADEONConnectorReverse(pRADEONEnt); - head_reversed = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Primary and Secondary mapping is reversed\n"); - } - } - } - - if (pRADEONEnt->HasSecondary && pRADEONEnt->PortInfo[1]->MonType == MT_NONE) { - pRADEONEnt->HasSecondary = FALSE; - } - } - - if(pRADEONEnt->HasCRTC2) { - if(info->IsSecondary) { - pRADEONEnt->Controller[1]->binding = 2; - info->DisplayType = pRADEONEnt->PortInfo[1]->MonType; - pScrn->monitor->DDC = pRADEONEnt->PortInfo[1]->MonInfo; - } else { - pRADEONEnt->Controller[0]->binding = 1; - info->DisplayType = pRADEONEnt->PortInfo[0]->MonType; - pScrn->monitor->DDC = pRADEONEnt->PortInfo[0]->MonInfo; - } - - if(!pRADEONEnt->HasSecondary) { - info->MergeType = pRADEONEnt->PortInfo[1]->MonType; - if (info->MergeType) - pRADEONEnt->Controller[1]->binding = 1; - } - } else { - if (pRADEONEnt->PortInfo[0]->MonType == MT_NONE) - pRADEONEnt->PortInfo[0]->MonType = MT_CRT; - info->DisplayType = pRADEONEnt->PortInfo[0]->MonType; - pScrn->monitor->DDC = pRADEONEnt->PortInfo[0]->MonInfo; - - pRADEONEnt->PortInfo[1]->MonType = MT_NONE; - pRADEONEnt->Controller[1]->binding = 1; - } - - if (!info->IsSecondary) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "---- Primary Head: Port%d ---- \n", head_reversed?2:1); - if (pRADEONEnt->PortInfo[1]->MonType != MT_NONE) - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "---- Secondary Head: Port%d ----\n", head_reversed?1:2); - else - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "---- Secondary Head: Not used ----\n"); - } - - info->HBlank = 0; - info->HOverPlus = 0; - info->HSyncWidth = 0; - info->VBlank = 0; - info->VOverPlus = 0; - info->VSyncWidth = 0; - info->DotClock = 0; - info->UseBiosDividers = FALSE; - - info->OverlayOnCRTC2 = FALSE; - - return TRUE; } /* @@ -1442,8 +186,7 @@ static void RADEONDacPowerSet(ScrnInfoPtr pScrn, Bool IsOn, Bool IsPrimaryDAC) CARD32 dac_cntl; CARD32 dac_macro_cntl = 0; dac_cntl = INREG(RADEON_DAC_CNTL); - if ((!info->IsMobility) || (info->ChipFamily == CHIP_FAMILY_RV350)) - dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL); + dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL); if (IsOn) { dac_cntl &= ~RADEON_DAC_PDWN; dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | @@ -1456,8 +199,7 @@ static void RADEONDacPowerSet(ScrnInfoPtr pScrn, Bool IsOn, Bool IsPrimaryDAC) RADEON_DAC_PDWN_B); } OUTREG(RADEON_DAC_CNTL, dac_cntl); - if ((!info->IsMobility) || (info->ChipFamily == CHIP_FAMILY_RV350)) - OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); } else { CARD32 tv_dac_cntl; CARD32 fp2_gen_cntl; @@ -1534,6 +276,13 @@ void RADEONDisableDisplays(ScrnInfoPtr pScrn) { } RADEONDacPowerSet(pScrn, FALSE, FALSE); + /* turn off tv-out */ + if (info->InternalTVOut) { + tmp = INREG(RADEON_TV_MASTER_CNTL); + tmp &= ~RADEON_TV_ON; + OUTREG(RADEON_TV_MASTER_CNTL, tmp); + } + /* FP 1 */ tmp = INREG(RADEON_FP_GEN_CNTL); tmp &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); @@ -1565,21 +314,25 @@ void RADEONDisableDisplays(ScrnInfoPtr pScrn) { } /* This is to be used enable/disable displays dynamically */ -void RADEONEnableDisplay(ScrnInfoPtr pScrn, RADEONConnector* pPort, BOOL bEnable) +void RADEONEnableDisplay(xf86OutputPtr output, BOOL bEnable) { + ScrnInfoPtr pScrn = output->scrn; RADEONInfoPtr info = RADEONPTR(pScrn); RADEONSavePtr save = &info->ModeReg; unsigned char * RADEONMMIO = info->MMIO; unsigned long tmp; + RADEONOutputPrivatePtr radeon_output; + radeon_output = output->driver_private; if (bEnable) { - if (pPort->MonType == MT_CRT) { - if (pPort->DACType == DAC_PRIMARY) { + ErrorF("enable montype: %d\n", radeon_output->MonType); + if (radeon_output->MonType == MT_CRT) { + if (radeon_output->DACType == DAC_PRIMARY) { tmp = INREG(RADEON_CRTC_EXT_CNTL); tmp |= RADEON_CRTC_CRT_ON; OUTREG(RADEON_CRTC_EXT_CNTL, tmp); save->crtc_ext_cntl |= RADEON_CRTC_CRT_ON; - } else if (pPort->DACType == DAC_TVDAC) { + } else if (radeon_output->DACType == DAC_TVDAC) { if (info->ChipFamily == CHIP_FAMILY_R200) { tmp = INREG(RADEON_FP2_GEN_CNTL); tmp |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); @@ -1587,41 +340,45 @@ void RADEONEnableDisplay(ScrnInfoPtr pScrn, RADEONConnector* pPort, BOOL bEnable save->fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); } else { tmp = INREG(RADEON_CRTC2_GEN_CNTL); - tmp |= RADEON_CRTC2_CRT2_ON; + tmp |= RADEON_CRTC2_CRT2_ON; OUTREG(RADEON_CRTC2_GEN_CNTL, tmp); save->crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON; } } - RADEONDacPowerSet(pScrn, bEnable, (pPort->DACType == DAC_PRIMARY)); - } else if (pPort->MonType == MT_DFP) { - if (pPort->TMDSType == TMDS_INT) { + RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY)); + } else if (radeon_output->MonType == MT_DFP) { + if (radeon_output->TMDSType == TMDS_INT) { tmp = INREG(RADEON_FP_GEN_CNTL); tmp |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); OUTREG(RADEON_FP_GEN_CNTL, tmp); save->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); - } else if (pPort->TMDSType == TMDS_EXT) { + } else if (radeon_output->TMDSType == TMDS_EXT) { tmp = INREG(RADEON_FP2_GEN_CNTL); tmp |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); OUTREG(RADEON_FP2_GEN_CNTL, tmp); save->fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN); } - } else if (pPort->MonType == MT_LCD) { + } else if (radeon_output->MonType == MT_LCD) { tmp = INREG(RADEON_LVDS_GEN_CNTL); tmp |= (RADEON_LVDS_ON | RADEON_LVDS_BLON); tmp &= ~(RADEON_LVDS_DISPLAY_DIS); - usleep (info->PanelPwrDly * 1000); + usleep (radeon_output->PanelPwrDly * 1000); OUTREG(RADEON_LVDS_GEN_CNTL, tmp); save->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON); save->lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); - } + } else if (radeon_output->MonType == MT_STV || + radeon_output->MonType == MT_CTV) { + RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY)); + } } else { - if (pPort->MonType == MT_CRT || pPort->MonType == NONE) { - if (pPort->DACType == DAC_PRIMARY) { + ErrorF("disable montype: %d\n", radeon_output->MonType); + if (radeon_output->MonType == MT_CRT) { + if (radeon_output->DACType == DAC_PRIMARY) { tmp = INREG(RADEON_CRTC_EXT_CNTL); - tmp &= ~RADEON_CRTC_CRT_ON; + tmp &= ~RADEON_CRTC_CRT_ON; OUTREG(RADEON_CRTC_EXT_CNTL, tmp); save->crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON; - } else if (pPort->DACType == DAC_TVDAC) { + } else if (radeon_output->DACType == DAC_TVDAC) { if (info->ChipFamily == CHIP_FAMILY_R200) { tmp = INREG(RADEON_FP2_GEN_CNTL); tmp &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); @@ -1634,25 +391,20 @@ void RADEONEnableDisplay(ScrnInfoPtr pScrn, RADEONConnector* pPort, BOOL bEnable save->crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON; } } - RADEONDacPowerSet(pScrn, bEnable, (pPort->DACType == DAC_PRIMARY)); - } - - if (pPort->MonType == MT_DFP || pPort->MonType == NONE) { - if (pPort->TMDSType == TMDS_INT) { + RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY)); + } else if (radeon_output->MonType == MT_DFP) { + if (radeon_output->TMDSType == TMDS_INT) { tmp = INREG(RADEON_FP_GEN_CNTL); tmp &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); OUTREG(RADEON_FP_GEN_CNTL, tmp); save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); - } else if (pPort->TMDSType == TMDS_EXT) { + } else if (radeon_output->TMDSType == TMDS_EXT) { tmp = INREG(RADEON_FP2_GEN_CNTL); tmp &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); OUTREG(RADEON_FP2_GEN_CNTL, tmp); save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); } - } - - if (pPort->MonType == MT_LCD || - (pPort->MonType == NONE && pPort->ConnectorType == CONNECTOR_PROPRIETARY)) { + } else if (radeon_output->MonType == MT_LCD) { unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); if (info->IsMobility || info->IsIGP) { /* Asic bug, when turning off LVDS_ON, we have to make sure @@ -1669,13 +421,14 @@ void RADEONEnableDisplay(ScrnInfoPtr pScrn, RADEONConnector* pPort, BOOL bEnable if (info->IsMobility || info->IsIGP) { OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmpPixclksCntl); } - } + } else if (radeon_output->MonType == MT_STV || radeon_output->MonType == MT_CTV) { + RADEONDacPowerSet(pScrn, bEnable, (radeon_output->DACType == DAC_PRIMARY)); + } } } /* Calculate display buffer watermark to prevent buffer underflow */ -void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoPtr info2, - DisplayModePtr mode1, DisplayModePtr mode2) +void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, int pixel_bytes2, DisplayModePtr mode1, DisplayModePtr mode2) { RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; @@ -1713,7 +466,7 @@ void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoP */ if ((info->DispPriority == 2) && IS_R300_VARIANT) { CARD32 mc_init_misc_lat_timer = INREG(R300_MC_INIT_MISC_LAT_TIMER); - if (pRADEONEnt->Controller[1]->IsActive) { + if (pRADEONEnt->pCrtc[1]->enabled) { mc_init_misc_lat_timer |= 0x1100; /* display 0 and 1 */ } else { mc_init_misc_lat_timer |= 0x0100; /* display 0 only */ @@ -1725,11 +478,6 @@ void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoP /* R420 and RV410 family not supported yet */ if (info->ChipFamily == CHIP_FAMILY_R420 || info->ChipFamily == CHIP_FAMILY_RV410) return; - if (pRADEONEnt->pSecondaryScrn) { - if (info->IsSecondary) return; - info2 = RADEONPTR(pRADEONEnt->pSecondaryScrn); - } else if (pRADEONEnt->Controller[1]->binding == 1) info2 = info; - /* * Determine if there is enough bandwidth for current display mode */ @@ -1742,8 +490,8 @@ void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoP pix_clk2 = 0; peak_disp_bw = (pix_clk * info->CurrentLayout.pixel_bytes); - if (info2) - peak_disp_bw += (pix_clk2 * info2->CurrentLayout.pixel_bytes); + if (pixel_bytes2) + peak_disp_bw += (pix_clk2 * pixel_bytes2); if (peak_disp_bw >= mem_bw * min_mem_eff) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, @@ -1883,8 +631,8 @@ void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoP Find the drain rate of the display buffer. */ disp_drain_rate = pix_clk / (16.0/info->CurrentLayout.pixel_bytes); - if (info2) - disp_drain_rate2 = pix_clk2 / (16.0/info2->CurrentLayout.pixel_bytes); + if (pixel_bytes2) + disp_drain_rate2 = pix_clk2 / (16.0/pixel_bytes2); else disp_drain_rate2 = 0; @@ -1939,7 +687,7 @@ void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoP INREG(RADEON_GRPH_BUFFER_CNTL)); if (mode2) { - stop_req = mode2->HDisplay * info2->CurrentLayout.pixel_bytes / 16; + stop_req = mode2->HDisplay * pixel_bytes2 / 16; if (stop_req > max_stop_req) stop_req = max_stop_req; @@ -1993,313 +741,71 @@ void RADEONInitDispBandwidth2(ScrnInfoPtr pScrn, RADEONInfoPtr info, RADEONInfoP void RADEONInitDispBandwidth(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); DisplayModePtr mode1, mode2; - RADEONInfoPtr info2 = NULL; - - if (pRADEONEnt->pSecondaryScrn) { - if (info->IsSecondary) return; - info2 = RADEONPTR(pRADEONEnt->pSecondaryScrn); - } else if (pRADEONEnt->Controller[1]->binding == 1) info2 = info; + int pixel_bytes2 = 0; mode1 = info->CurrentLayout.mode; - if (info->MergedFB) { - mode1 = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT1; - mode2 = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2; - } else if ((pRADEONEnt->HasSecondary) && info2) { - mode2 = info2->CurrentLayout.mode; - } else { - mode2 = NULL; - } - - RADEONInitDispBandwidth2(pScrn, info, info2, mode1, mode2); -} - -static void -RADEONOutputsBlank(ScrnInfoPtr pScrn, RADEONConnector *pPort, Bool Blank) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - CARD32 val; - - switch(pPort->MonType) { - case MT_LCD: - val = (Blank == TRUE) ? RADEON_LVDS_DISPLAY_DIS : 0; - OUTREGP(RADEON_LVDS_GEN_CNTL, val, ~RADEON_LVDS_DISPLAY_DIS); - break; - case MT_CRT: - if ((info->ChipFamily == CHIP_FAMILY_R200) && (pPort->DACType == DAC_TVDAC)) { - val = (Blank == TRUE) ? RADEON_FP2_BLANK_EN : 0; - OUTREGP(RADEON_FP2_GEN_CNTL, val, ~RADEON_FP2_BLANK_EN); - } - break; - case MT_DFP: - if (pPort->TMDSType == TMDS_EXT) { - val = Blank ? RADEON_FP2_BLANK_EN : 0; - OUTREGP(RADEON_FP2_GEN_CNTL, val, ~RADEON_FP2_BLANK_EN); - } else { - val = Blank ? RADEON_FP_BLANK_EN : 0; - OUTREGP(RADEON_FP_GEN_CNTL, val, ~RADEON_FP_BLANK_EN); - } - break; - case MT_NONE: - default: - break; + mode2 = NULL; + pixel_bytes2 = info->CurrentLayout.pixel_bytes; + + if (xf86_config->num_crtc == 2) { + pixel_bytes2 = 0; + mode2 = NULL; + + if (xf86_config->crtc[1]->enabled && xf86_config->crtc[0]->enabled) { + pixel_bytes2 = info->CurrentLayout.pixel_bytes; + mode1 = &xf86_config->crtc[0]->mode; + mode2 = &xf86_config->crtc[1]->mode; + } else if (xf86_config->crtc[0]->enabled) { + mode1 = &xf86_config->crtc[0]->mode; + } else if (xf86_config->crtc[1]->enabled) { + mode1 = &xf86_config->crtc[1]->mode; + } else + return; } -} - -static void -RADEONCRTC1Blank(RADEONInfoPtr info, Bool Blank) -{ - unsigned char *RADEONMMIO = info->MMIO; - CARD32 val = (Blank == TRUE) ? (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS) : 0; - OUTREGP(RADEON_CRTC_EXT_CNTL, val, - ~(RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS)); + RADEONInitDispBandwidth2(pScrn, info, pixel_bytes2, mode1, mode2); } -static void -RADEONCRTC2Blank(RADEONInfoPtr info, Bool Blank) +void RADEONBlank(ScrnInfoPtr pScrn) { - unsigned char *RADEONMMIO = info->MMIO; - CARD32 val = (Blank == TRUE) ? (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) : 0; - OUTREGP(RADEON_CRTC2_GEN_CNTL, val, - ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS)); -} + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + int o, c; -/* Blank screen */ -void RADEONBlank(ScrnInfoPtr pScrn, Bool Blank) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + for (o = 0; o < xf86_config->num_output; o++) { + output = xf86_config->output[o]; + if (output->crtc != crtc) + continue; - if (!pRADEONEnt->HasSecondary || - (pRADEONEnt->HasSecondary && !info->IsSwitching) || - (info->IsSwitching && (!info->IsSecondary))) { - - RADEONOutputsBlank(pScrn, pRADEONEnt->PortInfo[0], Blank); - RADEONCRTC1Blank(info, Blank); - - if (!pRADEONEnt->HasCRTC2) - return; - - if (pRADEONEnt->Controller[1]->binding == 1) { - RADEONOutputsBlank(pScrn, pRADEONEnt->PortInfo[1], Blank); - RADEONCRTC2Blank(info, Blank); + output->funcs->dpms(output, DPMSModeOff); } - } - - if ((pRADEONEnt->HasSecondary && !info->IsSwitching) || - (info->IsSwitching && info->IsSecondary)) { - RADEONOutputsBlank(pScrn, pRADEONEnt->PortInfo[1], Blank); - RADEONCRTC2Blank(info, Blank); + crtc->funcs->dpms(crtc, DPMSModeOff); } } - -static void -RADEONOutputsDPMS(ScrnInfoPtr pScrn, RADEONConnector *pPort, int Mode) +void RADEONUnblank(ScrnInfoPtr pScrn) { - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output; + xf86CrtcPtr crtc; + int o, c; - RADEONMonitorType MonType; - RADEONTmdsType TmdsType; - RADEONDacType DacType; - - MonType = pPort->MonType; - TmdsType = pPort->TMDSType; - DacType = pPort->DACType; - - switch (MonType) { - case MT_LCD: - if (Mode == DPMSModeOn) { - OUTREGP(RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON); - usleep (info->PanelPwrDly * 1000); - OUTREGP(RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON); - } else { - unsigned int tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); - - /* Asic bug, when turning off LVDS_ON, we have to make sure - RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off */ - if (info->IsMobility || info->IsIGP) - OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); - OUTREGP(RADEON_LVDS_GEN_CNTL, 0, ~(RADEON_LVDS_BLON | RADEON_LVDS_ON)); - if (info->IsMobility || info->IsIGP) - OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmpPixclksCntl); - } - break; - case MT_DFP: - if (Mode == DPMSModeOn) { - if (TmdsType == TMDS_EXT) { - OUTREGP(RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_BLANK_EN); - OUTREGP(RADEON_FP2_GEN_CNTL, RADEON_FP2_ON, ~RADEON_FP2_ON); - if (info->ChipFamily >= CHIP_FAMILY_R200) - OUTREGP(RADEON_FP2_GEN_CNTL, RADEON_FP2_DVO_EN, ~RADEON_FP2_DVO_EN); - } else - OUTREGP(RADEON_FP_GEN_CNTL, (RADEON_FP_FPON | RADEON_FP_TMDS_EN), - ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); - } else { - if (TmdsType == TMDS_EXT) { - OUTREGP(RADEON_FP2_GEN_CNTL, RADEON_FP2_BLANK_EN, ~RADEON_FP2_BLANK_EN); - OUTREGP(RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_ON); - if (info->ChipFamily >= CHIP_FAMILY_R200) { - OUTREGP(RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DVO_EN); - } - } else - OUTREGP(RADEON_FP_GEN_CNTL, 0, ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); - } - break; - case MT_CRT: - default: - RADEONDacPowerSet(pScrn, (Mode == DPMSModeOn), (DacType == DAC_PRIMARY)); - break; - } -} - -void -RADEONCRTC1DPMS(RADEONInfoPtr info, int Mode) -{ - unsigned char *RADEONMMIO = info->MMIO; - CARD32 val; - switch (Mode) { - case DPMSModeOn: - /* Screen: On; HSync: On, VSync: On */ - val = 0; - break; - case DPMSModeStandby: - /* Screen: Off; HSync: Off, VSync: On */ - val = (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS); - break; - case DPMSModeSuspend: - /* Screen: Off; HSync: On, VSync: Off */ - val = (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS); - break; - case DPMSModeOff: - default: - /* Screen: Off; HSync: Off, VSync: Off */ - val = (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_VSYNC_DIS); - break; - } - OUTREGP(RADEON_CRTC_EXT_CNTL, val, - ~(RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_VSYNC_DIS)); - -} + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + if(!crtc->enabled) + continue; + crtc->funcs->dpms(crtc, DPMSModeOn); + for (o = 0; o < xf86_config->num_output; o++) { + output = xf86_config->output[o]; + if (output->crtc != crtc) + continue; -void -RADEONCRTC2DPMS(RADEONInfoPtr info, int Mode) -{ - unsigned char *RADEONMMIO = info->MMIO; - CARD32 val; - switch (Mode) { - case DPMSModeOn: - /* Screen: On; HSync: On, VSync: On */ - val = 0; - break; - case DPMSModeStandby: - /* Screen: Off; HSync: Off, VSync: On */ - val = (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS); - break; - case DPMSModeSuspend: - /* Screen: Off; HSync: On, VSync: Off */ - val = (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS); - break; - case DPMSModeOff: - default: - /* Screen: Off; HSync: Off, VSync: Off */ - val = (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS); - break; - - } - OUTREGP(RADEON_CRTC2_GEN_CNTL, val, - ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS)); -} - - -/* Sets VESA Display Power Management Signaling (DPMS) Mode */ -void -RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - - if (!pScrn->vtSema) - return; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "RADEONDisplayPowerManagementSet(%d,0x%x)\n", - PowerManagementMode, flags); - -#ifdef XF86DRI - if (info->CPStarted) - DRILock(pScrn->pScreen, 0); -#endif - - if (info->accelOn) - RADEON_SYNC(info, pScrn); - - if (info->FBDev) { - fbdevHWDPMSSet(pScrn, PowerManagementMode, flags); - } else { - if (info->IsSecondary) { - RADEONCRTC2DPMS(info, PowerManagementMode); - RADEONOutputsDPMS(pScrn, pRADEONEnt->PortInfo[1], PowerManagementMode); - } else { - RADEONCRTC1DPMS(info, PowerManagementMode); - RADEONOutputsDPMS(pScrn, pRADEONEnt->PortInfo[0], PowerManagementMode); - - if (pRADEONEnt->Controller[1]->binding == 1) { - RADEONCRTC2DPMS(info, PowerManagementMode); - RADEONOutputsDPMS(pScrn, pRADEONEnt->PortInfo[1], PowerManagementMode); - } + output->funcs->dpms(output, DPMSModeOn); } } - -#ifdef XF86DRI - if (info->CPStarted) - DRIUnlock(pScrn->pScreen); -#endif -} - -Bool RADEONAllocateControllers(ScrnInfoPtr pScrn) -{ - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - - if (pRADEONEnt->Controller[0]) - return TRUE; - - pRADEONEnt->Controller[0] = xcalloc(sizeof(RADEONController), 1); - if (!pRADEONEnt->Controller[0]) - return FALSE; - - pRADEONEnt->Controller[1] = xcalloc(sizeof(RADEONController), 1); - if (!pRADEONEnt->Controller[1]) - { - xfree(pRADEONEnt->Controller[0]); - return FALSE; - } - - return TRUE; -} - -Bool RADEONAllocateConnectors(ScrnInfoPtr pScrn) -{ - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - - if (pRADEONEnt->PortInfo[0]) - return TRUE; - - /* for now always allocate both connectors */ - pRADEONEnt->PortInfo[0] = xcalloc(sizeof(RADEONConnector), 1); - if (!pRADEONEnt->PortInfo[0]) - return FALSE; - - pRADEONEnt->PortInfo[1] = xcalloc(sizeof(RADEONConnector), 1); - if (!pRADEONEnt->PortInfo[1]) { - xfree(pRADEONEnt->PortInfo[0]); - return FALSE; - } - - return TRUE; } - diff --git a/src/radeon_dri.c b/src/radeon_dri.c index 315b204..7949c5b 100644 --- a/src/radeon_dri.c +++ b/src/radeon_dri.c @@ -1351,12 +1351,16 @@ Bool RADEONDRIGetVersion(ScrnInfoPtr pScrn) Bool RADEONDRISetVBlankInterrupt(ScrnInfoPtr pScrn, Bool on) { RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); int value = 0; if (info->directRenderingEnabled && info->pKernelDRMVersion->version_minor >= 28) { - /* we could do something with mergedfb here I'm sure */ - if (on) + if (on) { + if (xf86_config->num_crtc > 1 && xf86_config->crtc[1]->enabled) + value = DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2; + else value = DRM_RADEON_VBLANK_CRTC1; + } if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_VBLANK_CRTC, value)) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RADEON Vblank Crtc Setup Failed %d\n", value); diff --git a/src/radeon_driver.c b/src/radeon_driver.c index 74323c9..f338d16 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -74,7 +74,6 @@ #include "radeon_macros.h" #include "radeon_probe.h" #include "radeon_version.h" -#include "radeon_mergedfb.h" #ifdef XF86DRI #define _XF86DRI_SERVER_ @@ -94,6 +93,7 @@ #include "xf86_ansic.h" /* For xf86getsecs() */ #include "xf86_OSproc.h" #include "xf86RAC.h" +#include "xf86RandR12.h" #include "xf86Resources.h" #include "xf86cmap.h" #include "vbe.h" @@ -116,10 +116,7 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen); static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode); static void RADEONSave(ScrnInfoPtr pScrn); -static void RADEONRestore(ScrnInfoPtr pScrn); -static Bool RADEONModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode); -static void RADEONGetMergedFBOptions(ScrnInfoPtr pScrn); static void RADEONSetDynamicClock(ScrnInfoPtr pScrn, int mode); static void RADEONForceSomeClocks(ScrnInfoPtr pScrn); static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); @@ -128,9 +125,11 @@ static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save); #endif -/* psuedo xinerama support */ +DisplayModePtr +RADEONCrtcFindClosestMode(xf86CrtcPtr crtc, DisplayModePtr pMode); -extern Bool RADEONnoPanoramiXExtension; +static void RADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests, + unsigned nWaitLoops, unsigned cntThreshold); static const OptionInfoRec RADEONOptions[] = { { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, @@ -159,19 +158,8 @@ static const OptionInfoRec RADEONOptions[] = { #endif #endif { OPTION_DDC_MODE, "DDCMode", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_MONITOR_LAYOUT, "MonitorLayout", OPTV_ANYSTR, {0}, FALSE }, { OPTION_IGNORE_EDID, "IgnoreEDID", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_MERGEDFB, "MergedFB", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_CRT2HSYNC, "CRT2HSync", OPTV_ANYSTR, {0}, FALSE }, - { OPTION_CRT2VREFRESH, "CRT2VRefresh", OPTV_ANYSTR, {0}, FALSE }, - { OPTION_CRT2POS, "CRT2Position", OPTV_ANYSTR, {0}, FALSE }, - { OPTION_METAMODES, "MetaModes", OPTV_ANYSTR, {0}, FALSE }, - { OPTION_MERGEDDPI, "MergedDPI", OPTV_ANYSTR, {0}, FALSE }, - { OPTION_RADEONXINERAMA, "MergedXinerama", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_CRT2ISSCRN0, "MergedXineramaCRT2IsScreen0", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_MERGEDFBNONRECT, "MergedNonRectangular", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_MERGEDFBMOUSER, "MergedMouseRestriction", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DISP_PRIORITY, "DisplayPriority", OPTV_ANYSTR, {0}, FALSE }, { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE }, { OPTION_MIN_DOTCLOCK, "ForceMinDotClock", OPTV_FREQ, {0}, FALSE }, @@ -198,8 +186,8 @@ static const OptionInfoRec RADEONOptions[] = { { OPTION_LVDS_PROBE_PLL, "LVDSProbePLL", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE }, { OPTION_CONSTANTDPI, "ConstantDPI", OPTV_BOOLEAN, {0}, FALSE }, - { OPTION_REVERSE_DISPLAY,"ReverseDisplay", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_CONNECTORTABLE, "ConnectorTable", OPTV_STRING, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -441,6 +429,24 @@ struct RADEONInt10Save { static Bool RADEONMapMMIO(ScrnInfoPtr pScrn); static Bool RADEONUnmapMMIO(ScrnInfoPtr pScrn); +#if 0 +static Bool +RADEONCreateScreenResources (ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + RADEONInfoPtr info = RADEONPTR(pScrn); + + pScreen->CreateScreenResources = info->CreateScreenResources; + if (!(*pScreen->CreateScreenResources)(pScreen)) + return FALSE; + + if (!xf86RandR12CreateScreenResources(pScreen)) + return FALSE; + + return TRUE; +} +#endif + RADEONEntPtr RADEONEntPriv(ScrnInfoPtr pScrn) { DevUnion *pPriv; @@ -534,48 +540,6 @@ static Bool RADEONGetRec(ScrnInfoPtr pScrn) /* Free our private RADEONInfoRec */ static void RADEONFreeRec(ScrnInfoPtr pScrn) { - RADEONInfoPtr info = RADEONPTR(pScrn); - if(info->CRT2HSync) xfree(info->CRT2HSync); - info->CRT2HSync = NULL; - if(info->CRT2VRefresh) xfree(info->CRT2VRefresh); - info->CRT2VRefresh = NULL; - if(info->MetaModes) xfree(info->MetaModes); - info->MetaModes = NULL; - if(info->CRT2pScrn) { - if(info->CRT2pScrn->modes) { - while(info->CRT2pScrn->modes) - xf86DeleteMode(&info->CRT2pScrn->modes, info->CRT2pScrn->modes); - } - if(info->CRT2pScrn->monitor) { - if(info->CRT2pScrn->monitor->Modes) { - while(info->CRT2pScrn->monitor->Modes) - xf86DeleteMode(&info->CRT2pScrn->monitor->Modes, info->CRT2pScrn->monitor->Modes); - } - if(info->CRT2pScrn->monitor->DDC) xfree(info->CRT2pScrn->monitor->DDC); - xfree(info->CRT2pScrn->monitor); - } - xfree(info->CRT2pScrn); - info->CRT2pScrn = NULL; - } - if(info->CRT1Modes) { - if(info->CRT1Modes != pScrn->modes) { - if(pScrn->modes) { - pScrn->currentMode = pScrn->modes; - do { - DisplayModePtr p = pScrn->currentMode->next; - if(pScrn->currentMode->Private) - xfree(pScrn->currentMode->Private); - xfree(pScrn->currentMode); - pScrn->currentMode = p; - } while(pScrn->currentMode != pScrn->modes); - } - pScrn->currentMode = info->CRT1CurrentMode; - pScrn->modes = info->CRT1Modes; - info->CRT1CurrentMode = NULL; - info->CRT1Modes = NULL; - } - } - if (!pScrn || !pScrn->driverPrivate) return; xfree(pScrn->driverPrivate); pScrn->driverPrivate = NULL; @@ -1203,7 +1167,7 @@ static Bool RADEONPreInitWeight(ScrnInfoPtr pScrn) return TRUE; } -static void RADEONInitMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, +void RADEONInitMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, RADEONInfoPtr info) { save->mc_fb_location = info->mc_fb_location; @@ -1466,24 +1430,6 @@ static Bool RADEONPreInitVRAM(ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, from, "Mapped VideoRAM: %d kByte (%d bit %s SDRAM)\n", pScrn->videoRam, info->RamWidth, info->IsDDR?"DDR":"SDR"); - /* FIXME: For now, split FB into two equal sections. This should - * be able to be adjusted by user with a config option. */ - if (info->IsPrimary) { - pScrn->videoRam /= 2; - info->MergedFB = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Using %dk of videoram for primary head\n", - pScrn->videoRam); - } - - if (info->IsSecondary) { - pScrn->videoRam /= 2; - info->LinearAddr += pScrn->videoRam * 1024; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Using %dk of videoram for secondary head\n", - pScrn->videoRam); - } - pScrn->videoRam &= ~1023; info->FbMapSize = pScrn->videoRam * 1024; @@ -1550,6 +1496,7 @@ static Bool RADEONPreInitChipType(ScrnInfoPtr pScrn) info->IsIGP = FALSE; info->IsDellServer = FALSE; info->HasSingleDAC = FALSE; + info->InternalTVOut = TRUE; switch (info->Chipset) { case PCI_CHIP_RADEON_LY: case PCI_CHIP_RADEON_LZ: @@ -1609,6 +1556,7 @@ static Bool RADEONPreInitChipType(ScrnInfoPtr pScrn) case PCI_CHIP_R200_QL: case PCI_CHIP_R200_QM: info->ChipFamily = CHIP_FAMILY_R200; + info->InternalTVOut = FALSE; break; case PCI_CHIP_RADEON_LW: @@ -1791,6 +1739,7 @@ static Bool RADEONPreInitChipType(ScrnInfoPtr pScrn) /* Original Radeon/7200 */ info->ChipFamily = CHIP_FAMILY_RADEON; pRADEONEnt->HasCRTC2 = FALSE; + info->InternalTVOut = FALSE; } @@ -1969,9 +1918,7 @@ static void RADEONPreInitDDC(ScrnInfoPtr pScrn) if (info->ddc2) { if (xf86LoadSubModule(pScrn, "i2c")) { xf86LoaderReqSymLists(i2cSymbols,NULL); - info->ddc2 = RADEONI2cInit(pScrn); } - else info->ddc2 = FALSE; } } @@ -1984,405 +1931,6 @@ static Bool RADEONPreInitGamma(ScrnInfoPtr pScrn) return TRUE; } -/* This is called by RADEONPreInit to validate modes and compute - * parameters for all of the valid modes. - */ -static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - ClockRangePtr clockRanges; - int modesFound; - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - char *s; - RADEONConnector *connector; - /* This option has two purposes: - * - * 1. For CRT, if this option is on, xf86ValidateModes (to - * LOOKUP_BEST_REFRESH) is not going to be used for mode - * validation. Instead, we'll validate modes by matching exactly - * the modes supported from the DDC data. This option can be - * used (a) to enable non-standard modes listed in the Detailed - * Timings block of EDID, like 2048x1536 (not included in - * xf86DefModes), (b) to avoid unstable modes for some flat - * panels working in analog mode (some modes validated by - * xf86ValidateModes don't really work with these panels). - * - * 2. For DFP on primary head, with this option on, the validation - * routine will try to use supported modes from DDC data first - * before trying on-chip RMX streching. By default, native mode - * + RMX streching is used for all non-native modes, it appears - * more reliable. Some non-native modes listed in the DDC data - * may not work properly if they are used directly. This seems to - * only happen to a few panels (haven't nailed this down yet, it - * may related to the incorrect setting in TMDS_PLL_CNTL when - * pixel clock is changed). Use this option may give you better - * refresh rate for some non-native modes. The 2nd DVI port will - * always use DDC modes directly (only have one on-chip RMX - * unit). - * - * Note: This option will be dismissed if no DDC data is available. - */ - - if (info->MergedFB) { - if (!(pScrn->display->virtualX)) - info->NoVirtual = TRUE; - else - info->NoVirtual = FALSE; - } - - info->ddc_mode = - xf86ReturnOptValBool(info->Options, OPTION_DDC_MODE, FALSE); - - /* don't use RMX if we have a dual-tmds panels */ - if (pRADEONEnt->PortInfo[1]->MonType == MT_DFP) - info->ddc_mode = TRUE; - /* don't use RMX if we are Dell Server */ - if (info->IsDellServer) - info->ddc_mode = TRUE; - /* IBM Lewis server have troubles using the on-chip RMX mode */ - if (info->ChipFamily == CHIP_FAMILY_RV100 && !pRADEONEnt->HasCRTC2 && pRADEONEnt->PortInfo[0]->MonInfo) { - struct vendor *ven = &pRADEONEnt->PortInfo[0]->MonInfo->vendor; - if (ven && ven->prod_id == 0x029a && ven->serial == 0x01010101) - info->ddc_mode = TRUE; - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Validating modes on %s head ---------\n", - info->IsSecondary ? "Secondary" : "Primary"); - - if (!pRADEONEnt->PortInfo[0]->MonInfo && !pRADEONEnt->PortInfo[1]->MonInfo && info->ddc_mode) { - info->ddc_mode = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No DDC data available, DDCMode option is dismissed\n"); - } - - if ((info->DisplayType == MT_DFP) || - (info->DisplayType == MT_LCD)) { - if ((s = xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) { - int PanelX, PanelY; - DisplayModePtr tmp_mode = NULL; - if (sscanf(s, "%dx%d", &PanelX, &PanelY) == 2) { - info->PanelXRes = PanelX; - info->PanelYRes = PanelY; - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, - "Panel size is forced to: %s\n", s); - - /* We can't trust BIOS or DDC timings anymore, - Use whatever specified in the Modeline. - If no Modeline specified, we'll just pick the VESA mode at - 60Hz refresh rate which is likely to be the best for a flat panel. - */ - info->ddc_mode = FALSE; - pScrn->monitor->DDC = NULL; - tmp_mode = pScrn->monitor->Modes; - while(tmp_mode) { - if ((tmp_mode->HDisplay == PanelX) && - (tmp_mode->VDisplay == PanelY)) { - - float refresh = - (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal; - if ((abs(60.0 - refresh) < 1.0) || - (tmp_mode->type == 0)) { - info->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay; - info->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay; - info->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart; - info->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay; - info->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay; - info->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart; - info->DotClock = tmp_mode->Clock; - info->Flags = 0; - break; - } - } - tmp_mode = tmp_mode->next; - } - if (info->DotClock == 0) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No valid timing info for specified panel size.\n" - "Please specify the Modeline for this panel\n"); - return FALSE; - } - } else { - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, - "Invalid PanelSize value: %s\n", s); - } - } else - RADEONGetPanelInfo(pScrn); - } - - if (pScrn->monitor->DDC) { - /* If we still don't know sync range yet, let's try EDID. - * - * Note that, since we can have dual heads, Xconfigurator - * may not be able to probe both monitors correctly through - * vbe probe function (RADEONProbeDDC). Here we provide an - * additional way to auto-detect sync ranges if they haven't - * been added to XF86Config manually. - */ - if (pScrn->monitor->nHsync <= 0) - RADEONSetSyncRangeFromEdid(pScrn, 1); - if (pScrn->monitor->nVrefresh <= 0) - RADEONSetSyncRangeFromEdid(pScrn, 0); - } - - /* Get mode information */ - pScrn->progClock = TRUE; - clockRanges = xnfcalloc(sizeof(*clockRanges), 1); - clockRanges->next = NULL; - clockRanges->minClock = info->pll.min_pll_freq; - clockRanges->maxClock = info->pll.max_pll_freq * 10; - clockRanges->clockIndex = -1; - clockRanges->interlaceAllowed = (info->DisplayType == MT_CRT); - clockRanges->doubleScanAllowed = (info->DisplayType == MT_CRT); - - /* We'll use our own mode validation routine for DFP/LCD, since - * xf86ValidateModes does not work correctly with the DFP/LCD modes - * 'stretched' from their native mode. - */ - if (info->DisplayType == MT_CRT && !info->ddc_mode) { - xf86SetDDCproperties(pScrn, pScrn->monitor->DDC); - modesFound = - xf86ValidateModes(pScrn, - pScrn->monitor->Modes, - pScrn->display->modes, - clockRanges, - NULL, /* linePitches */ - 8 * 64, /* minPitch */ - 8 * 1024, /* maxPitch */ - info->allowColorTiling ? 2048 : - 64 * pScrn->bitsPerPixel, /* pitchInc */ - 128, /* minHeight */ - info->MaxLines, /* maxHeight */ - pScrn->display->virtualX, - pScrn->display->virtualY, - info->FbMapSize, - LOOKUP_BEST_REFRESH); - - if (modesFound < 1 && info->FBDev) { - fbdevHWUseBuildinMode(pScrn); - pScrn->displayWidth = fbdevHWGetLineLength(pScrn) - / info->CurrentLayout.pixel_bytes; - modesFound = 1; - } - - if (modesFound == -1) return FALSE; - - xf86PruneDriverModes(pScrn); - if (!modesFound || !pScrn->modes) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); - return FALSE; - } - - } else { - /* First, free any allocated modes during configuration, since - * we don't need them - */ - while (pScrn->modes) - xf86DeleteMode(&pScrn->modes, pScrn->modes); - while (pScrn->modePool) - xf86DeleteMode(&pScrn->modePool, pScrn->modePool); - - /* Next try to add DDC modes */ - modesFound = RADEONValidateDDCModes(pScrn, pScrn->display->modes, - info->DisplayType, 0); - - /* If that fails and we're connect to a flat panel, then try to - * add the flat panel modes - */ - if (info->DisplayType != MT_CRT) { - - /* some panels have DDC, but don't have internal scaler. - * in this case, we need to validate additional modes - * by using on-chip RMX. - */ - int user_modes_asked = 0, user_modes_found = 0, i; - DisplayModePtr tmp_mode = pScrn->modes; - while (pScrn->display->modes[user_modes_asked]) user_modes_asked++; - if (tmp_mode) { - for (i = 0; i < modesFound; i++) { - if (tmp_mode->type & M_T_USERDEF) user_modes_found++; - tmp_mode = tmp_mode->next; - } - } - - if ((modesFound <= 1) || (user_modes_found < user_modes_asked)) { - /* when panel size is not valid, try to validate - * mode using xf86ValidateModes routine - * This can happen when DDC is disabled. - */ - if (info->PanelXRes < 320 || info->PanelYRes < 200) - modesFound = - xf86ValidateModes(pScrn, - pScrn->monitor->Modes, - pScrn->display->modes, - clockRanges, - NULL, /* linePitches */ - 8 * 64, /* minPitch */ - 8 * 1024, /* maxPitch */ - info->allowColorTiling ? 2048 : - 64 * pScrn->bitsPerPixel, /* pitchInc */ - 128, /* minHeight */ - info->MaxLines, /* maxHeight */ - pScrn->display->virtualX, - pScrn->display->virtualY, - info->FbMapSize, - LOOKUP_BEST_REFRESH); - else if (!info->IsSecondary && !info->ddc_mode) - modesFound = RADEONValidateFPModes(pScrn, pScrn->display->modes); - } - } - - /* Setup the screen's clockRanges for the VidMode extension */ - if (!pScrn->clockRanges) { - pScrn->clockRanges = xnfcalloc(sizeof(*(pScrn->clockRanges)), 1); - memcpy(pScrn->clockRanges, clockRanges, sizeof(*clockRanges)); - pScrn->clockRanges->strategy = LOOKUP_BEST_REFRESH; - } - - /* Fail if we still don't have any valid modes */ - if (modesFound < 1) { - if (info->DisplayType == MT_CRT) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No valid DDC modes found for this CRT\n"); - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Try turning off the \"DDCMode\" option\n"); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No valid mode found for this DFP/LCD\n"); - } - return FALSE; - } - } - - xf86SetCrtcForModes(pScrn, 0); - - if (pRADEONEnt->HasCRTC2) { - if (pRADEONEnt->Controller[1]->binding == 1) { - - /* If we have 2 screens from the config file, we don't need - * to do clone thing, let each screen handles one head. - */ - if (info->MergedFB) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Validating CRTC2 modes for MergedFB ------------ \n"); - - modesFound = RADEONValidateMergeModes(pScrn); - if (modesFound < 1) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No valid mode found for CRTC2, disabling MergedFB\n"); - info->MergedFB = FALSE; - } - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Total of %d CRTC2 modes found for MergedFB------------ \n", - modesFound); - } - } - } - - pScrn->currentMode = pScrn->modes; - if(info->MergedFB) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Modes for CRT1: ********************\n"); - } - xf86PrintModes(pScrn); - - - if (pRADEONEnt->HasCRTC2) { - if(pRADEONEnt->Controller[1]->binding == 1 && info->MergedFB) { - - xf86SetCrtcForModes(info->CRT2pScrn, INTERLACE_HALVE_V); - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Modes for CRT2: ********************\n"); - - xf86PrintModes(info->CRT2pScrn); - - info->CRT1Modes = pScrn->modes; - info->CRT1CurrentMode = pScrn->currentMode; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Generating MergedFB mode list\n"); - - if (info->NoVirtual) { - pScrn->display->virtualX = 0; - pScrn->display->virtualY = 0; - } - pScrn->modes = RADEONGenerateModeList(pScrn, info->MetaModes, - info->CRT1Modes, info->CRT2pScrn->modes, - info->CRT2Position); - - if(!pScrn->modes) { - - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to parse MetaModes or no modes found. MergeFB mode disabled.\n"); - if(info->CRT2pScrn) { - if(info->CRT2pScrn->modes) { - while(info->CRT2pScrn->modes) - xf86DeleteMode(&info->CRT2pScrn->modes, info->CRT2pScrn->modes); - } - if(info->CRT2pScrn->monitor) { - if(info->CRT2pScrn->monitor->Modes) { - while(info->CRT2pScrn->monitor->Modes) - xf86DeleteMode(&info->CRT2pScrn->monitor->Modes, info->CRT2pScrn->monitor->Modes); - } - if(info->CRT2pScrn->monitor->DDC) xfree(info->CRT2pScrn->monitor->DDC); - xfree(info->CRT2pScrn->monitor); - } - xfree(info->CRT2pScrn); - info->CRT2pScrn = NULL; - } - pScrn->modes = info->CRT1Modes; - info->CRT1Modes = NULL; - info->MergedFB = FALSE; - - } - } - else - info->MergedFB = FALSE; - } - else - info->MergedFB = FALSE; - - if (info->MergedFB) { - /* If no virtual dimension was given by the user, - * calculate a sane one now. Adapts pScrn->virtualX, - * pScrn->virtualY and pScrn->displayWidth. - */ - RADEONRecalcDefaultVirtualSize(pScrn); - info->CRT2pScrn->virtualX = pScrn->virtualX; - info->CRT2pScrn->virtualY = pScrn->virtualY; - RADEONSetPitch(pScrn); - RADEONSetPitch(info->CRT2pScrn); - - pScrn->modes = pScrn->modes->next; /* We get the last from GenerateModeList() */ - pScrn->currentMode = pScrn->modes; - - /* Update CurrentLayout */ - info->CurrentLayout.mode = pScrn->currentMode; - info->CurrentLayout.displayWidth = pScrn->displayWidth; - } - - /* Set DPI */ - /* xf86SetDpi(pScrn, 0, 0); */ - - if (info->MergedFB) { - RADEONMergedFBSetDpi(pScrn, info->CRT2pScrn, info->CRT2Position); - } else { - xf86SetDpi(pScrn, 0, 0); - info->RADEONDPIVX = pScrn->virtualX; - info->RADEONDPIVY = pScrn->virtualY; - } - - /* Get ScreenInit function */ - if (!xf86LoadSubModule(pScrn, "fb")) return FALSE; - - xf86LoaderReqSymLists(fbSymbols, NULL); - - info->CurrentLayout.displayWidth = pScrn->displayWidth; - info->CurrentLayout.mode = pScrn->currentMode; - - return TRUE; -} - /* This is called by RADEONPreInit to initialize the hardware cursor */ static Bool RADEONPreInitCursor(ScrnInfoPtr pScrn) { @@ -2519,18 +2067,6 @@ static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn) info->pLibDRMVersion = NULL; info->pKernelDRMVersion = NULL; - if (xf86IsEntityShared(info->pEnt->index)) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Direct Rendering Disabled -- " - "Dual-head configuration is not working with " - "DRI at present.\n" - "Please use the radeon MergedFB option if you " - "want Dual-head with DRI.\n"); - return FALSE; - } - if (info->IsSecondary) - return FALSE; - if (info->Chipset == PCI_CHIP_RN50_515E || info->Chipset == PCI_CHIP_RN50_5969) { if (xf86ReturnOptValBool(info->Options, OPTION_DRI, FALSE)) { @@ -2727,6 +2263,7 @@ static void RADEONPreInitColorTiling(ScrnInfoPtr pScrn) info->allowColorTiling = xf86ReturnOptValBool(info->Options, OPTION_COLOR_TILING, TRUE); if (IS_R300_VARIANT) { + /* this may be 4096 on r4xx -- need to double check */ info->MaxSurfaceWidth = 3968; /* one would have thought 4096...*/ info->MaxLines = 4096; } else { @@ -2753,14 +2290,7 @@ static void RADEONPreInitColorTiling(ScrnInfoPtr pScrn) } #endif /* XF86DRI */ - if ((info->allowColorTiling) && (info->IsSecondary)) { - /* can't have tiling on the 2nd head (as long as it can't use drm). - * We'd never get the surface save/restore (vt switching) right... - */ - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Color tiling disabled for 2nd head\n"); - info->allowColorTiling = FALSE; - } - else if ((info->allowColorTiling) && (info->FBDev)) { + if ((info->allowColorTiling) && (info->FBDev)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Color tiling not supported with UseFBDev option\n"); info->allowColorTiling = FALSE; @@ -2960,30 +2490,39 @@ static Bool RADEONPreInitXv(ScrnInfoPtr pScrn) return TRUE; } -static Bool RADEONPreInitControllers(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) +static void RADEONPreInitBIOS(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) { - RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONGetBIOSInfo(pScrn, pInt10); +#if 0 + RADEONGetBIOSInitTableOffsets(pScrn); + RADEONPostCardFromBIOSTables(pScrn); +#endif +} - if (!info->IsSecondary) { - if (!RADEONAllocateConnectors(pScrn)) - return FALSE; +static Bool RADEONPreInitControllers(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; - if (!RADEONAllocateControllers(pScrn)) + if (!RADEONAllocateControllers(pScrn)) return FALSE; - - } - RADEONGetBIOSInfo(pScrn, pInt10); + RADEONGetClockInfo(pScrn); - if (!info->IsSecondary) { - RADEONSetupConnectors(pScrn); + if (!RADEONSetupConnectors(pScrn)) { + return FALSE; } - RADEONMapControllers(pScrn); + + RADEONPrintPortMap(pScrn); - RADEONGetClockInfo(pScrn); - RADEONGetPanelInfo(pScrn); - RADEONGetTVDacAdjInfo(pScrn); - + for (i = 0; i < config->num_output; i++) + { + xf86OutputPtr output = config->output[i]; + + output->status = (*output->funcs->detect) (output); + ErrorF("finished output detect: %d\n", i); + } + ErrorF("finished all detect\n"); return TRUE; } @@ -2998,13 +2537,28 @@ RADEONProbeDDC(ScrnInfoPtr pScrn, int indx) } } -Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) +static Bool +RADEONCRTCResize(ScrnInfoPtr scrn, int width, int height) +{ + scrn->virtualX = width; + scrn->virtualY = height; + /* RADEONSetPitch(scrn); */ + return TRUE; +} + +static const xf86CrtcConfigFuncsRec RADEONCRTCResizeFuncs = { + RADEONCRTCResize +}; + +_X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) { + xf86CrtcConfigPtr xf86_config; RADEONInfoPtr info; xf86Int10InfoPtr pInt10 = NULL; void *int10_save = NULL; const char *s; MessageType from; + int crtc_max_X, crtc_max_Y; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONPreInit\n"); @@ -3013,10 +2567,6 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (!RADEONGetRec(pScrn)) return FALSE; info = RADEONPTR(pScrn); - info->IsSecondary = FALSE; - info->IsPrimary = FALSE; - info->MergedFB = FALSE; - info->IsSwitching = FALSE; info->MMIO = NULL; info->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); @@ -3060,30 +2610,6 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) RADEONPreInt10Save(pScrn, &int10_save); #endif - if (xf86IsEntityShared(info->pEnt->index)) { - if (xf86IsPrimInitDone(info->pEnt->index)) { - - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - - info->IsSecondary = TRUE; - if (!pRADEONEnt->HasSecondary) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Only one monitor detected, Second screen " - "will NOT be created\n"); - goto fail2; - } - pRADEONEnt->pSecondaryScrn = pScrn; - } else { - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - - info->IsPrimary = TRUE; - - xf86SetPrimInitDone(info->pEnt->index); - - pRADEONEnt->pPrimaryScrn = pScrn; - } - } - if (flags & PROBE_DETECT) { RADEONProbeDDC(pScrn, info->pEnt->index); RADEONPostInt10Check(pScrn, int10_save); @@ -3107,6 +2633,11 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; pScrn->monitor = pScrn->confScreen->monitor; + /* Allocate an xf86CrtcConfig */ + xf86CrtcConfigInit (pScrn, &RADEONCRTCResizeFuncs); + xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + + if (!RADEONPreInitVisual(pScrn)) goto fail; @@ -3211,33 +2742,69 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (!RADEONPreInitChipType(pScrn)) goto fail; + RADEONPreInitBIOS(pScrn, pInt10); + #ifdef XF86DRI /* PreInit DRI first of all since we need that for getting a proper * memory map */ info->directRenderingEnabled = RADEONPreInitDRI(pScrn); #endif - if (!RADEONPreInitVRAM(pScrn)) goto fail; RADEONPreInitColorTiling(pScrn); + /* we really need an FB manager... */ + if (pScrn->display->virtualX) { + crtc_max_X = pScrn->display->virtualX; + crtc_max_Y = pScrn->display->virtualY; + if (info->allowColorTiling) { + if (crtc_max_X > info->MaxSurfaceWidth) + crtc_max_X = info->MaxSurfaceWidth; + if (crtc_max_Y > info->MaxLines) + crtc_max_Y = info->MaxLines; + } else { + if (crtc_max_X > 8192) + crtc_max_X = 8192; + if (crtc_max_Y > 8192) + crtc_max_Y = 8192; + } + } else { + crtc_max_X = 1600; + crtc_max_Y = 1200; + } + + /*xf86CrtcSetSizeRange (pScrn, 320, 200, info->MaxSurfaceWidth, info->MaxLines);*/ + xf86CrtcSetSizeRange (pScrn, 320, 200, crtc_max_X, crtc_max_Y); + RADEONPreInitDDC(pScrn); - if (!RADEONPreInitControllers(pScrn, pInt10)) + if (!RADEONPreInitControllers(pScrn)) goto fail; - /* collect MergedFB options */ - /* only parse mergedfb options on the primary head. - Mergedfb is already disabled in xinerama/screen based - multihead */ - if (!info->IsSecondary) - RADEONGetMergedFBOptions(pScrn); - if (!RADEONPreInitGamma(pScrn)) goto fail; + ErrorF("before xf86InitialConfiguration\n"); + + if (!xf86InitialConfiguration (pScrn, FALSE)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n"); + goto fail; + } + + ErrorF("after xf86InitialConfiguration\n"); + + RADEONSetPitch(pScrn); + + /* Set display resolution */ + xf86SetDpi(pScrn, 0, 0); - if (!RADEONPreInitModes(pScrn, pInt10)) goto fail; + /* Get ScreenInit function */ + if (!xf86LoadSubModule(pScrn, "fb")) return FALSE; + + xf86LoaderReqSymLists(fbSymbols, NULL); + + if (!RADEONPreInitGamma(pScrn)) goto fail; if (!RADEONPreInitCursor(pScrn)) goto fail; @@ -3245,6 +2812,17 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (!RADEONPreInitXv(pScrn)) goto fail; + if (!xf86RandR12PreInit (pScrn)) + { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n"); + goto fail; + } + + if (pScrn->modes == NULL) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n"); + goto fail; + } + /* Free the video bios (if applicable) */ if (info->VBIOS) { xfree(info->VBIOS); @@ -3266,10 +2844,6 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) fail: /* Pre-init failed. */ - if (info->IsSecondary) { - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - pRADEONEnt->HasSecondary = FALSE; - } /* Free the video bios (if applicable) */ if (info->VBIOS) { xfree(info->VBIOS); @@ -3285,7 +2859,6 @@ fail: vgaHWFreeHWRec(pScrn); #endif - fail2: if(info->MMIO) RADEONUnmapMMIO(pScrn); info->MMIO = NULL; @@ -3300,10 +2873,11 @@ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, VisualPtr pVisual) { RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); int i; - int idx, j; - unsigned char r, g, b; + int index, j; + CARD16 lut_r[256], lut_g[256], lut_b[256]; + int c; #ifdef XF86DRI if (info->CPStarted && pScrn->pScreen) DRILock(pScrn->pScreen, 0); @@ -3315,109 +2889,59 @@ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, if (info->FBDev) { fbdevHWLoadPalette(pScrn, numColors, indices, colors, pVisual); } else { - /* If the second monitor is connected, we also need to deal with - * the secondary palette - */ - if (info->IsSecondary) j = 1; - else j = 0; - - PAL_SELECT(j); - - if (info->CurrentLayout.depth == 15) { - /* 15bpp mode. This sends 32 values. */ - for (i = 0; i < numColors; i++) { - idx = indices[i]; - r = colors[idx].red; - g = colors[idx].green; - b = colors[idx].blue; - OUTPAL(idx * 8, r, g, b); - } - } else if (info->CurrentLayout.depth == 16) { - /* 16bpp mode. This sends 64 values. - * - * There are twice as many green values as there are values - * for red and blue. So, we take each red and blue pair, - * and combine it with each of the two green values. - */ - for (i = 0; i < numColors; i++) { - idx = indices[i]; - r = colors[idx / 2].red; - g = colors[idx].green; - b = colors[idx / 2].blue; - RADEONWaitForFifo(pScrn, 32); /* delay */ - OUTPAL(idx * 4, r, g, b); - - /* AH - Added to write extra green data - How come this isn't - * needed on R128? We didn't load the extra green data in the - * other routine - */ - if (idx <= 31) { - r = colors[idx].red; - g = colors[(idx * 2) + 1].green; - b = colors[idx].blue; - RADEONWaitForFifo(pScrn, 32); /* delay */ - OUTPAL(idx * 8, r, g, b); - } - } - } else { - /* 8bpp mode. This sends 256 values. */ - for (i = 0; i < numColors; i++) { - idx = indices[i]; - r = colors[idx].red; - b = colors[idx].blue; - g = colors[idx].green; - RADEONWaitForFifo(pScrn, 32); /* delay */ - OUTPAL(idx, r, g, b); - } - } - if (info->MergedFB) { - PAL_SELECT(1); - if (info->CurrentLayout.depth == 15) { - /* 15bpp mode. This sends 32 values. */ - for (i = 0; i < numColors; i++) { - idx = indices[i]; - r = colors[idx].red; - g = colors[idx].green; - b = colors[idx].blue; - OUTPAL(idx * 8, r, g, b); - } - } else if (info->CurrentLayout.depth == 16) { - /* 16bpp mode. This sends 64 values. - * - * There are twice as many green values as there are values - * for red and blue. So, we take each red and blue pair, - * and combine it with each of the two green values. - */ - for (i = 0; i < numColors; i++) { - idx = indices[i]; - r = colors[idx / 2].red; - g = colors[idx].green; - b = colors[idx / 2].blue; - OUTPAL(idx * 4, r, g, b); - - /* AH - Added to write extra green data - How come - * this isn't needed on R128? We didn't load the - * extra green data in the other routine. - */ - if (idx <= 31) { - r = colors[idx].red; - g = colors[(idx * 2) + 1].green; - b = colors[idx].blue; - OUTPAL(idx * 8, r, g, b); - } - } - } else { - /* 8bpp mode. This sends 256 values. */ - for (i = 0; i < numColors; i++) { - idx = indices[i]; - r = colors[idx].red; - b = colors[idx].blue; - g = colors[idx].green; - OUTPAL(idx, r, g, b); - } - } - } + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr crtc = xf86_config->crtc[c]; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + + for (i = 0 ; i < 256; i++) { + lut_r[i] = radeon_crtc->lut_r[i] << 8; + lut_g[i] = radeon_crtc->lut_g[i] << 8; + lut_b[i] = radeon_crtc->lut_b[i] << 8; + } + + switch (info->CurrentLayout.depth) { + case 15: + for (i = 0; i < numColors; i++) { + index = indices[i]; + for (j = 0; j < 8; j++) { + lut_r[index * 8 + j] = colors[index].red << 8; + lut_g[index * 8 + j] = colors[index].green << 8; + lut_b[index * 8 + j] = colors[index].blue << 8; + } + } + case 16: + for (i = 0; i < numColors; i++) { + index = indices[i]; + + if (i <= 31) { + for (j = 0; j < 8; j++) { + lut_r[index * 8 + j] = colors[index].red << 8; + lut_b[index * 8 + j] = colors[index].blue << 8; + } + } + + for (j = 0; j < 4; j++) { + lut_g[index * 4 + j] = colors[index].green << 8; + } + } + default: + for (i = 0; i < numColors; i++) { + index = indices[i]; + lut_r[index] = colors[index].red << 8; + lut_g[index] = colors[index].green << 8; + lut_b[index] = colors[index].blue << 8; + } + break; + } + + /* Make the change through RandR */ +#ifdef RANDR_12_INTERFACE + RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b); +#else + crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256); +#endif + } } #ifdef XF86DRI @@ -3786,12 +3310,40 @@ Bool RADEONSetupMemXAA(int scrnIndex, ScreenPtr pScreen) } #endif /* USE_XAA */ +static void +RADEONPointerMoved(int index, int x, int y) +{ + ScrnInfoPtr pScrn = xf86Screens[index]; + RADEONInfoPtr info = RADEONPTR(pScrn); + int newX = x, newY = y; + + switch (info->rotation) { + case RR_Rotate_0: + break; + case RR_Rotate_90: + newX = y; + newY = pScrn->pScreen->width - x - 1; + break; + case RR_Rotate_180: + newX = pScrn->pScreen->width - x - 1; + newY = pScrn->pScreen->height - y - 1; + break; + case RR_Rotate_270: + newX = pScrn->pScreen->height - y - 1; + newY = x; + break; + } + + (*info->PointerMoved)(index, newX, newY); +} + /* Called at the start of each server generation. */ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); int hasDRI = 0; #ifdef RENDER int subPixelOrder = SubPixelUnknown; @@ -3815,7 +3367,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, #ifdef XF86DRI pScrn->fbOffset = info->frontOffset; #endif - if (info->IsSecondary) pScrn->fbOffset = pScrn->videoRam * 1024; + if (!RADEONMapMem(pScrn)) return FALSE; #ifdef XF86DRI @@ -3825,9 +3377,14 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, info->PaletteSavedOnVT = FALSE; + info->crtc_on = FALSE; + info->crtc2_on = FALSE; + RADEONSave(pScrn); - if ((!info->IsSecondary) && info->IsMobility) { + RADEONDisableDisplays(pScrn); + + if (info->IsMobility) { if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) { RADEONSetDynamicClock(pScrn, 1); } else { @@ -3835,8 +3392,8 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, } } - if ((!info->IsSecondary) && (IS_R300_VARIANT || IS_RV100_VARIANT)) - RADEONForceSomeClocks(pScrn); + if (IS_R300_VARIANT || IS_RV100_VARIANT) + RADEONForceSomeClocks(pScrn); if (info->allowColorTiling && (pScrn->virtualX > info->MaxSurfaceWidth)) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -3845,17 +3402,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, info->allowColorTiling = FALSE; } if (info->allowColorTiling) { - if (info->MergedFB) { - if ((((RADEONMergedDisplayModePtr)pScrn->currentMode->Private)->CRT1->Flags & - (V_DBLSCAN | V_INTERLACE)) || - (((RADEONMergedDisplayModePtr)pScrn->currentMode->Private)->CRT2->Flags & - (V_DBLSCAN | V_INTERLACE))) - info->tilingEnabled = FALSE; - else info->tilingEnabled = TRUE; - } - else { - info->tilingEnabled = (pScrn->currentMode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; - } + info->tilingEnabled = (pScrn->currentMode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; } /* Visual setup */ @@ -3896,15 +3443,13 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, */ RADEONInitMemoryMap(pScrn); - if (!info->IsSecondary) { - /* empty the surfaces */ - unsigned char *RADEONMMIO = info->MMIO; - unsigned int i; - for (i = 0; i < 8; i++) { - OUTREG(RADEON_SURFACE0_INFO + 16 * i, 0); - OUTREG(RADEON_SURFACE0_LOWER_BOUND + 16 * i, 0); - OUTREG(RADEON_SURFACE0_UPPER_BOUND + 16 * i, 0); - } + /* empty the surfaces */ + unsigned char *RADEONMMIO = info->MMIO; + unsigned int i; + for (i = 0; i < 8; i++) { + OUTREG(RADEON_SURFACE0_INFO + 16 * i, 0); + OUTREG(RADEON_SURFACE0_LOWER_BOUND + 16 * i, 0); + OUTREG(RADEON_SURFACE0_UPPER_BOUND + 16 * i, 0); } #ifdef XF86DRI @@ -3924,11 +3469,9 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, #endif /* Initial setup of surfaces */ - if (!info->IsSecondary) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Setting up initial surfaces\n"); - RADEONChangeSurfaces(pScrn); - } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Setting up initial surfaces\n"); + RADEONChangeSurfaces(pScrn); /* Memory manager setup */ @@ -4076,18 +3619,9 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, else if (strcmp(s, "NONE") == 0) subPixelOrder = SubPixelNone; PictureSetSubpixelOrder (pScreen, subPixelOrder); } - - if (PictureGetSubpixelOrder (pScreen) == SubPixelUnknown) { - switch (info->DisplayType) { - case MT_NONE: subPixelOrder = SubPixelUnknown; break; - case MT_LCD: subPixelOrder = SubPixelHorizontalRGB; break; - case MT_DFP: subPixelOrder = SubPixelHorizontalRGB; break; - default: subPixelOrder = SubPixelNone; break; - } - PictureSetSubpixelOrder (pScreen, subPixelOrder); - } #endif + pScrn->vtSema = TRUE; if (info->FBDev) { unsigned char *RADEONMMIO = info->MMIO; @@ -4099,12 +3633,29 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, info->ModeReg.surface_cntl = INREG(RADEON_SURFACE_CNTL); info->ModeReg.surface_cntl &= ~RADEON_SURF_TRANSLATION_DIS; } else { - if (!RADEONModeInit(pScrn, pScrn->currentMode)) return FALSE; + int i; + for (i = 0; i < xf86_config->num_crtc; i++) + { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + + /* Mark that we'll need to re-set the mode for sure */ + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desiredMode.CrtcHDisplay) { + crtc->desiredMode = *RADEONCrtcFindClosestMode (crtc, pScrn->currentMode); + crtc->desiredRotation = RR_Rotate_0; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + + if (!xf86CrtcSetMode (crtc, &crtc->desiredMode, crtc->desiredRotation, crtc->desiredX, crtc->desiredY)) + return FALSE; + + } } RADEONSaveScreen(pScreen, SCREEN_SAVER_ON); - pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + // pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); /* Backing store setup */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, @@ -4158,15 +3709,10 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, #endif /* Make sure surfaces are allright since DRI setup may have changed them */ - if (!info->IsSecondary) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Setting up final surfaces\n"); - RADEONChangeSurfaces(pScrn); - } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Setting up final surfaces\n"); - if(info->MergedFB) - /* need this here to fix up sarea values */ - RADEONAdjustFrameMerged(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + RADEONChangeSurfaces(pScrn); /* Enable aceleration */ if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { @@ -4189,7 +3735,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, /* Init DPMS */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing DPMS\n"); - xf86DPMSInit(pScreen, RADEONDisplayPowerManagementSet, 0); + xf86DPMSInit(pScreen, xf86DPMSSet, 0); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing Cursor\n"); @@ -4229,45 +3775,16 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, xf86DrvMsg(scrnIndex, X_INFO, "Using software cursor\n"); } - /* Colormap setup */ - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "Initializing color map\n"); - if (!miCreateDefColormap(pScreen)) return FALSE; - if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8, - RADEONLoadPalette, NULL, - CMAP_PALETTED_TRUECOLOR -#if 0 /* This option messes up text mode! (eich@suse.de) */ - | CMAP_LOAD_EVEN_IF_OFFSCREEN -#endif - | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; - /* DGA setup */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing DGA\n"); RADEONDGAInit(pScreen); - /* Wrap some funcs for MergedFB */ - if(info->MergedFB) { - info->PointerMoved = pScrn->PointerMoved; - pScrn->PointerMoved = RADEONMergePointerMoved; - /* Psuedo xinerama */ - if(info->UseRADEONXinerama) { - RADEONnoPanoramiXExtension = FALSE; - RADEONXineramaExtensionInit(pScrn); - } else { - info->MouseRestrictions = FALSE; - } - } - /* Init Xv */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Initializing Xv\n"); RADEONInitVideo(pScreen); - if(info->MergedFB) - /* need this here to fix up sarea values */ - RADEONAdjustFrameMerged(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); - /* Provide SaveScreen & wrap BlockHandler and CloseScreen */ /* Wrap CloseScreen */ info->CloseScreen = pScreen->CloseScreen; @@ -4276,6 +3793,25 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, info->BlockHandler = pScreen->BlockHandler; pScreen->BlockHandler = RADEONBlockHandler; + if (!xf86CrtcScreenInit (pScreen)) + return FALSE; + + /* Wrap pointer motion to flip touch screen around */ + info->PointerMoved = pScrn->PointerMoved; + pScrn->PointerMoved = RADEONPointerMoved; + + /* Colormap setup */ + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Initializing color map\n"); + if (!miCreateDefColormap(pScreen)) return FALSE; + if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8, + RADEONLoadPalette, NULL, + CMAP_PALETTED_TRUECOLOR +#if 0 /* This option messes up text mode! (eich@suse.de) */ + | CMAP_LOAD_EVEN_IF_OFFSCREEN +#endif + | CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE; + /* Note unused options */ if (serverGeneration == 1) xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); @@ -4287,7 +3823,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, } /* Write memory mapping registers */ -static void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn, +void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); @@ -4500,7 +4036,7 @@ static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) #endif /* Write common registers */ -static void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, +void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); @@ -4525,17 +4061,13 @@ static void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn, * CRT are connected. */ if (pRADEONEnt->HasCRTC2 && - !info->IsSwitching && info->ChipFamily != CHIP_FAMILY_R200 && !IS_R300_VARIANT) { CARD32 tmp; - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - if (pRADEONEnt->HasSecondary || info->MergedFB) { - tmp = INREG(RADEON_DAC_CNTL2); - OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL); - usleep(100000); - } + tmp = INREG(RADEON_DAC_CNTL2); + OUTREG(RADEON_DAC_CNTL2, tmp & ~RADEON_DAC2_DAC_CLK_SEL); + usleep(100000); } } @@ -4565,8 +4097,44 @@ static void RADEONRestoreFBDevRegisters(ScrnInfoPtr pScrn, #endif } +void RADEONRestoreDACRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (IS_R300_VARIANT) + OUTREGP(RADEON_GPIOPAD_A, restore->gpiopad_a, ~1); + + OUTREGP(RADEON_DAC_CNTL, + restore->dac_cntl, + RADEON_DAC_RANGE_CNTL | + RADEON_DAC_BLANKING); + + OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); + + if ((info->ChipFamily != CHIP_FAMILY_RADEON) && + (info->ChipFamily != CHIP_FAMILY_R200)) + OUTREG (RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); + + OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl); + + if ((info->ChipFamily == CHIP_FAMILY_R200) || + IS_R300_VARIANT) { + OUTREG(RADEON_DISP_TV_OUT_CNTL, restore->disp_tv_out_cntl); + } else { + OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); + } + + OUTREG(RADEON_DAC_MACRO_CNTL, restore->dac_macro_cntl); + + /* R200 DAC connected via DVO */ + if (info->ChipFamily == CHIP_FAMILY_R200) + OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); +} + /* Write CRTC registers */ -static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, +void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); @@ -4588,11 +4156,6 @@ static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS); - OUTREGP(RADEON_DAC_CNTL, - restore->dac_cntl, - RADEON_DAC_RANGE_CNTL | - RADEON_DAC_BLANKING); - OUTREG(RADEON_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); OUTREG(RADEON_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); OUTREG(RADEON_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); @@ -4603,8 +4166,11 @@ static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, OUTREG(RADEON_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp); OUTREG(RADEON_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp); - OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset); + if (IS_R300_VARIANT) + OUTREG(R300_CRTC_TILE_X0_Y0, restore->crtc_tile_x0_y0); OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); + OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset); + OUTREG(RADEON_CRTC_PITCH, restore->crtc_pitch); OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl); OUTREG(RADEON_CRTC_MORE_CNTL, restore->crtc_more_cntl); @@ -4620,43 +4186,24 @@ static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, } /* Write CRTC2 registers */ -static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, +void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - CARD32 crtc2_gen_cntl; + /* CARD32 crtc2_gen_cntl;*/ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Programming CRTC2, offset: 0x%08lx\n", restore->crtc2_offset); - crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL) & - (RADEON_CRTC2_VSYNC_DIS | - RADEON_CRTC2_HSYNC_DIS | - RADEON_CRTC2_DISP_DIS); - crtc2_gen_cntl |= restore->crtc2_gen_cntl; - /* We prevent the CRTC from hitting the memory controller until * fully programmed */ OUTREG(RADEON_CRTC2_GEN_CNTL, - crtc2_gen_cntl | RADEON_CRTC2_DISP_REQ_EN_B); - - OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); - - //OUTREG(RADEON_TV_DAC_CNTL, 0x00280203); - if ((info->ChipFamily != CHIP_FAMILY_RADEON) && - (info->ChipFamily != CHIP_FAMILY_R200)) - OUTREG (RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); - - if ((info->ChipFamily == CHIP_FAMILY_R200) || - IS_R300_VARIANT) { - OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl); - OUTREG(RADEON_DISP_TV_OUT_CNTL, restore->disp_tv_out_cntl); - } else { - OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug); - } + restore->crtc2_gen_cntl | RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | + RADEON_CRTC2_DISP_REQ_EN_B); OUTREG(RADEON_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp); OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid); @@ -4666,8 +4213,11 @@ static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp_h2_sync_strt_wid); OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp_v2_sync_strt_wid); - OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset); + if (IS_R300_VARIANT) + OUTREG(R300_CRTC2_TILE_X0_Y0, restore->crtc2_tile_x0_y0); OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl); + OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset); + OUTREG(RADEON_CRTC2_PITCH, restore->crtc2_pitch); OUTREG(RADEON_DISP2_MERGE_CNTL, restore->disp2_merge_cntl); @@ -4677,12 +4227,12 @@ static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, OUTREG(RADEON_RS480_UNK_e38, restore->rs480_unk_e38); OUTREG(RADEON_RS480_UNK_e3c, restore->rs480_unk_e3c); } - OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); } -/* Write flat panel registers */ -static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +/* Write TMDS registers */ +void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); @@ -4690,8 +4240,6 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) OUTREG(RADEON_TMDS_PLL_CNTL, restore->tmds_pll_cntl); OUTREG(RADEON_TMDS_TRANSMITTER_CNTL,restore->tmds_transmitter_cntl); - OUTREG(RADEON_FP_HORZ_STRETCH, restore->fp_horz_stretch); - OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch); OUTREG(RADEON_FP_GEN_CNTL, restore->fp_gen_cntl); /* old AIW Radeon has some BIOS initialization problem @@ -4701,7 +4249,40 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) OUTREG(RADEON_GRPH_BUFFER_CNTL, INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); +} + +/* Write FP2 registers */ +void RADEONRestoreFP2Registers(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); + +} + +/* Write RMX registers */ +void RADEONRestoreRMXRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_FP_HORZ_STRETCH, restore->fp_horz_stretch); + OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch); + +} + +/* Write LVDS registers */ +void RADEONRestoreLVDSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + if (info->IsMobility) { + OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl); + /*OUTREG(RADEON_LVDS_PLL_CNTL, restore->lvds_pll_cntl);*/ OUTREG(RADEON_BIOS_4_SCRATCH, restore->bios_4_scratch); OUTREG(RADEON_BIOS_5_SCRATCH, restore->bios_5_scratch); OUTREG(RADEON_BIOS_6_SCRATCH, restore->bios_6_scratch); @@ -4709,6 +4290,276 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) } +/* Write to TV FIFO RAM */ +static void RADEONWriteTVFIFO(ScrnInfoPtr pScrn, CARD16 addr, + CARD32 value) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 tmp; + int i = 0; + + OUTREG(RADEON_TV_HOST_WRITE_DATA, value); + + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_WT); + + do { + tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); + if ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0) + break; + i++; + } + while (i < 10000); + /*while ((tmp & RADEON_HOST_FIFO_WT_ACK) == 0);*/ + + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); +} + +/* Read from TV FIFO RAM */ +static CARD32 RADEONReadTVFIFO(ScrnInfoPtr pScrn, CARD16 addr) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 tmp; + int i = 0; + + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr); + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, addr | RADEON_HOST_FIFO_RD); + + do { + tmp = INREG(RADEON_TV_HOST_RD_WT_CNTL); + if ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0) + break; + i++; + } + while (i < 10000); + /*while ((tmp & RADEON_HOST_FIFO_RD_ACK) == 0);*/ + + OUTREG(RADEON_TV_HOST_RD_WT_CNTL, 0); + + return INREG(RADEON_TV_HOST_READ_DATA); +} + +/* Get FIFO addresses of horizontal & vertical code timing tables from + * settings of uv_adr register. + */ +static CARD16 RADEONGetHTimingTablesAddr(CARD32 tv_uv_adr) +{ + CARD16 hTable; + + switch ((tv_uv_adr & RADEON_HCODE_TABLE_SEL_MASK) >> RADEON_HCODE_TABLE_SEL_SHIFT) { + case 0: + hTable = RADEON_TV_MAX_FIFO_ADDR_INTERNAL; + break; + case 1: + hTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2; + break; + case 2: + hTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2; + break; + default: + /* Of course, this should never happen */ + hTable = 0; + break; + } + return hTable; +} + +static CARD16 RADEONGetVTimingTablesAddr(CARD32 tv_uv_adr) +{ + CARD16 vTable; + + switch ((tv_uv_adr & RADEON_VCODE_TABLE_SEL_MASK) >> RADEON_VCODE_TABLE_SEL_SHIFT) { + case 0: + vTable = ((tv_uv_adr & RADEON_MAX_UV_ADR_MASK) >> RADEON_MAX_UV_ADR_SHIFT) * 2 + 1; + break; + case 1: + vTable = ((tv_uv_adr & RADEON_TABLE1_BOT_ADR_MASK) >> RADEON_TABLE1_BOT_ADR_SHIFT) * 2 + 1; + break; + case 2: + vTable = ((tv_uv_adr & RADEON_TABLE3_TOP_ADR_MASK) >> RADEON_TABLE3_TOP_ADR_SHIFT) * 2 + 1; + break; + default: + /* Of course, this should never happen */ + vTable = 0; + break; + } + return vTable; +} + +/* Restore horizontal/vertical timing code tables */ +static void RADEONRestoreTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD16 hTable; + CARD16 vTable; + CARD32 tmp; + unsigned i; + + OUTREG(RADEON_TV_UV_ADR, restore->tv_uv_adr); + hTable = RADEONGetHTimingTablesAddr(restore->tv_uv_adr); + vTable = RADEONGetVTimingTablesAddr(restore->tv_uv_adr); + + OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | RADEON_RESTART_PHASE_FIX + | RADEON_CRT_FIFO_CE_EN + | RADEON_TV_FIFO_CE_EN + | RADEON_TV_ON)); + + /*OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl | RADEON_TV_ON);*/ + + for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2, hTable--) { + tmp = ((CARD32)restore->h_code_timing[ i ] << 14) | ((CARD32)restore->h_code_timing[ i + 1 ]); + RADEONWriteTVFIFO(pScrn, hTable, tmp); + if (restore->h_code_timing[ i ] == 0 || restore->h_code_timing[ i + 1 ] == 0) + break; + } + + for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2, vTable++) { + tmp = ((CARD32)restore->v_code_timing[ i + 1 ] << 14) | ((CARD32)restore->v_code_timing[ i ]); + RADEONWriteTVFIFO(pScrn, vTable, tmp); + if (restore->v_code_timing[ i ] == 0 || restore->v_code_timing[ i + 1 ] == 0) + break; + } +} + +/* restore TV PLLs */ +static void RADEONRestoreTVPLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVCLK_SRC_SEL_TVPLL); + OUTPLL(pScrn, RADEON_TV_PLL_CNTL, restore->tv_pll_cntl); + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVPLL_RESET, ~RADEON_TVPLL_RESET); + + RADEONWaitPLLLock(pScrn, 200, 800, 135); + + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_RESET); + + RADEONWaitPLLLock(pScrn, 300, 160, 27); + RADEONWaitPLLLock(pScrn, 200, 800, 135); + + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~0xf); + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, RADEON_TVCLK_SRC_SEL_TVPLL, ~RADEON_TVCLK_SRC_SEL_TVPLL); + + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, (1 << RADEON_TVPDC_SHIFT), ~RADEON_TVPDC_MASK); + OUTPLLP(pScrn, RADEON_TV_PLL_CNTL1, 0, ~RADEON_TVPLL_SLEEP); +} + +/* Restore TV horizontal/vertical settings */ +static void RADEONRestoreTVHVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_TV_RGB_CNTL, restore->tv_rgb_cntl); + + OUTREG(RADEON_TV_HTOTAL, restore->tv_htotal); + OUTREG(RADEON_TV_HDISP, restore->tv_hdisp); + OUTREG(RADEON_TV_HSTART, restore->tv_hstart); + + OUTREG(RADEON_TV_VTOTAL, restore->tv_vtotal); + OUTREG(RADEON_TV_VDISP, restore->tv_vdisp); + + OUTREG(RADEON_TV_FTOTAL, restore->tv_ftotal); + + OUTREG(RADEON_TV_VSCALER_CNTL1, restore->tv_vscaler_cntl1); + OUTREG(RADEON_TV_VSCALER_CNTL2, restore->tv_vscaler_cntl2); + + OUTREG(RADEON_TV_Y_FALL_CNTL, restore->tv_y_fall_cntl); + OUTREG(RADEON_TV_Y_RISE_CNTL, restore->tv_y_rise_cntl); + OUTREG(RADEON_TV_Y_SAW_TOOTH_CNTL, restore->tv_y_saw_tooth_cntl); +} + +/* restore TV RESTART registers */ +static void RADEONRestoreTVRestarts(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_TV_FRESTART, restore->tv_frestart); + OUTREG(RADEON_TV_HRESTART, restore->tv_hrestart); + OUTREG(RADEON_TV_VRESTART, restore->tv_vrestart); +} + +/* restore tv standard & output muxes */ +static void RADEONRestoreTVOutputStd(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + OUTREG(RADEON_TV_SYNC_CNTL, restore->tv_sync_cntl); + + OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); + + OUTREG(RADEON_TV_MODULATOR_CNTL1, restore->tv_modulator_cntl1); + OUTREG(RADEON_TV_MODULATOR_CNTL2, restore->tv_modulator_cntl2); + + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, restore->tv_pre_dac_mux_cntl); + + OUTREG(RADEON_TV_CRC_CNTL, restore->tv_crc_cntl); +} + +/* Restore TV out regs */ +void RADEONRestoreTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + ErrorF("Entering Restore TV\n"); + + OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl | RADEON_TV_ON); + + OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl + | RADEON_TV_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | RADEON_RESTART_PHASE_FIX + | RADEON_TV_FIFO_ASYNC_RST)); + + /* Temporarily turn the TV DAC off */ + OUTREG(RADEON_TV_DAC_CNTL, ((restore->tv_dac_cntl & ~RADEON_TV_DAC_NBLANK) + | RADEON_TV_DAC_BGSLEEP + | RADEON_TV_DAC_RDACPD + | RADEON_TV_DAC_GDACPD + | RADEON_TV_DAC_BDACPD)); + + ErrorF("Restore TV PLL\n"); + RADEONRestoreTVPLLRegisters(pScrn, restore); + + ErrorF("Restore TVHV\n"); + RADEONRestoreTVHVRegisters(pScrn, restore); + + OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl + | RADEON_TV_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | RADEON_RESTART_PHASE_FIX)); + + ErrorF("Restore TV Restarts\n"); + RADEONRestoreTVRestarts(pScrn, restore); + + ErrorF("Restore Timing Tables\n"); + RADEONRestoreTVTimingTables(pScrn, restore); + + + OUTREG(RADEON_TV_MASTER_CNTL, (restore->tv_master_cntl + | RADEON_TV_ASYNC_RST + | RADEON_RESTART_PHASE_FIX)); + + ErrorF("Restore TV standard\n"); + RADEONRestoreTVOutputStd(pScrn, restore); + + OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); + + OUTREG(RADEON_TV_GAIN_LIMIT_SETTINGS, restore->tv_gain_limit_settings); + OUTREG(RADEON_TV_LINEAR_GAIN_SETTINGS, restore->tv_linear_gain_settings); + + OUTREG(RADEON_TV_DAC_CNTL, restore->tv_dac_cntl); + + ErrorF("Leaving Restore TV\n"); +} + static void RADEONPLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn) { int i = 0; @@ -4755,12 +4606,81 @@ static void RADEONPLL2WriteUpdate(ScrnInfoPtr pScrn) ~(RADEON_P2PLL_ATOMIC_UPDATE_W)); } +static CARD8 RADEONComputePLLGain(CARD16 reference_freq, CARD16 ref_div, + CARD16 fb_div) +{ + unsigned vcoFreq; + + if (!ref_div) + return 1; + + vcoFreq = ((unsigned)reference_freq * fb_div) / ref_div; + + /* + * This is horribly crude: the VCO frequency range is divided into + * 3 parts, each part having a fixed PLL gain value. + */ + if (vcoFreq >= 30000) + /* + * [300..max] MHz : 7 + */ + return 7; + else if (vcoFreq >= 18000) + /* + * [180..300) MHz : 4 + */ + return 4; + else + /* + * [0..180) MHz : 1 + */ + return 1; +} + +/* Wait for PLLs to lock */ +static void RADEONWaitPLLLock(ScrnInfoPtr pScrn, unsigned nTests, + unsigned nWaitLoops, unsigned cntThreshold) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 savePLLTest; + unsigned i; + unsigned j; + + OUTREG(RADEON_TEST_DEBUG_MUX, (INREG(RADEON_TEST_DEBUG_MUX) & 0xffff60ff) | 0x100); + + savePLLTest = INPLL(pScrn, RADEON_PLL_TEST_CNTL); + + OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest & ~RADEON_PLL_MASK_READ_B); + + /* XXX: these should probably be OUTPLL to avoid various PLL errata */ + + OUTREG8(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_TEST_CNTL); + + for (i = 0; i < nTests; i++) { + OUTREG8(RADEON_CLOCK_CNTL_DATA + 3, 0); + + for (j = 0; j < nWaitLoops; j++) + if (INREG8(RADEON_CLOCK_CNTL_DATA + 3) >= cntThreshold) + break; + } + + OUTPLL(pScrn, RADEON_PLL_TEST_CNTL, savePLLTest); + + OUTREG(RADEON_TEST_DEBUG_MUX, INREG(RADEON_TEST_DEBUG_MUX) & 0xffffe0ff); +} + /* Write PLL registers */ -static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, - RADEONSavePtr restore) +void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, + RADEONSavePtr restore) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; + CARD8 pllGain; + + pllGain = RADEONComputePLLGain(info->pll.reference_freq, + restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK, + restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK); if (info->IsMobility) { /* A temporal workaround for the occational blanking on certain laptop panels. @@ -4788,10 +4708,12 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, RADEON_PPLL_CNTL, RADEON_PPLL_RESET | RADEON_PPLL_ATOMIC_UPDATE_EN - | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN, + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | ((CARD32)pllGain << RADEON_PPLL_PVG_SHIFT), ~(RADEON_PPLL_RESET | RADEON_PPLL_ATOMIC_UPDATE_EN - | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); + | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN + | RADEON_PPLL_PVG_MASK)); OUTREGP(RADEON_CLOCK_CNTL_INDEX, RADEON_PLL_DIV_SEL, @@ -4854,16 +4776,28 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, usleep(50000); /* Let the clock to lock */ - OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, + /* OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, RADEON_VCLK_SRC_SEL_PPLLCLK, - ~(RADEON_VCLK_SRC_SEL_MASK)); + ~(RADEON_VCLK_SRC_SEL_MASK));*/ + OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, restore->vclk_ecp_cntl); + + ErrorF("finished PLL1\n"); + } /* Write PLL2 registers */ -static void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, - RADEONSavePtr restore) +void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, + RADEONSavePtr restore) { + RADEONInfoPtr info = RADEONPTR(pScrn); + CARD8 pllGain; + + pllGain = RADEONComputePLLGain(info->pll.reference_freq, + restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, + restore->p2pll_div_0 & RADEON_P2PLL_FB0_DIV_MASK); + + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, RADEON_PIX2CLK_SRC_SEL_CPUCLK, ~(RADEON_PIX2CLK_SRC_SEL_MASK)); @@ -4871,9 +4805,11 @@ static void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, OUTPLLP(pScrn, RADEON_P2PLL_CNTL, RADEON_P2PLL_RESET - | RADEON_P2PLL_ATOMIC_UPDATE_EN, + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | ((CARD32)pllGain << RADEON_P2PLL_PVG_SHIFT), ~(RADEON_P2PLL_RESET - | RADEON_P2PLL_ATOMIC_UPDATE_EN)); + | RADEON_P2PLL_ATOMIC_UPDATE_EN + | RADEON_P2PLL_PVG_MASK)); OUTPLLP(pScrn, RADEON_P2PLL_REF_DIV, @@ -4913,9 +4849,13 @@ static void RADEONRestorePLL2Registers(ScrnInfoPtr pScrn, usleep(5000); /* Let the clock to lock */ - OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, + /*OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, RADEON_PIX2CLK_SRC_SEL_P2PLLCLK, - ~(RADEON_PIX2CLK_SRC_SEL_MASK)); + ~(RADEON_PIX2CLK_SRC_SEL_MASK));*/ + OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, restore->pixclks_cntl); + + ErrorF("finished PLL2\n"); + } @@ -5082,143 +5022,24 @@ void RADEONChangeSurfaces(ScrnInfoPtr pScrn) unsigned int surf_info = swap_pattern; unsigned char *RADEONMMIO = info->MMIO; /* we don't need anything like WaitForFifo, no? */ - if (!info->IsSecondary) { - if (info->tilingEnabled) { - if (IS_R300_VARIANT) - surf_info |= (width_bytes / 8) | color_pattern; - else - surf_info |= (width_bytes / 16) | color_pattern; - } - OUTREG(RADEON_SURFACE0_INFO, surf_info); - OUTREG(RADEON_SURFACE0_LOWER_BOUND, 0); - OUTREG(RADEON_SURFACE0_UPPER_BOUND, bufferSize - 1); + if (info->tilingEnabled) { + if (IS_R300_VARIANT) + surf_info |= (width_bytes / 8) | color_pattern; + else + surf_info |= (width_bytes / 16) | color_pattern; + } + OUTREG(RADEON_SURFACE0_INFO, surf_info); + OUTREG(RADEON_SURFACE0_LOWER_BOUND, 0); + OUTREG(RADEON_SURFACE0_UPPER_BOUND, bufferSize - 1); /* xf86DrvMsg(pScrn->scrnIndex, X_INFO, "surface0 set to %x, LB 0x%x UB 0x%x\n", surf_info, 0, bufferSize - 1024);*/ - } } /* Update surface images */ RADEONSaveSurfaces(pScrn, &info->ModeReg); } -#if 0 -/* Write palette data */ -static void RADEONRestorePalette(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - int i; - - if (!restore->palette_valid) return; - - PAL_SELECT(1); - OUTPAL_START(0); - for (i = 0; i < 256; i++) { - RADEONWaitForFifo(pScrn, 32); /* delay */ - OUTPAL_NEXT_CARD32(restore->palette2[i]); - } - - PAL_SELECT(0); - OUTPAL_START(0); - for (i = 0; i < 256; i++) { - RADEONWaitForFifo(pScrn, 32); /* delay */ - OUTPAL_NEXT_CARD32(restore->palette[i]); - } -} -#endif - -/* Write out state to define a new video mode */ -static void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONController* pCRTC1 = pRADEONEnt->Controller[0]; - RADEONController* pCRTC2 = pRADEONEnt->Controller[1]; - RADEONConnector *pPort; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "RADEONRestoreMode(%p)\n", restore); - - /* For Non-dual head card, we don't have private field in the Entity */ - if (!pRADEONEnt->HasCRTC2) { - RADEONRestoreMemMapRegisters(pScrn, restore); - RADEONRestoreCommonRegisters(pScrn, restore); - RADEONRestoreCrtcRegisters(pScrn, restore); - RADEONRestoreFPRegisters(pScrn, restore); - RADEONRestorePLLRegisters(pScrn, restore); - return; - } - - /* Disable all outputs at initial mode set. the ones we want will - get set by RADEONEnableDisplay() - */ - if (!info->IsSwitching && !info->IsSecondary) - RADEONDisableDisplays(pScrn); - - /* When changing mode with Dual-head card, care must be taken for - * the special order in setting registers. CRTC2 has to be set - * before changing CRTC_EXT register. In the dual-head setup, X - * server calls this routine twice with primary and secondary pScrn - * pointers respectively. The calls can come with different - * order. Regardless the order of X server issuing the calls, we - * have to ensure we set registers in the right order!!! Otherwise - * we may get a blank screen. - * - * We always restore MemMap first, the saverec should be up to date - * in all cases - */ - if (info->IsSwitching) { - if (info->IsSecondary) { - RADEONRestoreMemMapRegisters(pScrn, restore); - RADEONRestoreCommonRegisters(pScrn, restore); - RADEONRestoreCrtc2Registers(pScrn, restore); - RADEONRestorePLL2Registers(pScrn, restore); - RADEONRestoreFPRegisters(pScrn, restore); - RADEONEnableDisplay(pScrn, pRADEONEnt->PortInfo[1], TRUE); - pCRTC2->IsActive = TRUE; - } else { - RADEONRestoreMemMapRegisters(pScrn, restore); - RADEONRestoreCommonRegisters(pScrn, restore); - if (pCRTC2->binding == 1) { - RADEONRestoreCrtc2Registers(pScrn, restore); - RADEONRestorePLL2Registers(pScrn, restore); - } - - RADEONRestoreCrtcRegisters(pScrn, restore); - RADEONRestorePLLRegisters(pScrn, restore); - RADEONRestoreFPRegisters(pScrn, restore); - RADEONEnableDisplay(pScrn, pRADEONEnt->PortInfo[0], TRUE); - pCRTC1->IsActive = TRUE; - if (pCRTC2->binding == 1) { - RADEONEnableDisplay(pScrn, pRADEONEnt->PortInfo[1], TRUE); - pCRTC2->IsActive = TRUE; - } - } - } else { - RADEONRestoreMemMapRegisters(pScrn, restore); - RADEONRestoreCommonRegisters(pScrn, restore); - if ((pCRTC2->binding == 1) || pRADEONEnt->HasSecondary) { - RADEONRestoreCrtc2Registers(pScrn, restore); - RADEONRestorePLL2Registers(pScrn, restore); - } - - RADEONRestoreCrtcRegisters(pScrn, restore); - RADEONRestorePLLRegisters(pScrn, restore); - RADEONRestoreFPRegisters(pScrn, restore); - RADEONEnableDisplay(pScrn, pRADEONEnt->PortInfo[0], TRUE); - pCRTC1->IsActive = TRUE; - if (pCRTC2->binding == 1) { - RADEONEnableDisplay(pScrn, pRADEONEnt->PortInfo[1], TRUE); - pCRTC2->IsActive = TRUE; - } - } - -#if 0 - RADEONRestorePalette(pScrn, &info->SavedReg); -#endif -} - /* Read memory map */ static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) { @@ -5285,7 +5106,6 @@ static void RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) save->crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); save->crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); - save->dac_cntl = INREG(RADEON_DAC_CNTL); save->crtc_h_total_disp = INREG(RADEON_CRTC_H_TOTAL_DISP); save->crtc_h_sync_strt_wid = INREG(RADEON_CRTC_H_SYNC_STRT_WID); save->crtc_v_total_disp = INREG(RADEON_CRTC_V_TOTAL_DISP); @@ -5302,12 +5122,39 @@ static void RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) save->disp_merge_cntl = INREG(RADEON_DISP_MERGE_CNTL); save->crtc_more_cntl = INREG(RADEON_CRTC_MORE_CNTL); + if (IS_R300_VARIANT) + save->crtc_tile_x0_y0 = INREG(R300_CRTC_TILE_X0_Y0); + if (info->IsDellServer) { save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); save->dac2_cntl = INREG(RADEON_DAC_CNTL2); save->disp_hw_debug = INREG (RADEON_DISP_HW_DEBUG); save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); } + + /* track if the crtc is enabled for text restore */ + if (save->crtc_ext_cntl & RADEON_CRTC_DISPLAY_DIS) + info->crtc_on = FALSE; + else + info->crtc_on = TRUE; + +} + +/* Read DAC registers */ +static void RADEONSaveDACRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + save->dac_cntl = INREG(RADEON_DAC_CNTL); + save->dac2_cntl = INREG(RADEON_DAC_CNTL2); + save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + save->disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); + save->disp_tv_out_cntl = INREG(RADEON_DISP_TV_OUT_CNTL); + save->disp_hw_debug = INREG(RADEON_DISP_HW_DEBUG); + save->dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL); + save->gpiopad_a = INREG(RADEON_GPIOPAD_A); + } /* Read flat panel registers */ @@ -5340,12 +5187,6 @@ static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - save->dac2_cntl = INREG(RADEON_DAC_CNTL2); - save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); - save->disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); - save->disp_tv_out_cntl = INREG(RADEON_DISP_TV_OUT_CNTL); - save->disp_hw_debug = INREG (RADEON_DISP_HW_DEBUG); - save->crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); save->crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP); save->crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); @@ -5355,6 +5196,9 @@ static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL); save->crtc2_pitch = INREG(RADEON_CRTC2_PITCH); + if (IS_R300_VARIANT) + save->crtc2_tile_x0_y0 = INREG(R300_CRTC2_TILE_X0_Y0); + save->fp_h2_sync_strt_wid = INREG (RADEON_FP_H2_SYNC_STRT_WID); save->fp_v2_sync_strt_wid = INREG (RADEON_FP_V2_SYNC_STRT_WID); @@ -5366,6 +5210,106 @@ static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save) } save->disp2_merge_cntl = INREG(RADEON_DISP2_MERGE_CNTL); + + /* track if the crtc is enabled for text restore */ + if (save->crtc2_gen_cntl & RADEON_CRTC2_DISP_DIS) + info->crtc2_on = FALSE; + else + info->crtc2_on = TRUE; + +} + +/* Save horizontal/vertical timing code tables */ +static void RADEONSaveTVTimingTables(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD16 hTable; + CARD16 vTable; + CARD32 tmp; + unsigned i; + + save->tv_uv_adr = INREG(RADEON_TV_UV_ADR); + hTable = RADEONGetHTimingTablesAddr(save->tv_uv_adr); + vTable = RADEONGetVTimingTablesAddr(save->tv_uv_adr); + + /* + * Reset FIFO arbiter in order to be able to access FIFO RAM + */ + + OUTREG(RADEON_TV_MASTER_CNTL, (RADEON_TV_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | RADEON_RESTART_PHASE_FIX + | RADEON_CRT_FIFO_CE_EN + | RADEON_TV_FIFO_CE_EN + | RADEON_TV_ON)); + + /*OUTREG(RADEON_TV_MASTER_CNTL, save->tv_master_cntl | RADEON_TV_ON);*/ + + ErrorF("saveTimingTables: reading timing tables\n"); + + for (i = 0; i < MAX_H_CODE_TIMING_LEN; i += 2) { + tmp = RADEONReadTVFIFO(pScrn, hTable--); + save->h_code_timing[ i ] = (CARD16)((tmp >> 14) & 0x3fff); + save->h_code_timing[ i + 1 ] = (CARD16)(tmp & 0x3fff); + + if (save->h_code_timing[ i ] == 0 || save->h_code_timing[ i + 1 ] == 0) + break; + } + + for (i = 0; i < MAX_V_CODE_TIMING_LEN; i += 2) { + tmp = RADEONReadTVFIFO(pScrn, vTable++); + save->v_code_timing[ i ] = (CARD16)(tmp & 0x3fff); + save->v_code_timing[ i + 1 ] = (CARD16)((tmp >> 14) & 0x3fff); + + if (save->v_code_timing[ i ] == 0 || save->v_code_timing[ i + 1 ] == 0) + break; + } +} + +/* read TV regs */ +static void RADEONSaveTVRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + unsigned i; + + ErrorF("Entering TV Save\n"); + + save->tv_crc_cntl = INREG(RADEON_TV_CRC_CNTL); + save->tv_frestart = INREG(RADEON_TV_FRESTART); + save->tv_hrestart = INREG(RADEON_TV_HRESTART); + save->tv_vrestart = INREG(RADEON_TV_VRESTART); + save->tv_gain_limit_settings = INREG(RADEON_TV_GAIN_LIMIT_SETTINGS); + save->tv_hdisp = INREG(RADEON_TV_HDISP); + save->tv_hstart = INREG(RADEON_TV_HSTART); + save->tv_htotal = INREG(RADEON_TV_HTOTAL); + save->tv_linear_gain_settings = INREG(RADEON_TV_LINEAR_GAIN_SETTINGS); + save->tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL); + save->tv_rgb_cntl = INREG(RADEON_TV_RGB_CNTL); + save->tv_modulator_cntl1 = INREG(RADEON_TV_MODULATOR_CNTL1); + save->tv_modulator_cntl2 = INREG(RADEON_TV_MODULATOR_CNTL2); + save->tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); + save->tv_sync_cntl = INREG(RADEON_TV_SYNC_CNTL); + save->tv_timing_cntl = INREG(RADEON_TV_TIMING_CNTL); + save->tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + save->tv_upsamp_and_gain_cntl = INREG(RADEON_TV_UPSAMP_AND_GAIN_CNTL); + save->tv_vdisp = INREG(RADEON_TV_VDISP); + save->tv_ftotal = INREG(RADEON_TV_FTOTAL); + save->tv_vscaler_cntl1 = INREG(RADEON_TV_VSCALER_CNTL1); + save->tv_vscaler_cntl2 = INREG(RADEON_TV_VSCALER_CNTL2); + save->tv_vtotal = INREG(RADEON_TV_VTOTAL); + save->tv_y_fall_cntl = INREG(RADEON_TV_Y_FALL_CNTL); + save->tv_y_rise_cntl = INREG(RADEON_TV_Y_RISE_CNTL); + save->tv_y_saw_tooth_cntl = INREG(RADEON_TV_Y_SAW_TOOTH_CNTL); + + save->tv_pll_cntl = INPLL(pScrn, RADEON_TV_PLL_CNTL); + + ErrorF("Save TV timing tables\n"); + + RADEONSaveTVTimingTables(pScrn, save); + + ErrorF("TV Save done\n"); } /* Read PLL registers */ @@ -5374,7 +5318,7 @@ static void RADEONSavePLLRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) save->ppll_ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV); save->ppll_div_3 = INPLL(pScrn, RADEON_PPLL_DIV_3); save->htotal_cntl = INPLL(pScrn, RADEON_HTOTAL_CNTL); - save->vclk_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); + save->vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "Read: 0x%08x 0x%08x 0x%08lx\n", @@ -5431,26 +5375,22 @@ static void RADEONSavePalette(ScrnInfoPtr pScrn, RADEONSavePtr save) /* Save state that defines current video mode */ static void RADEONSaveMode(ScrnInfoPtr pScrn, RADEONSavePtr save) { - RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONInfoPtr info = RADEONPTR(pScrn); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONSaveMode(%p)\n", save); - if (info->IsSecondary) { - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONInfoPtr info0 = RADEONPTR(pRADEONEnt->pPrimaryScrn); - memcpy(&info->SavedReg, &info0->SavedReg, sizeof(RADEONSaveRec)); - } else { - RADEONSaveMemMapRegisters(pScrn, save); - RADEONSaveCommonRegisters(pScrn, save); - RADEONSavePLLRegisters (pScrn, save); - RADEONSaveCrtcRegisters (pScrn, save); - RADEONSaveFPRegisters (pScrn, save); - RADEONSaveCrtc2Registers (pScrn, save); - RADEONSavePLL2Registers (pScrn, save); - /*RADEONSavePalette(pScrn, save);*/ - /*memcpy(&info->ModeReg, &info->SavedReg, sizeof(RADEONSaveRec));*/ - } + RADEONSaveMemMapRegisters(pScrn, save); + RADEONSaveCommonRegisters(pScrn, save); + RADEONSavePLLRegisters(pScrn, save); + RADEONSaveCrtcRegisters(pScrn, save); + RADEONSaveFPRegisters(pScrn, save); + RADEONSaveDACRegisters(pScrn, save); + RADEONSaveCrtc2Registers(pScrn, save); + RADEONSavePLL2Registers(pScrn, save); + if (info->InternalTVOut) + RADEONSaveTVRegisters(pScrn, save); + /*RADEONSavePalette(pScrn, save);*/ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONSaveMode returns %p\n", save); @@ -5472,43 +5412,44 @@ static void RADEONSave(ScrnInfoPtr pScrn) return; } - if (!info->IsSecondary) { + #ifdef WITH_VGAHW - if (info->VGAAccess) { - vgaHWPtr hwp = VGAHWPTR(pScrn); + if (info->VGAAccess) { + vgaHWPtr hwp = VGAHWPTR(pScrn); - vgaHWUnlock(hwp); + vgaHWUnlock(hwp); # if defined(__powerpc__) - /* temporary hack to prevent crashing on PowerMacs when trying to - * read VGA fonts and colormap, will find a better solution - * in the future. TODO: Check if there's actually some VGA stuff - * setup in the card at all !! - */ - vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */ + /* temporary hack to prevent crashing on PowerMacs when trying to + * read VGA fonts and colormap, will find a better solution + * in the future. TODO: Check if there's actually some VGA stuff + * setup in the card at all !! + */ + vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */ # else - /* Save mode * & fonts & cmap */ - vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS); + /* Save mode * & fonts & cmap */ + vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS); # endif - vgaHWLock(hwp); - } -#endif - save->dp_datatype = INREG(RADEON_DP_DATATYPE); - save->rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET); - save->clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX); - RADEONPllErrataAfterIndex(info); + vgaHWLock(hwp); } +#endif + save->dp_datatype = INREG(RADEON_DP_DATATYPE); + save->rbbm_soft_reset = INREG(RADEON_RBBM_SOFT_RESET); + save->clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX); + RADEONPllErrataAfterIndex(info); RADEONSaveMode(pScrn, save); - if (!info->IsSecondary) - RADEONSaveSurfaces(pScrn, save); + RADEONSaveSurfaces(pScrn, save); } /* Restore the original (text) mode */ -static void RADEONRestore(ScrnInfoPtr pScrn) +void RADEONRestore(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; RADEONSavePtr restore = &info->SavedReg; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86CrtcPtr crtc; xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONRestore\n"); @@ -5522,7 +5463,7 @@ static void RADEONRestore(ScrnInfoPtr pScrn) fbdevHWRestore(pScrn); return; } - RADEONBlank(pScrn, TRUE); + RADEONBlank(pScrn); OUTREG(RADEON_CLOCK_CNTL_INDEX, restore->clock_cntl_index); RADEONPllErrataAfterIndex(info); @@ -5540,11 +5481,27 @@ static void RADEONRestore(ScrnInfoPtr pScrn) OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); #endif - RADEONRestoreMode(pScrn, restore); - if (!info->IsSecondary) - RADEONRestoreSurfaces(pScrn, restore); + RADEONRestoreMemMapRegisters(pScrn, restore); + RADEONRestoreCommonRegisters(pScrn, restore); -#if 0 + if (pRADEONEnt->HasCRTC2) { + RADEONRestoreCrtc2Registers(pScrn, restore); + RADEONRestorePLL2Registers(pScrn, restore); + } + + RADEONRestoreCrtcRegisters(pScrn, restore); + RADEONRestorePLLRegisters(pScrn, restore); + RADEONRestoreRMXRegisters(pScrn, restore); + RADEONRestoreFPRegisters(pScrn, restore); + RADEONRestoreFP2Registers(pScrn, restore); + RADEONRestoreLVDSRegisters(pScrn, restore); + + if (info->InternalTVOut) + RADEONRestoreTVRegisters(pScrn, restore); + + RADEONRestoreSurfaces(pScrn, restore); + +#if 1 /* Temp fix to "solve" VT switch problems. When switching VTs on * some systems, the console can either hang or the fonts can be * corrupted. This hack solves the problem 99% of the time. A @@ -5556,829 +5513,36 @@ static void RADEONRestore(ScrnInfoPtr pScrn) #ifdef WITH_VGAHW if (info->VGAAccess) { vgaHWPtr hwp = VGAHWPTR(pScrn); - if (!info->IsSecondary) { - vgaHWUnlock(hwp); + vgaHWUnlock(hwp); # if defined(__powerpc__) - /* Temporary hack to prevent crashing on PowerMacs when trying to - * write VGA fonts, will find a better solution in the future - */ - vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE ); + /* Temporary hack to prevent crashing on PowerMacs when trying to + * write VGA fonts, will find a better solution in the future + */ + vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE ); # else - vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); + vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); # endif - vgaHWLock(hwp); - } else { - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - ScrnInfoPtr pScrn0 = pRADEONEnt->pPrimaryScrn; - RADEONInfoPtr info0 = RADEONPTR(pScrn0); - vgaHWPtr hwp0; - - if (info0->VGAAccess) { - hwp0 = VGAHWPTR(pScrn0); - vgaHWUnlock(hwp0); -#if defined(__powerpc__) - vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE); -#else - vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE | VGA_SR_FONTS ); -#endif - vgaHWLock(hwp0); - } - } + vgaHWLock(hwp); } #endif - RADEONBlank(pScrn, FALSE); - -#if 0 - RADEONWaitForVerticalSync(pScrn); -#endif -} - -/* Define common registers for requested video mode */ -static void RADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info) -{ - save->ovr_clr = 0; - save->ovr_wid_left_right = 0; - save->ovr_wid_top_bottom = 0; - save->ov0_scale_cntl = 0; - save->subpic_cntl = 0; - save->viph_control = 0; - save->i2c_cntl_1 = 0; - save->rbbm_soft_reset = 0; - save->cap0_trig_cntl = 0; - save->cap1_trig_cntl = 0; - save->bus_cntl = info->BusCntl; - /* - * If bursts are enabled, turn on discards - * Radeon doesn't have write bursts - */ - if (save->bus_cntl & (RADEON_BUS_READ_BURST)) - save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN; -} - -/* XXX: fix me */ -static void RADEONInitTvDacCntl(ScrnInfoPtr pScrn, RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - if (info->ChipFamily == CHIP_FAMILY_R420 || - info->ChipFamily == CHIP_FAMILY_RV410) { - save->tv_dac_cntl = info->SavedReg.tv_dac_cntl & - ~(RADEON_TV_DAC_STD_MASK | - RADEON_TV_DAC_BGADJ_MASK | - R420_TV_DAC_DACADJ_MASK | - R420_TV_DAC_RDACPD | - R420_TV_DAC_GDACPD | - R420_TV_DAC_GDACPD | - R420_TV_DAC_TVENABLE); - } else { - save->tv_dac_cntl = info->SavedReg.tv_dac_cntl & - ~(RADEON_TV_DAC_STD_MASK | - RADEON_TV_DAC_BGADJ_MASK | - RADEON_TV_DAC_DACADJ_MASK | - RADEON_TV_DAC_RDACPD | - RADEON_TV_DAC_GDACPD | - RADEON_TV_DAC_GDACPD); - } - /* FIXME: doesn't make sense, this just replaces the previous value... */ - save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | - RADEON_TV_DAC_NHOLD | - RADEON_TV_DAC_STD_PS2); - // info->tv_dac_adj); -} - -static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, BOOL IsPrimary) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - int i; - CARD32 tmp = info->SavedReg.tmds_pll_cntl & 0xfffff; - - for (i=0; i<4; i++) { - if (info->tmds_pll[i].freq == 0) break; - if ((CARD32)(mode->Clock/10) < info->tmds_pll[i].freq) { - tmp = info->tmds_pll[i].value ; - break; - } - } - - if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_RV280)) { - if (tmp & 0xfff00000) - save->tmds_pll_cntl = tmp; - else { - save->tmds_pll_cntl = info->SavedReg.tmds_pll_cntl & 0xfff00000; - save->tmds_pll_cntl |= tmp; - } - } else save->tmds_pll_cntl = tmp; - - save->tmds_transmitter_cntl = info->SavedReg.tmds_transmitter_cntl & - ~(RADEON_TMDS_TRANSMITTER_PLLRST); - - if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_R200) || !pRADEONEnt->HasCRTC2) - save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); - else /* weird, RV chips got this bit reversed? */ - save->tmds_transmitter_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN); - - save->fp_gen_cntl = info->SavedReg.fp_gen_cntl | - (RADEON_FP_CRTC_DONT_SHADOW_VPAR | - RADEON_FP_CRTC_DONT_SHADOW_HEND ); - - if (pScrn->rgbBits == 8) - save->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ - else - save->fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ - - - if (IsPrimary) { - if ((IS_R300_VARIANT) || (info->ChipFamily == CHIP_FAMILY_R200)) { - save->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; - if (mode->Flags & RADEON_USE_RMX) - save->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; - else - save->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; - } else - save->fp_gen_cntl |= RADEON_FP_SEL_CRTC1; - } else { - if ((IS_R300_VARIANT) || (info->ChipFamily == CHIP_FAMILY_R200)) { - save->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; - save->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; - } else - save->fp_gen_cntl |= RADEON_FP_SEL_CRTC2; - } - -} - -static void RADEONInitFP2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, BOOL IsPrimary) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - if (pScrn->rgbBits == 8) - save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl | - RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ - else - save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl & - ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ - - if (IsPrimary) { - if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { - save->fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | - RADEON_FP2_DVO_EN | - RADEON_FP2_DVO_RATE_SEL_SDR); - if (mode->Flags & RADEON_USE_RMX) - save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; - } else { - save->fp2_gen_cntl &= ~(RADEON_FP2_SRC_SEL_CRTC2 | - RADEON_FP2_DVO_RATE_SEL_SDR); - } - /*save->fp2_gen_cntl |= ( RADEON_FP2_ON | - RADEON_FP2_BLANK_EN | - RADEON_FP2_DVO_EN);*/ - } else { - if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { - save->fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | - RADEON_FP2_DVO_RATE_SEL_SDR); - save->fp2_gen_cntl |= (R200_FP2_SOURCE_SEL_CRTC2 /*| - RADEON_FP2_PANEL_FORMAT | - RADEON_FP2_BLANK_EN | - RADEON_FP2_ON | - RADEON_FP2_DVO_EN*/); - } else { - save->fp2_gen_cntl &= ~(RADEON_FP2_DVO_RATE_SEL_SDR); - save->fp2_gen_cntl |= (RADEON_FP2_SRC_SEL_CRTC2 /*| - RADEON_FP2_PANEL_FORMAT | - RADEON_FP2_BLANK_EN | - RADEON_FP2_ON | - RADEON_FP2_DVO_EN*/); - } + /* need to make sure we don't enable a crtc by accident or we may get a hang */ + if (info->crtc2_on) { + crtc = xf86_config->crtc[1]; + crtc->funcs->dpms(crtc, DPMSModeOn); } - -} - -static void RADEONInitLVDSRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, BOOL IsPrimary) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); -/* XXX saved but never used??? */ - if (IsPrimary) - save->lvds_gen_cntl = info->SavedReg.lvds_gen_cntl & - ~RADEON_LVDS_SEL_CRTC2; - else - save->lvds_gen_cntl = info->SavedReg.lvds_gen_cntl | - RADEON_LVDS_SEL_CRTC2; - -} - -static void RADEONInitRMXRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - int xres = mode->HDisplay; - int yres = mode->VDisplay; - float Hratio, Vratio; - - - if (info->PanelXRes == 0 || info->PanelYRes == 0) { - Hratio = 1.0; - Vratio = 1.0; - } else { - if (xres > info->PanelXRes) xres = info->PanelXRes; - if (yres > info->PanelYRes) yres = info->PanelYRes; - - Hratio = (float)xres/(float)info->PanelXRes; - Vratio = (float)yres/(float)info->PanelYRes; - } - - save->fp_vert_stretch = info->SavedReg.fp_vert_stretch & - RADEON_VERT_STRETCH_RESERVED; - save->fp_horz_stretch = info->SavedReg.fp_horz_stretch & - (RADEON_HORZ_FP_LOOP_STRETCH | - RADEON_HORZ_AUTO_RATIO_INC); - - if (Hratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { - save->fp_horz_stretch |= ((xres/8-1)<<16); - } else { - save->fp_horz_stretch |= ((((unsigned long)(Hratio * RADEON_HORZ_STRETCH_RATIO_MAX + - 0.5)) & RADEON_HORZ_STRETCH_RATIO_MASK) | - RADEON_HORZ_STRETCH_BLEND | - RADEON_HORZ_STRETCH_ENABLE | - ((info->PanelXRes/8-1)<<16)); + if (info->crtc_on) { + crtc = xf86_config->crtc[0]; + crtc->funcs->dpms(crtc, DPMSModeOn); } - - if (Vratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { - save->fp_vert_stretch |= ((yres-1)<<12); - } else { - save->fp_vert_stretch |= ((((unsigned long)(Vratio * RADEON_VERT_STRETCH_RATIO_MAX + - 0.5)) & RADEON_VERT_STRETCH_RATIO_MASK) | - RADEON_VERT_STRETCH_ENABLE | - RADEON_VERT_STRETCH_BLEND | - ((info->PanelYRes-1)<<12)); - } - -} - -static void RADEONInitDACRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, BOOL IsPrimary) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - if (IsPrimary) { - if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { - save->disp_output_cntl = info->SavedReg.disp_output_cntl & - ~RADEON_DISP_DAC_SOURCE_MASK; - } else { - save->dac2_cntl = info->SavedReg.dac2_cntl & ~(RADEON_DAC2_DAC_CLK_SEL); - } - save->dac_cntl = (RADEON_DAC_MASK_ALL - | RADEON_DAC_VGA_ADR_EN - | (info->dac6bits ? 0 : RADEON_DAC_8BIT_EN)); - - } else { - if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { - save->disp_output_cntl = info->SavedReg.disp_output_cntl & - ~RADEON_DISP_DAC_SOURCE_MASK; - save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; - } else { - save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC_CLK_SEL; - } - } -} - -static void RADEONInitDAC2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, BOOL IsPrimary) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - /*0x0028023;*/ - RADEONInitTvDacCntl(pScrn, save); - - if (IsPrimary) { - /*save->crtc2_gen_cntl = info->SavedReg.crtc2_gen_cntl | RADEON_CRTC2_CRT2_ON;*/ - save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL; - if (IS_R300_VARIANT) { - save->disp_output_cntl = info->SavedReg.disp_output_cntl & - ~RADEON_DISP_TVDAC_SOURCE_MASK; - save->disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; - } else if (info->ChipFamily == CHIP_FAMILY_R200) { - save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl & - ~(R200_FP2_SOURCE_SEL_MASK | - RADEON_FP2_DVO_RATE_SEL_SDR); - /*save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl | - (RADEON_FP2_ON | - RADEON_FP2_BLANK_EN | - RADEON_FP2_DVO_EN);*/ - } else { - save->disp_hw_debug = info->SavedReg.disp_hw_debug | RADEON_CRT2_DISP1_SEL; - } - } else { - save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL; - if (IS_R300_VARIANT) { - save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL; - save->disp_output_cntl = info->SavedReg.disp_output_cntl & - ~RADEON_DISP_TVDAC_SOURCE_MASK; - save->disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; - } else if (info->ChipFamily == CHIP_FAMILY_R200) { - save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl & - ~(R200_FP2_SOURCE_SEL_MASK | - RADEON_FP2_DVO_RATE_SEL_SDR); - save->fp2_gen_cntl |= (R200_FP2_SOURCE_SEL_CRTC2 /*| - RADEON_FP2_BLANK_EN | - RADEON_FP2_ON | - RADEON_FP2_DVO_EN*/); - /*save->fp_h2_sync_strt_wid = save->crtc2_h_sync_strt_wid; - save->fp_v2_sync_strt_wid = save->crtc2_v_sync_strt_wid;*/ - } else { - save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL; - save->disp_hw_debug = info->SavedReg.disp_hw_debug & - ~RADEON_CRT2_DISP1_SEL; - } - } -} - -static void RADEONInitOutputRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, DisplayModePtr mode, RADEONConnector *pPort, Bool IsPrimary) -{ - if (pPort->MonType == MT_CRT) { - if (pPort->DACType == DAC_PRIMARY) { - RADEONInitDACRegisters(pScrn, save, mode, IsPrimary); - } else { - RADEONInitDAC2Registers(pScrn, save, mode, IsPrimary); - } - } else if (pPort->MonType == MT_LCD) { - if (IsPrimary) - RADEONInitRMXRegisters(pScrn, save, mode); - RADEONInitLVDSRegisters(pScrn, save, mode, IsPrimary); - } else if (pPort->MonType == MT_DFP) { - if (IsPrimary) - RADEONInitRMXRegisters(pScrn, save, mode); - if (pPort->TMDSType == TMDS_INT) { - RADEONInitFPRegisters(pScrn, save, mode, IsPrimary); - } else { - RADEONInitFP2Registers(pScrn, save, mode, IsPrimary); - } - } -} - -/* Define CRTC registers for requested video mode */ -static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, RADEONInfoPtr info) -{ - int format; - int hsync_start; - int hsync_wid; - int vsync_wid; - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - - pRADEONEnt->Controller[0]->IsUsed = TRUE; - pRADEONEnt->Controller[0]->IsActive = TRUE; - pRADEONEnt->Controller[0]->pCurMode = mode; - - switch (info->CurrentLayout.pixel_code) { - case 4: format = 1; break; - case 8: format = 2; break; - case 15: format = 3; break; /* 555 */ - case 16: format = 4; break; /* 565 */ - case 24: format = 5; break; /* RGB */ - case 32: format = 6; break; /* xRGB */ - default: - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Unsupported pixel depth (%d)\n", - info->CurrentLayout.bitsPerPixel); - return FALSE; - } - - save->bios_4_scratch = info->SavedReg.bios_4_scratch; - save->crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN - | RADEON_CRTC_EN - | (format << 8) - | ((mode->Flags & V_DBLSCAN) - ? RADEON_CRTC_DBL_SCAN_EN - : 0) - | ((mode->Flags & V_CSYNC) - ? RADEON_CRTC_CSYNC_EN - : 0) - | ((mode->Flags & V_INTERLACE) - ? RADEON_CRTC_INTERLACE_EN - : 0)); - - save->crtc_ext_cntl |= (RADEON_CRTC_CRT_ON | - RADEON_CRTC_VSYNC_DIS | - RADEON_CRTC_HSYNC_DIS | - RADEON_CRTC_DISPLAY_DIS); - - save->surface_cntl = 0; - save->disp_merge_cntl = info->SavedReg.disp_merge_cntl; - save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; - -#if X_BYTE_ORDER == X_BIG_ENDIAN - /* We must set both apertures as they can be both used to map the entire - * video memory. -BenH. - */ - switch (pScrn->bitsPerPixel) { - case 16: - save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP; - save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP; - break; - - case 32: - save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP; - save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP; - break; - } -#endif - - save->crtc_more_cntl = 0; - if ((info->ChipFamily == CHIP_FAMILY_RS100) || - (info->ChipFamily == CHIP_FAMILY_RS200)) { - /* This is to workaround the asic bug for RMX, some versions - of BIOS dosen't have this register initialized correctly. - */ - save->crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN; - } - - if (mode->Flags & RADEON_USE_RMX) { - mode->CrtcHTotal = mode->CrtcHDisplay + info->HBlank; - mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlus; - mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidth; - mode->CrtcVTotal = mode->CrtcVDisplay + info->VBlank; - mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlus; - mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidth; - mode->Clock = info->DotClock; - mode->Flags = info->Flags | RADEON_USE_RMX; - } - - - - save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff) - | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) - << 16)); - - hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; - if (!hsync_wid) hsync_wid = 1; - if (hsync_wid > 0x3f) hsync_wid = 0x3f; - hsync_start = mode->CrtcHSyncStart - 8; - - save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) - | (hsync_wid << 16) - | ((mode->Flags & V_NHSYNC) - ? RADEON_CRTC_H_SYNC_POL - : 0)); - - /* This works for double scan mode. */ - save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) - | ((mode->CrtcVDisplay - 1) << 16)); - - vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; - if (!vsync_wid) vsync_wid = 1; - if (vsync_wid > 0x1f) vsync_wid = 0x1f; - - save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) - | (vsync_wid << 16) - | ((mode->Flags & V_NVSYNC) - ? RADEON_CRTC_V_SYNC_POL - : 0)); - - save->crtc_offset = pScrn->fbOffset; - if (info->tilingEnabled) { - if (IS_R300_VARIANT) - save->crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | - R300_CRTC_MICRO_TILE_BUFFER_DIS | - R300_CRTC_MACRO_TILE_EN); - else - save->crtc_offset_cntl |= RADEON_CRTC_TILE_EN; - } - else { - if (IS_R300_VARIANT) - save->crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | - R300_CRTC_MICRO_TILE_BUFFER_DIS | - R300_CRTC_MACRO_TILE_EN); - else - save->crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN; - } - - save->crtc_pitch = (((pScrn->displayWidth * pScrn->bitsPerPixel) + - ((pScrn->bitsPerPixel * 8) -1)) / - (pScrn->bitsPerPixel * 8)); - save->crtc_pitch |= save->crtc_pitch << 16; - - save->fp_h_sync_strt_wid = save->crtc_h_sync_strt_wid; - save->fp_v_sync_strt_wid = save->crtc_v_sync_strt_wid; - save->fp_crtc_h_total_disp = save->crtc_h_total_disp; - save->fp_crtc_v_total_disp = save->crtc_v_total_disp; - - /* Set following registers for all cases first, if a DFP/LCD is connected on - internal TMDS/LVDS port, they will be set by RADEONInitFPRegister - */ - if (!info->IsSwitching) { - save->fp_gen_cntl = 0; - save->fp_vert_stretch = info->SavedReg.fp_vert_stretch & - RADEON_VERT_STRETCH_RESERVED; - save->fp_horz_stretch = info->SavedReg.fp_horz_stretch & - (RADEON_HORZ_FP_LOOP_STRETCH | - RADEON_HORZ_AUTO_RATIO_INC); - } - - /* get the output connected to this CRTC */ - RADEONInitOutputRegisters(pScrn, save, mode, pRADEONEnt->PortInfo[0], TRUE); - - if (info->IsDellServer) { - save->dac2_cntl = info->SavedReg.dac2_cntl; - save->tv_dac_cntl = info->SavedReg.tv_dac_cntl; - save->crtc2_gen_cntl = info->SavedReg.crtc2_gen_cntl; - save->disp_hw_debug = info->SavedReg.disp_hw_debug; - - save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; - save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL; - - /* For CRT on DAC2, don't turn it on if BIOS didn't - enable it, even it's detected. - */ - save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; - save->tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16)); - save->tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16)); - } - - return TRUE; -} - -/* Define CRTC2 registers for requested video mode */ -static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, - DisplayModePtr mode, RADEONInfoPtr info) -{ - int format; - int hsync_start; - int hsync_wid; - int vsync_wid; - - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONInfoPtr info0 = NULL; - if (info->IsSecondary) - info0 = RADEONPTR(pRADEONEnt->pPrimaryScrn); - - pRADEONEnt->Controller[1]->IsUsed = TRUE; - pRADEONEnt->Controller[1]->IsActive = TRUE; - pRADEONEnt->Controller[1]->pCurMode = mode; - - switch (info->CurrentLayout.pixel_code) { - case 4: format = 1; break; - case 8: format = 2; break; - case 15: format = 3; break; /* 555 */ - case 16: format = 4; break; /* 565 */ - case 24: format = 5; break; /* RGB */ - case 32: format = 6; break; /* xRGB */ - default: - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Unsupported pixel depth (%d)\n", - info->CurrentLayout.bitsPerPixel); - return FALSE; - } - - save->crtc2_h_total_disp = - ((((mode->CrtcHTotal / 8) - 1) & 0x3ff) - | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 16)); - - hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; - if (!hsync_wid) hsync_wid = 1; - if (hsync_wid > 0x3f) hsync_wid = 0x3f; - hsync_start = mode->CrtcHSyncStart - 8; - - save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff) - | (hsync_wid << 16) - | ((mode->Flags & V_NHSYNC) - ? RADEON_CRTC_H_SYNC_POL - : 0)); - - /* This works for double scan mode. */ - save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) - | ((mode->CrtcVDisplay - 1) << 16)); - - vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; - if (!vsync_wid) vsync_wid = 1; - if (vsync_wid > 0x1f) vsync_wid = 0x1f; - - save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) - | (vsync_wid << 16) - | ((mode->Flags & V_NVSYNC) - ? RADEON_CRTC2_V_SYNC_POL - : 0)); - - /* It seems all fancy options apart from pflip can be safely disabled - */ - save->crtc2_offset = pScrn->fbOffset; - save->crtc2_offset_cntl &= RADEON_CRTC_OFFSET_FLIP_CNTL; - if (info->tilingEnabled) { - if (IS_R300_VARIANT) - save->crtc2_offset_cntl |= (R300_CRTC_X_Y_MODE_EN | - R300_CRTC_MICRO_TILE_BUFFER_DIS | - R300_CRTC_MACRO_TILE_EN); - else - save->crtc2_offset_cntl |= RADEON_CRTC_TILE_EN; - } - else { - if (IS_R300_VARIANT) - save->crtc2_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN | - R300_CRTC_MICRO_TILE_BUFFER_DIS | - R300_CRTC_MACRO_TILE_EN); - else - save->crtc2_offset_cntl &= ~RADEON_CRTC_TILE_EN; - } - - save->crtc2_pitch = ((pScrn->displayWidth * pScrn->bitsPerPixel) + - ((pScrn->bitsPerPixel * 8) -1)) / (pScrn->bitsPerPixel * 8); - save->crtc2_pitch |= save->crtc2_pitch << 16; - - save->crtc2_gen_cntl = (RADEON_CRTC2_EN - | RADEON_CRTC2_CRT2_ON - | (format << 8) - | RADEON_CRTC2_VSYNC_DIS - | RADEON_CRTC2_HSYNC_DIS - | RADEON_CRTC2_DISP_DIS - | ((mode->Flags & V_DBLSCAN) - ? RADEON_CRTC2_DBL_SCAN_EN - : 0) - | ((mode->Flags & V_CSYNC) - ? RADEON_CRTC2_CSYNC_EN - : 0) - | ((mode->Flags & V_INTERLACE) - ? RADEON_CRTC2_INTERLACE_EN - : 0)); - - save->disp2_merge_cntl = info->SavedReg.disp2_merge_cntl; - save->disp2_merge_cntl &= ~(RADEON_DISP2_RGB_OFFSET_EN); - - save->fp_h2_sync_strt_wid = save->crtc2_h_sync_strt_wid; - save->fp_v2_sync_strt_wid = save->crtc2_v_sync_strt_wid; - - /* get the output connected to this CRTC */ - RADEONInitOutputRegisters(pScrn, save, mode, pRADEONEnt->PortInfo[1], FALSE); - - /* We must set SURFACE_CNTL properly on the second screen too */ - save->surface_cntl = 0; -#if X_BYTE_ORDER == X_BIG_ENDIAN - /* We must set both apertures as they can be both used to map the entire - * video memory. -BenH. + /* to restore console mode, DAC registers should be set after every other registers are set, + * otherwise,we may get blank screen */ - switch (pScrn->bitsPerPixel) { - case 16: - save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP; - save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP; - break; + RADEONRestoreDACRegisters(pScrn, restore); - case 32: - save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP; - save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP; - break; - } +#if 0 + RADEONWaitForVerticalSync(pScrn); #endif - - if (info->ChipFamily == CHIP_FAMILY_RS400) { - save->rs480_unk_e30 = 0x105DC1CC; /* because I'm worth it */ - save->rs480_unk_e34 = 0x2749D000; /* AMD really should */ - save->rs480_unk_e38 = 0x29ca71dc; /* release docs */ - save->rs480_unk_e3c = 0x28FBC3AC; /* this is so a trade secret */ - } - - return TRUE; -} - - -/* Define PLL registers for requested video mode */ -static void RADEONInitPLLRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info, - RADEONSavePtr save, RADEONPLLPtr pll, - double dot_clock) -{ - unsigned long freq = dot_clock * 100; - - struct { - int divider; - int bitvalue; - } *post_div, post_divs[] = { - /* From RAGE 128 VR/RAGE 128 GL Register - * Reference Manual (Technical Reference - * Manual P/N RRG-G04100-C Rev. 0.04), page - * 3-17 (PLL_DIV_[3:0]). - */ - { 1, 0 }, /* VCLK_SRC */ - { 2, 1 }, /* VCLK_SRC/2 */ - { 4, 2 }, /* VCLK_SRC/4 */ - { 8, 3 }, /* VCLK_SRC/8 */ - { 3, 4 }, /* VCLK_SRC/3 */ - { 16, 5 }, /* VCLK_SRC/16 */ - { 6, 6 }, /* VCLK_SRC/6 */ - { 12, 7 }, /* VCLK_SRC/12 */ - { 0, 0 } - }; - - if (info->UseBiosDividers) { - save->ppll_ref_div = info->RefDivider; - save->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16); - save->htotal_cntl = 0; - return; - } - - if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; - if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; - - for (post_div = &post_divs[0]; post_div->divider; ++post_div) { - save->pll_output_freq = post_div->divider * freq; - - if (save->pll_output_freq >= pll->min_pll_freq - && save->pll_output_freq <= pll->max_pll_freq) break; - } - - if (!post_div->divider) { - save->pll_output_freq = freq; - post_div = &post_divs[0]; - } - - save->dot_clock_freq = freq; - save->feedback_div = RADEONDiv(pll->reference_div - * save->pll_output_freq, - pll->reference_freq); - save->post_div = post_div->divider; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "dc=%ld, of=%ld, fd=%d, pd=%d\n", - save->dot_clock_freq, - save->pll_output_freq, - save->feedback_div, - save->post_div); - - save->ppll_ref_div = pll->reference_div; - save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16)); - save->htotal_cntl = 0; - - save->vclk_cntl = (info->SavedReg.vclk_cntl & - ~RADEON_VCLK_SRC_SEL_MASK) | RADEON_VCLK_SRC_SEL_PPLLCLK; - -} - -/* Define PLL2 registers for requested video mode */ -static void RADEONInitPLL2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, - RADEONPLLPtr pll, double dot_clock, - int no_odd_postdiv) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned long freq = dot_clock * 100; - - struct { - int divider; - int bitvalue; - } *post_div, post_divs[] = { - /* From RAGE 128 VR/RAGE 128 GL Register - * Reference Manual (Technical Reference - * Manual P/N RRG-G04100-C Rev. 0.04), page - * 3-17 (PLL_DIV_[3:0]). - */ - { 1, 0 }, /* VCLK_SRC */ - { 2, 1 }, /* VCLK_SRC/2 */ - { 4, 2 }, /* VCLK_SRC/4 */ - { 8, 3 }, /* VCLK_SRC/8 */ - { 3, 4 }, /* VCLK_SRC/3 */ - { 6, 6 }, /* VCLK_SRC/6 */ - { 12, 7 }, /* VCLK_SRC/12 */ - { 0, 0 } - }; - - if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; - if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; - - for (post_div = &post_divs[0]; post_div->divider; ++post_div) { - /* Odd post divider value don't work properly on the second digital - * output - */ - if (no_odd_postdiv && (post_div->divider & 1)) - continue; - save->pll_output_freq_2 = post_div->divider * freq; - if (save->pll_output_freq_2 >= pll->min_pll_freq - && save->pll_output_freq_2 <= pll->max_pll_freq) break; - } - - if (!post_div->divider) { - save->pll_output_freq_2 = freq; - post_div = &post_divs[0]; - } - - save->dot_clock_freq_2 = freq; - save->feedback_div_2 = RADEONDiv(pll->reference_div - * save->pll_output_freq_2, - pll->reference_freq); - save->post_div_2 = post_div->divider; - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "dc=%ld, of=%ld, fd=%d, pd=%d\n", - save->dot_clock_freq_2, - save->pll_output_freq_2, - save->feedback_div_2, - save->post_div_2); - - save->p2pll_ref_div = pll->reference_div; - save->p2pll_div_0 = (save->feedback_div_2 | - (post_div->bitvalue << 16)); - save->htotal_cntl2 = 0; - - save->pixclks_cntl = ((info->SavedReg.pixclks_cntl & - ~(RADEON_PIX2CLK_SRC_SEL_MASK)) | - RADEON_PIX2CLK_SRC_SEL_P2PLLCLK); - } #if 0 @@ -6391,169 +5555,6 @@ static void RADEONInitPalette(RADEONSavePtr save) } #endif -/* Define registers for a requested video mode */ -static Bool RADEONInit2(ScrnInfoPtr pScrn, DisplayModePtr crtc1, - DisplayModePtr crtc2, int crtc_mask, - RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - double dot_clock; - RADEONInfoPtr info0 = NULL; - ScrnInfoPtr pScrn0 = NULL; - - if (crtc1 && (crtc_mask & 1)) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "%-12.12s %7.2f %4d %4d %4d %4d %4d %4d %4d %4d (%d,%d)%s%s%s%s%s%s%s\n", - crtc1->name, - crtc1->Clock/1000.0, - - crtc1->HDisplay, - crtc1->HSyncStart, - crtc1->HSyncEnd, - crtc1->HTotal, - - crtc1->VDisplay, - crtc1->VSyncStart, - crtc1->VSyncEnd, - crtc1->VTotal, - pScrn->depth, - pScrn->bitsPerPixel, - (crtc1->Flags & V_DBLSCAN) ? " D" : "", - (crtc1->Flags & V_CSYNC) ? " C" : "", - (crtc1->Flags & V_INTERLACE) ? " I" : "", - (crtc1->Flags & V_PHSYNC) ? " +H" : "", - (crtc1->Flags & V_NHSYNC) ? " -H" : "", - (crtc1->Flags & V_PVSYNC) ? " +V" : "", - (crtc1->Flags & V_NVSYNC) ? " -V" : ""); - } - if (crtc2 && (crtc_mask & 2)) { - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "%-12.12s %7.2f %4d %4d %4d %4d %4d %4d %4d %4d (%d,%d)%s%s%s%s%s%s%s\n", - crtc2->name, - crtc2->Clock/1000.0, - - crtc2->CrtcHDisplay, - crtc2->CrtcHSyncStart, - crtc2->CrtcHSyncEnd, - crtc2->CrtcHTotal, - - crtc2->CrtcVDisplay, - crtc2->CrtcVSyncStart, - crtc2->CrtcVSyncEnd, - crtc2->CrtcVTotal, - pScrn->depth, - pScrn->bitsPerPixel, - (crtc2->Flags & V_DBLSCAN) ? " D" : "", - (crtc2->Flags & V_CSYNC) ? " C" : "", - (crtc2->Flags & V_INTERLACE) ? " I" : "", - (crtc2->Flags & V_PHSYNC) ? " +H" : "", - (crtc2->Flags & V_NHSYNC) ? " -H" : "", - (crtc2->Flags & V_PVSYNC) ? " +V" : "", - (crtc2->Flags & V_NVSYNC) ? " -V" : ""); - } - - if (crtc1 && (crtc_mask & 1)) - info->Flags = crtc1->Flags; - - RADEONInitMemMapRegisters(pScrn, save, info); - RADEONInitCommonRegisters(save, info); - - switch(crtc_mask) { - case 1: - if (!RADEONInitCrtcRegisters(pScrn, save, crtc1, info)) - return FALSE; - dot_clock = crtc1->Clock/1000.0; - if (dot_clock) { - RADEONInitPLLRegisters(pScrn, info, save, &info->pll, dot_clock); - } else { - save->ppll_ref_div = info->SavedReg.ppll_ref_div; - save->ppll_div_3 = info->SavedReg.ppll_div_3; - save->htotal_cntl = info->SavedReg.htotal_cntl; - } - if (pRADEONEnt->HasSecondary) { - pScrn0 = pRADEONEnt->pSecondaryScrn; - info0 = RADEONPTR(pScrn0); - /* carry over to secondary screen */ - memcpy(&info0->ModeReg, save, sizeof(RADEONSaveRec)); - } - - /* Not used for now: */ - /* if (!info->PaletteSavedOnVT) RADEONInitPalette(save); */ - break; - case 2: - pScrn0 = pRADEONEnt->pPrimaryScrn; - info0 = RADEONPTR(pScrn0); - dot_clock = crtc2->Clock/1000.0; - if (!RADEONInitCrtc2Registers(pScrn, save, crtc2, info)) - return FALSE; - RADEONInitPLL2Registers(pScrn, save, &info->pll, dot_clock, info->DisplayType != MT_CRT); - /* Make sure primary has the same copy */ - memcpy(&info0->ModeReg, save, sizeof(RADEONSaveRec)); - break; - case 3: - if (!RADEONInitCrtcRegisters(pScrn, save, - crtc1, info)) - return FALSE; - dot_clock = crtc1->Clock / 1000.0; - if (dot_clock) { - RADEONInitPLLRegisters(pScrn, info, save, &info->pll, dot_clock); - } else { - save->ppll_ref_div = info->SavedReg.ppll_ref_div; - save->ppll_div_3 = info->SavedReg.ppll_div_3; - save->htotal_cntl = info->SavedReg.htotal_cntl; - } - RADEONInitCrtc2Registers(pScrn, save, crtc2, info); - dot_clock = crtc2->Clock / 1000.0; - RADEONInitPLL2Registers(pScrn, save, &info->pll, dot_clock, info->MergeType != MT_CRT); - break; - default: - return FALSE; - } - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "RADEONInit returns %p\n", save); - return TRUE; -} - -static Bool RADEONInit(ScrnInfoPtr pScrn, DisplayModePtr mode, - RADEONSavePtr save) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - if (info->IsSecondary) { - return RADEONInit2(pScrn, NULL, mode, 2, save); - } else if (info->MergedFB) { - return RADEONInit2(pScrn, ((RADEONMergedDisplayModePtr)mode->Private)->CRT1, - ((RADEONMergedDisplayModePtr)mode->Private)->CRT2, 3, save); - } else { - return RADEONInit2(pScrn, mode, NULL, 1, save); - } -} - -/* Initialize a new mode */ -static Bool RADEONModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "RADEONModeInit()\n"); - - if (!RADEONInit(pScrn, mode, &info->ModeReg)) return FALSE; - - pScrn->vtSema = TRUE; - RADEONBlank(pScrn, TRUE); - RADEONRestoreMode(pScrn, &info->ModeReg); - RADEONBlank(pScrn, FALSE); - - info->CurrentLayout.mode = mode; - - if (info->DispPriority) - RADEONInitDispBandwidth(pScrn); - - return TRUE; -} - static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; @@ -6567,9 +5568,9 @@ static Bool RADEONSaveScreen(ScreenPtr pScreen, int mode) if ((pScrn != NULL) && pScrn->vtSema) { if (unblank) - RADEONBlank(pScrn, FALSE); + RADEONUnblank(pScrn); else - RADEONBlank(pScrn, TRUE); + RADEONBlank(pScrn); } return TRUE; } @@ -6613,17 +5614,7 @@ Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) "RADEONSwitchMode() !n"); if (info->allowColorTiling) { - if (info->MergedFB) { - if ((((RADEONMergedDisplayModePtr)mode->Private)->CRT1->Flags & - (V_DBLSCAN | V_INTERLACE)) || - (((RADEONMergedDisplayModePtr)mode->Private)->CRT2->Flags & - (V_DBLSCAN | V_INTERLACE))) - info->tilingEnabled = FALSE; - else info->tilingEnabled = TRUE; - } - else { - info->tilingEnabled = (mode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; - } + info->tilingEnabled = (mode->Flags & (V_DBLSCAN | V_INTERLACE)) ? FALSE : TRUE; #ifdef XF86DRI if (info->directRenderingEnabled && (info->tilingEnabled != tilingOld)) { RADEONSAREAPrivPtr pSAREAPriv; @@ -6648,9 +5639,7 @@ Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) RADEONRestoreFBDevRegisters(pScrn, &info->ModeReg); } else { - info->IsSwitching = TRUE; - ret = RADEONModeInit(xf86Screens[scrnIndex], mode); - info->IsSwitching = FALSE; + ret = xf86SetSingleMode (pScrn, mode, RR_Rotate_0); } if (info->tilingEnabled != tilingOld) { @@ -6676,10 +5665,7 @@ Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) /* Since RandR (indirectly) uses SwitchMode(), we need to * update our Xinerama info here, too, in case of resizing */ - if (info->MergedFB) { - RADEONMergedFBResetDpi(pScrn, FALSE); - RADEONUpdateXineramaScreenInfo(pScrn); - } else if(info->constantDPI) { + if(info->constantDPI) { RADEONResetDPI(pScrn, FALSE); } @@ -6717,11 +5703,11 @@ ModeStatus RADEONValidMode(int scrnIndex, DisplayModePtr mode, /* Adjust viewport into virtual desktop such that (0,0) in viewport * space is (x,y) in virtual space. */ -void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) +void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, Bool crtc2) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - int reg, Base, regcntl, crtcoffsetcntl, xytilereg, crtcxytile = 0; + int Base, reg, regcntl, crtcoffsetcntl, xytilereg, crtcxytile = 0; #ifdef XF86DRI RADEONSAREAPrivPtr pSAREAPriv; XF86DRISAREAPtr pSAREA; @@ -6749,12 +5735,12 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) pick up the new offset value at the end of each scanline, but the new offset_cntl value only after a vsync. We'd probably need to wait (in drm) for vsync and only then update OFFSET and OFFSET_CNTL, if the y coord has changed. Seems hard to fix. */ - if (clone || info->IsSecondary) { - reg = RADEON_CRTC2_OFFSET; + if (crtc2) { + reg = RADEON_CRTC2_OFFSET; regcntl = RADEON_CRTC2_OFFSET_CNTL; xytilereg = R300_CRTC2_TILE_X0_Y0; } else { - reg = RADEON_CRTC_OFFSET; + reg = RADEON_CRTC_OFFSET; regcntl = RADEON_CRTC_OFFSET_CNTL; xytilereg = R300_CRTC_TILE_X0_Y0; } @@ -6806,7 +5792,7 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) /* can't get at sarea in a semi-sane way? */ pSAREA = (void *)((char*)pSAREAPriv - sizeof(XF86DRISAREARec)); - if (clone || info->IsSecondary) { + if (crtc2) { pSAREAPriv->crtc2_base = Base; } else { @@ -6824,20 +5810,23 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) } #endif - OUTREG(reg, Base); - if (IS_R300_VARIANT) { - OUTREG(xytilereg, crtcxytile); + OUTREG(xytilereg, crtcxytile); } else { - OUTREG(regcntl, crtcoffsetcntl); + OUTREG(regcntl, crtcoffsetcntl); } + OUTREG(reg, Base); } void RADEONAdjustFrame(int scrnIndex, int x, int y, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + xf86OutputPtr output = config->output[config->compat_output]; + xf86CrtcPtr crtc = output->crtc; #ifdef XF86DRI if (info->CPStarted && pScrn->pScreen) DRILock(pScrn->pScreen, 0); @@ -6846,14 +5835,20 @@ void RADEONAdjustFrame(int scrnIndex, int x, int y, int flags) if (info->accelOn) RADEON_SYNC(info, pScrn); - if(info->MergedFB) { - RADEONAdjustFrameMerged(scrnIndex, x, y, flags); - } else if (info->FBDev) { - fbdevHWAdjustFrame(scrnIndex, x, y, flags); - } else { - RADEONDoAdjustFrame(pScrn, x, y, FALSE); + if (crtc && crtc->enabled) { + if (info->FBDev) { + fbdevHWAdjustFrame(scrnIndex, crtc->desiredX + x, crtc->desiredY + y, flags); + } else { + if (crtc == pRADEONEnt->pCrtc[0]) + RADEONDoAdjustFrame(pScrn, crtc->desiredX + x, crtc->desiredY + y, FALSE); + else + RADEONDoAdjustFrame(pScrn, crtc->desiredX + x, crtc->desiredY + y, TRUE); + } + crtc->x = output->initial_x + x; + crtc->y = output->initial_y + y; } + #ifdef XF86DRI if (info->CPStarted && pScrn->pScreen) DRIUnlock(pScrn->pScreen); #endif @@ -6867,6 +5862,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags) ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONEnterVT\n"); @@ -6893,11 +5889,30 @@ Bool RADEONEnterVT(int scrnIndex, int flags) info->ModeReg.surface_cntl = INREG(RADEON_SURFACE_CNTL); RADEONRestoreFBDevRegisters(pScrn, &info->ModeReg); - } else - if (!RADEONModeInit(pScrn, pScrn->currentMode)) return FALSE; + } else { + int i; + + pScrn->vtSema = TRUE; + for (i = 0; i < xf86_config->num_crtc; i++) + { + xf86CrtcPtr crtc = xf86_config->crtc[i]; + /* Mark that we'll need to re-set the mode for sure */ + memset(&crtc->mode, 0, sizeof(crtc->mode)); + if (!crtc->desiredMode.CrtcHDisplay) { + crtc->desiredMode = *RADEONCrtcFindClosestMode (crtc, pScrn->currentMode); + crtc->desiredRotation = RR_Rotate_0; + crtc->desiredX = 0; + crtc->desiredY = 0; + } + + if (!xf86CrtcSetMode (crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) + return FALSE; - if (!info->IsSecondary) - RADEONRestoreSurfaces(pScrn, &info->ModeReg); + } + } + + RADEONRestoreSurfaces(pScrn, &info->ModeReg); #ifdef XF86DRI if (info->directRenderingEnabled) { if (info->cardType == CARD_PCIE && info->pKernelDRMVersion->version_minor >= 19 && info->FbSecureSize) @@ -6910,6 +5925,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags) RADEONDRISetVBlankInterrupt (pScrn, TRUE); RADEONDRIResume(pScrn->pScreen); RADEONAdjustMemMapRegisters(pScrn, &info->ModeReg); + } #endif /* this will get XVideo going again, but only if XVideo was initialised @@ -6927,7 +5943,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags) } #endif - pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + // pScrn->AdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); return TRUE; } @@ -7025,7 +6041,6 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen) #endif /* USE_XAA */ if (pScrn->vtSema) { - RADEONDisplayPowerManagementSet(pScrn, DPMSModeOn, 0); RADEONRestore(pScrn); } @@ -7083,40 +6098,6 @@ void RADEONFreeScreen(int scrnIndex, int flags) /* when server quits at PreInit, we don't need do this anymore*/ if (!info) return; - if(info->MergedFB) { - if(pScrn->modes) { - pScrn->currentMode = pScrn->modes; - do { - DisplayModePtr p = pScrn->currentMode->next; - if(pScrn->currentMode->Private) - xfree(pScrn->currentMode->Private); - xfree(pScrn->currentMode); - pScrn->currentMode = p; - } while(pScrn->currentMode != pScrn->modes); - } - pScrn->currentMode = info->CRT1CurrentMode; - pScrn->modes = info->CRT1Modes; - info->CRT1CurrentMode = NULL; - info->CRT1Modes = NULL; - - if(info->CRT2pScrn) { - if(info->CRT2pScrn->modes) { - while(info->CRT2pScrn->modes) - xf86DeleteMode(&info->CRT2pScrn->modes, info->CRT2pScrn->modes); - } - if(info->CRT2pScrn->monitor) { - if(info->CRT2pScrn->monitor->Modes) { - while(info->CRT2pScrn->monitor->Modes) - xf86DeleteMode(&info->CRT2pScrn->monitor->Modes, info->CRT2pScrn->monitor->Modes); - } - if(info->CRT2pScrn->monitor->DDC) xfree(info->CRT2pScrn->monitor->DDC); - xfree(info->CRT2pScrn->monitor); - } - xfree(info->CRT2pScrn); - info->CRT2pScrn = NULL; - } - } - #ifdef WITH_VGAHW if (info->VGAAccess && xf86LoaderCheckSymbol("vgaHWFreeHWRec")) vgaHWFreeHWRec(pScrn); @@ -7124,233 +6105,6 @@ void RADEONFreeScreen(int scrnIndex, int flags) RADEONFreeRec(pScrn); } -static void -RADEONGetMergedFBOptions(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - char *strptr; - char *default_hsync = "28-33"; - char *default_vrefresh = "43-72"; - Bool val; - Bool default_range = FALSE; - static const char *mybadparm = "\"%s\" is is not a valid parameter for option \"%s\"\n"; - - if (info->FBDev == TRUE) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "MergedFB does not work with Option UseFBDev, MergedFB mode is disabled\n"); - info->MergedFB = FALSE; - return; - } - - /* collect MergedFB options */ - info->MergedFB = TRUE; - info->UseRADEONXinerama = TRUE; - info->CRT2IsScrn0 = FALSE; - info->CRT2Position = radeonClone; - info->MergedFBXDPI = info->MergedFBYDPI = 0; - info->CRT1XOffs = info->CRT1YOffs = info->CRT2XOffs = info->CRT2YOffs = 0; - info->NonRect = info->HaveNonRect = info->HaveOffsRegions = FALSE; - info->MBXNR1XMAX = info->MBXNR1YMAX = info->MBXNR2XMAX = info->MBXNR2YMAX = 65536; - info->MouseRestrictions = TRUE; - - if (info->MergeType == MT_NONE) { - info->MergedFB = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to detect secondary monitor, MergedFB/Clone mode disabled\n"); - } else if (!pRADEONEnt->PortInfo[1]->MonInfo) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Failed to detect secondary monitor DDC, default HSync and VRefresh used\n"); - default_range = TRUE; - } - - if (xf86GetOptValBool(info->Options, OPTION_MERGEDFB, &val)) { - if (val) { - info->MergedFB = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "MergedFB mode forced on.\n"); - } else { - info->MergedFB = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "MergedFB mode forced off.\n"); - } - } - - /* Do some MergedFB mode initialisation */ - if(info->MergedFB) { - info->CRT2pScrn = xalloc(sizeof(ScrnInfoRec)); - if(!info->CRT2pScrn) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to allocate memory for merged pScrn, MergedFB mode is disabled\n"); - info->MergedFB = FALSE; - } else { - memcpy(info->CRT2pScrn, pScrn, sizeof(ScrnInfoRec)); - } - } - if(info->MergedFB) { - int result, ival; - Bool valid = FALSE; - char *tempstr; - strptr = (char *)xf86GetOptValString(info->Options, OPTION_CRT2POS); - if (strptr) { - tempstr = xalloc(strlen(strptr) + 1); - result = sscanf(strptr, "%s %d", tempstr, &ival); - } else { /* Not specified - default is "Clone" */ - tempstr = NULL; - result = 0; - info->CRT2Position = radeonClone; - valid = TRUE; - } - if(result >= 1) { - if(!xf86NameCmp(tempstr,"LeftOf")) { - info->CRT2Position = radeonLeftOf; - valid = TRUE; - if(result == 2) { - if(ival < 0) info->CRT1YOffs = -ival; - else info->CRT2YOffs = ival; - } - info->CRT2IsScrn0 = TRUE; - } else if(!xf86NameCmp(tempstr,"RightOf")) { - info->CRT2Position = radeonRightOf; - valid = TRUE; - if(result == 2) { - if(ival < 0) info->CRT1YOffs = -ival; - else info->CRT2YOffs = ival; - } - info->CRT2IsScrn0 = FALSE; - } else if(!xf86NameCmp(tempstr,"Above")) { - info->CRT2Position = radeonAbove; - valid = TRUE; - if(result == 2) { - if(ival < 0) info->CRT1XOffs = -ival; - else info->CRT2XOffs = ival; - } - info->CRT2IsScrn0 = FALSE; - } else if(!xf86NameCmp(tempstr,"Below")) { - info->CRT2Position = radeonBelow; - valid = TRUE; - if(result == 2) { - if(ival < 0) info->CRT1XOffs = -ival; - else info->CRT2XOffs = ival; - } - info->CRT2IsScrn0 = TRUE; - } else if(!xf86NameCmp(tempstr,"Clone")) { - info->CRT2Position = radeonClone; - if(result == 1) valid = TRUE; - /*info->CRT2IsScrn0 = TRUE;*/ - } - } - if(!valid) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\"%s\" is not a valid parameter for Option \"CRT2Position\"\n", strptr); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Valid parameters are \"RightOf\", \"LeftOf\", \"Above\", \"Below\", or \"Clone\"\n"); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Except for \"Clone\", the parameter may be followed by an integer.\n"); - } - xfree(tempstr); - - strptr = (char *)xf86GetOptValString(info->Options, OPTION_METAMODES); - if(strptr) { - info->MetaModes = xalloc(strlen(strptr) + 1); - if(info->MetaModes) memcpy(info->MetaModes, strptr, strlen(strptr) + 1); - } - strptr = (char *)xf86GetOptValString(info->Options, OPTION_CRT2HSYNC); - if(strptr) { - info->CRT2HSync = xalloc(strlen(strptr) + 1); - if(info->CRT2HSync) memcpy(info->CRT2HSync, strptr, strlen(strptr) + 1); - } - strptr = (char *)xf86GetOptValString(info->Options, OPTION_CRT2VREFRESH); - if(strptr) { - info->CRT2VRefresh = xalloc(strlen(strptr) + 1); - if(info->CRT2VRefresh) memcpy(info->CRT2VRefresh, strptr, strlen(strptr) + 1); - } - - if(xf86GetOptValBool(info->Options, OPTION_RADEONXINERAMA, &val)) { - if (!val) - info->UseRADEONXinerama = FALSE; - } - if(info->UseRADEONXinerama) { - if(xf86GetOptValBool(info->Options, OPTION_CRT2ISSCRN0, &val)) { - if(val) info->CRT2IsScrn0 = TRUE; - else info->CRT2IsScrn0 = FALSE; - } - if(xf86GetOptValBool(info->Options, OPTION_MERGEDFBNONRECT, &val)) { - info->NonRect = val ? TRUE : FALSE; - } - if(xf86GetOptValBool(info->Options, OPTION_MERGEDFBMOUSER, &val)) { - info->MouseRestrictions = val ? TRUE : FALSE; - } - } - strptr = (char *)xf86GetOptValString(info->Options, OPTION_MERGEDDPI); - if(strptr) { - int val1 = 0, val2 = 0; - sscanf(strptr, "%d %d", &val1, &val2); - if(val1 && val2) { - info->MergedFBXDPI = val1; - info->MergedFBYDPI = val2; - } else { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, mybadparm, strptr, "MergedDPI"); - } - } - } - - if(info->MergedFB) { - /* fill in monitor */ - info->CRT2pScrn->monitor = xcalloc(1, sizeof(MonRec)); - if(info->CRT2pScrn->monitor) { - DisplayModePtr tempm = NULL, currentm = NULL, newm = NULL; - memcpy(info->CRT2pScrn->monitor, pScrn->monitor, sizeof(MonRec)); - info->CRT2pScrn->monitor->DDC = NULL; - info->CRT2pScrn->monitor->Modes = NULL; - info->CRT2pScrn->monitor->id = "CRT2 Monitor"; - tempm = pScrn->monitor->Modes; - while(tempm) { - if(!(newm = xalloc(sizeof(DisplayModeRec)))) break; - memcpy(newm, tempm, sizeof(DisplayModeRec)); - if(!(newm->name = xalloc(strlen(tempm->name) + 1))) { - xfree(newm); - break; - } - strcpy(newm->name, tempm->name); - if(!info->CRT2pScrn->monitor->Modes) - info->CRT2pScrn->monitor->Modes = newm; - if(currentm) { - currentm->next = newm; - newm->prev = currentm; - } - currentm = newm; - tempm = tempm->next; - } - info->CRT2pScrn->monitor->Last = currentm; - - /* xf86SetDDCproperties(info->CRT2pScrn, pRADEONEnt->MonInfo2); */ - - info->CRT2pScrn->monitor->DDC = pRADEONEnt->PortInfo[1]->MonInfo; - - if (default_range) { - RADEONStrToRanges(info->CRT2pScrn->monitor->hsync, default_hsync, MAX_HSYNC); - RADEONStrToRanges(info->CRT2pScrn->monitor->vrefresh, default_vrefresh, MAX_VREFRESH); - } - if(info->CRT2HSync) { - info->CRT2pScrn->monitor->nHsync = - RADEONStrToRanges(info->CRT2pScrn->monitor->hsync, info->CRT2HSync, MAX_HSYNC); - } - if(info->CRT2VRefresh) { - info->CRT2pScrn->monitor->nVrefresh = - RADEONStrToRanges(info->CRT2pScrn->monitor->vrefresh, info->CRT2VRefresh, MAX_VREFRESH); - } - - } else { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to allocate memory for CRT2 monitor, MergedFB mode disabled.\n"); - if(info->CRT2pScrn) xfree(info->CRT2pScrn); - info->CRT2pScrn = NULL; - info->MergedFB = FALSE; - } - } -} - static void RADEONForceSomeClocks(ScrnInfoPtr pScrn) { /* It appears from r300 and rv100 may need some clocks forced-on */ diff --git a/src/radeon_mergedfb.c b/src/radeon_mergedfb.c deleted file mode 100644 index abbc160..0000000 --- a/src/radeon_mergedfb.c +++ /dev/null @@ -1,2118 +0,0 @@ -/* - * Copyright 2003 Alex Deucher. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL ALEX DEUCHER, OR ANY OTHER - * CONTRIBUTORS 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 - -/* - * Authors: - * Alex Deucher <agd5f@yahoo.com> - * Based, in large part, on the sis driver by Thomas Winischhofer. - */ - -#include <string.h> -#include <stdio.h> - -#include "xf86.h" -#include "xf86Priv.h" -#include "xf86Resources.h" -#include "xf86_OSproc.h" -#include "extnsionst.h" /* required */ -#include <X11/extensions/panoramiXproto.h> /* required */ -#include "dixstruct.h" -#include "vbe.h" - - -#include "radeon.h" -#include "radeon_reg.h" -#include "radeon_macros.h" -#include "radeon_mergedfb.h" - -/* psuedo xinerama support */ -static unsigned char RADEONXineramaReqCode = 0; -int RADEONXineramaPixWidth = 0; -int RADEONXineramaPixHeight = 0; -int RADEONXineramaNumScreens = 0; -RADEONXineramaData *RADEONXineramadataPtr = NULL; -static int RADEONXineramaGeneration; -Bool RADEONnoPanoramiXExtension = TRUE; - -int RADEONProcXineramaQueryVersion(ClientPtr client); -int RADEONProcXineramaGetState(ClientPtr client); -int RADEONProcXineramaGetScreenCount(ClientPtr client); -int RADEONProcXineramaGetScreenSize(ClientPtr client); -int RADEONProcXineramaIsActive(ClientPtr client); -int RADEONProcXineramaQueryScreens(ClientPtr client); -int RADEONSProcXineramaDispatch(ClientPtr client); - -static void -RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y); - -/* mergedfb functions */ -/* Helper function for CRT2 monitor vrefresh/hsync options - * (Taken from mga, sis drivers) - */ -int -RADEONStrToRanges(range *r, char *s, int max) -{ - float num = 0.0; - int rangenum = 0; - Bool gotdash = FALSE; - Bool nextdash = FALSE; - char* strnum = NULL; - do { - switch(*s) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '.': - if(strnum == NULL) { - strnum = s; - gotdash = nextdash; - nextdash = FALSE; - } - break; - case '-': - case ' ': - case 0: - if(strnum == NULL) break; - sscanf(strnum, "%f", &num); - strnum = NULL; - if(gotdash) - r[rangenum - 1].hi = num; - else { - r[rangenum].lo = num; - r[rangenum].hi = num; - rangenum++; - } - if(*s == '-') nextdash = (rangenum != 0); - else if(rangenum >= max) return rangenum; - break; - default : - return 0; - } - } while(*(s++) != 0); - - return rangenum; -} - -/* Copy and link two modes (i, j) for merged-fb mode - * (Taken from mga, sis drivers) - * Copys mode i, merges j to copy of i, links the result to dest, and returns it. - * Links i and j in Private record. - * If dest is NULL, return value is copy of i linked to itself. - * For mergedfb auto-config, we only check the dimension - * against virtualX/Y, if they were user-provided. - */ -static DisplayModePtr -RADEONCopyModeNLink(ScrnInfoPtr pScrn, DisplayModePtr dest, - DisplayModePtr i, DisplayModePtr j, - RADEONScrn2Rel srel) -{ - DisplayModePtr mode; - int dx = 0,dy = 0; - RADEONInfoPtr info = RADEONPTR(pScrn); - - if(!((mode = xalloc(sizeof(DisplayModeRec))))) return dest; - memcpy(mode, i, sizeof(DisplayModeRec)); - if(!((mode->Private = xalloc(sizeof(RADEONMergedDisplayModeRec))))) { - xfree(mode); - return dest; - } - ((RADEONMergedDisplayModePtr)mode->Private)->CRT1 = i; - ((RADEONMergedDisplayModePtr)mode->Private)->CRT2 = j; - ((RADEONMergedDisplayModePtr)mode->Private)->CRT2Position = srel; - mode->PrivSize = 0; - - switch(srel) { - case radeonLeftOf: - case radeonRightOf: - if(!(pScrn->display->virtualX)) { - dx = i->HDisplay + j->HDisplay; - } else { - dx = min(pScrn->virtualX, i->HDisplay + j->HDisplay); - } - dx -= mode->HDisplay; - if(!(pScrn->display->virtualY)) { - dy = max(i->VDisplay, j->VDisplay); - } else { - dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); - } - dy -= mode->VDisplay; - break; - case radeonAbove: - case radeonBelow: - if(!(pScrn->display->virtualY)) { - dy = i->VDisplay + j->VDisplay; - } else { - dy = min(pScrn->virtualY, i->VDisplay + j->VDisplay); - } - dy -= mode->VDisplay; - if(!(pScrn->display->virtualX)) { - dx = max(i->HDisplay, j->HDisplay); - } else { - dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); - } - dx -= mode->HDisplay; - break; - case radeonClone: - if(!(pScrn->display->virtualX)) { - dx = max(i->HDisplay, j->HDisplay); - } else { - dx = min(pScrn->virtualX, max(i->HDisplay, j->HDisplay)); - } - dx -= mode->HDisplay; - if(!(pScrn->display->virtualY)) { - dy = max(i->VDisplay, j->VDisplay); - } else { - dy = min(pScrn->virtualY, max(i->VDisplay, j->VDisplay)); - } - dy -= mode->VDisplay; - break; - } - mode->HDisplay += dx; - mode->HSyncStart += dx; - mode->HSyncEnd += dx; - mode->HTotal += dx; - mode->VDisplay += dy; - mode->VSyncStart += dy; - mode->VSyncEnd += dy; - mode->VTotal += dy; - - /* Provide a fake VRefresh/DotClock in order to trick the vidmode - * extension to allow selecting among a number of modes whose merged result - * looks identical but consists of different modes for CRT1 and CRT2 - */ - { - float ref1, ref2; - ref1 = ((float)i->Clock * 100.0 / i->HTotal / i->VTotal) * 50.0; - ref2 = ((float)j->Clock * 100.0 / j->HTotal / j->VTotal) / 2.0; - - mode->VRefresh = (float) ref1 + ref2; - } - - mode->Clock = (int)(mode->VRefresh * 0.001 * mode->HTotal * mode->VTotal); - - if( ((mode->HDisplay * ((pScrn->bitsPerPixel + 7) / 8) * mode->VDisplay) > - (pScrn->videoRam * 1024)) || - (mode->HDisplay > 8191) || - (mode->VDisplay > 8191) ) { - - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Skipped \"%s\" (%dx%d), not enough video RAM or beyond hardware specs\n", - mode->name, mode->HDisplay, mode->VDisplay); - xfree(mode->Private); - xfree(mode); - - return dest; - } - - if(srel != radeonClone) { - info->AtLeastOneNonClone = TRUE; - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Merged \"%s\" (%dx%d) and \"%s\" (%dx%d) to %dx%d%s\n", - i->name, i->HDisplay, i->VDisplay, j->name, j->HDisplay, j->VDisplay, - mode->HDisplay, mode->VDisplay, (srel == radeonClone) ? " (Clone)" : ""); - - mode->next = mode; - mode->prev = mode; - - if(dest) { - mode->next = dest->next; /* Insert node after "dest" */ - dest->next->prev = mode; - mode->prev = dest; - dest->next = mode; - } - - return mode; -} - -/* Helper function to find a mode from a given name - * (Taken from mga, sis drivers) - */ -static DisplayModePtr -RADEONGetModeFromName(char* str, DisplayModePtr i) -{ - DisplayModePtr c = i; - if(!i) return NULL; - do { - if(strcmp(str, c->name) == 0) return c; - c = c->next; - } while(c != i); - return NULL; -} - -static DisplayModePtr -RADEONFindWidestTallestMode(DisplayModePtr i, Bool tallest) -{ - DisplayModePtr c = i, d = NULL; - int max = 0; - if(!i) return NULL; - do { - if(tallest) { - if(c->VDisplay > max) { - max = c->VDisplay; - d = c; - } - } else { - if(c->HDisplay > max) { - max = c->HDisplay; - d = c; - } - } - c = c->next; - } while(c != i); - return d; -} - -static void -RADEONFindWidestTallestCommonMode(DisplayModePtr i, DisplayModePtr j, Bool tallest, - DisplayModePtr *a, DisplayModePtr *b) -{ - DisplayModePtr c = i, d; - int max = 0; - Bool foundone; - - (*a) = (*b) = NULL; - - if(!i || !j) return; - - do { - d = j; - foundone = FALSE; - do { - if( (c->HDisplay == d->HDisplay) && - (c->VDisplay == d->VDisplay) ) { - foundone = TRUE; - break; - } - d = d->next; - } while(d != j); - if(foundone) { - if(tallest) { - if(c->VDisplay > max) { - max = c->VDisplay; - (*a) = c; - (*b) = d; - } - } else { - if(c->HDisplay > max) { - max = c->HDisplay; - (*a) = c; - (*b) = d; - } - } - } - c = c->next; - } while(c != i); -} - -static DisplayModePtr -RADEONGenerateModeListFromLargestModes(ScrnInfoPtr pScrn, - DisplayModePtr i, DisplayModePtr j, - RADEONScrn2Rel srel) -{ - - RADEONInfoPtr info = RADEONPTR(pScrn); - DisplayModePtr mode1 = NULL; - DisplayModePtr mode2 = NULL; - DisplayModePtr mode3 = NULL; - DisplayModePtr mode4 = NULL; - DisplayModePtr result = NULL; - - info->AtLeastOneNonClone = FALSE; - - /* Now build a default list of MetaModes. - * - Non-clone: If the user enabled NonRectangular, we use the - * largest mode for each CRT1 and CRT2. If not, we use the largest - * common mode for CRT1 and CRT2 (if available). Additionally, and - * regardless if the above, we produce a clone mode consisting of - * the largest common mode (if available) in order to use DGA. - * - Clone: If the (global) CRT2Position is Clone, we use the - * largest common mode if available, otherwise the first two modes - * in each list. - */ - - switch(srel) { - case radeonLeftOf: - case radeonRightOf: - mode1 = RADEONFindWidestTallestMode(i, FALSE); - mode2 = RADEONFindWidestTallestMode(j, FALSE); - RADEONFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4); - break; - case radeonAbove: - case radeonBelow: - mode1 = RADEONFindWidestTallestMode(i, TRUE); - mode2 = RADEONFindWidestTallestMode(j, TRUE); - RADEONFindWidestTallestCommonMode(i, j, TRUE, &mode3, &mode4); - break; - case radeonClone: - RADEONFindWidestTallestCommonMode(i, j, FALSE, &mode3, &mode4); - if(mode3 && mode4) { - mode1 = mode3; - mode2 = mode4; - } else { - mode1 = i; - mode2 = j; - } - } - - if(srel != radeonClone) { - if(mode3 && mode4 && !info->NonRect) { - mode1 = mode3; - mode2 = mode4; - } - } - - if(mode1 && mode2) { - result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, srel); - } - - if(srel != radeonClone) { - if(mode3 && mode4) { - result = RADEONCopyModeNLink(pScrn, result, mode3, mode4, radeonClone); - } - } - return result; -} - -/* Generate the merged-fb mode modelist - * (Taken from mga, sis drivers) - */ -static DisplayModePtr -RADEONGenerateModeListFromMetaModes(ScrnInfoPtr pScrn, char* str, - DisplayModePtr i, DisplayModePtr j, - RADEONScrn2Rel srel) -{ - char* strmode = str; - char modename[256]; - Bool gotdash = FALSE; - char gotsep = 0; - RADEONScrn2Rel sr; - DisplayModePtr mode1 = NULL; - DisplayModePtr mode2 = NULL; - DisplayModePtr result = NULL; - int myslen; - RADEONInfoPtr info = RADEONPTR(pScrn); - - info->AtLeastOneNonClone = FALSE; - - do { - switch(*str) { - case 0: - case '-': - case '+': - case ' ': - case ',': - case ';': - if(strmode != str) { - - myslen = str - strmode; - if(myslen > 255) myslen = 255; - strncpy(modename, strmode, myslen); - modename[myslen] = 0; - - if(gotdash) { - if(mode1 == NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Error parsing MetaModes parameter\n"); - return NULL; - } - mode2 = RADEONGetModeFromName(modename, j); - if(!mode2) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Mode \"%s\" is not a supported mode for CRT2\n", modename); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\t(Skipping metamode \"%s%c%s\")\n", mode1->name, gotsep, modename); - mode1 = NULL; - gotsep = 0; - } - } else { - mode1 = RADEONGetModeFromName(modename, i); - if(!mode1) { - char* tmps = str; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Mode \"%s\" is not a supported mode for CRT1\n", modename); - while(*tmps == ' ' || *tmps == ';') tmps++; - /* skip the next mode */ - if(*tmps == '-' || *tmps == '+' || *tmps == ',') { - tmps++; - /* skip spaces */ - while(*tmps == ' ' || *tmps == ';') tmps++; - /* skip modename */ - while(*tmps && *tmps != ' ' && *tmps != ';' && *tmps != '-' && *tmps != '+' && *tmps != ',') tmps++; - myslen = tmps - strmode; - if(myslen > 255) myslen = 255; - strncpy(modename,strmode,myslen); - modename[myslen] = 0; - str = tmps-1; - } - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\t(Skipping metamode \"%s\")\n", modename); - mode1 = NULL; - gotsep = 0; - } - } - gotdash = FALSE; - } - strmode = str + 1; - gotdash |= (*str == '-' || *str == '+' || *str == ','); - if (*str == '-' || *str == '+' || *str == ',') - gotsep = *str; - - if(*str != 0) break; - /* Fall through otherwise */ - - default: - if(!gotdash && mode1) { - sr = srel; - if(gotsep == '+') sr = radeonClone; - if(!mode2) { - mode2 = RADEONGetModeFromName(mode1->name, j); - sr = radeonClone; - } - if(!mode2) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Mode \"%s\" is not a supported mode for CRT2\n", mode1->name); - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "\t(Skipping metamode \"%s\")\n", modename); - mode1 = NULL; - } else { - result = RADEONCopyModeNLink(pScrn, result, mode1, mode2, sr); - mode1 = NULL; - mode2 = NULL; - } - gotsep = 0; - } - break; - - } - - } while(*(str++) != 0); - - return result; -} - -DisplayModePtr -RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, - DisplayModePtr i, DisplayModePtr j, - RADEONScrn2Rel srel) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - if(str != NULL) { - return(RADEONGenerateModeListFromMetaModes(pScrn, str, i, j, srel)); - } else { - if (srel == radeonClone ) { - DisplayModePtr p, q, result = NULL; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Clone mode, linking all nearest modes\n"); - - p = i; - q = j; - - result = RADEONCopyModeNLink(pScrn, result, p, q, srel); - - while (p->next != i || q->next != j) { - DisplayModePtr next_p = p; - - if (q->next == j || (p->next != i && - (p->HDisplay > q->HDisplay || - (p->HDisplay == q->HDisplay && - p->VDisplay >= q->VDisplay)))) - next_p = p->next; - - if (p->next == i || (q->next != j && - (q->HDisplay > p->HDisplay || - (q->HDisplay == p->HDisplay && - q->VDisplay >= p->VDisplay)))) - q = q->next; - - p = next_p; - - result = RADEONCopyModeNLink(pScrn, result, p, q, srel); - } - - return result; - } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "No MetaModes given, linking %s modes by default\n", - (info->NonRect ? - (((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest" : "tallest") - : - (((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest common" : "tallest common")) ); - return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel)); - } - } -} - -void -RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - DisplayModePtr mode, bmode; - int maxh, maxv; - static const char *str = "MergedFB: Virtual %s %d\n"; - static const char *errstr = "Virtual %s to small for given CRT2Position offset\n"; - - mode = bmode = pScrn->modes; - maxh = maxv = 0; - do { - if(mode->HDisplay > maxh) maxh = mode->HDisplay; - if(mode->VDisplay > maxv) maxv = mode->VDisplay; - mode = mode->next; - } while(mode != bmode); - maxh += info->CRT1XOffs + info->CRT2XOffs; - maxv += info->CRT1YOffs + info->CRT2YOffs; - - if(!(pScrn->display->virtualX)) { - if(maxh > 8191) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Virtual width with CRT2Position offset beyond hardware specs\n"); - info->CRT1XOffs = info->CRT2XOffs = 0; - maxh -= (info->CRT1XOffs + info->CRT2XOffs); - } - if (maxh > pScrn->virtualX) - pScrn->virtualX = maxh; - if (maxh > pScrn->displayWidth) - pScrn->displayWidth = maxh; - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "width", maxh); - } else { - if(maxh < pScrn->display->virtualX) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "width"); - info->CRT1XOffs = info->CRT2XOffs = 0; - } - } - - if(!(pScrn->display->virtualY)) { - if (maxv > pScrn->virtualY) - pScrn->virtualY = maxv; - xf86DrvMsg(pScrn->scrnIndex, X_PROBED, str, "height", maxv); - } else { - if(maxv < pScrn->display->virtualY) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, errstr, "height"); - info->CRT1YOffs = info->CRT2YOffs = 0; - } - } -} - -/* Pseudo-Xinerama extension for MergedFB mode */ -void -RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1) -{ - RADEONInfoPtr info = RADEONPTR(pScrn1); - ScrnInfoPtr pScrn2 = NULL; - int crt1scrnnum = 0, crt2scrnnum = 1; - int x1=0, x2=0, y1=0, y2=0, h1=0, h2=0, w1=0, w2=0; - int realvirtX, realvirtY; - DisplayModePtr currentMode, firstMode; - Bool infochanged = FALSE; - Bool usenonrect = info->NonRect; - const char *rectxine = "\t... setting up rectangular Xinerama layout\n"; - - info->MBXNR1XMAX = info->MBXNR1YMAX = info->MBXNR2XMAX = info->MBXNR2YMAX = 65536; - info->HaveNonRect = info->HaveOffsRegions = FALSE; - - if(!info->MergedFB) return; - - if(RADEONnoPanoramiXExtension) return; - - if(!RADEONXineramadataPtr) return; - - if(info->CRT2IsScrn0) { - crt1scrnnum = 1; - crt2scrnnum = 0; - } - - pScrn2 = info->CRT2pScrn; - - /* Attention: Usage of RandR may lead into virtual X and Y values - * actually smaller than our MetaModes! To avoid this, we calculate - * the maxCRT fields here (and not somewhere else, like in CopyNLink) - */ - - /* "Real" virtual: Virtual without the Offset */ - realvirtX = pScrn1->virtualX - info->CRT1XOffs - info->CRT2XOffs; - realvirtY = pScrn1->virtualY - info->CRT1YOffs - info->CRT2YOffs; - - if((info->RADEONXineramaVX != pScrn1->virtualX) || (info->RADEONXineramaVY != pScrn1->virtualY)) { - - if(!(pScrn1->modes)) { - xf86DrvMsg(pScrn1->scrnIndex, X_ERROR, - "Internal error: RADEONUpdateXineramaScreenInfo(): pScrn->modes is NULL\n"); - return; - } - - info->maxCRT1_X1 = info->maxCRT1_X2 = 0; - info->maxCRT1_Y1 = info->maxCRT1_Y2 = 0; - info->maxCRT2_X1 = info->maxCRT2_X2 = 0; - info->maxCRT2_Y1 = info->maxCRT2_Y2 = 0; - info->maxClone_X1 = info->maxClone_X2 = 0; - info->maxClone_Y1 = info->maxClone_Y2 = 0; - - currentMode = firstMode = pScrn1->modes; - - do { - - DisplayModePtr p = currentMode->next; - DisplayModePtr i = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT1; - DisplayModePtr j = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2; - RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)currentMode->Private)->CRT2Position; - - if((currentMode->HDisplay <= realvirtX) && (currentMode->VDisplay <= realvirtY) && - (i->HDisplay <= realvirtX) && (j->HDisplay <= realvirtX) && - (i->VDisplay <= realvirtY) && (j->VDisplay <= realvirtY)) { - - if(srel != radeonClone) { - if(info->maxCRT1_X1 == i->HDisplay) { - if(info->maxCRT1_X2 < j->HDisplay) { - info->maxCRT1_X2 = j->HDisplay; /* Widest CRT2 mode displayed with widest CRT1 mode */ - } - } else if(info->maxCRT1_X1 < i->HDisplay) { - info->maxCRT1_X1 = i->HDisplay; /* Widest CRT1 mode */ - info->maxCRT1_X2 = j->HDisplay; - } - if(info->maxCRT2_X2 == j->HDisplay) { - if(info->maxCRT2_X1 < i->HDisplay) { - info->maxCRT2_X1 = i->HDisplay; /* Widest CRT1 mode displayed with widest CRT2 mode */ - } - } else if(info->maxCRT2_X2 < j->HDisplay) { - info->maxCRT2_X2 = j->HDisplay; /* Widest CRT2 mode */ - info->maxCRT2_X1 = i->HDisplay; - } - if(info->maxCRT1_Y1 == i->VDisplay) { /* Same as above, but tallest instead of widest */ - if(info->maxCRT1_Y2 < j->VDisplay) { - info->maxCRT1_Y2 = j->VDisplay; - } - } else if(info->maxCRT1_Y1 < i->VDisplay) { - info->maxCRT1_Y1 = i->VDisplay; - info->maxCRT1_Y2 = j->VDisplay; - } - if(info->maxCRT2_Y2 == j->VDisplay) { - if(info->maxCRT2_Y1 < i->VDisplay) { - info->maxCRT2_Y1 = i->VDisplay; - } - } else if(info->maxCRT2_Y2 < j->VDisplay) { - info->maxCRT2_Y2 = j->VDisplay; - info->maxCRT2_Y1 = i->VDisplay; - } - } else { - if(info->maxClone_X1 < i->HDisplay) { - info->maxClone_X1 = i->HDisplay; - } - if(info->maxClone_X2 < j->HDisplay) { - info->maxClone_X2 = j->HDisplay; - } - if(info->maxClone_Y1 < i->VDisplay) { - info->maxClone_Y1 = i->VDisplay; - } - if(info->maxClone_Y2 < j->VDisplay) { - info->maxClone_Y2 = j->VDisplay; - } - } - } - currentMode = p; - - } while((currentMode) && (currentMode != firstMode)); - - info->RADEONXineramaVX = pScrn1->virtualX; - info->RADEONXineramaVY = pScrn1->virtualY; - infochanged = TRUE; - - } - - if((usenonrect) && (info->CRT2Position != radeonClone) && info->maxCRT1_X1) { - switch(info->CRT2Position) { - case radeonLeftOf: - case radeonRightOf: - if((info->maxCRT1_Y1 != realvirtY) && (info->maxCRT2_Y2 != realvirtY)) { - usenonrect = FALSE; - } - break; - case radeonAbove: - case radeonBelow: - if((info->maxCRT1_X1 != realvirtX) && (info->maxCRT2_X2 != realvirtX)) { - usenonrect = FALSE; - } - break; - case radeonClone: - break; - } - - if(infochanged && !usenonrect) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Virtual screen size does not match maximum display modes...\n"); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine); - - } - } else if(infochanged && usenonrect) { - usenonrect = FALSE; - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Only clone modes available for this virtual screen size...\n"); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, rectxine); - } - - if(info->maxCRT1_X1) { /* Means we have at least one non-clone mode */ - switch(info->CRT2Position) { - case radeonLeftOf: - x1 = min(info->maxCRT1_X2, pScrn1->virtualX - info->maxCRT1_X1); - if(x1 < 0) x1 = 0; - y1 = info->CRT1YOffs; - w1 = pScrn1->virtualX - x1; - h1 = realvirtY; - if((usenonrect) && (info->maxCRT1_Y1 != realvirtY)) { - h1 = info->MBXNR1YMAX = info->maxCRT1_Y1; - info->NonRectDead.x0 = x1; - info->NonRectDead.x1 = x1 + w1 - 1; - info->NonRectDead.y0 = y1 + h1; - info->NonRectDead.y1 = pScrn1->virtualY - 1; - info->HaveNonRect = TRUE; - } - x2 = 0; - y2 = info->CRT2YOffs; - w2 = max(info->maxCRT2_X2, pScrn1->virtualX - info->maxCRT2_X1); - if(w2 > pScrn1->virtualX) w2 = pScrn1->virtualX; - h2 = realvirtY; - if((usenonrect) && (info->maxCRT2_Y2 != realvirtY)) { - h2 = info->MBXNR2YMAX = info->maxCRT2_Y2; - info->NonRectDead.x0 = x2; - info->NonRectDead.x1 = x2 + w2 - 1; - info->NonRectDead.y0 = y2 + h2; - info->NonRectDead.y1 = pScrn1->virtualY - 1; - info->HaveNonRect = TRUE; - } - break; - case radeonRightOf: - x1 = 0; - y1 = info->CRT1YOffs; - w1 = max(info->maxCRT1_X1, pScrn1->virtualX - info->maxCRT1_X2); - if(w1 > pScrn1->virtualX) w1 = pScrn1->virtualX; - h1 = realvirtY; - if((usenonrect) && (info->maxCRT1_Y1 != realvirtY)) { - h1 = info->MBXNR1YMAX = info->maxCRT1_Y1; - info->NonRectDead.x0 = x1; - info->NonRectDead.x1 = x1 + w1 - 1; - info->NonRectDead.y0 = y1 + h1; - info->NonRectDead.y1 = pScrn1->virtualY - 1; - info->HaveNonRect = TRUE; - } - x2 = min(info->maxCRT2_X1, pScrn1->virtualX - info->maxCRT2_X2); - if(x2 < 0) x2 = 0; - y2 = info->CRT2YOffs; - w2 = pScrn1->virtualX - x2; - h2 = realvirtY; - if((usenonrect) && (info->maxCRT2_Y2 != realvirtY)) { - h2 = info->MBXNR2YMAX = info->maxCRT2_Y2; - info->NonRectDead.x0 = x2; - info->NonRectDead.x1 = x2 + w2 - 1; - info->NonRectDead.y0 = y2 + h2; - info->NonRectDead.y1 = pScrn1->virtualY - 1; - info->HaveNonRect = TRUE; - } - break; - case radeonAbove: - x1 = info->CRT1XOffs; - y1 = min(info->maxCRT1_Y2, pScrn1->virtualY - info->maxCRT1_Y1); - if(y1 < 0) y1 = 0; - w1 = realvirtX; - h1 = pScrn1->virtualY - y1; - if((usenonrect) && (info->maxCRT1_X1 != realvirtX)) { - w1 = info->MBXNR1XMAX = info->maxCRT1_X1; - info->NonRectDead.x0 = x1 + w1; - info->NonRectDead.x1 = pScrn1->virtualX - 1; - info->NonRectDead.y0 = y1; - info->NonRectDead.y1 = y1 + h1 - 1; - info->HaveNonRect = TRUE; - } - x2 = info->CRT2XOffs; - y2 = 0; - w2 = realvirtX; - h2 = max(info->maxCRT2_Y2, pScrn1->virtualY - info->maxCRT2_Y1); - if(h2 > pScrn1->virtualY) h2 = pScrn1->virtualY; - if((usenonrect) && (info->maxCRT2_X2 != realvirtX)) { - w2 = info->MBXNR2XMAX = info->maxCRT2_X2; - info->NonRectDead.x0 = x2 + w2; - info->NonRectDead.x1 = pScrn1->virtualX - 1; - info->NonRectDead.y0 = y2; - info->NonRectDead.y1 = y2 + h2 - 1; - info->HaveNonRect = TRUE; - } - break; - case radeonBelow: - x1 = info->CRT1XOffs; - y1 = 0; - w1 = realvirtX; - h1 = max(info->maxCRT1_Y1, pScrn1->virtualY - info->maxCRT1_Y2); - if(h1 > pScrn1->virtualY) h1 = pScrn1->virtualY; - if((usenonrect) && (info->maxCRT1_X1 != realvirtX)) { - w1 = info->MBXNR1XMAX = info->maxCRT1_X1; - info->NonRectDead.x0 = x1 + w1; - info->NonRectDead.x1 = pScrn1->virtualX - 1; - info->NonRectDead.y0 = y1; - info->NonRectDead.y1 = y1 + h1 - 1; - info->HaveNonRect = TRUE; - } - x2 = info->CRT2XOffs; - y2 = min(info->maxCRT2_Y1, pScrn1->virtualY - info->maxCRT2_Y2); - if(y2 < 0) y2 = 0; - w2 = realvirtX; - h2 = pScrn1->virtualY - y2; - if((usenonrect) && (info->maxCRT2_X2 != realvirtX)) { - w2 = info->MBXNR2XMAX = info->maxCRT2_X2; - info->NonRectDead.x0 = x2 + w2; - info->NonRectDead.x1 = pScrn1->virtualX - 1; - info->NonRectDead.y0 = y2; - info->NonRectDead.y1 = y2 + h2 - 1; - info->HaveNonRect = TRUE; - } - default: - break; - } - - switch(info->CRT2Position) { - case radeonLeftOf: - case radeonRightOf: - if(info->CRT1YOffs) { - info->OffDead1.x0 = x1; - info->OffDead1.x1 = x1 + w1 - 1; - info->OffDead1.y0 = 0; - info->OffDead1.y1 = y1 - 1; - info->OffDead2.x0 = x2; - info->OffDead2.x1 = x2 + w2 - 1; - info->OffDead2.y0 = y2 + h2; - info->OffDead2.y1 = pScrn1->virtualY - 1; - info->HaveOffsRegions = TRUE; - } else if(info->CRT2YOffs) { - info->OffDead1.x0 = x2; - info->OffDead1.x1 = x2 + w2 - 1; - info->OffDead1.y0 = 0; - info->OffDead1.y1 = y2 - 1; - info->OffDead2.x0 = x1; - info->OffDead2.x1 = x1 + w1 - 1; - info->OffDead2.y0 = y1 + h1; - info->OffDead2.y1 = pScrn1->virtualY - 1; - info->HaveOffsRegions = TRUE; - } - break; - case radeonAbove: - case radeonBelow: - if(info->CRT1XOffs) { - info->OffDead1.x0 = x2 + w2; - info->OffDead1.x1 = pScrn1->virtualX - 1; - info->OffDead1.y0 = y2; - info->OffDead1.y1 = y2 + h2 - 1; - info->OffDead2.x0 = 0; - info->OffDead2.x1 = x1 - 1; - info->OffDead2.y0 = y1; - info->OffDead2.y1 = y1 + h1 - 1; - info->HaveOffsRegions = TRUE; - } else if(info->CRT2XOffs) { - info->OffDead1.x0 = x1 + w1; - info->OffDead1.x1 = pScrn1->virtualX - 1; - info->OffDead1.y0 = y1; - info->OffDead1.y1 = y1 + h1 - 1; - info->OffDead2.x0 = 0; - info->OffDead2.x1 = x2 - 1; - info->OffDead2.y0 = y2; - info->OffDead2.y1 = y2 + h2 - 1; - info->HaveOffsRegions = TRUE; - } - default: - break; - } - - } else { /* Only clone-modes left */ - - x1 = x2 = 0; - y1 = y2 = 0; - w1 = w2 = max(info->maxClone_X1, info->maxClone_X2); - h1 = h2 = max(info->maxClone_Y1, info->maxClone_Y2); - - } - - RADEONXineramadataPtr[crt1scrnnum].x = x1; - RADEONXineramadataPtr[crt1scrnnum].y = y1; - RADEONXineramadataPtr[crt1scrnnum].width = w1; - RADEONXineramadataPtr[crt1scrnnum].height = h1; - RADEONXineramadataPtr[crt2scrnnum].x = x2; - RADEONXineramadataPtr[crt2scrnnum].y = y2; - RADEONXineramadataPtr[crt2scrnnum].width = w2; - RADEONXineramadataPtr[crt2scrnnum].height = h2; - - if(infochanged) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: CRT1 (Screen %d) (%d,%d)-(%d,%d)\n", - crt1scrnnum, x1, y1, w1+x1-1, h1+y1-1); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: CRT2 (Screen %d) (%d,%d)-(%d,%d)\n", - crt2scrnnum, x2, y2, w2+x2-1, h2+y2-1); - if(info->HaveNonRect) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Inaccessible area (%d,%d)-(%d,%d)\n", - info->NonRectDead.x0, info->NonRectDead.y0, - info->NonRectDead.x1, info->NonRectDead.y1); - } - if(info->HaveOffsRegions) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n", - info->OffDead1.x0, info->OffDead1.y0, - info->OffDead1.x1, info->OffDead1.y1); - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Pseudo-Xinerama: Inaccessible offset area (%d,%d)-(%d,%d)\n", - info->OffDead2.x0, info->OffDead2.y0, - info->OffDead2.x1, info->OffDead2.y1); - } - if(info->HaveNonRect || info->HaveOffsRegions) { - xf86DrvMsg(pScrn1->scrnIndex, X_INFO, - "Mouse restriction for inaccessible areas is %s\n", - info->MouseRestrictions ? "enabled" : "disabled"); - } - } -} -/* Proc */ - -int -RADEONProcXineramaQueryVersion(ClientPtr client) -{ - xPanoramiXQueryVersionReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXQueryVersionReq); - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = RADEON_XINERAMA_MAJOR_VERSION; - rep.minorVersion = RADEON_XINERAMA_MINOR_VERSION; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - } - WriteToClient(client, sizeof(xPanoramiXQueryVersionReply), (char *)&rep); - return (client->noClientException); -} - -int -RADEONProcXineramaGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - WindowPtr pWin; - xPanoramiXGetStateReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - pWin = LookupWindow(stuff->window, client); - if(!pWin) return BadWindow; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !RADEONnoPanoramiXExtension; - if(client->swapped) { - swaps (&rep.sequenceNumber, n); - swapl (&rep.length, n); - swaps (&rep.state, n); - } - WriteToClient(client, sizeof(xPanoramiXGetStateReply), (char *)&rep); - return client->noClientException; -} - -int -RADEONProcXineramaGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - WindowPtr pWin; - xPanoramiXGetScreenCountReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - pWin = LookupWindow(stuff->window, client); - if(!pWin) return BadWindow; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.ScreenCount = RADEONXineramaNumScreens; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.ScreenCount, n); - } - WriteToClient(client, sizeof(xPanoramiXGetScreenCountReply), (char *)&rep); - return client->noClientException; -} - -int -RADEONProcXineramaGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - WindowPtr pWin; - xPanoramiXGetScreenSizeReply rep; - register int n; - - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - pWin = LookupWindow (stuff->window, client); - if(!pWin) return BadWindow; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.width = RADEONXineramadataPtr[stuff->screen].width; - rep.height = RADEONXineramadataPtr[stuff->screen].height; - if(client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.width, n); - swaps(&rep.height, n); - } - WriteToClient(client, sizeof(xPanoramiXGetScreenSizeReply), (char *)&rep); - return client->noClientException; -} - -int -RADEONProcXineramaIsActive(ClientPtr client) -{ - xXineramaIsActiveReply rep; - - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.state = !RADEONnoPanoramiXExtension; - if(client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.state, n); - } - WriteToClient(client, sizeof(xXineramaIsActiveReply), (char *) &rep); - return client->noClientException; -} - -int -RADEONProcXineramaQueryScreens(ClientPtr client) -{ - xXineramaQueryScreensReply rep; - - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.number = (RADEONnoPanoramiXExtension) ? 0 : RADEONXineramaNumScreens; - rep.length = rep.number * sz_XineramaScreenInfo >> 2; - if(client->swapped) { - register int n; - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.number, n); - } - WriteToClient(client, sizeof(xXineramaQueryScreensReply), (char *)&rep); - - if(!RADEONnoPanoramiXExtension) { - xXineramaScreenInfo scratch; - int i; - - for(i = 0; i < RADEONXineramaNumScreens; i++) { - scratch.x_org = RADEONXineramadataPtr[i].x; - scratch.y_org = RADEONXineramadataPtr[i].y; - scratch.width = RADEONXineramadataPtr[i].width; - scratch.height = RADEONXineramadataPtr[i].height; - if(client->swapped) { - register int n; - swaps(&scratch.x_org, n); - swaps(&scratch.y_org, n); - swaps(&scratch.width, n); - swaps(&scratch.height, n); - } - WriteToClient(client, sz_XineramaScreenInfo, (char *)&scratch); - } - } - - return client->noClientException; -} - -static int -RADEONProcXineramaDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) - { - case X_PanoramiXQueryVersion: - return RADEONProcXineramaQueryVersion(client); - case X_PanoramiXGetState: - return RADEONProcXineramaGetState(client); - case X_PanoramiXGetScreenCount: - return RADEONProcXineramaGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return RADEONProcXineramaGetScreenSize(client); - case X_XineramaIsActive: - return RADEONProcXineramaIsActive(client); - case X_XineramaQueryScreens: - return RADEONProcXineramaQueryScreens(client); - } - return BadRequest; -} - -/* SProc */ - -static int -RADEONSProcXineramaQueryVersion (ClientPtr client) -{ - REQUEST(xPanoramiXQueryVersionReq); - register int n; - swaps(&stuff->length,n); - REQUEST_SIZE_MATCH (xPanoramiXQueryVersionReq); - return RADEONProcXineramaQueryVersion(client); -} - -static int -RADEONSProcXineramaGetState(ClientPtr client) -{ - REQUEST(xPanoramiXGetStateReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetStateReq); - return RADEONProcXineramaGetState(client); -} - -static int -RADEONSProcXineramaGetScreenCount(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenCountReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenCountReq); - return RADEONProcXineramaGetScreenCount(client); -} - -static int -RADEONSProcXineramaGetScreenSize(ClientPtr client) -{ - REQUEST(xPanoramiXGetScreenSizeReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xPanoramiXGetScreenSizeReq); - return RADEONProcXineramaGetScreenSize(client); -} - -static int -RADEONSProcXineramaIsActive(ClientPtr client) -{ - REQUEST(xXineramaIsActiveReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaIsActiveReq); - return RADEONProcXineramaIsActive(client); -} - -static int -RADEONSProcXineramaQueryScreens(ClientPtr client) -{ - REQUEST(xXineramaQueryScreensReq); - register int n; - swaps (&stuff->length, n); - REQUEST_SIZE_MATCH(xXineramaQueryScreensReq); - return RADEONProcXineramaQueryScreens(client); -} - -int -RADEONSProcXineramaDispatch(ClientPtr client) -{ - REQUEST(xReq); - switch (stuff->data) { - case X_PanoramiXQueryVersion: - return RADEONSProcXineramaQueryVersion(client); - case X_PanoramiXGetState: - return RADEONSProcXineramaGetState(client); - case X_PanoramiXGetScreenCount: - return RADEONSProcXineramaGetScreenCount(client); - case X_PanoramiXGetScreenSize: - return RADEONSProcXineramaGetScreenSize(client); - case X_XineramaIsActive: - return RADEONSProcXineramaIsActive(client); - case X_XineramaQueryScreens: - return RADEONSProcXineramaQueryScreens(client); - } - return BadRequest; -} - -static void -RADEONXineramaResetProc(ExtensionEntry* extEntry) -{ - if(RADEONXineramadataPtr) { - Xfree(RADEONXineramadataPtr); - RADEONXineramadataPtr = NULL; - } -} - -void -RADEONXineramaExtensionInit(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - Bool success = FALSE; - - if(!(RADEONXineramadataPtr)) { - - if(!info->MergedFB) { - RADEONnoPanoramiXExtension = TRUE; - info->MouseRestrictions = FALSE; - return; - } - -#ifdef PANORAMIX - if(!noPanoramiXExtension) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Xinerama active, not initializing Radeon Pseudo-Xinerama\n"); - RADEONnoPanoramiXExtension = TRUE; - info->MouseRestrictions = FALSE; - return; - } -#endif - - if(RADEONnoPanoramiXExtension) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Radeon Pseudo-Xinerama disabled\n"); - info->MouseRestrictions = FALSE; - return; - } - - if(info->CRT2Position == radeonClone) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Running MergedFB in Clone mode, Radeon Pseudo-Xinerama disabled\n"); - RADEONnoPanoramiXExtension = TRUE; - info->MouseRestrictions = FALSE; - return; - } - - if(!(info->AtLeastOneNonClone)) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Only Clone modes defined, Radeon Pseudo-Xinerama disabled\n"); - RADEONnoPanoramiXExtension = TRUE; - info->MouseRestrictions = FALSE; - return; - } - - RADEONXineramaNumScreens = 2; - - while(RADEONXineramaGeneration != serverGeneration) { - - info->XineramaExtEntry = AddExtension(PANORAMIX_PROTOCOL_NAME, 0,0, - RADEONProcXineramaDispatch, - RADEONSProcXineramaDispatch, - RADEONXineramaResetProc, - StandardMinorOpcode); - - if(!info->XineramaExtEntry) break; - - RADEONXineramaReqCode = (unsigned char)info->XineramaExtEntry->base; - - if(!(RADEONXineramadataPtr = (RADEONXineramaData *) - xcalloc(RADEONXineramaNumScreens, sizeof(RADEONXineramaData)))) break; - - RADEONXineramaGeneration = serverGeneration; - success = TRUE; - } - - if(!success) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Failed to initialize Radeon Pseudo-Xinerama extension\n"); - RADEONnoPanoramiXExtension = TRUE; - info->MouseRestrictions = FALSE; - return; - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Initialized Radeon Pseudo-Xinerama extension\n"); - - info->RADEONXineramaVX = 0; - info->RADEONXineramaVY = 0; - - } - - RADEONUpdateXineramaScreenInfo(pScrn); - -} -/* End of PseudoXinerama */ - -static Bool -InRegion(int x, int y, region r) -{ - return (r.x0 <= x) && (x <= r.x1) && (r.y0 <= y) && (y <= r.y1); -} - -void -RADEONMergePointerMoved(int scrnIndex, int x, int y) -{ - ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; - RADEONInfoPtr info = RADEONPTR(pScrn1); - ScrnInfoPtr pScrn2 = info->CRT2pScrn; - region out, in1, in2, f2, f1; - int deltax, deltay; - int temp1, temp2; - int old1x0, old1y0, old2x0, old2y0; - int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0; - int HVirt = pScrn1->virtualX; - int VVirt = pScrn1->virtualY; - int sigstate; - Bool doit = FALSE, HaveNonRect = FALSE, HaveOffsRegions = FALSE; - RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; - - if(info->DGAactive) { - return; - /* DGA: There is no cursor and no panning while DGA is active. */ - /* If it were, we would need to do: */ - /* HVirt = info->CurrentLayout.displayWidth; - VVirt = info->CurrentLayout.displayHeight; - BOUND(x, info->CurrentLayout.DGAViewportX, HVirt); - BOUND(y, info->CurrentLayout.DGAViewportY, VVirt); */ - } else { - CRT1XOffs = info->CRT1XOffs; - CRT1YOffs = info->CRT1YOffs; - CRT2XOffs = info->CRT2XOffs; - CRT2YOffs = info->CRT2YOffs; - HaveNonRect = info->HaveNonRect; - HaveOffsRegions = info->HaveOffsRegions; - } - - /* Check if the pointer is inside our dead areas */ - if((info->MouseRestrictions) && (srel != radeonClone) && !RADEONnoPanoramiXExtension) { - if(HaveNonRect) { - if(InRegion(x, y, info->NonRectDead)) { - switch(srel) { - case radeonLeftOf: - case radeonRightOf: y = info->NonRectDead.y0 - 1; - doit = TRUE; - break; - case radeonAbove: - case radeonBelow: x = info->NonRectDead.x0 - 1; - doit = TRUE; - default: break; - } - } - } - if(HaveOffsRegions) { - if(InRegion(x, y, info->OffDead1)) { - switch(srel) { - case radeonLeftOf: - case radeonRightOf: y = info->OffDead1.y1; - doit = TRUE; - break; - case radeonAbove: - case radeonBelow: x = info->OffDead1.x1; - doit = TRUE; - default: break; - } - } else if(InRegion(x, y, info->OffDead2)) { - switch(srel) { - case radeonLeftOf: - case radeonRightOf: y = info->OffDead2.y0 - 1; - doit = TRUE; - break; - case radeonAbove: - case radeonBelow: x = info->OffDead2.x0 - 1; - doit = TRUE; - default: break; - } - } - } - if(doit) { - UpdateCurrentTime(); - sigstate = xf86BlockSIGIO(); - miPointerAbsoluteCursor(x, y, currentTime.milliseconds); - xf86UnblockSIGIO(sigstate); - return; - } - } - - f1.x0 = old1x0 = info->CRT1frameX0; - f1.x1 = info->CRT1frameX1; - f1.y0 = old1y0 = info->CRT1frameY0; - f1.y1 = info->CRT1frameY1; - f2.x0 = old2x0 = pScrn2->frameX0; - f2.x1 = pScrn2->frameX1; - f2.y0 = old2y0 = pScrn2->frameY0; - f2.y1 = pScrn2->frameY1; - - /* Define the outer region. Crossing this causes all frames to move */ - out.x0 = pScrn1->frameX0; - out.x1 = pScrn1->frameX1; - out.y0 = pScrn1->frameY0; - out.y1 = pScrn1->frameY1; - - /* - * Define the inner sliding window. Being outsize both frames but - * inside the outer clipping window will slide corresponding frame - */ - in1 = out; - in2 = out; - switch(srel) { - case radeonLeftOf: - in1.x0 = f1.x0; - in2.x1 = f2.x1; - break; - case radeonRightOf: - in1.x1 = f1.x1; - in2.x0 = f2.x0; - break; - case radeonBelow: - in1.y1 = f1.y1; - in2.y0 = f2.y0; - break; - case radeonAbove: - in1.y0 = f1.y0; - in2.y1 = f2.y1; - break; - case radeonClone: - break; - } - - deltay = 0; - deltax = 0; - - if(InRegion(x, y, out)) { /* inside outer region */ - - /* xf86DrvMsg(0, X_INFO, "1: %d %d | %d %d %d %d | %d %d %d %d\n", - x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ - - if(InRegion(x, y, in1) && !InRegion(x, y, f1)) { - REBOUND(f1.x0, f1.x1, x); - REBOUND(f1.y0, f1.y1, y); - deltax = 1; - /* xf86DrvMsg(0, X_INFO, "2: %d %d | %d %d %d %d | %d %d %d %d\n", - x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); */ - } - if(InRegion(x, y, in2) && !InRegion(x, y, f2)) { - REBOUND(f2.x0, f2.x1, x); - REBOUND(f2.y0, f2.y1, y); - deltax = 1; - } - - } else { /* outside outer region */ - - /* xf86DrvMsg(0, X_INFO, "3: %d %d | %d %d %d %d | %d %d %d %d\n", - x, y, in1.x0, in1.x1, in1.y0, in1.y1, f1.x0, f1.x1, f1.y0, f1.y1); - xf86DrvMsg(0, X_INFO, "3-out: %d %d %d %d\n", - out.x0, out.x1, out.y0, out.y1); */ - - if(out.x0 > x) { - deltax = x - out.x0; - } - if(out.x1 < x) { - deltax = x - out.x1; - } - if(deltax) { - pScrn1->frameX0 += deltax; - pScrn1->frameX1 += deltax; - f1.x0 += deltax; - f1.x1 += deltax; - f2.x0 += deltax; - f2.x1 += deltax; - } - - if(out.y0 > y) { - deltay = y - out.y0; - } - if(out.y1 < y) { - deltay = y - out.y1; - } - if(deltay) { - pScrn1->frameY0 += deltay; - pScrn1->frameY1 += deltay; - f1.y0 += deltay; - f1.y1 += deltay; - f2.y0 += deltay; - f2.y1 += deltay; - } - - switch(srel) { - case radeonLeftOf: - if(x >= f1.x0) { REBOUND(f1.y0, f1.y1, y); } - if(x <= f2.x1) { REBOUND(f2.y0, f2.y1, y); } - break; - case radeonRightOf: - if(x <= f1.x1) { REBOUND(f1.y0, f1.y1, y); } - if(x >= f2.x0) { REBOUND(f2.y0, f2.y1, y); } - break; - case radeonBelow: - if(y <= f1.y1) { REBOUND(f1.x0, f1.x1, x); } - if(y >= f2.y0) { REBOUND(f2.x0, f2.x1, x); } - break; - case radeonAbove: - if(y >= f1.y0) { REBOUND(f1.x0, f1.x1, x); } - if(y <= f2.y1) { REBOUND(f2.x0, f2.x1, x); } - break; - case radeonClone: - break; - } - - } - - if(deltax || deltay) { - info->CRT1frameX0 = f1.x0; - info->CRT1frameY0 = f1.y0; - pScrn2->frameX0 = f2.x0; - pScrn2->frameY0 = f2.y0; - - switch(((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position) { - case radeonLeftOf: - case radeonRightOf: - if(info->CRT1YOffs || info->CRT2YOffs || HaveNonRect) { - if(info->CRT1frameY0 != old1y0) { - if(info->CRT1frameY0 < info->CRT1YOffs) - info->CRT1frameY0 = info->CRT1YOffs; - temp1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay; - /*temp2 = pScrn1->virtualY - info->CRT2YOffs;*/ - temp2 = min((VVirt - CRT2YOffs), (CRT1YOffs + info->MBXNR1YMAX)); - if(temp1 > temp2) - info->CRT1frameY0 -= (temp1 - temp2); - } - if(pScrn2->frameY0 != old2y0) { - if(pScrn2->frameY0 < info->CRT2YOffs) - pScrn2->frameY0 = info->CRT2YOffs; - temp1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay; - /*temp2 = pScrn1->virtualY - info->CRT1YOffs;*/ - temp2 = min((VVirt - CRT1YOffs), (CRT2YOffs + info->MBXNR2YMAX)); - if(temp1 > temp2) - pScrn2->frameY0 -= (temp1 - temp2); - } - } - break; - case radeonBelow: - case radeonAbove: - if(info->CRT1XOffs || info->CRT2XOffs || HaveNonRect) { - if(info->CRT1frameX0 != old1x0) { - if(info->CRT1frameX0 < info->CRT1XOffs) - info->CRT1frameX0 = info->CRT1XOffs; - temp1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay; - /*temp2 = pScrn1->virtualX - info->CRT2XOffs;*/ - temp2 = min((HVirt - CRT2XOffs), (CRT1XOffs + info->MBXNR1XMAX)); - if(temp1 > temp2) - info->CRT1frameX0 -= (temp1 - temp2); - } - if(pScrn2->frameX0 != old2x0) { - if(pScrn2->frameX0 < info->CRT2XOffs) - pScrn2->frameX0 = info->CRT2XOffs; - temp1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay; - /*temp2 = pScrn1->virtualX - info->CRT1XOffs;*/ - temp2 = min((HVirt - CRT1XOffs), (CRT2XOffs + info->MBXNR2XMAX)); - if(temp1 > temp2) - pScrn2->frameX0 -= (temp1 - temp2); - } - } - break; - case radeonClone: - break; - } - - info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; - info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; - pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; - pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; -#if 0 - pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; - pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; -#endif - - RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); - RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); - } -} - -static void -RADEONAdjustFrameMergedHelper(int scrnIndex, int x, int y, int flags) -{ - ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; - RADEONInfoPtr info = RADEONPTR(pScrn1); - ScrnInfoPtr pScrn2 = info->CRT2pScrn; - int VTotal = info->CurrentLayout.mode->VDisplay; - int HTotal = info->CurrentLayout.mode->HDisplay; - int VMax = VTotal; - int HMax = HTotal; - int HVirt = pScrn1->virtualX; - int VVirt = pScrn1->virtualY; - int x1 = x, x2 = x; - int y1 = y, y2 = y; - int CRT1XOffs = 0, CRT1YOffs = 0, CRT2XOffs = 0, CRT2YOffs = 0; - int MBXNR1XMAX = 65536, MBXNR1YMAX = 65536, MBXNR2XMAX = 65536, MBXNR2YMAX = 65536; - - if(info->DGAactive) { - HVirt = info->CurrentLayout.displayWidth; - VVirt = info->CurrentLayout.displayHeight; - } else { - CRT1XOffs = info->CRT1XOffs; - CRT1YOffs = info->CRT1YOffs; - CRT2XOffs = info->CRT2XOffs; - CRT2YOffs = info->CRT2YOffs; - MBXNR1XMAX = info->MBXNR1XMAX; - MBXNR1YMAX = info->MBXNR1YMAX; - MBXNR2XMAX = info->MBXNR2XMAX; - MBXNR2YMAX = info->MBXNR2YMAX; - } - - - BOUND(x, 0, pScrn1->virtualX - HTotal); - BOUND(y, 0, pScrn1->virtualY - VTotal); - if(SDMPTR(pScrn1)->CRT2Position != radeonClone) { -#if 0 - BOUND(x1, info->CRT1XOffs, pScrn1->virtualX - HTotal - info->CRT2XOffs); - BOUND(y1, info->CRT1YOffs, pScrn1->virtualY - VTotal - info->CRT2YOffs); - BOUND(x2, info->CRT2XOffs, pScrn1->virtualX - HTotal - info->CRT1XOffs); - BOUND(y2, info->CRT2YOffs, pScrn1->virtualY - VTotal - info->CRT1YOffs); -#endif - BOUND(x1, CRT1XOffs, min(HVirt, MBXNR1XMAX + CRT1XOffs) - min(HTotal, MBXNR1XMAX) - CRT2XOffs); - BOUND(y1, CRT1YOffs, min(VVirt, MBXNR1YMAX + CRT1YOffs) - min(VTotal, MBXNR1YMAX) - CRT2YOffs); - BOUND(x2, CRT2XOffs, min(HVirt, MBXNR2XMAX + CRT2XOffs) - min(HTotal, MBXNR2XMAX) - CRT1XOffs); - BOUND(y2, CRT2YOffs, min(VVirt, MBXNR2YMAX + CRT2YOffs) - min(VTotal, MBXNR2YMAX) - CRT1YOffs); - } - - switch(SDMPTR(pScrn1)->CRT2Position) { - case radeonLeftOf: - pScrn2->frameX0 = x2; - /*BOUND(pScrn2->frameY0, y2, y2 + VMax - CDMPTR->CRT2->VDisplay);*/ - BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay); - info->CRT1frameX0 = x1 + CDMPTR->CRT2->HDisplay; - /*BOUND(info->CRT1frameY0, y1, y1 + VMax - CDMPTR->CRT1->VDisplay);*/ - BOUND(info->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay); - break; - case radeonRightOf: - info->CRT1frameX0 = x1; - /*BOUND(info->CRT1frameY0, y1, y1 + VMax - CDMPTR->CRT1->VDisplay);*/ - BOUND(info->CRT1frameY0, y1, y1 + min(VMax, MBXNR1YMAX) - CDMPTR->CRT1->VDisplay); - pScrn2->frameX0 = x2 + CDMPTR->CRT1->HDisplay; - /*BOUND(pScrn2->frameY0, y2, y2 + VMax - CDMPTR->CRT2->VDisplay);*/ - BOUND(pScrn2->frameY0, y2, y2 + min(VMax, MBXNR2YMAX) - CDMPTR->CRT2->VDisplay); - break; - case radeonAbove: - /*BOUND(pScrn2->frameX0, x2, x2 + HMax - CDMPTR->CRT2->HDisplay);*/ - BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay); - pScrn2->frameY0 = y2; - /*BOUND(info->CRT1frameX0, x1, x1 + HMax - CDMPTR->CRT1->HDisplay);*/ - BOUND(info->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay); - info->CRT1frameY0 = y1 + CDMPTR->CRT2->VDisplay; - break; - case radeonBelow: - /*BOUND(info->CRT1frameX0, x1, x1 + HMax - CDMPTR->CRT1->HDisplay);*/ - BOUND(info->CRT1frameX0, x1, x1 + min(HMax, MBXNR1XMAX) - CDMPTR->CRT1->HDisplay); - info->CRT1frameY0 = y1; - /*BOUND(pScrn2->frameX0, x2, x2 + HMax - CDMPTR->CRT2->HDisplay);*/ - BOUND(pScrn2->frameX0, x2, x2 + min(HMax, MBXNR2XMAX) - CDMPTR->CRT2->HDisplay); - pScrn2->frameY0 = y2 + CDMPTR->CRT1->VDisplay; - break; - case radeonClone: - BOUND(info->CRT1frameX0, x, x + HMax - CDMPTR->CRT1->HDisplay); - BOUND(info->CRT1frameY0, y, y + VMax - CDMPTR->CRT1->VDisplay); - BOUND(pScrn2->frameX0, x, x + HMax - CDMPTR->CRT2->HDisplay); - BOUND(pScrn2->frameY0, y, y + VMax - CDMPTR->CRT2->VDisplay); - break; - } - - BOUND(info->CRT1frameX0, 0, pScrn1->virtualX - CDMPTR->CRT1->HDisplay); - BOUND(info->CRT1frameY0, 0, pScrn1->virtualY - CDMPTR->CRT1->VDisplay); - BOUND(pScrn2->frameX0, 0, pScrn1->virtualX - CDMPTR->CRT2->HDisplay); - BOUND(pScrn2->frameY0, 0, pScrn1->virtualY - CDMPTR->CRT2->VDisplay); - - pScrn1->frameX0 = x; - pScrn1->frameY0 = y; - - info->CRT1frameX1 = info->CRT1frameX0 + CDMPTR->CRT1->HDisplay - 1; - info->CRT1frameY1 = info->CRT1frameY0 + CDMPTR->CRT1->VDisplay - 1; - pScrn2->frameX1 = pScrn2->frameX0 + CDMPTR->CRT2->HDisplay - 1; - pScrn2->frameY1 = pScrn2->frameY0 + CDMPTR->CRT2->VDisplay - 1; - pScrn1->frameX1 = pScrn1->frameX0 + info->CurrentLayout.mode->HDisplay - 1; - pScrn1->frameY1 = pScrn1->frameY0 + info->CurrentLayout.mode->VDisplay - 1; - - if(SDMPTR(pScrn1)->CRT2Position != radeonClone) { - pScrn1->frameX1 += CRT1XOffs + CRT2XOffs; - pScrn1->frameY1 += CRT1YOffs + CRT2YOffs; - } - -/* - RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); - RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); -*/ -} - -void -RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags) -{ - ScrnInfoPtr pScrn1 = xf86Screens[scrnIndex]; - RADEONInfoPtr info = RADEONPTR(pScrn1); - ScrnInfoPtr pScrn2 = info->CRT2pScrn; - - RADEONAdjustFrameMergedHelper(scrnIndex, x, y, flags); - RADEONDoAdjustFrame(pScrn1, info->CRT1frameX0, info->CRT1frameY0, FALSE); - RADEONDoAdjustFrame(pScrn1, pScrn2->frameX0, pScrn2->frameY0, TRUE); -} - -static void -RADEONMergedFBCalcDPI(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel, Bool quiet) -{ - RADEONInfoPtr info = RADEONPTR(pScrn1); - MessageType from = X_DEFAULT; - xf86MonPtr DDC1 = (xf86MonPtr)(pScrn1->monitor->DDC); - xf86MonPtr DDC2 = (xf86MonPtr)(pScrn2->monitor->DDC); - int ddcWidthmm = 0, ddcHeightmm = 0; - const char *dsstr = "MergedFB: Display dimensions: %dx%d mm\n"; - - /* This sets the DPI for MergedFB mode. The problem is that - * this can never be exact, because the output devices may - * have different dimensions. This function tries to compromise - * through a few assumptions, and it just calculates an average - * DPI value for both monitors. - */ - - /* Copy user-given DisplaySize (which should regard BOTH monitors!) */ - pScrn1->widthmm = pScrn1->monitor->widthmm; - pScrn1->heightmm = pScrn1->monitor->heightmm; - - if(monitorResolution > 0) { - - /* Set command line given values (overrules given options) */ - pScrn1->xDpi = monitorResolution; - pScrn1->yDpi = monitorResolution; - from = X_CMDLINE; - - } else if(info->MergedFBXDPI) { - - /* Set option-wise given values (overrules DisplaySize config option) */ - pScrn1->xDpi = info->MergedFBXDPI; - pScrn1->yDpi = info->MergedFBYDPI; - from = X_CONFIG; - - } else if(pScrn1->widthmm > 0 || pScrn1->heightmm > 0) { - - /* Set values calculated from given DisplaySize */ - from = X_CONFIG; - if(pScrn1->widthmm > 0) { - pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); - } - if(pScrn1->heightmm > 0) { - pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); - } - if(!quiet) { - xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, pScrn1->widthmm, pScrn1->heightmm); - } - - } else if(ddcWidthmm && ddcHeightmm) { - - /* Set values from DDC-provided display size */ - - /* Get DDC display size; if only either CRT1 or CRT2 provided these, - * assume equal dimensions for both, otherwise add dimensions - */ - if( (DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) && - (DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0)) ) { - ddcWidthmm = max(DDC1->features.hsize, DDC2->features.hsize) * 10; - ddcHeightmm = max(DDC1->features.vsize, DDC2->features.vsize) * 10; - switch(srel) { - case radeonLeftOf: - case radeonRightOf: - ddcWidthmm = (DDC1->features.hsize + DDC2->features.hsize) * 10; - break; - case radeonAbove: - case radeonBelow: - ddcHeightmm = (DDC1->features.vsize + DDC2->features.vsize) * 10; - default: - break; - } - } else if(DDC1 && (DDC1->features.hsize > 0 && DDC1->features.vsize > 0)) { - ddcWidthmm = DDC1->features.hsize * 10; - ddcHeightmm = DDC1->features.vsize * 10; - switch(srel) { - case radeonLeftOf: - case radeonRightOf: - ddcWidthmm *= 2; - break; - case radeonAbove: - case radeonBelow: - ddcHeightmm *= 2; - default: - break; - } - } else if(DDC2 && (DDC2->features.hsize > 0 && DDC2->features.vsize > 0) ) { - ddcWidthmm = DDC2->features.hsize * 10; - ddcHeightmm = DDC2->features.vsize * 10; - switch(srel) { - case radeonLeftOf: - case radeonRightOf: - ddcWidthmm *= 2; - break; - case radeonAbove: - case radeonBelow: - ddcHeightmm *= 2; - default: - break; - } - } - - from = X_PROBED; - - if(!quiet) { - xf86DrvMsg(pScrn1->scrnIndex, from, dsstr, ddcWidthmm, ddcHeightmm); - } - - pScrn1->widthmm = ddcWidthmm; - pScrn1->heightmm = ddcHeightmm; - if(pScrn1->widthmm > 0) { - pScrn1->xDpi = (int)((double)pScrn1->virtualX * 25.4 / pScrn1->widthmm); - } - if(pScrn1->heightmm > 0) { - pScrn1->yDpi = (int)((double)pScrn1->virtualY * 25.4 / pScrn1->heightmm); - } - - } else { - - pScrn1->xDpi = pScrn1->yDpi = DEFAULT_DPI; - - } - - /* Sanity check */ - if(pScrn1->xDpi > 0 && pScrn1->yDpi <= 0) - pScrn1->yDpi = pScrn1->xDpi; - if(pScrn1->yDpi > 0 && pScrn1->xDpi <= 0) - pScrn1->xDpi = pScrn1->yDpi; - - pScrn2->xDpi = pScrn1->xDpi; - pScrn2->yDpi = pScrn1->yDpi; - - if(!quiet) { - xf86DrvMsg(pScrn1->scrnIndex, from, "MergedFB: DPI set to (%d, %d)\n", - pScrn1->xDpi, pScrn1->yDpi); - } -} - - -void -RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel) -{ - RADEONInfoPtr info = RADEONPTR(pScrn1); - - RADEONMergedFBCalcDPI(pScrn1, pScrn2, srel, FALSE); - - info->MergedDPISRel = srel; - info->RADEONMergedDPIVX = pScrn1->virtualX; - info->RADEONMergedDPIVY = pScrn1->virtualY; - -} - -void -RADEONMergedFBResetDpi(ScrnInfoPtr pScrn, Bool force) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex]; - RADEONScrn2Rel srel = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; - - /* This does the same calculation for the DPI as - * the initial run. This means that an eventually - * given -dpi command line switch will lead to - * constant dpi values, regardless of the virtual - * screen size. - * I consider this consequent. If this is undesired, - * one should use the DisplaySize parameter in the - * config file instead of the command line switch. - * The DPI will be calculated then. - */ - - if(force || - (info->MergedDPISRel != srel) || - (info->RADEONMergedDPIVX != pScrn->virtualX) || - (info->RADEONMergedDPIVY != pScrn->virtualY) - ) { - - RADEONMergedFBCalcDPI(pScrn, info->CRT2pScrn, srel, TRUE); - - pScreen->mmWidth = (pScrn->virtualX * 254 + pScrn->xDpi * 5) / (pScrn->xDpi * 10); - pScreen->mmHeight = (pScrn->virtualY * 254 + pScrn->yDpi * 5) / (pScrn->yDpi * 10); - - info->MergedDPISRel = srel; - info->RADEONMergedDPIVX = pScrn->virtualX; - info->RADEONMergedDPIVY = pScrn->virtualY; - - } -} - -/* radeon cursor helpers */ -static void -RADEONChooseCursorCRTC(ScrnInfoPtr pScrn1, int x, int y) -{ - RADEONInfoPtr info = RADEONPTR(pScrn1); - unsigned char *RADEONMMIO = info->MMIO; - RADEONScrn2Rel srel = - ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; - ScrnInfoPtr pScrn2 = info->CRT2pScrn; - - if (srel == radeonClone) { - /* show cursor 2 */ - OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, - ~RADEON_CRTC2_CUR_EN); - /* show cursor 1 */ - OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, - ~RADEON_CRTC_CUR_EN); - } - else { - if (((x >= pScrn1->frameX0) && (x <= pScrn1->frameX1)) && - ((y >= pScrn1->frameY0) && (y <= pScrn1->frameY1))) { - /* hide cursor 2 */ - OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN); - /* show cursor 1 */ - OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN, - ~RADEON_CRTC_CUR_EN); - } - if (((x >= pScrn2->frameX0) && (x <= pScrn2->frameX1)) && - ((y >= pScrn2->frameY0) && (y <= pScrn2->frameY1))) { - /* hide cursor 1 */ - OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN); - /* show cursor 2 */ - OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN, - ~RADEON_CRTC2_CUR_EN); - } - } -} - -void -RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - unsigned char *RADEONMMIO = info->MMIO; - xf86CursorInfoPtr cursor = info->cursor; - int xorigin = 0; - int yorigin = 0; - int stride = 256; - ScrnInfoPtr pScrn2 = info->CRT2pScrn; - DisplayModePtr mode1 = CDMPTR->CRT1; - DisplayModePtr mode2 = CDMPTR->CRT2; - int x1, y1, x2, y2; - int total_y1 = pScrn->frameY1 - pScrn->frameY0; - int total_y2 = pScrn2->frameY1 - pScrn2->frameY0; - - if (x < 0) xorigin = -x+1; - if (y < 0) yorigin = -y+1; - /* if (y > total_y) y = total_y; */ - if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1; - if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1; - - x += pScrn->frameX0; - y += pScrn->frameY0; - - x1 = x - info->CRT1frameX0; - y1 = y - info->CRT1frameY0; - - x2 = x - pScrn2->frameX0; - y2 = y - pScrn2->frameY0; - - if (y1 > total_y1) - y1 = total_y1; - if (y2 > total_y2) - y2 = total_y2; - - if(mode1->Flags & V_INTERLACE) - y1 /= 2; - else if(mode1->Flags & V_DBLSCAN) - y1 *= 2; - - if(mode2->Flags & V_INTERLACE) - y2 /= 2; - else if(mode2->Flags & V_DBLSCAN) - y2 *= 2; - - if (x < 0) - x = 0; - if (y < 0) - y = 0; - - RADEONChooseCursorCRTC(pScrn, x, y); - - /* cursor1 */ - OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK - | (xorigin << 16) - | yorigin)); - OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK - | ((xorigin ? 0 : x1) << 16) - | (yorigin ? 0 : y1))); - OUTREG(RADEON_CUR_OFFSET, info->cursor_offset + yorigin * stride); - /* cursor2 */ - OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK - | (xorigin << 16) - | yorigin)); - OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK - | ((xorigin ? 0 : x2) << 16) - | (yorigin ? 0 : y2))); - OUTREG(RADEON_CUR2_OFFSET, info->cursor_offset + yorigin * stride); -} - -/* radeon Xv helpers */ - -/* choose the crtc for the overlay for mergedfb based on the location - of the output window and the orientation of the crtcs */ - -void -RADEONChooseOverlayCRTC( - ScrnInfoPtr pScrn, - BoxPtr dstBox -) { - RADEONInfoPtr info = RADEONPTR(pScrn); - RADEONScrn2Rel srel = - ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; - - if (srel == radeonLeftOf) { - if (dstBox->x1 >= info->CRT2pScrn->frameX1) - info->OverlayOnCRTC2 = FALSE; - else - info->OverlayOnCRTC2 = TRUE; - } - if (srel == radeonRightOf) { - if (dstBox->x2 <= info->CRT2pScrn->frameX0) - info->OverlayOnCRTC2 = FALSE; - else - info->OverlayOnCRTC2 = TRUE; - } - if (srel == radeonAbove) { - if (dstBox->y1 >= info->CRT2pScrn->frameY1) - info->OverlayOnCRTC2 = FALSE; - else - info->OverlayOnCRTC2 = TRUE; - } - if (srel == radeonBelow) { - if (dstBox->y2 <= info->CRT2pScrn->frameY0) - info->OverlayOnCRTC2 = FALSE; - else - info->OverlayOnCRTC2 = TRUE; - } -} diff --git a/src/radeon_mergedfb.h b/src/radeon_mergedfb.h deleted file mode 100644 index d9bcc03..0000000 --- a/src/radeon_mergedfb.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2003 Alex Deucher. - * - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL ALEX DEUCHER, OR ANY OTHER - * CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -/* - * Authors: - * Alex Deucher <agd5f@yahoo.com> - * - */ - -#ifndef _RADEON_MERGEDFB_H_ -#define _RADEON_MERGEDFB_H_ - -#include "xf86.h" - -#include "radeon.h" - -#if 0 - /* Psuedo Xinerama support */ -#define NEED_REPLIES /* ? */ -#define EXTENSION_PROC_ARGS void * -#include "extnsionst.h" /* required */ -#include <X11/extensions/panoramiXproto.h> /* required */ -#define RADEON_XINERAMA_MAJOR_VERSION 1 -#define RADEON_XINERAMA_MINOR_VERSION 1 - -/* needed for pseudo-xinerama by radeon_driver.c */ -Bool RADEONnoPanoramiXExtension = TRUE; - -/* Relative merge position */ -typedef enum { - radeonLeftOf, - radeonRightOf, - radeonAbove, - radeonBelow, - radeonClone -} RADEONScrn2Rel; -#endif - -#define SDMPTR(x) ((RADEONMergedDisplayModePtr)(x->currentMode->Private)) -#define CDMPTR ((RADEONMergedDisplayModePtr)(info->CurrentLayout.mode->Private)) - -#define BOUND(test,low,hi) { \ - if(test < low) test = low; \ - if(test > hi) test = hi; } - -#define REBOUND(low,hi,test) { \ - if(test < low) { \ - hi += test-low; \ - low = test; } \ - if(test > hi) { \ - low += test-hi; \ - hi = test; } } - -typedef struct _MergedDisplayModeRec { - DisplayModePtr CRT1; - DisplayModePtr CRT2; - RADEONScrn2Rel CRT2Position; -} RADEONMergedDisplayModeRec, *RADEONMergedDisplayModePtr; - -typedef struct _RADEONXineramaData { - int x; - int y; - int width; - int height; -} RADEONXineramaData; - -/* needed by radeon_driver.c */ -extern void -RADEONAdjustFrameMerged(int scrnIndex, int x, int y, int flags); -extern void -RADEONMergePointerMoved(int scrnIndex, int x, int y); -extern DisplayModePtr -RADEONGenerateModeList(ScrnInfoPtr pScrn, char* str, - DisplayModePtr i, DisplayModePtr j, - RADEONScrn2Rel srel); -extern int -RADEONStrToRanges(range *r, char *s, int max); -extern void -RADEONXineramaExtensionInit(ScrnInfoPtr pScrn); -extern void -RADEONUpdateXineramaScreenInfo(ScrnInfoPtr pScrn1); -extern void -RADEONMergedFBSetDpi(ScrnInfoPtr pScrn1, ScrnInfoPtr pScrn2, RADEONScrn2Rel srel); -extern void -RADEONMergedFBResetDpi(ScrnInfoPtr pScrn, Bool force); -extern void -RADEONRecalcDefaultVirtualSize(ScrnInfoPtr pScrn); - -/* needed by radeon_cursor.c */ -extern void -RADEONSetCursorPositionMerged(ScrnInfoPtr pScrn, int x, int y); - -/* needed by radeon_video.c */ -extern void -RADEONChooseOverlayCRTC(ScrnInfoPtr, BoxPtr); - -#endif /* _RADEON_MERGEDFB_H_ */ diff --git a/src/radeon_modes.c b/src/radeon_modes.c index e1635e0..a5e1cc4 100644 --- a/src/radeon_modes.c +++ b/src/radeon_modes.c @@ -42,86 +42,18 @@ #include "xf86.h" /* Driver data structures */ +#include "randrstr.h" +#include "radeon_probe.h" #include "radeon.h" #include "radeon_reg.h" #include "radeon_macros.h" -#include "radeon_probe.h" + #include "radeon_version.h" +#include "xf86Modes.h" /* DDC support */ #include "xf86DDC.h" - -/* Established timings from EDID standard */ -static struct -{ - int hsize; - int vsize; - int refresh; -} est_timings[] = { - {1280, 1024, 75}, - {1024, 768, 75}, - {1024, 768, 70}, - {1024, 768, 60}, - {1024, 768, 87}, - {832, 624, 75}, - {800, 600, 75}, - {800, 600, 72}, - {800, 600, 60}, - {800, 600, 56}, - {640, 480, 75}, - {640, 480, 72}, - {640, 480, 67}, - {640, 480, 60}, - {720, 400, 88}, - {720, 400, 70}, -}; - -/* This function will sort all modes according to their resolution. - * Highest resolution first. - */ -static void RADEONSortModes(DisplayModePtr *new, DisplayModePtr *first, - DisplayModePtr *last) -{ - DisplayModePtr p; - - p = *last; - while (p) { - if (((*new)->HDisplay < p->HDisplay) || - (((*new)->HDisplay == p->HDisplay) && - ((*new)->VDisplay < p->VDisplay)) || - (((*new)->HDisplay == p->HDisplay) && - ((*new)->VDisplay == p->VDisplay) && - ((*new)->type < p->type) && - !(((*new)->type == M_T_USERDEF) || (!(*new)->type))) || - (((*new)->HDisplay == p->HDisplay) && - ((*new)->VDisplay == p->VDisplay) && - ((*new)->type == p->type) && - ((*new)->Clock < p->Clock))) { - - if (p->next) p->next->prev = *new; - (*new)->prev = p; - (*new)->next = p->next; - p->next = *new; - if (!((*new)->next)) *last = *new; - break; - } - if (!p->prev) { - (*new)->prev = NULL; - (*new)->next = p; - p->prev = *new; - *first = *new; - break; - } - p = p->prev; - } - - if (!*first) { - *first = *new; - (*new)->prev = NULL; - (*new)->next = NULL; - *last = *new; - } -} +#include <randrstr.h> void RADEONSetPitch (ScrnInfoPtr pScrn) { @@ -142,350 +74,61 @@ void RADEONSetPitch (ScrnInfoPtr pScrn) break; } pScrn->displayWidth = dummy; -} - -/* When no mode provided in config file, this will add all modes supported in - * DDC date the pScrn->modes list - */ -static DisplayModePtr RADEONDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) -{ - DisplayModePtr p; - DisplayModePtr last = NULL; - DisplayModePtr new = NULL; - DisplayModePtr first = NULL; - int count = 0; - int j, tmp; - char stmp[32]; - - /* Go thru detailed timing table first */ - for (j = 0; j < 4; j++) { - if (ddc->det_mon[j].type == 0) { - struct detailed_timings *d_timings = - &ddc->det_mon[j].section.d_timings; - - if (d_timings->h_active == 0 || d_timings->v_active == 0) break; - - new = xnfcalloc(1, sizeof (DisplayModeRec)); - memset(new, 0, sizeof (DisplayModeRec)); - - new->HDisplay = d_timings->h_active; - new->VDisplay = d_timings->v_active; - - sprintf(stmp, "%dx%d", new->HDisplay, new->VDisplay); - new->name = xnfalloc(strlen(stmp) + 1); - strcpy(new->name, stmp); - - new->HTotal = new->HDisplay + d_timings->h_blanking; - new->HSyncStart = new->HDisplay + d_timings->h_sync_off; - new->HSyncEnd = new->HSyncStart + d_timings->h_sync_width; - new->VTotal = new->VDisplay + d_timings->v_blanking; - new->VSyncStart = new->VDisplay + d_timings->v_sync_off; - new->VSyncEnd = new->VSyncStart + d_timings->v_sync_width; - new->Clock = d_timings->clock / 1000; - new->Flags = (d_timings->interlaced ? V_INTERLACE : 0); - new->status = MODE_OK; -#ifdef M_T_PREFERRED - if (PREFERRED_TIMING_MODE(ddc->features.msc)) - new->type |= M_T_PREFERRED; -#endif -#ifdef M_T_DRIVER - new->type |= M_T_DRIVER; -#endif - - switch (d_timings->misc) { - case 0: new->Flags |= V_NHSYNC | V_NVSYNC; break; - case 1: new->Flags |= V_PHSYNC | V_NVSYNC; break; - case 2: new->Flags |= V_NHSYNC | V_PVSYNC; break; - case 3: new->Flags |= V_PHSYNC | V_PVSYNC; break; - } - count++; + info->CurrentLayout.displayWidth = pScrn->displayWidth; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Valid Mode from Detailed timing table: %s\n", - new->name); - - RADEONSortModes(&new, &first, &last); - } - } - - /* Search thru standard VESA modes from EDID */ - for (j = 0; j < 8; j++) { - if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0) - continue; - for (p = pScrn->monitor->Modes; p; p = p->next) { - /* Ignore all double scan modes */ - if (p->Flags & V_DBLSCAN) - continue; - if ((ddc->timings2[j].hsize == p->HDisplay) && - (ddc->timings2[j].vsize == p->VDisplay)) { - float refresh = - (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; - - if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { - /* Is this good enough? */ - new = xnfcalloc(1, sizeof (DisplayModeRec)); - memcpy(new, p, sizeof(DisplayModeRec)); - new->name = xnfalloc(strlen(p->name) + 1); - strcpy(new->name, p->name); - new->status = MODE_OK; - if ((new->type != M_T_USERDEF) && (new->type)) - new->type = M_T_DEFAULT; - - count++; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Valid Mode from standard timing table: %s\n", - new->name); - - RADEONSortModes(&new, &first, &last); - break; - } - } - } - } - - /* Search thru established modes from EDID */ - tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2; - for (j = 0; j < 16; j++) { - if (tmp & (1 << j)) { - for (p = pScrn->monitor->Modes; p; p = p->next) { - /* Ignore all double scan modes */ - if (p->Flags & V_DBLSCAN) - continue; - if ((est_timings[j].hsize == p->HDisplay) && - (est_timings[j].vsize == p->VDisplay)) { - float refresh = - (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; - - if (abs((float)est_timings[j].refresh - refresh) < 1.0) { - /* Is this good enough? */ - new = xnfcalloc(1, sizeof (DisplayModeRec)); - memcpy(new, p, sizeof(DisplayModeRec)); - new->name = xnfalloc(strlen(p->name) + 1); - strcpy(new->name, p->name); - new->status = MODE_OK; - if ((new->type != M_T_USERDEF) && (new->type)) - new->type = M_T_DEFAULT; - - count++; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Valid Mode from established timing " - "table: %s\n", new->name); - - RADEONSortModes(&new, &first, &last); - break; - } - } - } - } - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Total of %d mode(s) found.\n", count); - - return first; } -/* XFree86's xf86ValidateModes routine doesn't work well with DDC modes, - * so here is our own validation routine. - */ -int RADEONValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName, - RADEONMonitorType DisplayType, int crtc2) +static DisplayModePtr RADEONTVModes(xf86OutputPtr output) { - RADEONInfoPtr info = RADEONPTR(pScrn1); - DisplayModePtr p; - DisplayModePtr last = NULL; - DisplayModePtr first = NULL; - DisplayModePtr ddcModes = NULL; - int count = 0; - int maxXRes = 0; - int maxYRes = 0; - int i, width, height; - ScrnInfoPtr pScrn = pScrn1; - - if (crtc2) - pScrn = info->CRT2pScrn; - - pScrn->virtualX = pScrn1->display->virtualX; - pScrn->virtualY = pScrn1->display->virtualY; - - if (pScrn->monitor->DDC) { - int maxVirtX = pScrn->virtualX; - int maxVirtY = pScrn->virtualY; + DisplayModePtr new = NULL; - /* Collect all of the DDC modes */ - first = last = ddcModes = RADEONDDCModes(pScrn, pScrn->monitor->DDC); + /* just a place holder */ + new = xf86CVTMode(800, 600, 60.00, FALSE, FALSE); + new->type = M_T_DRIVER | M_T_PREFERRED; - for (p = ddcModes; p; p = p->next) { - - /* If primary head is a flat panel, use RMX by default */ - if ((!info->IsSecondary && DisplayType != MT_CRT) && - (!info->ddc_mode) && (!crtc2)) { - /* These values are effective values after expansion. - * They are not really used to set CRTC registers. - */ - p->HTotal = info->PanelXRes + info->HBlank; - p->HSyncStart = info->PanelXRes + info->HOverPlus; - p->HSyncEnd = p->HSyncStart + info->HSyncWidth; - p->VTotal = info->PanelYRes + info->VBlank; - p->VSyncStart = info->PanelYRes + info->VOverPlus; - p->VSyncEnd = p->VSyncStart + info->VSyncWidth; - p->Clock = info->DotClock; - - p->Flags |= RADEON_USE_RMX; - } - - maxXRes = maxVirtX = MAX(maxVirtX, p->HDisplay); - maxYRes = maxVirtY = MAX(maxVirtY, p->VDisplay); - count++; - - last = p; - } - - /* Match up modes that are specified in the XF86Config file */ - if (ppModeName[0]) { - DisplayModePtr next; - - /* Reset the max virtual dimensions */ - maxVirtX = pScrn->virtualX; - maxVirtY = pScrn->virtualY; - - /* Reset list */ - first = last = NULL; - - for (i = 0; ppModeName[i]; i++) { - /* FIXME: Use HDisplay and VDisplay instead of mode string */ - if (sscanf(ppModeName[i], "%dx%d", &width, &height) == 2) { - for (p = ddcModes; p; p = next) { - next = p->next; - - if (p->HDisplay == width && p->VDisplay == height) { - /* We found a DDC mode that matches the one - requested in the XF86Config file */ - p->type |= M_T_USERDEF; - - /* Update the max virtual setttings */ - maxVirtX = MAX(maxVirtX, width); - maxVirtY = MAX(maxVirtY, height); - - /* Unhook from DDC modes */ - if (p->prev) p->prev->next = p->next; - if (p->next) p->next->prev = p->prev; - if (p == ddcModes) ddcModes = p->next; - - /* Add to used modes */ - RADEONSortModes(&p, &first, &last); - - break; - } - } - if (!p) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - " %dx%d is not supported by the device\n", - width, height); - } - } - } - /* just for sanity check, if maxVirtX and maxVirtY are not - * specified, set max resolution that panel support for the max - * virtual dimensions */ - if ((!maxVirtX) || (!maxVirtY)) { - maxVirtX = maxXRes; - maxVirtY = maxYRes; - } - - /* - * Add remaining DDC modes if they're smaller than the user - * specified modes - */ - for (p = ddcModes; p; p = next) { - next = p->next; - if (p->HDisplay <= maxVirtX && p->VDisplay <= maxVirtY) { - /* Unhook from DDC modes */ - if (p->prev) p->prev->next = p->next; - if (p->next) p->next->prev = p->prev; - if (p == ddcModes) ddcModes = p->next; - - /* Add to used modes */ - RADEONSortModes(&p, &first, &last); - } - } - - /* Delete unused modes */ - while (ddcModes) - xf86DeleteMode(&ddcModes, ddcModes); - } else { - /* - * No modes were configured, so we make the DDC modes - * available for the user to cycle through. - */ - for (p = ddcModes; p; p = p->next) - p->type |= M_T_USERDEF; - } - - if (crtc2) { - pScrn->virtualX = maxVirtX; - pScrn->virtualY = maxVirtY; - } else { - pScrn->virtualX = pScrn->display->virtualX = maxVirtX; - pScrn->virtualY = pScrn->display->virtualY = maxVirtY; - } - } - - /* Close the doubly-linked mode list, if we found any usable modes */ - if (last) { - last->next = first; - first->prev = last; - pScrn->modes = first; - RADEONSetPitch(pScrn); - } - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Total number of valid DDC mode(s) found: %d\n", count); - - return count; + return new; } /* This is used only when no mode is specified for FP and no ddc is * available. We force it to native mode, if possible. */ -static DisplayModePtr RADEONFPNativeMode(ScrnInfoPtr pScrn) +static DisplayModePtr RADEONFPNativeMode(xf86OutputPtr output) { - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = output->scrn; + RADEONOutputPrivatePtr radeon_output = output->driver_private; DisplayModePtr new = NULL; char stmp[32]; - if (info->PanelXRes != 0 && - info->PanelYRes != 0 && - info->DotClock != 0) { + if (radeon_output->PanelXRes != 0 && + radeon_output->PanelYRes != 0 && + radeon_output->DotClock != 0) { /* Add native panel size */ new = xnfcalloc(1, sizeof (DisplayModeRec)); - sprintf(stmp, "%dx%d", info->PanelXRes, info->PanelYRes); + sprintf(stmp, "%dx%d", radeon_output->PanelXRes, radeon_output->PanelYRes); new->name = xnfalloc(strlen(stmp) + 1); strcpy(new->name, stmp); - new->HDisplay = info->PanelXRes; - new->VDisplay = info->PanelYRes; + new->HDisplay = radeon_output->PanelXRes; + new->VDisplay = radeon_output->PanelYRes; - new->HTotal = new->HDisplay + info->HBlank; - new->HSyncStart = new->HDisplay + info->HOverPlus; - new->HSyncEnd = new->HSyncStart + info->HSyncWidth; - new->VTotal = new->VDisplay + info->VBlank; - new->VSyncStart = new->VDisplay + info->VOverPlus; - new->VSyncEnd = new->VSyncStart + info->VSyncWidth; + new->HTotal = new->HDisplay + radeon_output->HBlank; + new->HSyncStart = new->HDisplay + radeon_output->HOverPlus; + new->HSyncEnd = new->HSyncStart + radeon_output->HSyncWidth; + new->VTotal = new->VDisplay + radeon_output->VBlank; + new->VSyncStart = new->VDisplay + radeon_output->VOverPlus; + new->VSyncEnd = new->VSyncStart + radeon_output->VSyncWidth; - new->Clock = info->DotClock; + new->Clock = radeon_output->DotClock; new->Flags = 0; - new->type = M_T_USERDEF; + new->type = M_T_USERDEF | M_T_PREFERRED; new->next = NULL; new->prev = NULL; pScrn->display->virtualX = - pScrn->virtualX = MAX(pScrn->virtualX, info->PanelXRes); + pScrn->virtualX = MAX(pScrn->virtualX, radeon_output->PanelXRes); pScrn->display->virtualY = - pScrn->virtualY = MAX(pScrn->virtualY, info->PanelYRes); + pScrn->virtualY = MAX(pScrn->virtualY, radeon_output->PanelYRes); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No valid mode specified, force to native mode\n"); @@ -496,9 +139,10 @@ static DisplayModePtr RADEONFPNativeMode(ScrnInfoPtr pScrn) /* FP mode initialization routine for using on-chip RMX to scale */ -int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) +int RADEONValidateFPModes(xf86OutputPtr output, char **ppModeName, DisplayModePtr *modeList) { - RADEONInfoPtr info = RADEONPTR(pScrn); + ScrnInfoPtr pScrn = output->scrn; + RADEONOutputPrivatePtr radeon_output = output->driver_private; DisplayModePtr last = NULL; DisplayModePtr new = NULL; DisplayModePtr first = NULL; @@ -521,13 +165,13 @@ int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) * need the internal RMX unit in the video chips (and there is * only one per card), this will only apply to the primary head. */ - if (width < 320 || width > info->PanelXRes || - height < 200 || height > info->PanelYRes) { + if (width < 320 || width > radeon_output->PanelXRes || + height < 200 || height > radeon_output->PanelYRes) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Mode %s is out of range.\n", ppModeName[i]); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Valid modes must be between 320x200-%dx%d\n", - info->PanelXRes, info->PanelYRes); + radeon_output->PanelXRes, radeon_output->PanelYRes); continue; } @@ -540,23 +184,28 @@ int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) /* These values are effective values after expansion They are * not really used to set CRTC registers. */ - new->HTotal = info->PanelXRes + info->HBlank; - new->HSyncStart = info->PanelXRes + info->HOverPlus; - new->HSyncEnd = new->HSyncStart + info->HSyncWidth; - new->VTotal = info->PanelYRes + info->VBlank; - new->VSyncStart = info->PanelYRes + info->VOverPlus; - new->VSyncEnd = new->VSyncStart + info->VSyncWidth; - new->Clock = info->DotClock; + new->HTotal = radeon_output->PanelXRes + radeon_output->HBlank; + new->HSyncStart = radeon_output->PanelXRes + radeon_output->HOverPlus; + new->HSyncEnd = new->HSyncStart + radeon_output->HSyncWidth; + new->VTotal = radeon_output->PanelYRes + radeon_output->VBlank; + new->VSyncStart = radeon_output->PanelYRes + radeon_output->VOverPlus; + new->VSyncEnd = new->VSyncStart + radeon_output->VSyncWidth; + new->Clock = radeon_output->DotClock; new->Flags |= RADEON_USE_RMX; #ifdef M_T_PREFERRED - if (width == info->PanelXRes && height == info->PanelYRes) + if (width == radeon_output->PanelXRes && height == radeon_output->PanelYRes) new->type |= M_T_PREFERRED; #endif new->type |= M_T_USERDEF; - RADEONSortModes(&new, &first, &last); + new->next = NULL; + new->prev = last; + + if (last) last->next = new; + last = new; + if (!first) first = new; pScrn->display->virtualX = pScrn->virtualX = MAX(pScrn->virtualX, width); @@ -569,13 +218,13 @@ int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) /* If all else fails, add the native mode */ if (!count) { - first = last = RADEONFPNativeMode(pScrn); + first = last = RADEONFPNativeMode(output); if (first) count = 1; } /* add in all default vesa modes smaller than panel size, used for randr*/ - for (p = pScrn->monitor->Modes; p; p = p->next) { - if ((p->HDisplay <= info->PanelXRes) && (p->VDisplay <= info->PanelYRes)) { + for (p = *modeList; p && p->next; p = p->next->next) { + if ((p->HDisplay <= radeon_output->PanelXRes) && (p->VDisplay <= radeon_output->PanelYRes)) { tmp = first; while (tmp) { if ((p->HDisplay == tmp->HDisplay) && (p->VDisplay == tmp->VDisplay)) break; @@ -591,28 +240,30 @@ int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) /* These values are effective values after expansion They are * not really used to set CRTC registers. */ - new->HTotal = info->PanelXRes + info->HBlank; - new->HSyncStart = info->PanelXRes + info->HOverPlus; - new->HSyncEnd = new->HSyncStart + info->HSyncWidth; - new->VTotal = info->PanelYRes + info->VBlank; - new->VSyncStart = info->PanelYRes + info->VOverPlus; - new->VSyncEnd = new->VSyncStart + info->VSyncWidth; - new->Clock = info->DotClock; + new->HTotal = radeon_output->PanelXRes + radeon_output->HBlank; + new->HSyncStart = radeon_output->PanelXRes + radeon_output->HOverPlus; + new->HSyncEnd = new->HSyncStart + radeon_output->HSyncWidth; + new->VTotal = radeon_output->PanelYRes + radeon_output->VBlank; + new->VSyncStart = radeon_output->PanelYRes + radeon_output->VOverPlus; + new->VSyncEnd = new->VSyncStart + radeon_output->VSyncWidth; + new->Clock = radeon_output->DotClock; new->Flags |= RADEON_USE_RMX; new->type |= M_T_DEFAULT; - RADEONSortModes(&new, &first, &last); + if (last) last->next = new; + last = new; + if (!first) first = new; } } } /* Close the doubly-linked mode list, if we found any usable modes */ if (last) { - last->next = first; - first->prev = last; - pScrn->modes = first; - RADEONSetPitch(pScrn); + last->next = NULL; //first; + first->prev = NULL; //last; + *modeList = first; + //RADEONSetPitch(pScrn); } xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -621,164 +272,66 @@ int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) return count; } - -int RADEONValidateMergeModes(ScrnInfoPtr pScrn1) +DisplayModePtr +RADEONProbeOutputModes(xf86OutputPtr output) { - RADEONInfoPtr info = RADEONPTR(pScrn1); - ClockRangePtr clockRanges; - int modesFound; - ScrnInfoPtr pScrn = info->CRT2pScrn; - - /* fill in pScrn2 */ - pScrn->videoRam = pScrn1->videoRam; - pScrn->depth = pScrn1->depth; - pScrn->numClocks = pScrn1->numClocks; - pScrn->progClock = pScrn1->progClock; - pScrn->fbFormat = pScrn1->fbFormat; - pScrn->videoRam = pScrn1->videoRam; - pScrn->maxHValue = pScrn1->maxHValue; - pScrn->maxVValue = pScrn1->maxVValue; - pScrn->xInc = pScrn1->xInc; - - if (info->NoVirtual) { - pScrn1->display->virtualX = 0; - pScrn1->display->virtualY = 0; - } - - if (pScrn->monitor->DDC) { - /* If we still don't know sync range yet, let's try EDID. - * - * Note that, since we can have dual heads, Xconfigurator - * may not be able to probe both monitors correctly through - * vbe probe function (RADEONProbeDDC). Here we provide an - * additional way to auto-detect sync ranges if they haven't - * been added to XF86Config manually. - */ - if (pScrn->monitor->nHsync <= 0) - RADEONSetSyncRangeFromEdid(pScrn, 1); - if (pScrn->monitor->nVrefresh <= 0) - RADEONSetSyncRangeFromEdid(pScrn, 0); - } - - /* Get mode information */ - pScrn->progClock = TRUE; - clockRanges = xnfcalloc(sizeof(*clockRanges), 1); - clockRanges->next = NULL; - clockRanges->minClock = info->pll.min_pll_freq; - clockRanges->maxClock = info->pll.max_pll_freq * 10; - clockRanges->clockIndex = -1; - clockRanges->interlaceAllowed = (info->MergeType == MT_CRT); - clockRanges->doubleScanAllowed = (info->MergeType == MT_CRT); - - /* We'll use our own mode validation routine for DFP/LCD, since - * xf86ValidateModes does not work correctly with the DFP/LCD modes - * 'stretched' from their native mode. - */ - if (info->MergeType == MT_CRT && !info->ddc_mode) { - xf86SetDDCproperties(pScrn, pScrn->monitor->DDC); - modesFound = - xf86ValidateModes(pScrn, - pScrn->monitor->Modes, - pScrn1->display->modes, - clockRanges, - NULL, /* linePitches */ - 8 * 64, /* minPitch */ - 8 * 1024, /* maxPitch */ - info->allowColorTiling ? 2048 : - 64 * pScrn1->bitsPerPixel, /* pitchInc */ - 128, /* minHeight */ - info->MaxLines, /* maxHeight */ - pScrn1->display->virtualX ? pScrn1->virtualX : 0, - pScrn1->display->virtualY ? pScrn1->virtualY : 0, - info->FbMapSize, - LOOKUP_BEST_REFRESH); - - if (modesFound == -1) return 0; - - xf86PruneDriverModes(pScrn); - if (!modesFound || !pScrn->modes) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); - return 0; - } - - } else { - /* First, free any allocated modes during configuration, since - * we don't need them - */ - while (pScrn->modes) - xf86DeleteMode(&pScrn->modes, pScrn->modes); - while (pScrn->modePool) - xf86DeleteMode(&pScrn->modePool, pScrn->modePool); + ScrnInfoPtr pScrn = output->scrn; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + DisplayModePtr mode; + xf86MonPtr edid_mon; + DisplayModePtr modes = NULL; + +#if 0 + /* force reprobe */ + radeon_output->MonType = MT_UNKNOWN; + + RADEONConnectorFindMonitor(pScrn, output); +#endif + ErrorF("in RADEONProbeOutputModes\n"); - /* Next try to add DDC modes */ - modesFound = RADEONValidateDDCModes(pScrn, pScrn1->display->modes, - info->MergeType, 1); - /* If that fails and we're connect to a flat panel, then try to - * add the flat panel modes - */ - if (info->MergeType != MT_CRT) { - - /* some panels have DDC, but don't have internal scaler. - * in this case, we need to validate additional modes - * by using on-chip RMX. - */ - int user_modes_asked = 0, user_modes_found = 0, i; - DisplayModePtr tmp_mode = pScrn->modes; - while (pScrn1->display->modes[user_modes_asked]) user_modes_asked++; - if (tmp_mode) { - for (i = 0; i < modesFound; i++) { - if (tmp_mode->type & M_T_USERDEF) user_modes_found++; - tmp_mode = tmp_mode->next; + if (radeon_output->type == OUTPUT_DVI || radeon_output->type == OUTPUT_VGA) { + edid_mon = xf86OutputGetEDID (output, radeon_output->pI2CBus); + xf86OutputSetEDID (output, edid_mon); + + modes = xf86OutputGetEDIDModes (output); + return modes; + } + if (radeon_output->type == OUTPUT_STV || radeon_output->type == OUTPUT_CTV) { + modes = RADEONTVModes(output); + return modes; + } + if (radeon_output->type == OUTPUT_LVDS) { + /* okay we got DDC info */ + if (output->MonInfo) { + /* Debug info for now, at least */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EDID for output %d\n", radeon_output->num); + xf86PrintEDID(output->MonInfo); + + modes = xf86DDCGetModes(pScrn->scrnIndex, output->MonInfo); + + for (mode = modes; mode != NULL; mode = mode->next) { + if (mode->Flags & V_DBLSCAN) { + if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768)) + mode->status = MODE_CLOCK_RANGE; } } - - if ((modesFound <= 1) || (user_modes_found < user_modes_asked)) { - /* when panel size is not valid, try to validate - * mode using xf86ValidateModes routine - * This can happen when DDC is disabled. - */ - /* if (info->PanelXRes < 320 || info->PanelYRes < 200) */ - modesFound = - xf86ValidateModes(pScrn, - pScrn->monitor->Modes, - pScrn1->display->modes, - clockRanges, - NULL, /* linePitches */ - 8 * 64, /* minPitch */ - 8 * 1024, /* maxPitch */ - info->allowColorTiling ? 2048 : - 64 * pScrn1->bitsPerPixel, /* pitchInc */ - 128, /* minHeight */ - info->MaxLines, /* maxHeight */ - pScrn1->display->virtualX, - pScrn1->display->virtualY, - info->FbMapSize, - LOOKUP_BEST_REFRESH); - - } - } - - /* Setup the screen's clockRanges for the VidMode extension */ - if (!pScrn->clockRanges) { - pScrn->clockRanges = xnfcalloc(sizeof(*(pScrn->clockRanges)), 1); - memcpy(pScrn->clockRanges, clockRanges, sizeof(*clockRanges)); - pScrn->clockRanges->strategy = LOOKUP_BEST_REFRESH; + xf86PruneInvalidModes(pScrn, &modes, TRUE); + + /* do some physcial size stuff */ } - - /* Fail if we still don't have any valid modes */ - if (modesFound < 1) { - if (info->MergeType == MT_CRT) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No valid DDC modes found for this CRT\n"); - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Try turning off the \"DDCMode\" option\n"); - } else { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "No valid mode found for this DFP/LCD\n"); - } - return 0; + + if (modes == NULL) { + RADEONValidateFPModes(output, pScrn->display->modes, &modes); } } - return modesFound; + + if (modes) { + xf86ValidateModesUserConfig(pScrn, modes); + xf86PruneInvalidModes(pScrn, &modes, + FALSE); + } + + return modes; } + diff --git a/src/radeon_output.c b/src/radeon_output.c new file mode 100644 index 0000000..73e44f3 --- /dev/null +++ b/src/radeon_output.c @@ -0,0 +1,2569 @@ +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR + * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdio.h> + +/* X and server generic header files */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "fbdevhw.h" +#include "vgaHW.h" +#include "xf86Modes.h" + +/* Driver data structures */ +#include "radeon.h" +#include "radeon_reg.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_version.h" +#include "radeon_tv.h" + + +const char *MonTypeName[7] = { + "AUTO", + "NONE", + "CRT", + "LVDS", + "TMDS", + "CTV", + "STV" +}; + +const RADEONMonitorType MonTypeID[7] = { + MT_UNKNOWN, /* this is just a dummy value for AUTO DETECTION */ + MT_NONE, /* NONE -> NONE */ + MT_CRT, /* CRT -> CRT */ + MT_LCD, /* Laptop LCDs are driven via LVDS port */ + MT_DFP, /* DFPs are driven via TMDS */ + MT_CTV, /* CTV -> CTV */ + MT_STV, /* STV -> STV */ +}; + +const char *TMDSTypeName[4] = { + "Unknown", + "Internal", + "External", + "None" +}; + +const char *DDCTypeName[6] = { + "NONE", + "MONID", + "DVI_DDC", + "VGA_DDC", + "CRT2_DDC", + "LCD_DDC" +}; + +const char *DACTypeName[4] = { + "Unknown", + "Primary", + "TVDAC/ExtDAC", + "None" +}; + +const char *ConnectorTypeName[8] = { + "None", + "Proprietary/LVDS", + "VGA", + "DVI-I", + "DVI-D", + "CTV", + "STV", + "Unsupported" +}; + +const char *ConnectorTypeNameATOM[10] = { + "None", + "VGA", + "DVI-I", + "DVI-D", + "DVI-A", + "STV", + "CTV", + "LVDS", + "Digital", + "Unsupported" +}; + +const char *OutputType[10] = { + "None", + "VGA", + "DVI", + "LVDS", + "S-video", + "Composite", +}; + +static const RADEONTMDSPll default_tmds_pll[CHIP_FAMILY_LAST][4] = +{ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_UNKNOW*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_LEGACY*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RADEON*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV100*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS100*/ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV200*/ + {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS200*/ + {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R200*/ + {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV250*/ + {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS300*/ + {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}}, /*CHIP_FAMILY_RV280*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R300*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R350*/ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV350*/ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV380*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R420*/ + {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV410*/ /* FIXME: just values from r420 used... */ + {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS400*/ /* FIXME: just values from rv380 used... */ +}; + +static RADEONMonitorType RADEONPortCheckNonDDC(ScrnInfoPtr pScrn, xf86OutputPtr output); +static void RADEONUpdatePanelSize(xf86OutputPtr output); +static RADEONMonitorType radeon_detect_tv(ScrnInfoPtr pScrn); +static RADEONMonitorType radeon_detect_primary_dac(ScrnInfoPtr pScrn, Bool color); +static RADEONMonitorType radeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color); +static RADEONMonitorType radeon_detect_ext_dac(ScrnInfoPtr pScrn); + +void RADEONPrintPortMap(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + RADEONOutputPrivatePtr radeon_output; + xf86OutputPtr output; + int o; + + for (o = 0; o < xf86_config->num_output; o++) { + output = xf86_config->output[o]; + radeon_output = output->driver_private; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Port%d:\n Monitor -- %s\n Connector -- %s\n DAC Type -- %s\n TMDS Type -- %s\n DDC Type -- %s\n", + o, + MonTypeName[radeon_output->MonType+1], + info->IsAtomBios ? + ConnectorTypeNameATOM[radeon_output->ConnectorType]: + ConnectorTypeName[radeon_output->ConnectorType], + DACTypeName[radeon_output->DACType+1], + TMDSTypeName[radeon_output->TMDSType+1], + DDCTypeName[radeon_output->DDCType]); + } + +} + +static RADEONMonitorType +RADEONDisplayDDCConnected(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + 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; + + DDCReg = radeon_output->DDCReg; + + /* Read and output monitor info using DDC2 over I2C bus */ + if (radeon_output->pI2CBus && info->ddc2 && (DDCReg != RADEON_LCD_GPIO_MASK)) { + OUTREG(DDCReg, INREG(DDCReg) & + (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1)); + + /* For some old monitors (like Compaq Presario FP500), we need + * following process to initialize/stop DDC + */ + OUTREG(DDCReg, INREG(DDCReg) & ~(RADEON_GPIO_EN_1)); + for (j = 0; j < 3; j++) { + OUTREG(DDCReg, + INREG(DDCReg) & ~(RADEON_GPIO_EN_0)); + usleep(13000); + + OUTREG(DDCReg, + INREG(DDCReg) & ~(RADEON_GPIO_EN_1)); + for (i = 0; i < 10; i++) { + usleep(15000); + if (INREG(DDCReg) & RADEON_GPIO_Y_1) + break; + } + if (i == 10) continue; + + usleep(15000); + + OUTREG(DDCReg, INREG(DDCReg) | RADEON_GPIO_EN_0); + usleep(15000); + + OUTREG(DDCReg, INREG(DDCReg) | RADEON_GPIO_EN_1); + usleep(15000); + OUTREG(DDCReg, + INREG(DDCReg) & ~(RADEON_GPIO_EN_0)); + usleep(15000); + *MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, radeon_output->pI2CBus); + + OUTREG(DDCReg, INREG(DDCReg) | RADEON_GPIO_EN_1); + OUTREG(DDCReg, INREG(DDCReg) | RADEON_GPIO_EN_0); + usleep(15000); + OUTREG(DDCReg, + INREG(DDCReg) & ~(RADEON_GPIO_EN_1)); + for (i = 0; i < 5; i++) { + usleep(15000); + if (INREG(DDCReg) & RADEON_GPIO_Y_1) + break; + } + usleep(15000); + OUTREG(DDCReg, + INREG(DDCReg) & ~(RADEON_GPIO_EN_0)); + usleep(15000); + + OUTREG(DDCReg, INREG(DDCReg) | RADEON_GPIO_EN_1); + OUTREG(DDCReg, INREG(DDCReg) | RADEON_GPIO_EN_0); + usleep(15000); + if(*MonInfo) break; + } + } else if (radeon_output->pI2CBus && info->ddc2 && DDCReg == RADEON_LCD_GPIO_MASK) { + *MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, radeon_output->pI2CBus); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DDC2/I2C is not properly initialized\n"); + MonType = MT_NONE; + } + + OUTREG(DDCReg, INREG(DDCReg) & + ~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1)); + + 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 ((*MonInfo)->rawData[0x14] & 0x80) { /* if it's digital */ + MonType = MT_DFP; + } else { + MonType = MT_CRT; + } + } else MonType = MT_NONE; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DDC Type: %d, Detected Monitor Type: %d\n", DDCType, MonType); + + return MonType; +} + +#if 0 +static RADEONMonitorType +RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + int bConnected = 0; + + /* the monitor either wasn't connected or it is a non-DDC CRT. + * try to probe it + */ + if(IsCrtDac) { + unsigned long ulOrigVCLK_ECP_CNTL; + unsigned long ulOrigDAC_CNTL; + unsigned long ulOrigDAC_MACRO_CNTL; + unsigned long ulOrigDAC_EXT_CNTL; + unsigned long ulOrigCRTC_EXT_CNTL; + unsigned long ulData; + unsigned long ulMask; + + ulOrigVCLK_ECP_CNTL = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); + + ulData = ulOrigVCLK_ECP_CNTL; + ulData &= ~(RADEON_PIXCLK_ALWAYS_ONb + | RADEON_PIXCLK_DAC_ALWAYS_ONb); + ulMask = ~(RADEON_PIXCLK_ALWAYS_ONb + |RADEON_PIXCLK_DAC_ALWAYS_ONb); + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); + + ulOrigCRTC_EXT_CNTL = INREG(RADEON_CRTC_EXT_CNTL); + ulData = ulOrigCRTC_EXT_CNTL; + ulData |= RADEON_CRTC_CRT_ON; + OUTREG(RADEON_CRTC_EXT_CNTL, ulData); + + ulOrigDAC_EXT_CNTL = INREG(RADEON_DAC_EXT_CNTL); + ulData = ulOrigDAC_EXT_CNTL; + ulData &= ~RADEON_DAC_FORCE_DATA_MASK; + ulData |= (RADEON_DAC_FORCE_BLANK_OFF_EN + |RADEON_DAC_FORCE_DATA_EN + |RADEON_DAC_FORCE_DATA_SEL_MASK); + if ((info->ChipFamily == CHIP_FAMILY_RV250) || + (info->ChipFamily == CHIP_FAMILY_RV280)) + ulData |= (0x01b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + ulData |= (0x01ac << RADEON_DAC_FORCE_DATA_SHIFT); + + OUTREG(RADEON_DAC_EXT_CNTL, ulData); + + /* turn on power so testing can go through */ + ulOrigDAC_CNTL = INREG(RADEON_DAC_CNTL); + ulOrigDAC_CNTL &= ~RADEON_DAC_PDWN; + OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL); + + ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL); + ulOrigDAC_MACRO_CNTL &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL); + + /* Enable comparators and set DAC range to PS2 (VGA) output level */ + ulData = ulOrigDAC_CNTL; + ulData |= RADEON_DAC_CMP_EN; + ulData &= ~RADEON_DAC_RANGE_CNTL_MASK; + ulData |= 0x2; + OUTREG(RADEON_DAC_CNTL, ulData); + + /* Settle down */ + usleep(10000); + + /* Read comparators */ + ulData = INREG(RADEON_DAC_CNTL); + bConnected = (RADEON_DAC_CMP_OUTPUT & ulData)?1:0; + + /* Restore things */ + ulData = ulOrigVCLK_ECP_CNTL; + ulMask = 0xFFFFFFFFL; + OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); + + OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL ); + OUTREG(RADEON_DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL ); + OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL); + + if (!bConnected) { + /* Power DAC down if CRT is not connected */ + ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL); + ulOrigDAC_MACRO_CNTL |= (RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL); + + ulData = INREG(RADEON_DAC_CNTL); + ulData |= RADEON_DAC_PDWN; + OUTREG(RADEON_DAC_CNTL, ulData); + } + } else { /* TV DAC */ + + /* This doesn't seem to work reliably (maybe worse on some OEM cards), + for now we always return false. If one wants to connected a + non-DDC monitor on the DVI port when CRT port is also connected, + he will need to explicitly tell the driver in the config file + with Option MonitorLayout. + */ + bConnected = FALSE; + +#if 0 + if (info->ChipFamily == CHIP_FAMILY_R200) { + unsigned long ulOrigGPIO_MONID; + unsigned long ulOrigFP2_GEN_CNTL; + unsigned long ulOrigDISP_OUTPUT_CNTL; + unsigned long ulOrigCRTC2_GEN_CNTL; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_A; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_B; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_C; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_D; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_E; + unsigned long ulOrigDISP_LIN_TRANS_GRPH_F; + unsigned long ulOrigCRTC2_H_TOTAL_DISP; + unsigned long ulOrigCRTC2_V_TOTAL_DISP; + unsigned long ulOrigCRTC2_H_SYNC_STRT_WID; + unsigned long ulOrigCRTC2_V_SYNC_STRT_WID; + unsigned long ulData, i; + + ulOrigGPIO_MONID = INREG(RADEON_GPIO_MONID); + ulOrigFP2_GEN_CNTL = INREG(RADEON_FP2_GEN_CNTL); + ulOrigDISP_OUTPUT_CNTL = INREG(RADEON_DISP_OUTPUT_CNTL); + ulOrigCRTC2_GEN_CNTL = INREG(RADEON_CRTC2_GEN_CNTL); + ulOrigDISP_LIN_TRANS_GRPH_A = INREG(RADEON_DISP_LIN_TRANS_GRPH_A); + ulOrigDISP_LIN_TRANS_GRPH_B = INREG(RADEON_DISP_LIN_TRANS_GRPH_B); + ulOrigDISP_LIN_TRANS_GRPH_C = INREG(RADEON_DISP_LIN_TRANS_GRPH_C); + ulOrigDISP_LIN_TRANS_GRPH_D = INREG(RADEON_DISP_LIN_TRANS_GRPH_D); + ulOrigDISP_LIN_TRANS_GRPH_E = INREG(RADEON_DISP_LIN_TRANS_GRPH_E); + ulOrigDISP_LIN_TRANS_GRPH_F = INREG(RADEON_DISP_LIN_TRANS_GRPH_F); + + ulOrigCRTC2_H_TOTAL_DISP = INREG(RADEON_CRTC2_H_TOTAL_DISP); + ulOrigCRTC2_V_TOTAL_DISP = INREG(RADEON_CRTC2_V_TOTAL_DISP); + ulOrigCRTC2_H_SYNC_STRT_WID = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); + ulOrigCRTC2_V_SYNC_STRT_WID = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); + + ulData = INREG(RADEON_GPIO_MONID); + ulData &= ~RADEON_GPIO_A_0; + OUTREG(RADEON_GPIO_MONID, ulData); + + OUTREG(RADEON_FP2_GEN_CNTL, 0x0a000c0c); + + OUTREG(RADEON_DISP_OUTPUT_CNTL, 0x00000012); + + OUTREG(RADEON_CRTC2_GEN_CNTL, 0x06000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); + + for (i = 0; i < 200; i++) { + ulData = INREG(RADEON_GPIO_MONID); + bConnected = (ulData & RADEON_GPIO_Y_0)?1:0; + if (!bConnected) break; + + usleep(1000); + } + + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, ulOrigDISP_LIN_TRANS_GRPH_A); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, ulOrigDISP_LIN_TRANS_GRPH_B); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, ulOrigDISP_LIN_TRANS_GRPH_C); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, ulOrigDISP_LIN_TRANS_GRPH_D); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, ulOrigDISP_LIN_TRANS_GRPH_E); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, ulOrigDISP_LIN_TRANS_GRPH_F); + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, ulOrigCRTC2_H_TOTAL_DISP); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, ulOrigCRTC2_V_TOTAL_DISP); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, ulOrigCRTC2_H_SYNC_STRT_WID); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, ulOrigCRTC2_V_SYNC_STRT_WID); + OUTREG(RADEON_CRTC2_GEN_CNTL, ulOrigCRTC2_GEN_CNTL); + OUTREG(RADEON_DISP_OUTPUT_CNTL, ulOrigDISP_OUTPUT_CNTL); + OUTREG(RADEON_FP2_GEN_CNTL, ulOrigFP2_GEN_CNTL); + OUTREG(RADEON_GPIO_MONID, ulOrigGPIO_MONID); + } else { + unsigned long ulOrigPIXCLKSDATA; + unsigned long ulOrigTV_MASTER_CNTL; + unsigned long ulOrigTV_DAC_CNTL; + unsigned long ulOrigTV_PRE_DAC_MUX_CNTL; + unsigned long ulOrigDAC_CNTL2; + unsigned long ulData; + unsigned long ulMask; + + ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL); + + ulData = ulOrigPIXCLKSDATA; + ulData &= ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + ulMask = ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); + + ulOrigTV_MASTER_CNTL = INREG(RADEON_TV_MASTER_CNTL); + ulData = ulOrigTV_MASTER_CNTL; + ulData &= ~RADEON_TVCLK_ALWAYS_ONb; + OUTREG(RADEON_TV_MASTER_CNTL, ulData); + + ulOrigDAC_CNTL2 = INREG(RADEON_DAC_CNTL2); + ulData = ulOrigDAC_CNTL2; + ulData &= ~RADEON_DAC2_DAC2_CLK_SEL; + OUTREG(RADEON_DAC_CNTL2, ulData); + + ulOrigTV_DAC_CNTL = INREG(RADEON_TV_DAC_CNTL); + + ulData = 0x00880213; + OUTREG(RADEON_TV_DAC_CNTL, ulData); + + ulOrigTV_PRE_DAC_MUX_CNTL = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); + + ulData = (RADEON_Y_RED_EN + | RADEON_C_GRN_EN + | RADEON_CMP_BLU_EN + | RADEON_RED_MX_FORCE_DAC_DATA + | RADEON_GRN_MX_FORCE_DAC_DATA + | RADEON_BLU_MX_FORCE_DAC_DATA); + if (IS_R300_VARIANT) + ulData |= 0x180 << RADEON_TV_FORCE_DAC_DATA_SHIFT; + else + ulData |= 0x1f5 << RADEON_TV_FORCE_DAC_DATA_SHIFT; + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulData); + + usleep(10000); + + ulData = INREG(RADEON_TV_DAC_CNTL); + bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0; + + ulData = ulOrigPIXCLKSDATA; + ulMask = 0xFFFFFFFFL; + OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); + + OUTREG(RADEON_TV_MASTER_CNTL, ulOrigTV_MASTER_CNTL); + OUTREG(RADEON_DAC_CNTL2, ulOrigDAC_CNTL2); + OUTREG(RADEON_TV_DAC_CNTL, ulOrigTV_DAC_CNTL); + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulOrigTV_PRE_DAC_MUX_CNTL); + } +#endif + return MT_UNKNOWN; + } + + return(bConnected ? MT_CRT : MT_NONE); +} +#endif + +/* Primary Head (DVI or Laptop Int. panel)*/ +/* A ddc capable display connected on DVI port */ +/* Secondary Head (mostly VGA, can be DVI on some OEM boards)*/ +void RADEONConnectorFindMonitor(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + if (radeon_output->MonType == MT_UNKNOWN) { + if (radeon_output->type == OUTPUT_STV || radeon_output->type == OUTPUT_CTV) { + if (info->InternalTVOut) + radeon_output->MonType = radeon_detect_tv(pScrn); + } else { + radeon_output->MonType = RADEONDisplayDDCConnected(pScrn, output); + if (!radeon_output->MonType) { + if (radeon_output->type == OUTPUT_LVDS || radeon_output->type == OUTPUT_DVI) + radeon_output->MonType = RADEONPortCheckNonDDC(pScrn, output); + if (!radeon_output->MonType) { + if (radeon_output->DACType == DAC_PRIMARY) + radeon_output->MonType = radeon_detect_primary_dac(pScrn, TRUE); + else if (radeon_output->DACType == DAC_TVDAC) { + if (info->ChipFamily == CHIP_FAMILY_R200) + radeon_output->MonType = radeon_detect_ext_dac(pScrn); + else + radeon_output->MonType = radeon_detect_tv_dac(pScrn, TRUE); + } + } + } + } + } + + /* 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 ); + } +} + +static RADEONMonitorType RADEONPortCheckNonDDC(ScrnInfoPtr pScrn, xf86OutputPtr output) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONMonitorType MonType = MT_NONE; + + + if (radeon_output->type == OUTPUT_LVDS) { + if (INREG(RADEON_BIOS_4_SCRATCH) & 4) + MonType = MT_LCD; + } 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; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Detected Monitor Type: %d\n", MonType); + + return MonType; + +} + +static void +radeon_dpms(xf86OutputPtr output, int mode) +{ + switch(mode) { + case DPMSModeOn: + RADEONEnableDisplay(output, TRUE); + break; + case DPMSModeOff: + case DPMSModeSuspend: + case DPMSModeStandby: + RADEONEnableDisplay(output, FALSE); + break; + } +} + +static void +radeon_save(xf86OutputPtr output) +{ + +} + +static void +radeon_restore(xf86OutputPtr restore) +{ + +} + +static int +radeon_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + if (radeon_output->type == OUTPUT_STV || + radeon_output->type == OUTPUT_CTV) { + /* FIXME: Update when more modes are added */ + if (pMode->HDisplay == 800 && pMode->VDisplay == 600) + return MODE_OK; + else + return MODE_CLOCK_RANGE; + } + + if (radeon_output->type != OUTPUT_LVDS) + return MODE_OK; + + if (pMode->HDisplay > radeon_output->PanelXRes || + pMode->VDisplay > radeon_output->PanelYRes) + return MODE_PANEL; + + return MODE_OK; +} + +static Bool +radeon_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + if (radeon_output->MonType == MT_LCD || radeon_output->MonType == MT_DFP) { + xf86CrtcPtr crtc = output->crtc; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + + if ((mode->HDisplay < radeon_output->PanelXRes || + mode->VDisplay < radeon_output->PanelYRes) && + radeon_crtc->crtc_id == 0) + adjusted_mode->Flags |= RADEON_USE_RMX; + + if (adjusted_mode->Flags & RADEON_USE_RMX) { + adjusted_mode->CrtcHTotal = mode->CrtcHDisplay + radeon_output->HBlank; + adjusted_mode->CrtcHSyncStart = mode->CrtcHDisplay + radeon_output->HOverPlus; + adjusted_mode->CrtcHSyncEnd = mode->CrtcHSyncStart + radeon_output->HSyncWidth; + adjusted_mode->CrtcVTotal = mode->CrtcVDisplay + radeon_output->VBlank; + adjusted_mode->CrtcVSyncStart = mode->CrtcVDisplay + radeon_output->VOverPlus; + adjusted_mode->CrtcVSyncEnd = mode->CrtcVSyncStart + radeon_output->VSyncWidth; + adjusted_mode->Clock = radeon_output->DotClock; + radeon_output->Flags |= RADEON_USE_RMX; + adjusted_mode->Flags = radeon_output->Flags; + } else + radeon_output->Flags &= ~RADEON_USE_RMX; + + } + + return TRUE; +} + +static void +radeon_mode_prepare(xf86OutputPtr output) +{ +} + +static void RADEONInitFPRegisters(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int i; + CARD32 tmp = info->SavedReg.tmds_pll_cntl & 0xfffff; + + for (i=0; i<4; i++) { + if (radeon_output->tmds_pll[i].freq == 0) break; + if ((CARD32)(mode->Clock/10) < radeon_output->tmds_pll[i].freq) { + tmp = radeon_output->tmds_pll[i].value ; + break; + } + } + + if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_RV280)) { + if (tmp & 0xfff00000) + save->tmds_pll_cntl = tmp; + else { + save->tmds_pll_cntl = info->SavedReg.tmds_pll_cntl & 0xfff00000; + save->tmds_pll_cntl |= tmp; + } + } else save->tmds_pll_cntl = tmp; + + save->tmds_transmitter_cntl = info->SavedReg.tmds_transmitter_cntl & + ~(RADEON_TMDS_TRANSMITTER_PLLRST); + + if (IS_R300_VARIANT || (info->ChipFamily == CHIP_FAMILY_R200) || !pRADEONEnt->HasCRTC2) + save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN); + else /* weird, RV chips got this bit reversed? */ + save->tmds_transmitter_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN); + + save->fp_gen_cntl = info->SavedReg.fp_gen_cntl | + (RADEON_FP_CRTC_DONT_SHADOW_VPAR | + RADEON_FP_CRTC_DONT_SHADOW_HEND ); + + save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN); + + if (pScrn->rgbBits == 8) + save->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ + else + save->fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ + + + if (IsPrimary) { + if ((IS_R300_VARIANT) || (info->ChipFamily == CHIP_FAMILY_R200)) { + save->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + if (mode->Flags & RADEON_USE_RMX) + save->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; + else + save->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1; + } else + save->fp_gen_cntl |= RADEON_FP_SEL_CRTC1; + } else { + if ((IS_R300_VARIANT) || (info->ChipFamily == CHIP_FAMILY_R200)) { + save->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; + save->fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2; + } else + save->fp_gen_cntl |= RADEON_FP_SEL_CRTC2; + } + +} + +static void RADEONInitFP2Registers(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + + + if (pScrn->rgbBits == 8) + save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl | + RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */ + else + save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl & + ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */ + + save->fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN); + + if (IsPrimary) { + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + save->fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_EN | + RADEON_FP2_DVO_RATE_SEL_SDR); + if (mode->Flags & RADEON_USE_RMX) + save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX; + } else { + save->fp2_gen_cntl &= ~(RADEON_FP2_SRC_SEL_CRTC2 | + RADEON_FP2_DVO_RATE_SEL_SDR); + } + } else { + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + save->fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else { + save->fp2_gen_cntl &= ~(RADEON_FP2_DVO_RATE_SEL_SDR); + save->fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; + } + } + +} + +static void RADEONInitLVDSRegisters(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + + save->lvds_pll_cntl = info->SavedReg.lvds_pll_cntl; + + save->lvds_gen_cntl = info->SavedReg.lvds_gen_cntl; + save->lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; + save->lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON); + + if (IsPrimary) + save->lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2; + else + save->lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2; + +} + +static void RADEONInitRMXRegisters(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int xres = mode->HDisplay; + int yres = mode->VDisplay; + float Hratio, Vratio; + + save->fp_vert_stretch = info->SavedReg.fp_vert_stretch & + RADEON_VERT_STRETCH_RESERVED; + save->fp_horz_stretch = info->SavedReg.fp_horz_stretch & + (RADEON_HORZ_FP_LOOP_STRETCH | + RADEON_HORZ_AUTO_RATIO_INC); + + if (radeon_output->MonType != MT_LCD && radeon_output->MonType != MT_DFP) + return; + + if (radeon_output->PanelXRes == 0 || radeon_output->PanelYRes == 0) { + Hratio = 1.0; + Vratio = 1.0; + } else { + if (xres > radeon_output->PanelXRes) xres = radeon_output->PanelXRes; + if (yres > radeon_output->PanelYRes) yres = radeon_output->PanelYRes; + + Hratio = (float)xres/(float)radeon_output->PanelXRes; + Vratio = (float)yres/(float)radeon_output->PanelYRes; + } + + if (Hratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { + save->fp_horz_stretch |= ((xres/8-1)<<16); + } else { + save->fp_horz_stretch |= ((((unsigned long)(Hratio * RADEON_HORZ_STRETCH_RATIO_MAX + + 0.5)) & RADEON_HORZ_STRETCH_RATIO_MASK) | + RADEON_HORZ_STRETCH_BLEND | + RADEON_HORZ_STRETCH_ENABLE | + ((radeon_output->PanelXRes/8-1)<<16)); + } + + if (Vratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { + save->fp_vert_stretch |= ((yres-1)<<12); + } else { + save->fp_vert_stretch |= ((((unsigned long)(Vratio * RADEON_VERT_STRETCH_RATIO_MAX + + 0.5)) & RADEON_VERT_STRETCH_RATIO_MASK) | + RADEON_VERT_STRETCH_ENABLE | + RADEON_VERT_STRETCH_BLEND | + ((radeon_output->PanelYRes-1)<<12)); + } + +} + +static void RADEONInitDACRegisters(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (IsPrimary) { + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + save->disp_output_cntl = info->SavedReg.disp_output_cntl & + ~RADEON_DISP_DAC_SOURCE_MASK; + } else { + save->dac2_cntl = info->SavedReg.dac2_cntl & ~(RADEON_DAC2_DAC_CLK_SEL); + } + } else { + if ((info->ChipFamily == CHIP_FAMILY_R200) || IS_R300_VARIANT) { + save->disp_output_cntl = info->SavedReg.disp_output_cntl & + ~RADEON_DISP_DAC_SOURCE_MASK; + save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; + } else { + save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC_CLK_SEL; + } + } + save->dac_cntl = (RADEON_DAC_MASK_ALL + | RADEON_DAC_VGA_ADR_EN + | (info->dac6bits ? 0 : RADEON_DAC_8BIT_EN)); + + save->dac_macro_cntl = info->SavedReg.dac_macro_cntl; +} + +/* XXX: fix me */ +static void +RADEONInitTvDacCntl(ScrnInfoPtr pScrn, RADEONSavePtr save) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + if (info->ChipFamily == CHIP_FAMILY_R420 || + info->ChipFamily == CHIP_FAMILY_RV410) { + save->tv_dac_cntl = info->SavedReg.tv_dac_cntl & + ~(RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_BGADJ_MASK | + R420_TV_DAC_DACADJ_MASK | + R420_TV_DAC_RDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_GDACPD | + R420_TV_DAC_TVENABLE); + } else { + save->tv_dac_cntl = info->SavedReg.tv_dac_cntl & + ~(RADEON_TV_DAC_STD_MASK | + RADEON_TV_DAC_BGADJ_MASK | + RADEON_TV_DAC_DACADJ_MASK | + RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_GDACPD); + } + /* FIXME: doesn't make sense, this just replaces the previous value... */ + save->tv_dac_cntl |= (RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_DAC_STD_PS2); + +} + +static void RADEONInitDAC2Registers(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + + /*0x0028023;*/ + RADEONInitTvDacCntl(pScrn, save); + + if (IS_R300_VARIANT) + save->gpiopad_a = info->SavedReg.gpiopad_a | 1; + + save->dac2_cntl = info->SavedReg.dac2_cntl | RADEON_DAC2_DAC2_CLK_SEL; + + if (IsPrimary) { + if (IS_R300_VARIANT) { + save->disp_output_cntl = info->SavedReg.disp_output_cntl & + ~RADEON_DISP_TVDAC_SOURCE_MASK; + save->disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC; + } else if (info->ChipFamily == CHIP_FAMILY_R200) { + save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl & + ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + } else { + save->disp_hw_debug = info->SavedReg.disp_hw_debug | RADEON_CRT2_DISP1_SEL; + } + } else { + if (IS_R300_VARIANT) { + save->disp_output_cntl = info->SavedReg.disp_output_cntl & + ~RADEON_DISP_TVDAC_SOURCE_MASK; + save->disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + } else if (info->ChipFamily == CHIP_FAMILY_R200) { + save->fp2_gen_cntl = info->SavedReg.fp2_gen_cntl & + ~(R200_FP2_SOURCE_SEL_MASK | + RADEON_FP2_DVO_RATE_SEL_SDR); + save->fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2; + } else { + save->disp_hw_debug = info->SavedReg.disp_hw_debug & + ~RADEON_CRT2_DISP1_SEL; + } + } +} + +static void +RADEONInitOutputRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output, + int crtc_num) +{ + Bool IsPrimary = crtc_num == 0 ? TRUE : FALSE; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + if (crtc_num == 0) + RADEONInitRMXRegisters(output, save, mode); + + if (radeon_output->MonType == MT_CRT) { + if (radeon_output->DACType == DAC_PRIMARY) { + RADEONInitDACRegisters(output, save, mode, IsPrimary); + } else { + RADEONInitDAC2Registers(output, save, mode, IsPrimary); + } + } else if (radeon_output->MonType == MT_LCD) { + RADEONInitLVDSRegisters(output, save, mode, IsPrimary); + } else if (radeon_output->MonType == MT_DFP) { + if (radeon_output->TMDSType == TMDS_INT) { + RADEONInitFPRegisters(output, save, mode, IsPrimary); + } else { + RADEONInitFP2Registers(output, save, mode, IsPrimary); + } + } else if (radeon_output->MonType == MT_STV || + radeon_output->MonType == MT_CTV) { + RADEONInitTVRegisters(output, save, mode, IsPrimary); + } +} + +static void +radeon_mode_set(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + xf86CrtcPtr crtc = output->crtc; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + + RADEONInitOutputRegisters(pScrn, &info->ModeReg, adjusted_mode, output, radeon_crtc->crtc_id); + + if (radeon_crtc->crtc_id == 0) + RADEONRestoreRMXRegisters(pScrn, &info->ModeReg); + + switch(radeon_output->MonType) { + case MT_LCD: + ErrorF("restore LVDS\n"); + RADEONRestoreLVDSRegisters(pScrn, &info->ModeReg); + break; + case MT_DFP: + if (radeon_output->TMDSType == TMDS_INT) { + ErrorF("restore FP\n"); + RADEONRestoreFPRegisters(pScrn, &info->ModeReg); + } else { + ErrorF("restore FP2\n"); + RADEONRestoreFP2Registers(pScrn, &info->ModeReg); + } + break; + case MT_STV: + case MT_CTV: + ErrorF("restore tv\n"); + RADEONRestoreDACRegisters(pScrn, &info->ModeReg); + RADEONRestoreTVRegisters(pScrn, &info->ModeReg); + break; + default: + ErrorF("restore dac\n"); + RADEONRestoreDACRegisters(pScrn, &info->ModeReg); + } + +} + +static void +radeon_mode_commit(xf86OutputPtr output) +{ + RADEONEnableDisplay(output, TRUE); +} + +/* the following functions are based on the load detection code + * in the beos radeon driver by Thomas Kurschel and the existing + * load detection code in this driver. + */ +static RADEONMonitorType +radeon_detect_primary_dac(ScrnInfoPtr pScrn, Bool color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 vclk_ecp_cntl, crtc_ext_cntl; + CARD32 dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp; + RADEONMonitorType found = MT_NONE; + + /* save the regs we need */ + vclk_ecp_cntl = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); + crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); + dac_ext_cntl = INREG(RADEON_DAC_EXT_CNTL); + dac_cntl = INREG(RADEON_DAC_CNTL); + dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL); + + tmp = vclk_ecp_cntl & + ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); + OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, tmp); + + tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON; + OUTREG(RADEON_CRTC_EXT_CNTL, tmp); + + tmp = RADEON_DAC_FORCE_BLANK_OFF_EN | + RADEON_DAC_FORCE_DATA_EN; + + if (color) + tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; + else + tmp |= RADEON_DAC_FORCE_DATA_SEL_G; + + if (IS_R300_VARIANT) + tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + + OUTREG(RADEON_DAC_EXT_CNTL, tmp); + + tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); + tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN; + OUTREG(RADEON_DAC_CNTL, tmp); + + tmp &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + + OUTREG(RADEON_DAC_MACRO_CNTL, tmp); + + usleep(2000); + + if (INREG(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) { + found = MT_CRT; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "Found %s CRT connected to primary DAC\n", + color ? "color" : "bw"); + } + + /* restore the regs we used */ + OUTREG(RADEON_DAC_CNTL, dac_cntl); + OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + OUTREG(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl); + OUTPLL(pScrn, RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl); + + return found; +} + +static RADEONMonitorType +radeon_detect_ext_dac(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 gpio_monid, fp2_gen_cntl, disp_output_cntl, crtc2_gen_cntl; + CARD32 disp_lin_trans_grph_a, disp_lin_trans_grph_b, disp_lin_trans_grph_c; + CARD32 disp_lin_trans_grph_d, disp_lin_trans_grph_e, disp_lin_trans_grph_f; + CARD32 tmp, crtc2_h_total_disp, crtc2_v_total_disp; + CARD32 crtc2_h_sync_strt_wid, crtc2_v_sync_strt_wid; + RADEONMonitorType found = MT_NONE; + int connected = 0; + int i = 0; + + /* save the regs we need */ + gpio_monid = INREG(RADEON_GPIO_MONID); + fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL); + disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); + crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + disp_lin_trans_grph_a = INREG(RADEON_DISP_LIN_TRANS_GRPH_A); + disp_lin_trans_grph_b = INREG(RADEON_DISP_LIN_TRANS_GRPH_B); + disp_lin_trans_grph_c = INREG(RADEON_DISP_LIN_TRANS_GRPH_C); + disp_lin_trans_grph_d = INREG(RADEON_DISP_LIN_TRANS_GRPH_D); + disp_lin_trans_grph_e = INREG(RADEON_DISP_LIN_TRANS_GRPH_E); + disp_lin_trans_grph_f = INREG(RADEON_DISP_LIN_TRANS_GRPH_F); + crtc2_h_total_disp = INREG(RADEON_CRTC2_H_TOTAL_DISP); + crtc2_v_total_disp = INREG(RADEON_CRTC2_V_TOTAL_DISP); + crtc2_h_sync_strt_wid = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); + crtc2_v_sync_strt_wid = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); + + tmp = INREG(RADEON_GPIO_MONID); + tmp &= ~RADEON_GPIO_A_0; + OUTREG(RADEON_GPIO_MONID, tmp); + + OUTREG(RADEON_FP2_GEN_CNTL, + RADEON_FP2_ON | + RADEON_FP2_PANEL_FORMAT | + R200_FP2_SOURCE_SEL_TRANS_UNIT | + RADEON_FP2_DVO_EN | + R200_FP2_DVO_RATE_SEL_SDR); + + OUTREG(RADEON_DISP_OUTPUT_CNTL, + RADEON_DISP_DAC_SOURCE_RMX | + RADEON_DISP_TRANS_MATRIX_GRAPHICS); + + OUTREG(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_EN | + RADEON_CRTC2_DISP_REQ_EN_B); + + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); + + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); + + for (i = 0; i < 200; i++) { + tmp = INREG(RADEON_GPIO_MONID); + if (tmp & RADEON_GPIO_Y_0) + connected = 1; + else + connected = 0; + + if (!connected) + break; + + usleep(1000); + } + + if (connected) + found = MT_CRT; + + /* restore the regs we used */ + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, disp_lin_trans_grph_a); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, disp_lin_trans_grph_b); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, disp_lin_trans_grph_c); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, disp_lin_trans_grph_d); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, disp_lin_trans_grph_e); + OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, disp_lin_trans_grph_f); + OUTREG(RADEON_CRTC2_H_TOTAL_DISP, crtc2_h_total_disp); + OUTREG(RADEON_CRTC2_V_TOTAL_DISP, crtc2_v_total_disp); + OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, crtc2_h_sync_strt_wid); + OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, crtc2_v_sync_strt_wid); + OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + OUTREG(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + OUTREG(RADEON_GPIO_MONID, gpio_monid); + + return found; +} + +static RADEONMonitorType +radeon_detect_tv_dac(ScrnInfoPtr pScrn, Bool color) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl; + CARD32 disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp; + RADEONMonitorType found = MT_NONE; + + /* save the regs we need */ + pixclks_cntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL); + if (IS_R300_VARIANT) { + gpiopad_a = INREG(RADEON_GPIOPAD_A); + disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); + } else { + disp_hw_debug = INREG(RADEON_DISP_HW_DEBUG); + } + crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + dac_ext_cntl = INREG(RADEON_DAC_EXT_CNTL); + dac_cntl2 = INREG(RADEON_DAC_CNTL2); + + tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb + | RADEON_PIX2CLK_DAC_ALWAYS_ONb); + OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, tmp); + + if (IS_R300_VARIANT) { + OUTREGP(RADEON_GPIOPAD_A, 1, ~1 ); + } + + tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK; + tmp |= RADEON_CRTC2_CRT2_ON | + (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT); + + OUTREG(RADEON_CRTC2_GEN_CNTL, tmp); + + if (IS_R300_VARIANT) { + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + OUTREG(RADEON_DISP_OUTPUT_CNTL, tmp); + } else { + tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL; + OUTREG(RADEON_DISP_HW_DEBUG, tmp); + } + + tmp = RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | + RADEON_TV_DAC_STD_PS2; + + OUTREG(RADEON_TV_DAC_CNTL, tmp); + + tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN | + RADEON_DAC2_FORCE_DATA_EN; + + if (color) + tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB; + else + tmp |= RADEON_DAC_FORCE_DATA_SEL_G; + + if (IS_R300_VARIANT) + tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT); + else + tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT); + + OUTREG(RADEON_DAC_EXT_CNTL, tmp); + + tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; + OUTREG(RADEON_DAC_CNTL2, tmp); + + usleep(10000); + + if (IS_R300_VARIANT) { + if (INREG(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) { + found = MT_CRT; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "Found %s CRT connected to TV DAC\n", + color ? "color" : "bw"); + } + } else { + if (INREG(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT) { + found = MT_CRT; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "Found %s CRT connected to TV DAC\n", + color ? "color" : "bw"); + } + } + + /* restore regs we used */ + OUTREG(RADEON_DAC_CNTL2, dac_cntl2); + OUTREG(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl); + OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + + if (IS_R300_VARIANT) { + OUTREG(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + OUTREGP(RADEON_GPIOPAD_A, gpiopad_a, ~1 ); + } else { + OUTREG(RADEON_DISP_HW_DEBUG, disp_hw_debug); + } + OUTPLL(pScrn, RADEON_PIXCLKS_CNTL, pixclks_cntl); + + return found; +} + +static RADEONMonitorType +r300_detect_tv(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 tmp, dac_cntl2, crtc2_gen_cntl, dac_ext_cntl, tv_dac_cntl; + CARD32 gpiopad_a, disp_output_cntl; + RADEONMonitorType found = MT_NONE; + + /* save the regs we need */ + gpiopad_a = INREG(RADEON_GPIOPAD_A); + dac_cntl2 = INREG(RADEON_DAC_CNTL2); + crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + dac_ext_cntl = INREG(RADEON_DAC_EXT_CNTL); + tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + disp_output_cntl = INREG(RADEON_DISP_OUTPUT_CNTL); + + OUTREGP(RADEON_GPIOPAD_A, 0, ~1 ); + + OUTREG(RADEON_DAC_CNTL2, RADEON_DAC2_DAC2_CLK_SEL ); + + OUTREG(RADEON_CRTC2_GEN_CNTL, + RADEON_CRTC2_CRT2_ON | RADEON_CRTC2_VSYNC_TRISTAT ); + + tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK; + tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2; + OUTREG(RADEON_DISP_OUTPUT_CNTL, tmp); + + OUTREG(RADEON_DAC_EXT_CNTL, + RADEON_DAC2_FORCE_BLANK_OFF_EN | + RADEON_DAC2_FORCE_DATA_EN | + RADEON_DAC_FORCE_DATA_SEL_RGB | + (0xec << RADEON_DAC_FORCE_DATA_SHIFT )); + + OUTREG(RADEON_TV_DAC_CNTL, + RADEON_TV_DAC_STD_NTSC | + (8 << RADEON_TV_DAC_BGADJ_SHIFT) | + (6 << RADEON_TV_DAC_DACADJ_SHIFT )); + + INREG(RADEON_TV_DAC_CNTL); + + usleep(4000); + + OUTREG(RADEON_TV_DAC_CNTL, + RADEON_TV_DAC_NBLANK | + RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | + RADEON_TV_DAC_STD_NTSC | + (8 << RADEON_TV_DAC_BGADJ_SHIFT) | + (6 << RADEON_TV_DAC_DACADJ_SHIFT )); + + INREG(RADEON_TV_DAC_CNTL); + + usleep(6000); + + tmp = INREG(RADEON_TV_DAC_CNTL); + if ( (tmp & RADEON_TV_DAC_GDACDET) != 0 ) { + found = MT_STV; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "S-Video TV connection detected\n"); + } else if ( (tmp & RADEON_TV_DAC_BDACDET) != 0 ) { + found = MT_CTV; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "Composite TV connection detected\n" ); + } + + OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl ); + OUTREG(RADEON_DAC_EXT_CNTL, dac_ext_cntl); + OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + OUTREG(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl); + OUTREG(RADEON_DAC_CNTL2, dac_cntl2); + OUTREGP(RADEON_GPIOPAD_A, gpiopad_a, ~1); + + return found; +} + +static RADEONMonitorType +radeon_detect_tv(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 tmp, dac_cntl2, tv_master_cntl; + CARD32 tv_dac_cntl, tv_pre_dac_mux_cntl, config_cntl; + RADEONMonitorType found = MT_NONE; + + if (IS_R300_VARIANT) + return r300_detect_tv(pScrn); + + /* save the regs we need */ + dac_cntl2 = INREG(RADEON_DAC_CNTL2); + tv_master_cntl = INREG(RADEON_TV_MASTER_CNTL); + tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + config_cntl = INREG(RADEON_CONFIG_CNTL); + tv_pre_dac_mux_cntl = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); + + tmp = dac_cntl2 & ~RADEON_DAC2_DAC2_CLK_SEL; + OUTREG(RADEON_DAC_CNTL2, tmp); + + tmp = tv_master_cntl | RADEON_TV_ON; + tmp &= ~(RADEON_TV_ASYNC_RST | + RADEON_RESTART_PHASE_FIX | + RADEON_CRT_FIFO_CE_EN | + RADEON_TV_FIFO_CE_EN | + RADEON_RE_SYNC_NOW_SEL_MASK); + tmp |= RADEON_TV_FIFO_ASYNC_RST | RADEON_CRT_ASYNC_RST; + + OUTREG(RADEON_TV_MASTER_CNTL, tmp); + + tmp = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | + RADEON_TV_MONITOR_DETECT_EN | RADEON_TV_DAC_STD_NTSC | + (8 << RADEON_TV_DAC_BGADJ_SHIFT); + + if (config_cntl & RADEON_CFG_ATI_REV_ID_MASK) + tmp |= (4 << RADEON_TV_DAC_DACADJ_SHIFT); + else + tmp |= (8 << RADEON_TV_DAC_DACADJ_SHIFT); + + OUTREG(RADEON_TV_DAC_CNTL, tmp); + + tmp = RADEON_C_GRN_EN | RADEON_CMP_BLU_EN | + RADEON_RED_MX_FORCE_DAC_DATA | + RADEON_GRN_MX_FORCE_DAC_DATA | + RADEON_BLU_MX_FORCE_DAC_DATA | + (0x109 << RADEON_TV_FORCE_DAC_DATA_SHIFT); + + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, tmp); + + usleep(3000); + + tmp = INREG(RADEON_TV_DAC_CNTL); + if (tmp & RADEON_TV_DAC_GDACDET) { + found = MT_STV; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "S-Video TV connection detected\n"); + } else if (tmp & RADEON_TV_DAC_BDACDET) { + found = MT_CTV; + xf86DrvMsg (pScrn->scrnIndex, X_INFO, + "Composite TV connection detected\n" ); + } + + OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl); + OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl); + OUTREG(RADEON_TV_MASTER_CNTL, tv_master_cntl); + OUTREG(RADEON_DAC_CNTL2, dac_cntl2); + + return found; +} + +static xf86OutputStatus +radeon_detect(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + Bool connected = TRUE; + + radeon_output->MonType = MT_UNKNOWN; + RADEONConnectorFindMonitor(pScrn, output); + + /* force montype based on output property */ + if (radeon_output->type == OUTPUT_DVI) { + if (radeon_output->MonType == MT_NONE) + connected = FALSE; + if ((info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_I_ATOM) || + (!info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_I)) { + if (radeon_output->DVIType == DVI_ANALOG) + radeon_output->MonType = MT_CRT; + else if (radeon_output->DVIType == DVI_DIGITAL) + radeon_output->MonType = MT_DFP; + } + } + + /* set montype so users can force outputs on even if detection fails */ + if (radeon_output->MonType == MT_NONE) { + connected = FALSE; + if (radeon_output->type == OUTPUT_LVDS) + radeon_output->MonType = MT_LCD; + else if (radeon_output->type == OUTPUT_VGA) + radeon_output->MonType = MT_CRT; + else if (radeon_output->type == OUTPUT_STV) + radeon_output->MonType = MT_STV; + else if (radeon_output->type == OUTPUT_CTV) + radeon_output->MonType = MT_CTV; + else if ((info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_D_ATOM) || + (!info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_D)) + radeon_output->MonType = MT_DFP; + } + + if (radeon_output->MonType == MT_UNKNOWN) { + output->subpixel_order = SubPixelUnknown; + return XF86OutputStatusUnknown; + } else { + + switch(radeon_output->MonType) { + case MT_LCD: + case MT_DFP: + output->subpixel_order = SubPixelHorizontalRGB; + break; + default: + output->subpixel_order = SubPixelNone; + break; + } + + if (connected) + return XF86OutputStatusConnected; + else + return XF86OutputStatusDisconnected; + } + +} + +static DisplayModePtr +radeon_get_modes(xf86OutputPtr output) +{ + DisplayModePtr modes; + modes = RADEONProbeOutputModes(output); + return modes; +} + +static void +radeon_destroy (xf86OutputPtr output) +{ + if(output->driver_private) + xfree(output->driver_private); +} + +static void +radeon_set_backlight_level(xf86OutputPtr output, int level) +{ +#if 0 + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char * RADEONMMIO = info->MMIO; + CARD32 lvds_gen_cntl; + + lvds_gen_cntl = INREG(RADEON_LVDS_GEN_CNTL); + lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; + lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_LEVEL_MASK; + lvds_gen_cntl |= (level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & RADEON_LVDS_BL_MOD_LEVEL_MASK; + //usleep (radeon_output->PanelPwrDly * 1000); + OUTREG(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); + lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN; + //usleep (radeon_output->PanelPwrDly * 1000); + OUTREG(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); +#endif +} + +static Atom backlight_atom; +static Atom rmx_atom; +static Atom monitor_type_atom; +static Atom tv_hsize_atom; +static Atom tv_hpos_atom; +static Atom tv_vpos_atom; +static Atom tv_std_atom; +#define RADEON_MAX_BACKLIGHT_LEVEL 255 + +static void +radeon_create_resources(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + INT32 range[2]; + int data, err; + const char *s; + + /* backlight control */ + if (radeon_output->type == OUTPUT_LVDS) { + backlight_atom = MAKE_ATOM("backlight"); + + range[0] = 0; + range[1] = RADEON_MAX_BACKLIGHT_LEVEL; + err = RRConfigureOutputProperty(output->randr_output, backlight_atom, + FALSE, TRUE, FALSE, 2, range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + //data = (info->SavedReg.lvds_gen_cntl & RADEON_LVDS_BL_MOD_LEVEL_MASK) >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT; + data = RADEON_MAX_BACKLIGHT_LEVEL; + err = RRChangeOutputProperty(output->randr_output, backlight_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + + /* RMX control - fullscreen, centered, keep ratio */ + /* actually more of a crtc property as only crtc1 has rmx */ + if (radeon_output->type == OUTPUT_LVDS || + radeon_output->type == OUTPUT_DVI) { + rmx_atom = MAKE_ATOM("scaler"); + + err = RRConfigureOutputProperty(output->randr_output, rmx_atom, + FALSE, FALSE, FALSE, 0, NULL); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the property */ + s = "fill"; + err = RRChangeOutputProperty(output->randr_output, rmx_atom, + XA_STRING, 8, PropModeReplace, strlen(s), (pointer)s, + FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + + /* force auto/analog/digital for DVI-I ports */ + if (radeon_output->type == OUTPUT_DVI) { + if ((info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_I_ATOM) || + (!info->IsAtomBios && radeon_output->ConnectorType == CONNECTOR_DVI_I)) { + monitor_type_atom = MAKE_ATOM("dvi_monitor_type"); + + err = RRConfigureOutputProperty(output->randr_output, monitor_type_atom, + FALSE, FALSE, FALSE, 0, NULL); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + s = "auto"; + err = RRChangeOutputProperty(output->randr_output, monitor_type_atom, + XA_STRING, 8, PropModeReplace, strlen(s), (pointer)s, + FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + } + + if (radeon_output->type == OUTPUT_STV || + radeon_output->type == OUTPUT_CTV) { + tv_hsize_atom = MAKE_ATOM("tv_horizontal_size"); + + range[0] = -MAX_H_SIZE; + range[1] = MAX_H_SIZE; + err = RRConfigureOutputProperty(output->randr_output, tv_hsize_atom, + FALSE, TRUE, FALSE, 2, range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + data = 0; + err = RRChangeOutputProperty(output->randr_output, tv_hsize_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + + if (radeon_output->type == OUTPUT_STV || + radeon_output->type == OUTPUT_CTV) { + tv_hpos_atom = MAKE_ATOM("tv_horizontal_position"); + + range[0] = -MAX_H_POSITION; + range[1] = MAX_H_POSITION; + err = RRConfigureOutputProperty(output->randr_output, tv_hpos_atom, + FALSE, TRUE, FALSE, 2, range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + data = 0; + err = RRChangeOutputProperty(output->randr_output, tv_hpos_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + + if (radeon_output->type == OUTPUT_STV || + radeon_output->type == OUTPUT_CTV) { + tv_vpos_atom = MAKE_ATOM("tv_vertical_position"); + + range[0] = -MAX_V_POSITION; + range[1] = MAX_V_POSITION; + err = RRConfigureOutputProperty(output->randr_output, tv_vpos_atom, + FALSE, TRUE, FALSE, 2, range); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + data = 0; + err = RRChangeOutputProperty(output->randr_output, tv_vpos_atom, + XA_INTEGER, 32, PropModeReplace, 1, &data, + FALSE, TRUE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } + + if (radeon_output->type == OUTPUT_STV || + radeon_output->type == OUTPUT_CTV) { + tv_std_atom = MAKE_ATOM("tv_standard"); + + err = RRConfigureOutputProperty(output->randr_output, tv_std_atom, + FALSE, FALSE, FALSE, 0, NULL); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRConfigureOutputProperty error, %d\n", err); + } + /* Set the current value of the backlight property */ + s = "default"; + err = RRChangeOutputProperty(output->randr_output, tv_std_atom, + XA_STRING, 8, PropModeReplace, strlen(s), (pointer)s, + FALSE, FALSE); + if (err != 0) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "RRChangeOutputProperty error, %d\n", err); + } + } +} + +static Bool +radeon_set_property(xf86OutputPtr output, Atom property, + RRPropertyValuePtr value) +{ + RADEONOutputPrivatePtr radeon_output = output->driver_private; + INT32 val; + + + if (property == backlight_atom) { + if (value->type != XA_INTEGER || + value->format != 32 || + value->size != 1) { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < 0 || val > RADEON_MAX_BACKLIGHT_LEVEL) + return FALSE; + +#if defined(__powerpc__) + val = RADEON_MAX_BACKLIGHT_LEVEL - val; +#endif + + radeon_set_backlight_level(output, val); + + } else if (property == rmx_atom) { + xf86CrtcPtr crtc = output->crtc; + RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; + if (radeon_crtc->crtc_id == 0) { + const char *s; + if (value->type != XA_STRING || value->format != 8) + return FALSE; + s = (char*)value->data; + if (value->size == strlen("full") && !strncmp("full", s, strlen("full"))) { + return TRUE; + } else if (value->size == strlen("aspect") && !strncmp("aspect", s, strlen("aspect"))) { + return TRUE; + } else if (value->size == strlen("center") && !strncmp("center", s, strlen("center"))) { + return TRUE; + } + return FALSE; + } else { + return FALSE; + } + } else if (property == monitor_type_atom) { + const char *s; + if (value->type != XA_STRING || value->format != 8) + return FALSE; + s = (char*)value->data; + if (value->size == strlen("auto") && !strncmp("auto", s, strlen("auto"))) { + radeon_output->DVIType = DVI_AUTO; + return TRUE; + } else if (value->size == strlen("analog") && !strncmp("analog", s, strlen("analog"))) { + radeon_output->DVIType = DVI_ANALOG; + return TRUE; + } else if (value->size == strlen("digital") && !strncmp("digital", s, strlen("digital"))) { + radeon_output->DVIType = DVI_DIGITAL; + return TRUE; + } + return FALSE; + } else if (property == tv_hsize_atom) { + if (value->type != XA_INTEGER || + value->format != 32 || + value->size != 1) { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < -MAX_H_SIZE || val > MAX_H_SIZE) + return FALSE; + + radeon_output->hSize = val; + /*RADEONUpdateHVPosition(output, NULL);*/ + return TRUE; + } else if (property == tv_hpos_atom) { + if (value->type != XA_INTEGER || + value->format != 32 || + value->size != 1) { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < -MAX_H_POSITION || val > MAX_H_POSITION) + return FALSE; + + radeon_output->hPos = val; + /*RADEONUpdateHVPosition(output, NULL);*/ + return TRUE; + } else if (property == tv_vpos_atom) { + if (value->type != XA_INTEGER || + value->format != 32 || + value->size != 1) { + return FALSE; + } + + val = *(INT32 *)value->data; + if (val < -MAX_H_POSITION || val > MAX_H_POSITION) + return FALSE; + + radeon_output->vPos = val; + /*RADEONUpdateHVPosition(output, NULL);*/ + return TRUE; + } else if (property == tv_std_atom) { + const char *s; + if (value->type != XA_STRING || value->format != 8) + return FALSE; + s = (char*)value->data; + if (value->size == strlen("default") && !strncmp("default", s, strlen("default"))) { + radeon_output->tvStd = radeon_output->default_tvStd; + return TRUE; + } else if (value->size == strlen("ntsc") && !strncmp("ntsc", s, strlen("ntsc"))) { + if (radeon_output->SupportedTVStds & TV_STD_NTSC) { + radeon_output->tvStd = TV_STD_NTSC; + return TRUE; + } else { + return FALSE; + } + } else if (value->size == strlen("pal") && !strncmp("pal", s, strlen("pal"))) { + if (radeon_output->SupportedTVStds & TV_STD_PAL) { + radeon_output->tvStd = TV_STD_PAL; + return TRUE; + } else { + return FALSE; + } + } else if (value->size == strlen("pal-m") && !strncmp("pal-m", s, strlen("pal-m"))) { + if (radeon_output->SupportedTVStds & TV_STD_PAL_M) { + radeon_output->tvStd = TV_STD_PAL_M; + return TRUE; + } else { + return FALSE; + } + } else if (value->size == strlen("pal-60") && !strncmp("pal-60", s, strlen("pal-60"))) { + if (radeon_output->SupportedTVStds & TV_STD_PAL_60) { + radeon_output->tvStd = TV_STD_PAL_60; + return TRUE; + } else { + return FALSE; + } + } else if (value->size == strlen("ntsc-j") && !strncmp("ntsc-j", s, strlen("ntsc-j"))) { + if (radeon_output->SupportedTVStds & TV_STD_NTSC_J) { + radeon_output->tvStd = TV_STD_NTSC_J; + return TRUE; + } else { + return FALSE; + } + } else if (value->size == strlen("scart-pal") && !strncmp("scart-pal", s, strlen("scart-pal"))) { + if (radeon_output->SupportedTVStds & TV_STD_SCART_PAL) { + radeon_output->tvStd = TV_STD_SCART_PAL; + return TRUE; + } else { + return FALSE; + } + } + return FALSE; + } + + return TRUE; +} + +static const xf86OutputFuncsRec radeon_output_funcs = { + .create_resources = radeon_create_resources, + .dpms = radeon_dpms, + .save = radeon_save, + .restore = radeon_restore, + .mode_valid = radeon_mode_valid, + .mode_fixup = radeon_mode_fixup, + .prepare = radeon_mode_prepare, + .mode_set = radeon_mode_set, + .commit = radeon_mode_commit, + .detect = radeon_detect, + .get_modes = radeon_get_modes, + .set_property = radeon_set_property, + .destroy = radeon_destroy +}; + +void RADEONSetOutputType(ScrnInfoPtr pScrn, RADEONOutputPrivatePtr radeon_output) +{ + RADEONInfoPtr info = RADEONPTR (pScrn); + RADEONOutputType output; + + if (info->IsAtomBios) { + switch(radeon_output->ConnectorType) { + case CONNECTOR_VGA_ATOM: + output = OUTPUT_VGA; break; + case CONNECTOR_DVI_I_ATOM: + case CONNECTOR_DVI_D_ATOM: + case CONNECTOR_DVI_A_ATOM: + output = OUTPUT_DVI; break; + case CONNECTOR_STV_ATOM: + output = OUTPUT_STV; break; + case CONNECTOR_CTV_ATOM: + output = OUTPUT_CTV; break; + case CONNECTOR_LVDS_ATOM: + case CONNECTOR_DIGITAL_ATOM: + output = OUTPUT_LVDS; break; + case CONNECTOR_NONE_ATOM: + case CONNECTOR_UNSUPPORTED_ATOM: + default: + output = OUTPUT_NONE; break; + } + } + else { + switch(radeon_output->ConnectorType) { + case CONNECTOR_PROPRIETARY: + output = OUTPUT_LVDS; break; + case CONNECTOR_CRT: + output = OUTPUT_VGA; break; + case CONNECTOR_DVI_I: + case CONNECTOR_DVI_D: + output = OUTPUT_DVI; break; + case CONNECTOR_CTV: + output = OUTPUT_CTV; break; + case CONNECTOR_STV: + output = OUTPUT_STV; break; + case CONNECTOR_NONE: + case CONNECTOR_UNSUPPORTED: + default: + output = OUTPUT_NONE; break; + } + } + radeon_output->type = output; +} + +static void RADEONI2CGetBits(I2CBusPtr b, int *Clock, int *data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long val; + unsigned char *RADEONMMIO = info->MMIO; + + /* Get the result */ + + if (b->DriverPrivate.uval == RADEON_LCD_GPIO_MASK) { + val = INREG(b->DriverPrivate.uval+4); + *Clock = (val & (1<<13)) != 0; + *data = (val & (1<<12)) != 0; + } else { + val = INREG(b->DriverPrivate.uval); + *Clock = (val & RADEON_GPIO_Y_1) != 0; + *data = (val & RADEON_GPIO_Y_0) != 0; + } +} + +static void RADEONI2CPutBits(I2CBusPtr b, int Clock, int data) +{ + ScrnInfoPtr pScrn = xf86Screens[b->scrnIndex]; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned long val; + unsigned char *RADEONMMIO = info->MMIO; + + if (b->DriverPrivate.uval == RADEON_LCD_GPIO_MASK) { + val = INREG(b->DriverPrivate.uval) & (CARD32)~((1<<12) | (1<<13)); + val |= (Clock ? 0:(1<<13)); + val |= (data ? 0:(1<<12)); + OUTREG(b->DriverPrivate.uval, val); + } else { + val = INREG(b->DriverPrivate.uval) & (CARD32)~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1); + val |= (Clock ? 0:RADEON_GPIO_EN_1); + val |= (data ? 0:RADEON_GPIO_EN_0); + OUTREG(b->DriverPrivate.uval, val); + } + /* read back to improve reliability on some cards. */ + val = INREG(b->DriverPrivate.uval); +} + +static Bool +RADEONI2CInit(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; + pI2CBus->I2CPutBits = RADEONI2CPutBits; + pI2CBus->I2CGetBits = RADEONI2CGetBits; + pI2CBus->AcknTimeout = 5; + pI2CBus->DriverPrivate.uval = i2c_reg; + + if (!xf86I2CBusInit(pI2CBus)) return FALSE; + + *bus_ptr = pI2CBus; + return TRUE; +} + +static void +RADEONGetPanelInfoFromReg (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + unsigned char *RADEONMMIO = info->MMIO; + CARD32 fp_vert_stretch = INREG(RADEON_FP_VERT_STRETCH); + CARD32 fp_horz_stretch = INREG(RADEON_FP_HORZ_STRETCH); + + radeon_output->PanelPwrDly = 200; + if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) { + radeon_output->PanelYRes = ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >> + RADEON_VERT_PANEL_SHIFT) + 1; + } else { + radeon_output->PanelYRes = (INREG(RADEON_CRTC_V_TOTAL_DISP)>>16) + 1; + } + if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE) { + radeon_output->PanelXRes = (((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >> + RADEON_HORZ_PANEL_SHIFT) + 1) * 8; + } else { + radeon_output->PanelXRes = ((INREG(RADEON_CRTC_H_TOTAL_DISP)>>16) + 1) * 8; + } + + if ((radeon_output->PanelXRes < 640) || (radeon_output->PanelYRes < 480)) { + radeon_output->PanelXRes = 640; + radeon_output->PanelYRes = 480; + } + + // move this to crtc function + if (xf86ReturnOptValBool(info->Options, OPTION_LVDS_PROBE_PLL, TRUE)) { + CARD32 ppll_div_sel, ppll_val; + + ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3; + RADEONPllErrataAfterIndex(info); + ppll_val = INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel); + if ((ppll_val & 0x000707ff) == 0x1bb) + goto noprobe; + info->FeedbackDivider = ppll_val & 0x7ff; + info->PostDivider = (ppll_val >> 16) & 0x7; + info->RefDivider = info->pll.reference_div; + info->UseBiosDividers = TRUE; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Existing panel PLL dividers will be used.\n"); + } + noprobe: + + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Panel size %dx%d is derived, this may not be correct.\n" + "If not, use PanelSize option to overwrite this setting\n", + radeon_output->PanelXRes, radeon_output->PanelYRes); +} + +/* BIOS may not have right panel size, we search through all supported + * DDC modes looking for the maximum panel size. + */ +static void +RADEONUpdatePanelSize(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int j; + /* XXX: fixme */ + //xf86MonPtr ddc = pScrn->monitor->DDC; + xf86MonPtr ddc = output->MonInfo; + DisplayModePtr p; + + // crtc should handle? + if ((info->UseBiosDividers && radeon_output->DotClock != 0) || (ddc == NULL)) + return; + + /* Go thru detailed timing table first */ + for (j = 0; j < 4; j++) { + if (ddc->det_mon[j].type == 0) { + struct detailed_timings *d_timings = + &ddc->det_mon[j].section.d_timings; + int match = 0; + + /* If we didn't get a panel clock or guessed one, try to match the + * mode with the panel size. We do that because we _need_ a panel + * clock, or ValidateFPModes will fail, even when UseBiosDividers + * is set. + */ + if (radeon_output->DotClock == 0 && + radeon_output->PanelXRes == d_timings->h_active && + radeon_output->PanelYRes == d_timings->v_active) + match = 1; + + /* If we don't have a BIOS provided panel data with fixed dividers, + * check for a larger panel size + */ + if (radeon_output->PanelXRes < d_timings->h_active && + radeon_output->PanelYRes < d_timings->v_active && + !info->UseBiosDividers) + match = 1; + + if (match) { + radeon_output->PanelXRes = d_timings->h_active; + radeon_output->PanelYRes = d_timings->v_active; + radeon_output->DotClock = d_timings->clock / 1000; + radeon_output->HOverPlus = d_timings->h_sync_off; + radeon_output->HSyncWidth = d_timings->h_sync_width; + radeon_output->HBlank = d_timings->h_blanking; + radeon_output->VOverPlus = d_timings->v_sync_off; + radeon_output->VSyncWidth = d_timings->v_sync_width; + radeon_output->VBlank = d_timings->v_blanking; + radeon_output->Flags = (d_timings->interlaced ? V_INTERLACE : 0); + switch (d_timings->misc) { + case 0: radeon_output->Flags |= V_NHSYNC | V_NVSYNC; break; + case 1: radeon_output->Flags |= V_PHSYNC | V_NVSYNC; break; + case 2: radeon_output->Flags |= V_NHSYNC | V_PVSYNC; break; + case 3: radeon_output->Flags |= V_PHSYNC | V_PVSYNC; break; + } + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n", + radeon_output->PanelXRes, radeon_output->PanelYRes); + } + } + } + + if (info->UseBiosDividers && radeon_output->DotClock != 0) + return; + + /* Search thru standard VESA modes from EDID */ + for (j = 0; j < 8; j++) { + if ((radeon_output->PanelXRes < ddc->timings2[j].hsize) && + (radeon_output->PanelYRes < ddc->timings2[j].vsize)) { + for (p = pScrn->monitor->Modes; p; p = p->next) { + if ((ddc->timings2[j].hsize == p->HDisplay) && + (ddc->timings2[j].vsize == p->VDisplay)) { + float refresh = + (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; + + if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { + /* Is this good enough? */ + radeon_output->PanelXRes = ddc->timings2[j].hsize; + radeon_output->PanelYRes = ddc->timings2[j].vsize; + radeon_output->HBlank = p->HTotal - p->HDisplay; + radeon_output->HOverPlus = p->HSyncStart - p->HDisplay; + radeon_output->HSyncWidth = p->HSyncEnd - p->HSyncStart; + radeon_output->VBlank = p->VTotal - p->VDisplay; + radeon_output->VOverPlus = p->VSyncStart - p->VDisplay; + radeon_output->VSyncWidth = p->VSyncEnd - p->VSyncStart; + radeon_output->DotClock = p->Clock; + radeon_output->Flags = p->Flags; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n", + radeon_output->PanelXRes, radeon_output->PanelYRes); + } + } + } + } + } +} + +static Bool +RADEONGetLVDSInfo (xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + char* s; + + if (!RADEONGetLVDSInfoFromBIOS(output)) + RADEONGetPanelInfoFromReg(output); + + if ((s = xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) { + radeon_output->PanelPwrDly = 200; + if (sscanf (s, "%dx%d", &radeon_output->PanelXRes, &radeon_output->PanelYRes) != 2) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid PanelSize option: %s\n", s); + RADEONGetPanelInfoFromReg(output); + } + } + + /* The panel size we collected from BIOS may not be the + * maximum size supported by the panel. If not, we update + * it now. These will be used if no matching mode can be + * found from EDID data. + */ + RADEONUpdatePanelSize(output); + + if (radeon_output->DotClock == 0) { + DisplayModePtr tmp_mode = NULL; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No valid timing info from BIOS.\n"); + /* No timing information for the native mode, + use whatever specified in the Modeline. + If no Modeline specified, we'll just pick + the VESA mode at 60Hz refresh rate which + is likely to be the best for a flat panel. + */ + tmp_mode = pScrn->monitor->Modes; + while(tmp_mode) { + if ((tmp_mode->HDisplay == radeon_output->PanelXRes) && + (tmp_mode->VDisplay == radeon_output->PanelYRes)) { + + float refresh = + (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal; + if ((abs(60.0 - refresh) < 1.0) || + (tmp_mode->type == 0)) { + radeon_output->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay; + radeon_output->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay; + radeon_output->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart; + radeon_output->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay; + radeon_output->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay; + radeon_output->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart; + radeon_output->DotClock = tmp_mode->Clock; + radeon_output->Flags = 0; + break; + } + } + + tmp_mode = tmp_mode->next; + + if (tmp_mode == pScrn->monitor->Modes) + break; + } + if ((radeon_output->DotClock == 0) && !output->MonInfo) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Panel size is not correctly detected.\n" + "Please try to use PanelSize option for correct settings.\n"); + return FALSE; + } + } + + return TRUE; +} + +static void +RADEONGetTMDSInfo(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int i; + + for (i=0; i<4; i++) { + radeon_output->tmds_pll[i].value = 0; + radeon_output->tmds_pll[i].freq = 0; + } + + if (RADEONGetTMDSInfoFromBIOS(output)) return; + + for (i=0; i<4; i++) { + radeon_output->tmds_pll[i].value = default_tmds_pll[info->ChipFamily][i].value; + radeon_output->tmds_pll[i].freq = default_tmds_pll[info->ChipFamily][i].freq; + } +} + +static void +RADEONGetTVInfo(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int i; + + radeon_output->hPos = 0; + radeon_output->vPos = 0; + radeon_output->hSize = 0; + + if (RADEONGetTVInfoFromBIOS(output)) return; + + /* set some reasonable defaults */ + radeon_output->default_tvStd = TV_STD_NTSC; + radeon_output->tvStd = TV_STD_NTSC; + radeon_output->TVRefClk = 27.000000000; + radeon_output->SupportedTVStds = TV_STD_NTSC | TV_STD_PAL; + +} + +void RADEONInitConnector(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + int DDCReg = 0; + char* name = (char*) DDCTypeName[radeon_output->DDCType]; + + switch(radeon_output->DDCType) { + case DDC_MONID: DDCReg = RADEON_GPIO_MONID; break; + case DDC_DVI : DDCReg = RADEON_GPIO_DVI_DDC; break; + case DDC_VGA : DDCReg = RADEON_GPIO_VGA_DDC; break; + case DDC_CRT2 : DDCReg = RADEON_GPIO_CRT2_DDC; break; + case DDC_LCD : DDCReg = RADEON_LCD_GPIO_MASK; break; + default: break; + } + + if (DDCReg) { + radeon_output->DDCReg = DDCReg; + RADEONI2CInit(pScrn, &radeon_output->pI2CBus, 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) { + RADEONGetTVDacAdjInfo(output); + } + +} + +/* + * initialise the static data sos we don't have to re-do at randr change */ +Bool RADEONSetupConnectors(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + xf86OutputPtr output; + char *optstr; + int i = 0; + int num_vga = 0; + int num_dvi = 0; + + /* We first get the information about all connectors from BIOS. + * This is how the card is phyiscally wired up. + * The information should be correct even on a OEM card. + * If not, we may have problem -- need to use MonitorLayout option. + */ + for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + info->BiosConnector[i].valid = FALSE; + info->BiosConnector[i].DDCType = DDC_NONE_DETECTED; + info->BiosConnector[i].DACType = DAC_UNKNOWN; + info->BiosConnector[i].TMDSType = TMDS_UNKNOWN; + info->BiosConnector[i].ConnectorType = CONNECTOR_NONE; + } + + if (!RADEONGetConnectorInfoFromBIOS(pScrn)) { + if (info->IsMobility) { + /* Below is the most common setting, but may not be true */ +#if defined(__powerpc__) + info->BiosConnector[0].DDCType = DDC_DVI; +#else + info->BiosConnector[0].DDCType = DDC_LCD; +#endif + info->BiosConnector[0].DACType = DAC_UNKNOWN; + info->BiosConnector[0].TMDSType = TMDS_UNKNOWN; + info->BiosConnector[0].ConnectorType = CONNECTOR_PROPRIETARY; + info->BiosConnector[0].valid = TRUE; + + info->BiosConnector[1].DDCType = DDC_VGA; + info->BiosConnector[1].DACType = DAC_PRIMARY; + info->BiosConnector[1].TMDSType = TMDS_EXT; + info->BiosConnector[1].ConnectorType = CONNECTOR_CRT; + info->BiosConnector[1].valid = TRUE; + + } else { + /* Below is the most common setting, but may not be true */ + info->BiosConnector[0].DDCType = DDC_DVI; + info->BiosConnector[0].DACType = DAC_TVDAC; + info->BiosConnector[0].TMDSType = TMDS_INT; + info->BiosConnector[0].ConnectorType = CONNECTOR_DVI_I; + info->BiosConnector[0].valid = TRUE; + + info->BiosConnector[1].DDCType = DDC_VGA; + info->BiosConnector[1].DACType = DAC_PRIMARY; + info->BiosConnector[1].TMDSType = TMDS_EXT; + info->BiosConnector[1].ConnectorType = CONNECTOR_CRT; + info->BiosConnector[1].valid = TRUE; + } + + if (info->InternalTVOut) { + info->BiosConnector[2].ConnectorType = CONNECTOR_STV; + info->BiosConnector[2].DACType = DAC_TVDAC; + info->BiosConnector[2].TMDSType = TMDS_NONE; + info->BiosConnector[2].DDCType = DDC_NONE_DETECTED; + info->BiosConnector[2].valid = TRUE; + } + + /* Some cards have the DDC lines swapped and we have no way to + * detect it yet (Mac cards) + */ + if (xf86ReturnOptValBool(info->Options, OPTION_REVERSE_DDC, FALSE)) { + info->BiosConnector[0].DDCType = DDC_VGA; + info->BiosConnector[1].DDCType = DDC_DVI; + } + } + + if (info->HasSingleDAC) { + /* For RS300/RS350/RS400 chips, there is no primary DAC. Force VGA port to use TVDAC*/ + if (info->BiosConnector[0].ConnectorType == CONNECTOR_CRT) { + info->BiosConnector[0].DACType = DAC_TVDAC; + info->BiosConnector[1].DACType = DAC_NONE; + } else { + info->BiosConnector[1].DACType = DAC_TVDAC; + info->BiosConnector[0].DACType = DAC_NONE; + } + } else if (!pRADEONEnt->HasCRTC2) { + info->BiosConnector[0].DACType = DAC_PRIMARY; + } + + /* parse connector table option */ + optstr = (char *)xf86GetOptValString(info->Options, OPTION_CONNECTORTABLE); + + if (optstr) { + for (i = 2; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + info->BiosConnector[i].valid = FALSE; + } + info->BiosConnector[0].valid = TRUE; + info->BiosConnector[1].valid = TRUE; + if (sscanf(optstr, "%u,%d,%d,%u,%u,%d,%d,%u", + &info->BiosConnector[0].DDCType, + &info->BiosConnector[0].DACType, + &info->BiosConnector[0].TMDSType, + &info->BiosConnector[0].ConnectorType, + &info->BiosConnector[1].DDCType, + &info->BiosConnector[1].DACType, + &info->BiosConnector[1].TMDSType, + &info->BiosConnector[1].ConnectorType) != 8) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid ConnectorTable option: %s\n", optstr); + return FALSE; + } + } + + for (i = 0; i < RADEON_MAX_BIOS_CONNECTOR; i++) { + if (info->BiosConnector[i].valid) { + 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)) { + num_dvi++; + } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_VGA_ATOM) { + num_vga++; + } + } else { + if ((info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_D) || + (info->BiosConnector[i].ConnectorType == CONNECTOR_DVI_I)) { + num_dvi++; + } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_CRT) { + num_vga++; + } + } + } + } + + 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; + 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); + 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, &radeon_output_funcs, "DVI-1"); + num_dvi--; + } else { + output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0"); + } + } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_VGA_ATOM) { + if (num_vga > 1) { + output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1"); + num_vga--; + } else { + output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0"); + } + } else + output = xf86OutputCreate(pScrn, &radeon_output_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, &radeon_output_funcs, "DVI-1"); + num_dvi--; + } else { + output = xf86OutputCreate(pScrn, &radeon_output_funcs, "DVI-0"); + } + } else if (info->BiosConnector[i].ConnectorType == CONNECTOR_CRT) { + if (num_vga > 1) { + output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-1"); + num_vga--; + } else { + output = xf86OutputCreate(pScrn, &radeon_output_funcs, "VGA-0"); + } + } else + output = xf86OutputCreate(pScrn, &radeon_output_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; + + RADEONInitConnector(output); + } + } + + return TRUE; +} + diff --git a/src/radeon_probe.h b/src/radeon_probe.h index dfec12f..d79e7ad 100644 --- a/src/radeon_probe.h +++ b/src/radeon_probe.h @@ -38,10 +38,20 @@ #include "xf86str.h" #include "xf86DDC.h" +#include "randrstr.h" #define _XF86MISC_SERVER_ #include <X11/extensions/xf86misc.h> +#include "xf86Crtc.h" + +#ifdef USE_EXA +#include "exa.h" +#endif +#ifdef USE_XAA +#include "xaa.h" +#endif + typedef enum { DDC_NONE_DETECTED, @@ -93,38 +103,111 @@ typedef enum { DAC_UNKNOWN = -1, DAC_PRIMARY = 0, - DAC_TVDAC = 1 + DAC_TVDAC = 1, + DAC_NONE = 2 } RADEONDacType; typedef enum { TMDS_UNKNOWN = -1, TMDS_INT = 0, - TMDS_EXT = 1 + TMDS_EXT = 1, + TMDS_NONE = 2 } RADEONTmdsType; -typedef struct +typedef enum { - Bool IsUsed; - Bool IsActive; - int binding; // which instance of the driver "owns" this controller - DisplayModePtr pCurMode; -} RADEONController; + DVI_AUTO, + DVI_DIGITAL, + DVI_ANALOG +} RADEONDviType; -typedef struct +typedef struct { + CARD32 freq; + CARD32 value; +}RADEONTMDSPll; + +typedef enum { + OUTPUT_NONE, + OUTPUT_VGA, + OUTPUT_DVI, + OUTPUT_LVDS, + OUTPUT_STV, + OUTPUT_CTV, +} RADEONOutputType; + +/* standards */ +typedef enum +{ + TV_STD_NTSC = 1, + TV_STD_PAL = 2, + TV_STD_PAL_M = 4, + TV_STD_PAL_60 = 8, + TV_STD_NTSC_J = 16, + TV_STD_SCART_PAL = 32, +} TVStd; + +typedef struct _RADEONCrtcPrivateRec { +#ifdef USE_XAA + FBLinearPtr rotate_mem_xaa; +#endif +#ifdef USE_EXA + ExaOffscreenArea *rotate_mem_exa; +#endif + int crtc_id; + int binding; + /* Lookup table values to be set when the CRTC is enabled */ + CARD8 lut_r[256], lut_g[256], lut_b[256]; +} RADEONCrtcPrivateRec, *RADEONCrtcPrivatePtr; + +typedef struct { RADEONDDCType DDCType; RADEONDacType DACType; RADEONTmdsType TMDSType; RADEONConnectorType ConnectorType; - RADEONMonitorType MonType; - xf86MonPtr MonInfo; -} RADEONConnector; - + Bool valid; +} RADEONBIOSConnector; +typedef struct _RADEONOutputPrivateRec { + int num; + RADEONOutputType type; + void *dev_priv; + RADEONDDCType DDCType; + RADEONDacType DACType; + RADEONDviType DVIType; + RADEONTmdsType TMDSType; + RADEONConnectorType ConnectorType; + RADEONMonitorType MonType; + int crtc_num; + int DDCReg; + I2CBusPtr pI2CBus; + CARD32 tv_dac_adj; + /* panel stuff */ + int PanelXRes; + int PanelYRes; + int HOverPlus; + int HSyncWidth; + int HBlank; + int VOverPlus; + int VSyncWidth; + int VBlank; + int Flags; /* Saved copy of mode flags */ + int PanelPwrDly; + int DotClock; + RADEONTMDSPll tmds_pll[4]; + /* TV out */ + TVStd default_tvStd; + TVStd tvStd; + int hPos; + int vPos; + int hSize; + float TVRefClk; + int SupportedTVStds; +} RADEONOutputPrivateRec, *RADEONOutputPrivatePtr; -#define RADEON_MAX_CONNECTOR 2 #define RADEON_MAX_CRTC 2 +#define RADEON_MAX_BIOS_CONNECTOR 8 typedef struct { @@ -137,13 +220,11 @@ typedef struct Bool IsSecondaryRestored; Bool RestorePrimary; - ScrnInfoPtr pSecondaryScrn; - ScrnInfoPtr pPrimaryScrn; - Bool ReversedDAC; /* TVDAC used as primary dac */ Bool ReversedTMDS; /* DDC_DVI is used for external TMDS */ - RADEONConnector *PortInfo[RADEON_MAX_CONNECTOR]; - RADEONController *Controller[RADEON_MAX_CRTC]; /* pointer to a controller */ + xf86CrtcPtr pCrtc[RADEON_MAX_CRTC]; + RADEONCrtcPrivatePtr Controller[RADEON_MAX_CRTC]; + } RADEONEntRec, *RADEONEntPtr; /* radeon_probe.c */ diff --git a/src/radeon_reg.h b/src/radeon_reg.h index 01bcec8..4e4d874 100644 --- a/src/radeon_reg.h +++ b/src/radeon_reg.h @@ -231,7 +231,13 @@ # define RADEON_ACTIVE_HILO_LAT_MASK (3 << 13) # define RADEON_ACTIVE_HILO_LAT_SHIFT 13 # define RADEON_DISP_DYN_STOP_LAT_MASK (1 << 12) +# define RADEON_MC_BUSY (1 << 16) +# define RADEON_DLL_READY (1 << 19) +# define RADEON_CG_NO1_DEBUG_0 (1 << 24) +# define RADEON_CG_NO1_DEBUG_MASK (0x1f << 24) # define RADEON_DYN_STOP_MODE_MASK (7 << 21) +# define RADEON_TVPLL_PWRMGT_OFF (1 << 30) +# define RADEON_TVCLK_TURNOFF (1 << 31) #define RADEON_PLL_PWRMGT_CNTL 0x0015 # define RADEON_TCL_BYPASS_DISABLE (1 << 20) #define RADEON_CLR_CMP_CLR_3D 0x1a24 @@ -319,6 +325,8 @@ # define RADEON_CRTC2_HSYNC_TRISTAT (1 << 5) # define RADEON_CRTC2_VSYNC_TRISTAT (1 << 6) # define RADEON_CRTC2_CRT2_ON (1 << 7) +# define RADEON_CRTC2_PIX_WIDTH_SHIFT 8 +# define RADEON_CRTC2_PIX_WIDTH_MASK (0xf << 8) # define RADEON_CRTC2_ICON_EN (1 << 15) # define RADEON_CRTC2_CUR_EN (1 << 16) # define RADEON_CRTC2_CUR_MODE_MASK (7 << 20) @@ -329,8 +337,8 @@ # define RADEON_CRTC2_HSYNC_DIS (1 << 28) # define RADEON_CRTC2_VSYNC_DIS (1 << 29) #define RADEON_CRTC_MORE_CNTL 0x27c -# define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) -# define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) +# define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4) +# define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5) #define RADEON_CRTC_GUI_TRIG_VLINE 0x0218 #define RADEON_CRTC_H_SYNC_STRT_WID 0x0204 # define RADEON_CRTC_H_SYNC_STRT_PIX (0x07 << 0) @@ -451,6 +459,7 @@ #define RADEON_DAC_CNTL 0x0058 # define RADEON_DAC_RANGE_CNTL (3 << 0) +# define RADEON_DAC_RANGE_CNTL_PS2 (2 << 0) # define RADEON_DAC_RANGE_CNTL_MASK 0x03 # define RADEON_DAC_BLANKING (1 << 2) # define RADEON_DAC_CMP_EN (1 << 3) @@ -461,13 +470,25 @@ # define RADEON_DAC_PDWN (1 << 15) # define RADEON_DAC_MASK_ALL (0xff << 24) #define RADEON_DAC_CNTL2 0x007c +# define RADEON_DAC2_TV_CLK_SEL (0 << 1) # define RADEON_DAC2_DAC_CLK_SEL (1 << 0) # define RADEON_DAC2_DAC2_CLK_SEL (1 << 1) # define RADEON_DAC2_PALETTE_ACC_CTL (1 << 5) +# define RADEON_DAC2_CMP_EN (1 << 7) +# define RADEON_DAC2_CMP_OUT_R (1 << 8) +# define RADEON_DAC2_CMP_OUT_G (1 << 9) +# define RADEON_DAC2_CMP_OUT_B (1 << 10) +# define RADEON_DAC2_CMP_OUTPUT (1 << 11) #define RADEON_DAC_EXT_CNTL 0x0280 -# define RADEON_DAC_FORCE_BLANK_OFF_EN (1 << 4) -# define RADEON_DAC_FORCE_DATA_EN (1 << 5) +# define RADEON_DAC2_FORCE_BLANK_OFF_EN (1 << 0) +# define RADEON_DAC2_FORCE_DATA_EN (1 << 1) +# define RADEON_DAC_FORCE_BLANK_OFF_EN (1 << 4) +# define RADEON_DAC_FORCE_DATA_EN (1 << 5) # define RADEON_DAC_FORCE_DATA_SEL_MASK (3 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_R (0 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_G (1 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_B (2 << 6) +# define RADEON_DAC_FORCE_DATA_SEL_RGB (3 << 6) # define RADEON_DAC_FORCE_DATA_MASK 0x0003ff00 # define RADEON_DAC_FORCE_DATA_SHIFT 8 #define RADEON_DAC_MACRO_CNTL 0x0d04 @@ -480,15 +501,22 @@ # define RADEON_TV_DAC_PEDESTAL (1 << 2) # define RADEON_TV_MONITOR_DETECT_EN (1 << 4) # define RADEON_TV_DAC_CMPOUT (1 << 5) +# define RADEON_TV_DAC_STD_MASK (3 << 8) +# define RADEON_TV_DAC_STD_PAL (0 << 8) # define RADEON_TV_DAC_STD_NTSC (1 << 8) -# define RADEON_TV_DAC_STD_MASK 0x0300 -# define RADEON_TV_DAC_STD_PS2 0x0200 +# define RADEON_TV_DAC_STD_PS2 (2 << 8) +# define RADEON_TV_DAC_STD_RS343 (3 << 8) # define RADEON_TV_DAC_BGSLEEP (1 << 6) # define RADEON_TV_DAC_BGADJ_MASK (0xf << 16) +# define RADEON_TV_DAC_BGADJ_SHIFT 16 # define RADEON_TV_DAC_DACADJ_MASK (0xf << 20) +# define RADEON_TV_DAC_DACADJ_SHIFT 20 # define RADEON_TV_DAC_RDACPD (1 << 24) # define RADEON_TV_DAC_GDACPD (1 << 25) # define RADEON_TV_DAC_BDACPD (1 << 26) +# define RADEON_TV_DAC_RDACDET (1 << 29) +# define RADEON_TV_DAC_GDACDET (1 << 30) +# define RADEON_TV_DAC_BDACDET (1 << 31) # define R420_TV_DAC_DACADJ_MASK (0x1f << 20) # define R420_TV_DAC_RDACPD (1 << 25) # define R420_TV_DAC_GDACPD (1 << 26) @@ -500,10 +528,18 @@ # define RADEON_DISP_DAC_SOURCE_MASK 0x03 # define RADEON_DISP_DAC2_SOURCE_MASK 0x0c # define RADEON_DISP_DAC_SOURCE_CRTC2 0x01 +# define RADEON_DISP_DAC_SOURCE_RMX 0x02 +# define RADEON_DISP_DAC_SOURCE_LTU 0x03 # define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04 -# define RADEON_DISP_TVDAC_SOURCE_MASK (0x03<<2) +# define RADEON_DISP_TVDAC_SOURCE_MASK (0x03 << 2) # define RADEON_DISP_TVDAC_SOURCE_CRTC 0x0 -# define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01<<2) +# define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01 << 2) +# define RADEON_DISP_TVDAC_SOURCE_RMX (0x02 << 2) +# define RADEON_DISP_TVDAC_SOURCE_LTU (0x03 << 2) +# define RADEON_DISP_TRANS_MATRIX_MASK (0x03 << 4) +# define RADEON_DISP_TRANS_MATRIX_ALPHA_MSB (0x00 << 4) +# define RADEON_DISP_TRANS_MATRIX_GRAPHICS (0x01 << 4) +# define RADEON_DISP_TRANS_MATRIX_VIDEO (0x02 << 4) # define RADEON_DISP_TV_SOURCE_CRTC (1 << 16) /* crtc1 or crtc2 */ # define RADEON_DISP_TV_SOURCE_LTU (0 << 16) /* linear transform unit */ #define RADEON_DISP_TV_OUT_CNTL 0x0d6c @@ -531,12 +567,12 @@ # define RADEON_DISP_ALPHA_MODE_KEY 0 # define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1 # define RADEON_DISP_ALPHA_MODE_GLOBAL 2 -# define RADEON_DISP_RGB_OFFSET_EN (1<<8) +# define RADEON_DISP_RGB_OFFSET_EN (1 << 8) # define RADEON_DISP_GRPH_ALPHA_MASK (0xff << 16) # define RADEON_DISP_OV0_ALPHA_MASK (0xff << 24) # define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9) #define RADEON_DISP2_MERGE_CNTL 0x0d68 -# define RADEON_DISP2_RGB_OFFSET_EN (1<<8) +# define RADEON_DISP2_RGB_OFFSET_EN (1 << 8) #define RADEON_DISP_LIN_TRANS_GRPH_A 0x0d80 #define RADEON_DISP_LIN_TRANS_GRPH_B 0x0d84 #define RADEON_DISP_LIN_TRANS_GRPH_C 0x0d88 @@ -742,10 +778,12 @@ # define RADEON_FP2_BLANK_EN (1 << 1) # define RADEON_FP2_ON (1 << 2) # define RADEON_FP2_PANEL_FORMAT (1 << 3) +# define RADEON_FP2_DETECT_SENSE (1 << 8) # define R200_FP2_SOURCE_SEL_MASK (3 << 10) # define R200_FP2_SOURCE_SEL_CRTC1 (0 << 10) # define R200_FP2_SOURCE_SEL_CRTC2 (1 << 10) # define R200_FP2_SOURCE_SEL_RMX (2 << 10) +# define R200_FP2_SOURCE_SEL_TRANS_UNIT (3 << 10) # define RADEON_FP2_SRC_SEL_MASK (3 << 13) # define RADEON_FP2_SRC_SEL_CRTC2 (1 << 13) # define RADEON_FP2_FP_POL (1 << 16) @@ -757,6 +795,7 @@ # define RADEON_FP2_CRC_READ_EN (1 << 24) # define RADEON_FP2_DVO_EN (1 << 25) # define RADEON_FP2_DVO_RATE_SEL_SDR (1 << 26) +# define R200_FP2_DVO_RATE_SEL_SDR (1 << 27) #define RADEON_FP_H_SYNC_STRT_WID 0x02c4 #define RADEON_FP_H2_SYNC_STRT_WID 0x03c4 #define RADEON_FP_HORZ_STRETCH 0x028c @@ -837,6 +876,7 @@ # define RADEON_HDP_SOFT_RESET (1 << 26) # define RADEON_HDP_APER_CNTL (1 << 23) #define RADEON_HTOTAL_CNTL 0x0009 /* PLL */ +# define RADEON_HTOT_CNTL_VGA_EN (1 << 28) #define RADEON_HTOTAL2_CNTL 0x002e /* PLL */ /* Multimedia I2C bus */ @@ -875,6 +915,9 @@ # define RADEON_LVDS_PANEL_TYPE (1 << 2) # define RADEON_LVDS_PANEL_FORMAT (1 << 3) # define RADEON_LVDS_EN (1 << 7) +# define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8 +# define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8) +# define RADEON_LVDS_BL_MOD_EN (1 << 16) # define RADEON_LVDS_DIGON (1 << 18) # define RADEON_LVDS_BLON (1 << 19) # define RADEON_LVDS_SEL_CRTC2 (1 << 23) @@ -885,9 +928,6 @@ #define RADEON_MAX_LATENCY 0x0f3f /* PCI */ #define RADEON_MC_AGP_LOCATION 0x014c #define RADEON_MC_FB_LOCATION 0x0148 -#define RADEON_MC_STATUS 0x0150 -# define RADEON_MC_IDLE (1 << 2) -# define R300_MC_IDLE (1 << 4) #define RADEON_DISPLAY_BASE_ADDR 0x23c #define RADEON_DISPLAY2_BASE_ADDR 0x33c #define RADEON_OV0_BASE_ADDR 0x43c @@ -903,8 +943,8 @@ # define R300_DISABLE_MC_MCLKA (1 << 21) # define R300_DISABLE_MC_MCLKB (1 << 21) #define RADEON_MCLK_MISC 0x001f /* PLL */ -# define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1<<12) -# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1<<13) +# define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1 << 12) +# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1 << 13) # define RADEON_MC_MCLK_DYN_ENABLE (1 << 14) # define RADEON_IO_MCLK_DYN_ENABLE (1 << 15) #define RADEON_LCD_GPIO_MASK 0x01a0 @@ -912,20 +952,32 @@ #define RADEON_MDGPIO_A_REG 0x01ac #define RADEON_MDGPIO_EN_REG 0x01b0 #define RADEON_MDGPIO_MASK 0x0198 +#define RADEON_GPIOPAD_A 0x019c #define RADEON_MDGPIO_Y_REG 0x01b4 #define RADEON_MEM_ADDR_CONFIG 0x0148 #define RADEON_MEM_BASE 0x0f10 /* PCI */ #define RADEON_MEM_CNTL 0x0140 # define RADEON_MEM_NUM_CHANNELS_MASK 0x01 -# define RADEON_MEM_USE_B_CH_ONLY (1<<1) -# define RV100_HALF_MODE (1<<3) +# define RADEON_MEM_USE_B_CH_ONLY (1 << 1) +# define RV100_HALF_MODE (1 << 3) # define R300_MEM_NUM_CHANNELS_MASK 0x03 -# define R300_MEM_USE_CD_CH_ONLY (1<<2) +# define R300_MEM_USE_CD_CH_ONLY (1 << 2) #define RADEON_MEM_TIMING_CNTL 0x0144 /* EXT_MEM_CNTL */ #define RADEON_MEM_INIT_LAT_TIMER 0x0154 #define RADEON_MEM_INTF_CNTL 0x014c #define RADEON_MEM_SDRAM_MODE_REG 0x0158 +# define RADEON_SDRAM_MODE_MASK 0xffff0000 +# define RADEON_B3MEM_RESET_MASK 0x6fffffff #define RADEON_MEM_STR_CNTL 0x0150 +# define RADEON_MEM_PWRUP_COMPL_A (1 << 0) +# define RADEON_MEM_PWRUP_COMPL_B (1 << 1) +# define R300_MEM_PWRUP_COMPL_C (1 << 2) +# define R300_MEM_PWRUP_COMPL_D (1 << 3) +# define RADEON_MEM_PWRUP_COMPLETE 0x03 +# define R300_MEM_PWRUP_COMPLETE 0x0f +#define RADEON_MC_STATUS 0x0150 +# define RADEON_MC_IDLE (1 << 2) +# define R300_MC_IDLE (1 << 4) #define RADEON_MEM_VGA_RP_SEL 0x003c #define RADEON_MEM_VGA_WP_SEL 0x0038 #define RADEON_MIN_GRANT 0x0f3e /* PCI */ @@ -1207,6 +1259,8 @@ #define RADEON_P2PLL_CNTL 0x002a /* P2PLL */ # define RADEON_P2PLL_RESET (1 << 0) # define RADEON_P2PLL_SLEEP (1 << 1) +# define RADEON_P2PLL_PVG_MASK (7 << 11) +# define RADEON_P2PLL_PVG_SHIFT 11 # define RADEON_P2PLL_ATOMIC_UPDATE_EN (1 << 16) # define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17) # define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC (1 << 18) @@ -1247,6 +1301,7 @@ # define R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF (1 << 23) #define RADEON_PLANE_3D_MASK_C 0x1d44 #define RADEON_PLL_TEST_CNTL 0x0013 /* PLL */ +# define RADEON_PLL_MASK_READ_B (1 << 9) #define RADEON_PMI_CAP_ID 0x0f5c /* PCI */ #define RADEON_PMI_DATA 0x0f63 /* PCI */ #define RADEON_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ @@ -1256,6 +1311,8 @@ #define RADEON_PPLL_CNTL 0x0002 /* PLL */ # define RADEON_PPLL_RESET (1 << 0) # define RADEON_PPLL_SLEEP (1 << 1) +# define RADEON_PPLL_PVG_MASK (7 << 11) +# define RADEON_PPLL_PVG_SHIFT 11 # define RADEON_PPLL_ATOMIC_UPDATE_EN (1 << 16) # define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) # define RADEON_PPLL_ATOMIC_UPDATE_VSYNC (1 << 18) @@ -3058,9 +3115,15 @@ # define RADEON_TV_ASYNC_RST (1 << 0) # define RADEON_CRT_ASYNC_RST (1 << 1) # define RADEON_RESTART_PHASE_FIX (1 << 3) +# define RADEON_TV_FIFO_ASYNC_RST (1 << 4) +# define RADEON_VIN_ASYNC_RST (1 << 5) +# define RADEON_AUD_ASYNC_RST (1 << 6) +# define RADEON_DVS_ASYNC_RST (1 << 7) # define RADEON_CRT_FIFO_CE_EN (1 << 9) # define RADEON_TV_FIFO_CE_EN (1 << 10) +# define RADEON_RE_SYNC_NOW_SEL_MASK (3 << 14) # define RADEON_TVCLK_ALWAYS_ONb (1 << 30) +# define RADEON_TV_ON (1 << 31) #define RADEON_TV_PRE_DAC_MUX_CNTL 0x0888 # define RADEON_Y_RED_EN (1 << 0) # define RADEON_C_GRN_EN (1 << 1) @@ -3078,7 +3141,14 @@ # define RADEON_RGB_SRC_SEL_RMX (1 << 8) # define RADEON_RGB_SRC_SEL_CRTC2 (2 << 8) # define RADEON_RGB_CONVERT_BY_PASS (1 << 10) +# define RADEON_TVOUT_SCALE_EN (1 << 26) #define RADEON_TV_SYNC_CNTL 0x0808 +# define RADEON_SYNC_OE (1 << 0) +# define RADEON_SYNC_OUT (1 << 1) +# define RADEON_SYNC_IN (1 << 2) +# define RADEON_SYNC_PUB (1 << 3) +# define RADEON_SYNC_PD (1 << 4) +# define RADEON_TV_SYNC_IO_DRIVE (1 << 5) #define RADEON_TV_HTOTAL 0x080c #define RADEON_TV_HDISP 0x0810 #define RADEON_TV_HSTART 0x0818 @@ -3094,10 +3164,23 @@ #define RADEON_TV_HOST_READ_DATA 0x0840 #define RADEON_TV_HOST_WRITE_DATA 0x0844 #define RADEON_TV_HOST_RD_WT_CNTL 0x0848 +# define RADEON_HOST_FIFO_RD (1 << 12) +# define RADEON_HOST_FIFO_RD_ACK (1 << 13) +# define RADEON_HOST_FIFO_WT (1 << 14) +# define RADEON_HOST_FIFO_WT_ACK (1 << 15) #define RADEON_TV_VSCALER_CNTL1 0x084c +# define RADEON_UV_INC_MASK 0xffff +# define RADEON_UV_INC_SHIFT 0 +# define RADEON_Y_W_EN (1 << 24) # define RADEON_RESTART_FIELD (1 << 29) /* restart on field 0 */ # define RADEON_Y_DEL_W_SIG_SHIFT 26 #define RADEON_TV_TIMING_CNTL 0x0850 +# define RADEON_H_INC_MASK 0xfff +# define RADEON_H_INC_SHIFT 0 +# define RADEON_REQ_Y_FIRST (1 << 19) +# define RADEON_FORCE_BURST_ALWAYS (1 << 21) +# define RADEON_UV_POST_SCALE_BYPASS (1 << 23) +# define RADEON_UV_OUTPUT_POST_SCALE_SHIFT 24 #define RADEON_TV_VSCALER_CNTL2 0x0854 # define RADEON_DITHER_MODE (1 << 0) # define RADEON_Y_OUTPUT_DITHER_EN (1 << 1) @@ -3105,27 +3188,64 @@ # define RADEON_UV_TO_BUF_DITHER_EN (1 << 3) #define RADEON_TV_Y_FALL_CNTL 0x0858 # define RADEON_Y_FALL_PING_PONG (1 << 16) +# define RADEON_Y_COEF_EN (1 << 17) #define RADEON_TV_Y_RISE_CNTL 0x085c # define RADEON_Y_RISE_PING_PONG (1 << 16) #define RADEON_TV_Y_SAW_TOOTH_CNTL 0x0860 #define RADEON_TV_UPSAMP_AND_GAIN_CNTL 0x0864 +# define RADEON_YUPSAMP_EN (1 << 0) +# define RADEON_UVUPSAMP_EN (1 << 2) #define RADEON_TV_GAIN_LIMIT_SETTINGS 0x0868 +# define RADEON_Y_GAIN_LIMIT_SHIFT 0 +# define RADEON_UV_GAIN_LIMIT_SHIFT 16 #define RADEON_TV_LINEAR_GAIN_SETTINGS 0x086c +# define RADEON_Y_GAIN_SHIFT 0 +# define RADEON_UV_GAIN_SHIFT 16 #define RADEON_TV_MODULATOR_CNTL1 0x0870 +# define RADEON_YFLT_EN (1 << 2) +# define RADEON_UVFLT_EN (1 << 3) # define RADEON_ALT_PHASE_EN (1 << 6) # define RADEON_SYNC_TIP_LEVEL (1 << 7) +# define RADEON_BLANK_LEVEL_SHIFT 8 +# define RADEON_SET_UP_LEVEL_SHIFT 16 +# define RADEON_SLEW_RATE_LIMIT (1 << 23) +# define RADEON_CY_FILT_BLEND_SHIFT 28 #define RADEON_TV_MODULATOR_CNTL2 0x0874 #define RADEON_TV_CRC_CNTL 0x0890 #define RADEON_TV_UV_ADR 0x08ac +# define RADEON_MAX_UV_ADR_MASK 0x000000ff +# define RADEON_MAX_UV_ADR_SHIFT 0 +# define RADEON_TABLE1_BOT_ADR_MASK 0x0000ff00 +# define RADEON_TABLE1_BOT_ADR_SHIFT 8 +# define RADEON_TABLE3_TOP_ADR_MASK 0x00ff0000 +# define RADEON_TABLE3_TOP_ADR_SHIFT 16 +# define RADEON_HCODE_TABLE_SEL_MASK 0x06000000 +# define RADEON_HCODE_TABLE_SEL_SHIFT 25 +# define RADEON_VCODE_TABLE_SEL_MASK 0x18000000 +# define RADEON_VCODE_TABLE_SEL_SHIFT 27 +# define RADEON_TV_MAX_FIFO_ADDR 0x1a7 +# define RADEON_TV_MAX_FIFO_ADDR_INTERNAL 0x1ff #define RADEON_TV_PLL_FINE_CNTL 0x0020 /* PLL */ #define RADEON_TV_PLL_CNTL 0x0021 /* PLL */ +# define RADEON_TV_M0LO_MASK 0xff +# define RADEON_TV_M0HI_MASK 0x3 +# define RADEON_TV_M0HI_SHIFT 18 +# define RADEON_TV_N0LO_MASK 0xff +# define RADEON_TV_N0LO_SHIFT 8 +# define RADEON_TV_N0HI_MASK 0x3 +# define RADEON_TV_N0HI_SHIFT 21 +# define RADEON_TV_P_MASK 0xf +# define RADEON_TV_P_SHIFT 24 # define RADEON_TV_SLIP_EN (1 << 23) # define RADEON_TV_DTO_EN (1 << 28) #define RADEON_TV_PLL_CNTL1 0x0022 /* PLL */ -# define RADEON_TVPLL_TEST_DIS (1 << 31) -# define RADEON_TVCLK_SRC_SEL_TVPLL (1 << 30) +# define RADEON_TVPLL_RESET (1 << 1) # define RADEON_TVPLL_SLEEP (1 << 3) # define RADEON_TVPLL_REFCLK_SEL (1 << 4) +# define RADEON_TVPDC_SHIFT 14 +# define RADEON_TVPDC_MASK (3 << 14) +# define RADEON_TVPLL_TEST_DIS (1 << 31) +# define RADEON_TVCLK_SRC_SEL_TVPLL (1 << 30) #define RADEON_RS480_UNK_e30 0xe30 #define RADEON_RS480_UNK_e34 0xe34 diff --git a/src/radeon_tv.c b/src/radeon_tv.c new file mode 100644 index 0000000..db5288a --- /dev/null +++ b/src/radeon_tv.c @@ -0,0 +1,759 @@ +/* + * Integrated TV out support based on the GATOS code by + * Federico Ulivi <fulivi@lycos.com> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <stdio.h> + +/* X and server generic header files */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "fbdevhw.h" +#include "vgaHW.h" +#include "xf86Modes.h" + +/* Driver data structures */ +#include "radeon.h" +#include "radeon_reg.h" +#include "radeon_macros.h" +#include "radeon_probe.h" +#include "radeon_version.h" +#include "radeon_tv.h" + +/********************************************************************** + * + * ModeConstants + * + * Storage of constants related to a single video mode + * + **********************************************************************/ + +typedef struct +{ + CARD16 horResolution; + CARD16 verResolution; + TVStd standard; + CARD16 horTotal; + CARD16 verTotal; + CARD16 horStart; + CARD16 horSyncStart; + CARD16 verSyncStart; + unsigned defRestart; + CARD16 crtcPLL_N; + CARD8 crtcPLL_M; + CARD8 crtcPLL_postDiv; + unsigned pixToTV; +} TVModeConstants; + +static const CARD16 hor_timing_NTSC[] = +{ + 0x0007, + 0x003f, + 0x0263, + 0x0a24, + 0x2a6b, + 0x0a36, + 0x126d, /* H_TABLE_POS1 */ + 0x1bfe, + 0x1a8f, /* H_TABLE_POS2 */ + 0x1ec7, + 0x3863, + 0x1bfe, + 0x1bfe, + 0x1a2a, + 0x1e95, + 0x0e31, + 0x201b, + 0 +}; + +static const CARD16 vert_timing_NTSC[] = +{ + 0x2001, + 0x200d, + 0x1006, + 0x0c06, + 0x1006, + 0x1818, + 0x21e3, + 0x1006, + 0x0c06, + 0x1006, + 0x1817, + 0x21d4, + 0x0002, + 0 +}; + +static const CARD16 hor_timing_PAL[] = +{ + 0x0007, + 0x0058, + 0x027c, + 0x0a31, + 0x2a77, + 0x0a95, + 0x124f, /* H_TABLE_POS1 */ + 0x1bfe, + 0x1b22, /* H_TABLE_POS2 */ + 0x1ef9, + 0x387c, + 0x1bfe, + 0x1bfe, + 0x1b31, + 0x1eb5, + 0x0e43, + 0x201b, + 0 +}; + +static const CARD16 vert_timing_PAL[] = +{ + 0x2001, + 0x200c, + 0x1005, + 0x0c05, + 0x1005, + 0x1401, + 0x1821, + 0x2240, + 0x1005, + 0x0c05, + 0x1005, + 0x1401, + 0x1822, + 0x2230, + 0x0002, + 0 +}; + +/********************************************************************** + * + * availableModes + * + * Table of all allowed modes for tv output + * + **********************************************************************/ +static const TVModeConstants availableTVModes[] = +{ + { + 800, /* horResolution */ + 600, /* verResolution */ + TV_STD_NTSC, /* standard */ + 990, /* horTotal */ + 740, /* verTotal */ + 813, /* horStart */ + 824, /* horSyncStart */ + 632, /* verSyncStart */ + 625592, /* defRestart */ + 592, /* crtcPLL_N */ + 91, /* crtcPLL_M */ + 4, /* crtcPLL_postDiv */ + 1022, /* pixToTV */ + }, + { + 800, /* horResolution */ + 600, /* verResolution */ + TV_STD_PAL, /* standard */ + 1144, /* horTotal */ + 706, /* verTotal */ + 812, /* horStart */ + 824, /* horSyncStart */ + 669, /* verSyncStart */ + 696700, /* defRestart */ + 1382, /* crtcPLL_N */ + 231, /* crtcPLL_M */ + 4, /* crtcPLL_postDiv */ + 759, /* pixToTV */ + } +}; + +#define N_AVAILABLE_MODES (sizeof(availableModes) / sizeof(availableModes[ 0 ])) + +static long YCOEF_value[5] = { 2, 2, 0, 4, 0 }; +static long YCOEF_EN_value[5] = { 1, 1, 0, 1, 0 }; +static long SLOPE_value[5] = { 1, 2, 2, 4, 8 }; +static long SLOPE_limit[5] = { 6, 5, 4, 3, 2 }; + + +/* Compute F,V,H restarts from default restart position and hPos & vPos + * Return TRUE when code timing table was changed + */ +static Bool RADEONInitTVRestarts(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(pScrn); + int restart; + unsigned hTotal; + unsigned vTotal; + unsigned fTotal; + int vOffset; + int hOffset; + CARD16 p1; + CARD16 p2; + Bool hChanged; + CARD16 hInc; + const TVModeConstants *constPtr; + + /* FIXME: need to revisit this when we add more modes */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + constPtr = &availableTVModes[0]; + else + constPtr = &availableTVModes[1]; + + hTotal = constPtr->horTotal; + vTotal = constPtr->verTotal; + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + fTotal = NTSC_TV_VFTOTAL + 1; + else + fTotal = PAL_TV_VFTOTAL + 1; + + /* Adjust positions 1&2 in hor. code timing table */ + hOffset = radeon_output->hPos * H_POS_UNIT; + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M) { + p1 = hor_timing_NTSC[ H_TABLE_POS1 ]; + p2 = hor_timing_NTSC[ H_TABLE_POS2 ]; + } else { + p1 = hor_timing_PAL[ H_TABLE_POS1 ]; + p2 = hor_timing_PAL[ H_TABLE_POS2 ]; + } + + + p1 = (CARD16)((int)p1 + hOffset); + p2 = (CARD16)((int)p2 - hOffset); + + hChanged = (p1 != save->h_code_timing[ H_TABLE_POS1 ] || + p2 != save->h_code_timing[ H_TABLE_POS2 ]); + + save->h_code_timing[ H_TABLE_POS1 ] = p1; + save->h_code_timing[ H_TABLE_POS2 ] = p2; + + /* Convert hOffset from n. of TV clock periods to n. of CRTC clock periods (CRTC pixels) */ + hOffset = (hOffset * (int)(constPtr->pixToTV)) / 1000; + + /* Adjust restart */ + restart = constPtr->defRestart; + + /* + * Convert vPos TV lines to n. of CRTC pixels + * Be verrrrry careful when mixing signed & unsigned values in C.. + */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M|| + radeon_output->tvStd == TV_STD_PAL_60) + vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(NTSC_TV_LINES_PER_FRAME); + else + vOffset = ((int)(vTotal * hTotal) * 2 * radeon_output->vPos) / (int)(PAL_TV_LINES_PER_FRAME); + + restart -= vOffset + hOffset; + + ErrorF("computeRestarts: def = %u, h = %d, v = %d, p1=%04x, p2=%04x, restart = %d\n", + constPtr->defRestart , radeon_output->hPos , radeon_output->vPos , p1 , p2 , restart); + + save->tv_hrestart = restart % hTotal; + restart /= hTotal; + save->tv_vrestart = restart % vTotal; + restart /= vTotal; + save->tv_frestart = restart % fTotal; + + ErrorF("computeRestarts: F/H/V=%u,%u,%u\n", + save->tv_frestart , save->tv_vrestart , save->tv_hrestart); + + /* Compute H_INC from hSize */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + hInc = (CARD16)((int)(constPtr->horResolution * 4096 * NTSC_TV_CLOCK_T) / + (radeon_output->hSize * (int)(NTSC_TV_H_SIZE_UNIT) + (int)(NTSC_TV_ZERO_H_SIZE))); + else + hInc = (CARD16)((int)(constPtr->horResolution * 4096 * PAL_TV_CLOCK_T) / + (radeon_output->hSize * (int)(PAL_TV_H_SIZE_UNIT) + (int)(PAL_TV_ZERO_H_SIZE))); + + save->tv_timing_cntl = (save->tv_timing_cntl & ~RADEON_H_INC_MASK) | + ((CARD32)hInc << RADEON_H_INC_SHIFT); + + ErrorF("computeRestarts: hSize=%d,hInc=%u\n" , radeon_output->hSize , hInc); + + return hChanged; +} + +/* intit TV-out regs */ +void RADEONInitTVRegisters(xf86OutputPtr output, RADEONSavePtr save, + DisplayModePtr mode, BOOL IsPrimary) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned i; + unsigned long vert_space, flicker_removal; + CARD32 tmp; + const TVModeConstants *constPtr; + const CARD16 *hor_timing; + const CARD16 *vert_timing; + + + /* FIXME: need to revisit this when we add more modes */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + constPtr = &availableTVModes[0]; + else + constPtr = &availableTVModes[1]; + + save->tv_crc_cntl = 0; + + save->tv_gain_limit_settings = (0x17f << RADEON_UV_GAIN_LIMIT_SHIFT) | + (0x5ff << RADEON_Y_GAIN_LIMIT_SHIFT); + + save->tv_hdisp = constPtr->horResolution - 1; + save->tv_hstart = constPtr->horStart; + save->tv_htotal = constPtr->horTotal - 1; + + save->tv_linear_gain_settings = (0x100 << RADEON_UV_GAIN_SHIFT) | + (0x100 << RADEON_Y_GAIN_SHIFT); + + save->tv_master_cntl = (RADEON_RESTART_PHASE_FIX + | RADEON_VIN_ASYNC_RST + | RADEON_AUD_ASYNC_RST + | RADEON_DVS_ASYNC_RST + | RADEON_CRT_FIFO_CE_EN + | RADEON_TV_FIFO_CE_EN + | RADEON_TV_ON); + + save->tv_modulator_cntl1 = RADEON_SLEW_RATE_LIMIT + | RADEON_SYNC_TIP_LEVEL + | RADEON_YFLT_EN + | RADEON_UVFLT_EN + | (0x3b << RADEON_BLANK_LEVEL_SHIFT) + | (0x6 << RADEON_CY_FILT_BLEND_SHIFT); + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60 || + radeon_output->tvStd == TV_STD_SCART_PAL) { + save->tv_modulator_cntl1 |= (0x46 << RADEON_SET_UP_LEVEL_SHIFT); + save->tv_modulator_cntl2 = 0x00000191; + } else { + save->tv_modulator_cntl1 |= RADEON_ALT_PHASE_EN + | (0x3b << RADEON_SET_UP_LEVEL_SHIFT); + save->tv_modulator_cntl2 = 0x003e01b2; + } + + save->pll_test_cntl = 0; + + save->tv_pre_dac_mux_cntl = (RADEON_Y_RED_EN + | RADEON_C_GRN_EN + | RADEON_CMP_BLU_EN + | RADEON_DAC_DITHER_EN); + + save->tv_rgb_cntl = (RADEON_RGB_DITHER_EN | RADEON_TVOUT_SCALE_EN + | (0x0b << 16) | (0x07 << 20)); + + if (IsPrimary) { + if (radeon_output->Flags & RADEON_USE_RMX) + save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_RMX; + else + save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC1; + } else { + save->tv_rgb_cntl |= RADEON_RGB_SRC_SEL_CRTC2; + } + + save->tv_sync_cntl = RADEON_SYNC_PUB | RADEON_TV_SYNC_IO_DRIVE; + + save->tv_sync_size = constPtr->horResolution + 8; + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + vert_space = constPtr->verTotal * 2 * 10000 / NTSC_TV_LINES_PER_FRAME; + else + vert_space = constPtr->verTotal * 2 * 10000 / PAL_TV_LINES_PER_FRAME; + + save->tv_vscaler_cntl1 = RADEON_Y_W_EN; + save->tv_vscaler_cntl1 = + (save->tv_vscaler_cntl1 & 0xe3ff0000) | (vert_space * (1 << FRAC_BITS) / 10000); + save->tv_vscaler_cntl1 |= RADEON_RESTART_FIELD; + if (constPtr->horResolution == 1024) + save->tv_vscaler_cntl1 |= (4 << RADEON_Y_DEL_W_SIG_SHIFT); + else + save->tv_vscaler_cntl1 |= (2 << RADEON_Y_DEL_W_SIG_SHIFT); + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + flicker_removal = + (float) constPtr->verTotal * 2.0 / NTSC_TV_LINES_PER_FRAME + 0.5; + else + flicker_removal = + (float) constPtr->verTotal * 2.0 / PAL_TV_LINES_PER_FRAME + 0.5; + + if (flicker_removal < 3) + flicker_removal = 3; + for (i = 0; i < 6; ++i) { + if (flicker_removal == SLOPE_limit[i]) + break; + } + save->tv_y_saw_tooth_cntl = + (vert_space * SLOPE_value[i] * (1 << (FRAC_BITS - 1)) + 5001) / 10000 / 8 + | ((SLOPE_value[i] * (1 << (FRAC_BITS - 1)) / 8) << 16); + save->tv_y_fall_cntl = + (YCOEF_EN_value[i] << 17) | ((YCOEF_value[i] * (1 << 8) / 8) << 24) | + RADEON_Y_FALL_PING_PONG | (272 * SLOPE_value[i] / 8) * (1 << (FRAC_BITS - 1)) / + 1024; + save->tv_y_rise_cntl = + RADEON_Y_RISE_PING_PONG + | (flicker_removal * 1024 - 272) * SLOPE_value[i] / 8 * (1 << (FRAC_BITS - 1)) / 1024; + + save->tv_vscaler_cntl2 = ((save->tv_vscaler_cntl2 & 0x00fffff0) + | (0x10 << 24) + | RADEON_DITHER_MODE + | RADEON_Y_OUTPUT_DITHER_EN + | RADEON_UV_OUTPUT_DITHER_EN + | RADEON_UV_TO_BUF_DITHER_EN); + + tmp = (save->tv_vscaler_cntl1 >> RADEON_UV_INC_SHIFT) & RADEON_UV_INC_MASK; + tmp = ((16384 * 256 * 10) / tmp + 5) / 10; + tmp = (tmp << RADEON_UV_OUTPUT_POST_SCALE_SHIFT) | 0x000b0000; + save->tv_timing_cntl = tmp; + + save->tv_dac_cntl = RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD | (8 << 16) | (6 << 20); + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + save->tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC; + else + save->tv_dac_cntl |= RADEON_TV_DAC_STD_PAL; + +#if 0 + /* needs fixes for r4xx */ + save->tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | RADEON_TV_DAC_GDACPD + | RADEON_TV_DAC_BDACPD); + + if (radeon_output->MonType == MT_CTV) { + save->tv_dac_cntl &= ~RADEON_TV_DAC_BDACPD; + } + + if (radeon_output->MonType == MT_STV) { + save->tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD); + } +#endif + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + save->tv_pll_cntl = (NTSC_TV_PLL_M & RADEON_TV_M0LO_MASK) | + (((NTSC_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | + ((NTSC_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | + (((NTSC_TV_PLL_N >> 8) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | + ((NTSC_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); + else + save->tv_pll_cntl = (PAL_TV_PLL_M & RADEON_TV_M0LO_MASK) | + (((PAL_TV_PLL_M >> 8) & RADEON_TV_M0HI_MASK) << RADEON_TV_M0HI_SHIFT) | + ((PAL_TV_PLL_N & RADEON_TV_N0LO_MASK) << RADEON_TV_N0LO_SHIFT) | + (((PAL_TV_PLL_N >> 8) & RADEON_TV_N0HI_MASK) << RADEON_TV_N0HI_SHIFT) | + ((PAL_TV_PLL_P & RADEON_TV_P_MASK) << RADEON_TV_P_SHIFT); + + save->tv_upsamp_and_gain_cntl = RADEON_YUPSAMP_EN | RADEON_UVUPSAMP_EN; + + save->tv_uv_adr = 0xc8; + + save->tv_vdisp = constPtr->verResolution - 1; + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + save->tv_ftotal = NTSC_TV_VFTOTAL; + else + save->tv_ftotal = PAL_TV_VFTOTAL; + + save->tv_vtotal = constPtr->verTotal - 1; + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M) { + hor_timing = hor_timing_NTSC; + } else { + hor_timing = hor_timing_PAL; + } + + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) { + vert_timing = vert_timing_NTSC; + } else { + vert_timing = vert_timing_PAL; + } + + for (i = 0; i < MAX_H_CODE_TIMING_LEN; i++) { + if ((save->h_code_timing[ i ] = hor_timing[ i ]) == 0) + break; + } + + for (i = 0; i < MAX_V_CODE_TIMING_LEN; i++) { + if ((save->v_code_timing[ i ] = vert_timing[ i ]) == 0) + break; + } + + /* + * This must be called AFTER loading timing tables as they are modified by this function + */ + RADEONInitTVRestarts(output, save, mode); + + save->dac_cntl &= ~RADEON_DAC_TVO_EN; + + if (IS_R300_VARIANT) + save->gpiopad_a = info->SavedReg.gpiopad_a & ~1; + + if (IsPrimary) { + save->disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK; + save->disp_output_cntl |= (RADEON_DISP_TVDAC_SOURCE_CRTC + | RADEON_DISP_TV_SOURCE_CRTC); + if (info->ChipFamily >= CHIP_FAMILY_R200) { + save->disp_tv_out_cntl &= ~RADEON_DISP_TV_PATH_SRC_CRTC2; + } else { + save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL; + } + } else { + save->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK; + save->disp_output_cntl |= RADEON_DISP_TV_SOURCE_CRTC; + + if (info->ChipFamily >= CHIP_FAMILY_R200) { + save->disp_tv_out_cntl |= RADEON_DISP_TV_PATH_SRC_CRTC2; + } else { + save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; + } + } +} + + +/* Set hw registers for a new h/v position & h size */ +void RADEONUpdateHVPosition(xf86OutputPtr output, DisplayModePtr mode) +{ + ScrnInfoPtr pScrn = output->scrn; + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + Bool reloadTable; + RADEONSavePtr restore = &info->ModeReg; + + reloadTable = RADEONInitTVRestarts(output, restore, mode); + + RADEONRestoreTVRestarts(pScrn, restore); + + OUTREG(RADEON_TV_TIMING_CNTL, restore->tv_timing_cntl); + + if (reloadTable) { + OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl + | RADEON_TV_ASYNC_RST + | RADEON_CRT_ASYNC_RST + | RADEON_RESTART_PHASE_FIX); + + RADEONRestoreTVTimingTables(pScrn, restore); + + OUTREG(RADEON_TV_MASTER_CNTL, restore->tv_master_cntl); + } +} + +void RADEONAdjustCrtcRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output) +{ + const TVModeConstants *constPtr; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + /* FIXME: need to revisit this when we add more modes */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + constPtr = &availableTVModes[0]; + else + constPtr = &availableTVModes[1]; + + save->crtc_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | + (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); + + save->crtc_h_sync_strt_wid = (save->crtc_h_sync_strt_wid + & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | + (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | + (constPtr->horSyncStart & 7); + + save->crtc_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | + ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); + + save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | + ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); + + save->disp_merge_cntl |= RADEON_DISP_RGB_OFFSET_EN; +} + +void RADEONAdjustPLLRegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output) +{ + unsigned postDiv; + const TVModeConstants *constPtr; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + /* FIXME: need to revisit this when we add more modes */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + constPtr = &availableTVModes[0]; + else + constPtr = &availableTVModes[1]; + + save->htotal_cntl = (constPtr->horTotal & 0x7 /*0xf*/) | RADEON_HTOT_CNTL_VGA_EN; + + save->ppll_ref_div = constPtr->crtcPLL_M; + + switch (constPtr->crtcPLL_postDiv) { + case 1: + postDiv = 0; + break; + case 2: + postDiv = 1; + break; + case 3: + postDiv = 4; + break; + case 4: + postDiv = 2; + break; + case 6: + postDiv = 6; + break; + case 8: + postDiv = 3; + break; + case 12: + postDiv = 7; + break; + case 16: + default: + postDiv = 5; + break; + } + + save->ppll_div_3 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); + + save->pixclks_cntl &= ~(RADEON_PIX2CLK_SRC_SEL_MASK | RADEON_PIXCLK_TV_SRC_SEL); + save->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLLCLK; + +} + +void RADEONAdjustCrtc2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output) +{ + const TVModeConstants *constPtr; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + /* FIXME: need to revisit this when we add more modes */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + constPtr = &availableTVModes[0]; + else + constPtr = &availableTVModes[1]; + + save->crtc2_h_total_disp = (((constPtr->horResolution / 8) - 1) << RADEON_CRTC_H_DISP_SHIFT) | + (((constPtr->horTotal / 8) - 1) << RADEON_CRTC_H_TOTAL_SHIFT); + + save->crtc2_h_sync_strt_wid = (save->crtc2_h_sync_strt_wid + & ~(RADEON_CRTC_H_SYNC_STRT_PIX | RADEON_CRTC_H_SYNC_STRT_CHAR)) | + (((constPtr->horSyncStart / 8) - 1) << RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT) | + (constPtr->horSyncStart & 7); + + save->crtc2_v_total_disp = ((constPtr->verResolution - 1) << RADEON_CRTC_V_DISP_SHIFT) | + ((constPtr->verTotal - 1) << RADEON_CRTC_V_TOTAL_SHIFT); + + save->crtc_v_sync_strt_wid = (save->crtc_v_sync_strt_wid & ~RADEON_CRTC_V_SYNC_STRT) | + ((constPtr->verSyncStart - 1) << RADEON_CRTC_V_SYNC_STRT_SHIFT); + + save->disp2_merge_cntl |= RADEON_DISP2_RGB_OFFSET_EN; +} + +void RADEONAdjustPLL2RegistersForTV(ScrnInfoPtr pScrn, RADEONSavePtr save, + DisplayModePtr mode, xf86OutputPtr output) +{ + unsigned postDiv; + const TVModeConstants *constPtr; + RADEONOutputPrivatePtr radeon_output = output->driver_private; + + /* FIXME: need to revisit this when we add more modes */ + if (radeon_output->tvStd == TV_STD_NTSC || + radeon_output->tvStd == TV_STD_NTSC_J || + radeon_output->tvStd == TV_STD_PAL_M || + radeon_output->tvStd == TV_STD_PAL_60) + constPtr = &availableTVModes[0]; + else + constPtr = &availableTVModes[1]; + + save->htotal_cntl2 = (constPtr->horTotal & 0x7); /* 0xf */ + + save->p2pll_ref_div = constPtr->crtcPLL_M; + + switch (constPtr->crtcPLL_postDiv) { + case 1: + postDiv = 0; + break; + case 2: + postDiv = 1; + break; + case 3: + postDiv = 4; + break; + case 4: + postDiv = 2; + break; + case 6: + postDiv = 6; + break; + case 8: + postDiv = 3; + break; + case 12: + postDiv = 7; + break; + case 16: + default: + postDiv = 5; + break; + } + + save->p2pll_div_0 = (constPtr->crtcPLL_N & 0x7ff) | (postDiv << 16); + + save->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; + save->pixclks_cntl |= (RADEON_PIX2CLK_SRC_SEL_P2PLLCLK + | RADEON_PIXCLK_TV_SRC_SEL); + +} diff --git a/src/radeon_tv.h b/src/radeon_tv.h new file mode 100644 index 0000000..5c8c8c9 --- /dev/null +++ b/src/radeon_tv.h @@ -0,0 +1,56 @@ +/* + * Integrated TV out support based on the GATOS code by + * Federico Ulivi <fulivi@lycos.com> + */ + +/* + * Maximum length of horizontal/vertical code timing tables for state storage + */ +#define MAX_H_CODE_TIMING_LEN 32 +#define MAX_V_CODE_TIMING_LEN 32 + +/* + * Limits of h/v positions (hPos & vPos) + */ +#define MAX_H_POSITION 5 /* Range: [-5..5], negative is on the left, 0 is default, positive is on the right */ +#define MAX_V_POSITION 5 /* Range: [-5..5], negative is up, 0 is default, positive is down */ + +/* + * Unit for hPos (in TV clock periods) + */ +#define H_POS_UNIT 10 + +/* + * Indexes in h. code timing table for horizontal line position adjustment + */ +#define H_TABLE_POS1 6 +#define H_TABLE_POS2 8 + +/* + * Limits of hor. size (hSize) + */ +#define MAX_H_SIZE 5 /* Range: [-5..5], negative is smaller, positive is larger */ + +/* tv standard constants */ +#define NTSC_TV_PLL_M 22 +#define NTSC_TV_PLL_N 175 +#define NTSC_TV_PLL_P 5 +#define NTSC_TV_CLOCK_T 233 +#define NTSC_TV_VFTOTAL 1 +#define NTSC_TV_LINES_PER_FRAME 525 +#define NTSC_TV_ZERO_H_SIZE 479166 +#define NTSC_TV_H_SIZE_UNIT 9478 + +#define PAL_TV_PLL_M 113 +#define PAL_TV_PLL_N 668 +#define PAL_TV_PLL_P 3 +#define PAL_TV_CLOCK_T 188 +#define PAL_TV_VFTOTAL 3 +#define PAL_TV_LINES_PER_FRAME 625 +#define PAL_TV_ZERO_H_SIZE 473200 +#define PAL_TV_H_SIZE_UNIT 9360 + + +#define VERT_LEAD_IN_LINES 2 +#define FRAC_BITS 0xe +#define FRAC_MASK 0x3fff diff --git a/src/radeon_version.h b/src/radeon_version.h index a1b2459..ccc1367 100644 --- a/src/radeon_version.h +++ b/src/radeon_version.h @@ -41,7 +41,7 @@ #define RADEON_VERSION_MAJOR 4 #define RADEON_VERSION_MAJOR_TILED 5 -#define RADEON_VERSION_MINOR 2 +#define RADEON_VERSION_MINOR 3 #define RADEON_VERSION_PATCH 0 #ifndef RADEON_VERSION_EXTRA diff --git a/src/radeon_video.c b/src/radeon_video.c index 2f8bec5..dbf66da 100644 --- a/src/radeon_video.c +++ b/src/radeon_video.c @@ -12,7 +12,6 @@ #include "radeon_reg.h" #include "radeon_macros.h" #include "radeon_probe.h" -#include "radeon_mergedfb.h" #include "radeon_video.h" #include "xf86.h" @@ -100,7 +99,7 @@ static void RADEON_TDA9885_SetEncoding(RADEONPortPrivPtr pPriv); static void RADEON_FI1236_SetEncoding(RADEONPortPrivPtr pPriv); -#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + #define ClipValue(v,min,max) ((v) < (min) ? (min) : (v) > (max) ? (max) : (v)) static Atom xvBrightness, xvColorKey, xvSaturation, xvDoubleBuffer; @@ -1194,7 +1193,6 @@ static void RADEONSetupTheatre(ScrnInfoPtr pScrn, RADEONPortPrivPtr pPriv) else pPriv->theatre=xf86_DetectTheatre(pPriv->VIP); - if(pPriv->theatre==NULL)return; /* just a matter of convenience */ @@ -1328,7 +1326,7 @@ RADEONAllocAdaptor(ScrnInfoPtr pScrn) */ /* Figure out which head we are on */ - if ((info->MergedFB && info->OverlayOnCRTC2) || info->IsSecondary) + if (info->OverlayOnCRTC2) dot_clock = info->ModeReg.dot_clock_freq_2; else dot_clock = info->ModeReg.dot_clock_freq; @@ -2404,6 +2402,7 @@ RADEONDisplayVideo( int deinterlacing_method ){ RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; CARD32 v_inc, h_inc, h_inc_uv, step_by_y, step_by_uv, tmp; double h_inc_d; @@ -2417,7 +2416,6 @@ RADEONDisplayVideo( int y_off; CARD32 scaler_src; CARD32 dot_clock; - DisplayModePtr overlay_mode; int is_rgb; int is_planar; int i; @@ -2427,6 +2425,10 @@ RADEONDisplayVideo( int predownscale=0; int src_w_d; int leftuv = 0; + xf86CrtcPtr crtc; + DisplayModePtr mode; + RADEONOutputPrivatePtr radeon_output; + xf86OutputPtr output; is_rgb=0; is_planar=0; switch(id){ @@ -2449,7 +2451,7 @@ RADEONDisplayVideo( workarounds for chip erratas */ /* Figure out which head we are on for dot clock */ - if ((info->MergedFB && info->OverlayOnCRTC2) || info->IsSecondary) + if (info->OverlayOnCRTC2) dot_clock = info->ModeReg.dot_clock_freq_2; else dot_clock = info->ModeReg.dot_clock_freq; @@ -2474,34 +2476,31 @@ RADEONDisplayVideo( v_inc_shift = 20; y_mult = 1; - if (info->MergedFB) { - if (info->OverlayOnCRTC2) - overlay_mode = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2; - else - overlay_mode = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT1; - if (overlay_mode->Flags & V_INTERLACE) - v_inc_shift++; - if (overlay_mode->Flags & V_DBLSCAN) { - v_inc_shift--; - y_mult = 2; + if (info->OverlayOnCRTC2) + crtc = xf86_config->crtc[1]; + else + crtc = xf86_config->crtc[0]; + + mode = &crtc->mode; + + if (mode->Flags & V_INTERLACE) + v_inc_shift++; + if (mode->Flags & V_DBLSCAN) { + v_inc_shift--; + y_mult = 2; + } + + for (i = 0; i < xf86_config->num_output; i++) { + output = xf86_config->output[i]; + if (output->crtc == crtc) { + radeon_output = output->driver_private; } - if (overlay_mode->Flags & RADEON_USE_RMX) { - v_inc = ((src_h * overlay_mode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h; - } else { - v_inc = (src_h << v_inc_shift) / drw_h; - } + } + + if (radeon_output->Flags & RADEON_USE_RMX) { + v_inc = ((src_h * mode->CrtcVDisplay / radeon_output->PanelYRes) << v_inc_shift) / drw_h; } else { - if (pScrn->currentMode->Flags & V_INTERLACE) - v_inc_shift++; - if (pScrn->currentMode->Flags & V_DBLSCAN) { - v_inc_shift--; - y_mult = 2; - } - if (pScrn->currentMode->Flags & RADEON_USE_RMX) { - v_inc = ((src_h * pScrn->currentMode->CrtcVDisplay / info->PanelYRes) << v_inc_shift) / drw_h; - } else { - v_inc = (src_h << v_inc_shift) / drw_h; - } + v_inc = (src_h << v_inc_shift) / drw_h; } h_inc = (1 << (12 + ecp_div)); @@ -2587,14 +2586,6 @@ RADEONDisplayVideo( offset5 += ((left >> 16) & ~7) << 1; offset6 += ((left >> 16) & ~7) << 1; } - if (info->IsSecondary) { - offset1 += info->FbMapSize; - offset2 += info->FbMapSize; - offset3 += info->FbMapSize; - offset4 += info->FbMapSize; - offset5 += info->FbMapSize; - offset6 += info->FbMapSize; - } tmp = (left & 0x0003ffff) + 0x00028000 + (h_inc << 3); p1_h_accum_init = ((tmp << 4) & 0x000f8000) | @@ -2645,19 +2636,15 @@ RADEONDisplayVideo( x_off = 0; /* needed to make the overlay work on crtc1 in leftof and above modes */ - if (info->MergedFB) { - RADEONScrn2Rel srel = - ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2Position; - overlay_mode = ((RADEONMergedDisplayModePtr)info->CurrentLayout.mode->Private)->CRT2; - if (srel == radeonLeftOf) { - x_off -= overlay_mode->CrtcHDisplay; - /* y_off -= pScrn->frameY0; */ - } - if (srel == radeonAbove) { - y_off -= overlay_mode->CrtcVDisplay; - /* x_off -= pScrn->frameX0; */ - } + /* XXX: may need to adjust x_off/y_off for dualhead like mergedfb -- need to test */ + /* + if (srel == radeonLeftOf) { + x_off -= mode->CrtcHDisplay; + } + if (srel == radeonAbove) { + y_off -= mode->CrtcVDisplay; } + */ /* Put the hardware overlay on CRTC2: * @@ -2666,7 +2653,7 @@ RADEONDisplayVideo( * rendering for the second head. */ - if ((info->MergedFB && info->OverlayOnCRTC2) || info->IsSecondary) { + if (info->OverlayOnCRTC2) { x_off = 0; OUTREG(RADEON_OV1_Y_X_START, ((dstBox->x1 + x_off) | ((dstBox->y1*y_mult) << 16))); @@ -2774,6 +2761,7 @@ RADEONPutImage( DrawablePtr pDraw ){ RADEONInfoPtr info = RADEONPTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; INT32 xa, xb, ya, yb; unsigned char *dst_start; @@ -2783,6 +2771,7 @@ RADEONPutImage( int top, left, npixels, nlines, bpp; BoxRec dstBox; CARD32 tmp; + xf86CrtcPtr crtc; /* * s2offset, s3offset - byte offsets into U and V plane of the @@ -2815,24 +2804,21 @@ RADEONPutImage( dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; - if (info->MergedFB) - RADEONChooseOverlayCRTC(pScrn, &dstBox); + RADEONChooseOverlayCRTC(pScrn, &dstBox); if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, width, height)) return Success; - if (info->MergedFB && info->OverlayOnCRTC2) { - dstBox.x1 -= info->CRT2pScrn->frameX0; - dstBox.x2 -= info->CRT2pScrn->frameX0; - dstBox.y1 -= info->CRT2pScrn->frameY0; - dstBox.y2 -= info->CRT2pScrn->frameY0; - } else { - dstBox.x1 -= pScrn->frameX0; - dstBox.x2 -= pScrn->frameX0; - dstBox.y1 -= pScrn->frameY0; - dstBox.y2 -= pScrn->frameY0; - } + if (info->OverlayOnCRTC2) + crtc = xf86_config->crtc[1]; + else + crtc = xf86_config->crtc[0]; + + dstBox.x1 -= crtc->x; + dstBox.x2 -= crtc->x; + dstBox.y1 -= crtc->y; + dstBox.y2 -= crtc->y; bpp = pScrn->bitsPerPixel >> 3; @@ -3174,12 +3160,13 @@ RADEONDisplaySurface( ){ OffscreenPrivPtr pPriv = (OffscreenPrivPtr)surface->devPrivate.ptr; ScrnInfoPtr pScrn = surface->pScrn; - + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); RADEONInfoPtr info = RADEONPTR(pScrn); RADEONPortPrivPtr portPriv = info->adaptor->pPortPrivates[0].ptr; INT32 xa, ya, xb, yb; BoxRec dstBox; + xf86CrtcPtr crtc; if (src_w > (drw_w << 4)) drw_w = src_w >> 4; @@ -3196,24 +3183,21 @@ RADEONDisplaySurface( dstBox.y1 = drw_y; dstBox.y2 = drw_y + drw_h; - if (info->MergedFB) - RADEONChooseOverlayCRTC(pScrn, &dstBox); + RADEONChooseOverlayCRTC(pScrn, &dstBox); if (!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, surface->width, surface->height)) return Success; - if (info->MergedFB && info->OverlayOnCRTC2) { - dstBox.x1 -= info->CRT2pScrn->frameX0; - dstBox.x2 -= info->CRT2pScrn->frameX0; - dstBox.y1 -= info->CRT2pScrn->frameY0; - dstBox.y2 -= info->CRT2pScrn->frameY0; - } else { - dstBox.x1 -= pScrn->frameX0; - dstBox.x2 -= pScrn->frameX0; - dstBox.y1 -= pScrn->frameY0; - dstBox.y2 -= pScrn->frameY0; - } + if (info->OverlayOnCRTC2) + crtc = xf86_config->crtc[1]; + else + crtc = xf86_config->crtc[0]; + + dstBox.x1 -= crtc->x; + dstBox.x2 -= crtc->x; + dstBox.y1 -= crtc->y; + dstBox.y2 -= crtc->y; #if 0 /* this isn't needed */ @@ -3285,6 +3269,7 @@ RADEONPutVideo( ){ RADEONInfoPtr info = RADEONPTR(pScrn); RADEONPortPrivPtr pPriv = (RADEONPortPrivPtr)data; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; INT32 xa, xb, ya, yb, top; unsigned int pitch, new_size, alloc_size; @@ -3297,6 +3282,7 @@ RADEONPutVideo( int width, height; int mult; int vbi_line_width, vbi_start, vbi_end; + xf86CrtcPtr crtc; RADEON_SYNC(info, pScrn); /* @@ -3338,23 +3324,20 @@ RADEONPutVideo( else vbi_line_width = 2000; /* might need adjustment */ - if (info->MergedFB) - RADEONChooseOverlayCRTC(pScrn, &dstBox); + RADEONChooseOverlayCRTC(pScrn, &dstBox); if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes, width, height)) return Success; - if (info->MergedFB && info->OverlayOnCRTC2) { - dstBox.x1 -= info->CRT2pScrn->frameX0; - dstBox.x2 -= info->CRT2pScrn->frameX0; - dstBox.y1 -= info->CRT2pScrn->frameY0; - dstBox.y2 -= info->CRT2pScrn->frameY0; - } else { - dstBox.x1 -= pScrn->frameX0; - dstBox.x2 -= pScrn->frameX0; - dstBox.y1 -= pScrn->frameY0; - dstBox.y2 -= pScrn->frameY0; - } + if (info->OverlayOnCRTC2) + crtc = xf86_config->crtc[1]; + else + crtc = xf86_config->crtc[0]; + + dstBox.x1 -= crtc->x; + dstBox.x2 -= crtc->x; + dstBox.y1 -= crtc->y; + dstBox.y2 -= crtc->y; bpp = pScrn->bitsPerPixel >> 3; pitch = bpp * pScrn->displayWidth; |