Merge branch 'modesetting-origin' into modesetting
This commit is contained in:
commit
cd9c6e2914
|
|
@ -53,6 +53,7 @@ i810_drv_la_SOURCES = \
|
|||
i830_bios.c \
|
||||
i830_bios.h \
|
||||
i830_common.h \
|
||||
i830_crt.c \
|
||||
i830_cursor.c \
|
||||
i830_debug.c \
|
||||
i830_debug.h \
|
||||
|
|
@ -65,6 +66,7 @@ i810_drv_la_SOURCES = \
|
|||
i830_gtf.c \
|
||||
i830_i2c.c \
|
||||
i830_io.c \
|
||||
i830_lvds.c \
|
||||
i830_memory.c \
|
||||
i830_modes.c \
|
||||
i830_video.c \
|
||||
|
|
@ -75,6 +77,7 @@ i810_drv_la_SOURCES = \
|
|||
i830_sdvo.c \
|
||||
i830_sdvo.h \
|
||||
i830_sdvo_regs.h \
|
||||
i830_tv.c \
|
||||
i830_xf86Modes.h \
|
||||
i830_xf86Modes.c \
|
||||
i915_3d.c \
|
||||
|
|
|
|||
563
src/i810_reg.h
563
src/i810_reg.h
|
|
@ -26,9 +26,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
**************************************************************************/
|
||||
|
||||
/** @file
|
||||
* Register names and fields for Intel graphics.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Authors:
|
||||
* Keith Whitwell <keith@tungstengraphics.com>
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
* based on the i740 driver by
|
||||
* Kevin E. Martin <kevin@precisioninsight.com>
|
||||
|
|
@ -928,6 +933,564 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
# define LVDS_CLKA_POWER_DOWN (0 << 8)
|
||||
# define LVDS_CLKA_POWER_UP (3 << 8)
|
||||
|
||||
/** @defgroup TV_CTL
|
||||
* @{
|
||||
*/
|
||||
#define TV_CTL 0x68000
|
||||
/** Enables the TV encoder */
|
||||
# define TV_ENC_ENABLE (1 << 31)
|
||||
/** Sources the TV encoder input from pipe B instead of A. */
|
||||
# define TV_ENC_PIPEB_SELECT (1 << 30)
|
||||
/** Outputs composite video (DAC A only) */
|
||||
# define TV_ENC_OUTPUT_COMPOSITE (0 << 28)
|
||||
/** Outputs SVideo video (DAC B/C) */
|
||||
# define TV_ENC_OUTPUT_SVIDEO (1 << 28)
|
||||
/** Outputs Component video (DAC A/B/C) */
|
||||
# define TV_ENC_OUTPUT_COMPONENT (2 << 28)
|
||||
# define TV_TRILEVEL_SYNC (1 << 21)
|
||||
/** Enables slow sync generation (945GM only) */
|
||||
# define TV_SLOW_SYNC (1 << 20)
|
||||
/** Selects 4x oversampling for 480i and 576p */
|
||||
# define TV_OVERSAMPLE_4X (0 << 18)
|
||||
/** Selects 2x oversampling for 720p and 1080i */
|
||||
# define TV_OVERSAMPLE_2X (1 << 18)
|
||||
/** Selects no oversampling for 1080p */
|
||||
# define TV_OVERSAMPLE_NONE (2 << 18)
|
||||
/** Selects 8x oversampling */
|
||||
# define TV_OVERSAMPLE_8X (3 << 18)
|
||||
/** Selects progressive mode rather than interlaced */
|
||||
# define TV_PROGRESSIVE (1 << 17)
|
||||
/** Sets the colorburst to PAL mode. Required for non-M PAL modes. */
|
||||
# define TV_PAL_BURST (1 << 16)
|
||||
/** Field for setting delay of Y compared to C */
|
||||
# define TV_YC_SKEW_MASK (7 << 12)
|
||||
/** Enables a fix for 480p/576p standard definition modes on the 915GM only */
|
||||
# define TV_ENC_SDP_FIX (1 << 11)
|
||||
/**
|
||||
* Enables a fix for the 915GM only.
|
||||
*
|
||||
* Not sure what it does.
|
||||
*/
|
||||
# define TV_ENC_C0_FIX (1 << 10)
|
||||
/** Bits that must be preserved by software */
|
||||
# define TV_CTL_SAVE ((3 << 8) | (3 << 6))
|
||||
# define TV_FUSE_STATE_MASK (3 << 4)
|
||||
/** Read-only state that reports all features enabled */
|
||||
# define TV_FUSE_STATE_ENABLED (0 << 4)
|
||||
/** Read-only state that reports that Macrovision is disabled in hardware*/
|
||||
# define TV_FUSE_STATE_NO_MACROVISION (1 << 4)
|
||||
/** Read-only state that reports that TV-out is disabled in hardware. */
|
||||
# define TV_FUSE_STATE_DISABLED (2 << 4)
|
||||
/**
|
||||
* This test mode forces the DACs to 50% of full output.
|
||||
*
|
||||
* This is used for load detection in combination with TVDAC_SENSE_MASK
|
||||
*/
|
||||
# define TV_TEST_MODE_MONITOR_DETECT (7 << 0)
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_DAC
|
||||
* @{
|
||||
*/
|
||||
#define TV_DAC 0x68004
|
||||
/**
|
||||
* Reports that DAC state change logic has reported change (RO).
|
||||
*
|
||||
* This gets cleared when TV_DAC_STATE_EN is cleared
|
||||
*/
|
||||
# define TVDAC_STATE_CHG (1 << 31)
|
||||
# define TVDAC_SENSE_MASK (7 << 28)
|
||||
/** Reports that DAC A voltage is above the detect threshold */
|
||||
# define TVDAC_A_SENSE (1 << 30)
|
||||
/** Reports that DAC B voltage is above the detect threshold */
|
||||
# define TVDAC_B_SENSE (1 << 29)
|
||||
/** Reports that DAC C voltage is above the detect threshold */
|
||||
# define TVDAC_C_SENSE (1 << 28)
|
||||
/**
|
||||
* Enables DAC state detection logic, for load-based TV detection.
|
||||
*
|
||||
* The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
|
||||
* to off, for load detection to work.
|
||||
*/
|
||||
# define TVDAC_STATE_CHG_EN (1 << 27)
|
||||
/** Sets the DAC A sense value to high */
|
||||
# define TVDAC_A_SENSE_CTL (1 << 26)
|
||||
/** Sets the DAC B sense value to high */
|
||||
# define TVDAC_B_SENSE_CTL (1 << 25)
|
||||
/** Sets the DAC C sense value to high */
|
||||
# define TVDAC_C_SENSE_CTL (1 << 24)
|
||||
/** Overrides the ENC_ENABLE and DAC voltage levels */
|
||||
# define DAC_CTL_OVERRIDE (1 << 7)
|
||||
/** Sets the slew rate. Must be preserved in software */
|
||||
# define ENC_TVDAC_SLEW_FAST (1 << 6)
|
||||
# define DAC_A_1_3_V (0 << 4)
|
||||
# define DAC_A_1_1_V (1 << 4)
|
||||
# define DAC_A_0_7_V (2 << 4)
|
||||
# define DAC_A_OFF (3 << 4)
|
||||
# define DAC_B_1_3_V (0 << 2)
|
||||
# define DAC_B_1_1_V (1 << 2)
|
||||
# define DAC_B_0_7_V (2 << 2)
|
||||
# define DAC_B_OFF (3 << 2)
|
||||
# define DAC_C_1_3_V (0 << 0)
|
||||
# define DAC_C_1_1_V (1 << 0)
|
||||
# define DAC_C_0_7_V (2 << 0)
|
||||
# define DAC_C_OFF (3 << 0)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* CSC coefficients are stored in a floating point format with 9 bits of
|
||||
* mantissa and 2 or 3 bits of exponent. The exponent is represented as 2**-n,
|
||||
* where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
|
||||
* -1 (0x3) being the only legal negative value.
|
||||
*/
|
||||
#define TV_CSC_Y 0x68010
|
||||
# define TV_RY_MASK 0x07ff0000
|
||||
# define TV_RY_SHIFT 16
|
||||
# define TV_GY_MASK 0x00000fff
|
||||
# define TV_GY_SHIFT 0
|
||||
|
||||
#define TV_CSC_Y2 0x68014
|
||||
# define TV_BY_MASK 0x07ff0000
|
||||
# define TV_BY_SHIFT 16
|
||||
/**
|
||||
* Y attenuation for component video.
|
||||
*
|
||||
* Stored in 1.9 fixed point.
|
||||
*/
|
||||
# define TV_AY_MASK 0x000003ff
|
||||
# define TV_AY_SHIFT 0
|
||||
|
||||
#define TV_CSC_U 0x68018
|
||||
# define TV_RU_MASK 0x07ff0000
|
||||
# define TV_RU_SHIFT 16
|
||||
# define TV_GU_MASK 0x000007ff
|
||||
# define TV_GU_SHIFT 0
|
||||
|
||||
#define TV_CSC_U2 0x6801c
|
||||
# define TV_BU_MASK 0x07ff0000
|
||||
# define TV_BU_SHIFT 16
|
||||
/**
|
||||
* U attenuation for component video.
|
||||
*
|
||||
* Stored in 1.9 fixed point.
|
||||
*/
|
||||
# define TV_AU_MASK 0x000003ff
|
||||
# define TV_AU_SHIFT 0
|
||||
|
||||
#define TV_CSC_V 0x68020
|
||||
# define TV_RV_MASK 0x0fff0000
|
||||
# define TV_RV_SHIFT 16
|
||||
# define TV_GV_MASK 0x000007ff
|
||||
# define TV_GV_SHIFT 0
|
||||
|
||||
#define TV_CSC_V2 0x68024
|
||||
# define TV_BV_MASK 0x07ff0000
|
||||
# define TV_BV_SHIFT 16
|
||||
/**
|
||||
* V attenuation for component video.
|
||||
*
|
||||
* Stored in 1.9 fixed point.
|
||||
*/
|
||||
# define TV_AV_MASK 0x000007ff
|
||||
# define TV_AV_SHIFT 0
|
||||
|
||||
/** @defgroup TV_CSC_KNOBS
|
||||
* @{
|
||||
*/
|
||||
#define TV_CLR_KNOBS 0x68028
|
||||
/** 2s-complement brightness adjustment */
|
||||
# define TV_BRIGHTNESS_MASK 0xff000000
|
||||
# define TV_BRIGHTNESS_SHIFT 24
|
||||
/** Contrast adjustment, as a 2.6 unsigned floating point number */
|
||||
# define TV_CONTRAST_MASK 0x00ff0000
|
||||
# define TV_CONTRAST_SHIFT 16
|
||||
/** Saturation adjustment, as a 2.6 unsigned floating point number */
|
||||
# define TV_SATURATION_MASK 0x0000ff00
|
||||
# define TV_SATURATION_SHIFT 8
|
||||
/** Hue adjustment, as an integer phase angle in degrees */
|
||||
# define TV_HUE_MASK 0x000000ff
|
||||
# define TV_HUE_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_CLR_LEVEL
|
||||
* @{
|
||||
*/
|
||||
#define TV_CLR_LEVEL 0x6802c
|
||||
/** Controls the DAC level for black */
|
||||
# define TV_BLACK_LEVEL_MASK 0x01ff0000
|
||||
# define TV_BLACK_LEVEL_SHIFT 16
|
||||
/** Controls the DAC level for blanking */
|
||||
# define TV_BLANK_LEVEL_MASK 0x000001ff
|
||||
# define TV_BLANK_LEVEL_SHIFT 0
|
||||
/* @} */
|
||||
|
||||
/** @defgroup TV_H_CTL_1
|
||||
* @{
|
||||
*/
|
||||
#define TV_H_CTL_1 0x68030
|
||||
/** Number of pixels in the hsync. */
|
||||
# define TV_HSYNC_END_MASK 0x1fff0000
|
||||
# define TV_HSYNC_END_SHIFT 16
|
||||
/** Total number of pixels minus one in the line (display and blanking). */
|
||||
# define TV_HTOTAL_MASK 0x00001fff
|
||||
# define TV_HTOTAL_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_H_CTL_2
|
||||
* @{
|
||||
*/
|
||||
#define TV_H_CTL_2 0x68034
|
||||
/** Enables the colorburst (needed for non-component color) */
|
||||
# define TV_BURST_ENA (1 << 31)
|
||||
/** Offset of the colorburst from the start of hsync, in pixels minus one. */
|
||||
# define TV_HBURST_START_SHIFT 16
|
||||
# define TV_HBURST_START_MASK 0x1fff0000
|
||||
/** Length of the colorburst */
|
||||
# define TV_HBURST_LEN_SHIFT 0
|
||||
# define TV_HBURST_LEN_MASK 0x0001fff
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_H_CTL_3
|
||||
* @{
|
||||
*/
|
||||
#define TV_H_CTL_3 0x68038
|
||||
/** End of hblank, measured in pixels minus one from start of hsync */
|
||||
# define TV_HBLANK_END_SHIFT 16
|
||||
# define TV_HBLANK_END_MASK 0x1fff0000
|
||||
/** Start of hblank, measured in pixels minus one from start of hsync */
|
||||
# define TV_HBLANK_START_SHIFT 0
|
||||
# define TV_HBLANK_START_MASK 0x0001fff
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_1
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_1 0x6803c
|
||||
/** XXX */
|
||||
# define TV_NBR_END_SHIFT 16
|
||||
# define TV_NBR_END_MASK 0x07ff0000
|
||||
/** XXX */
|
||||
# define TV_VI_END_F1_SHIFT 8
|
||||
# define TV_VI_END_F1_MASK 0x00003f00
|
||||
/** XXX */
|
||||
# define TV_VI_END_F2_SHIFT 0
|
||||
# define TV_VI_END_F2_MASK 0x0000003f
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_2
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_2 0x68040
|
||||
/** Length of vsync, in half lines */
|
||||
# define TV_VSYNC_LEN_MASK 0x07ff0000
|
||||
# define TV_VSYNC_LEN_SHIFT 16
|
||||
/** Offset of the start of vsync in field 1, measured in one less than the
|
||||
* number of half lines.
|
||||
*/
|
||||
# define TV_VSYNC_START_F1_MASK 0x00007f00
|
||||
# define TV_VSYNC_START_F1_SHIFT 8
|
||||
/**
|
||||
* Offset of the start of vsync in field 2, measured in one less than the
|
||||
* number of half lines.
|
||||
*/
|
||||
# define TV_VSYNC_START_F2_MASK 0x0000007f
|
||||
# define TV_VSYNC_START_F2_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_3
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_3 0x68044
|
||||
/** Enables generation of the equalization signal */
|
||||
# define TV_EQUAL_ENA (1 << 31)
|
||||
/** Length of vsync, in half lines */
|
||||
# define TV_VEQ_LEN_MASK 0x007f0000
|
||||
# define TV_VEQ_LEN_SHIFT 16
|
||||
/** Offset of the start of equalization in field 1, measured in one less than
|
||||
* the number of half lines.
|
||||
*/
|
||||
# define TV_VEQ_START_F1_MASK 0x0007f00
|
||||
# define TV_VEQ_START_F1_SHIFT 8
|
||||
/**
|
||||
* Offset of the start of equalization in field 2, measured in one less than
|
||||
* the number of half lines.
|
||||
*/
|
||||
# define TV_VEQ_START_F2_MASK 0x000007f
|
||||
# define TV_VEQ_START_F2_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_4
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_4 0x68048
|
||||
/**
|
||||
* Offset to start of vertical colorburst, measured in one less than the
|
||||
* number of lines from vertical start.
|
||||
*/
|
||||
# define TV_VBURST_START_F1_MASK 0x003f0000
|
||||
# define TV_VBURST_START_F1_SHIFT 16
|
||||
/**
|
||||
* Offset to the end of vertical colorburst, measured in one less than the
|
||||
* number of lines from the start of NBR.
|
||||
*/
|
||||
# define TV_VBURST_END_F1_MASK 0x000000ff
|
||||
# define TV_VBURST_END_F1_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_5
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_5 0x6804c
|
||||
/**
|
||||
* Offset to start of vertical colorburst, measured in one less than the
|
||||
* number of lines from vertical start.
|
||||
*/
|
||||
# define TV_VBURST_START_F2_MASK 0x003f0000
|
||||
# define TV_VBURST_START_F2_SHIFT 16
|
||||
/**
|
||||
* Offset to the end of vertical colorburst, measured in one less than the
|
||||
* number of lines from the start of NBR.
|
||||
*/
|
||||
# define TV_VBURST_END_F2_MASK 0x000000ff
|
||||
# define TV_VBURST_END_F2_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_6
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_6 0x68050
|
||||
/**
|
||||
* Offset to start of vertical colorburst, measured in one less than the
|
||||
* number of lines from vertical start.
|
||||
*/
|
||||
# define TV_VBURST_START_F3_MASK 0x003f0000
|
||||
# define TV_VBURST_START_F3_SHIFT 16
|
||||
/**
|
||||
* Offset to the end of vertical colorburst, measured in one less than the
|
||||
* number of lines from the start of NBR.
|
||||
*/
|
||||
# define TV_VBURST_END_F3_MASK 0x000000ff
|
||||
# define TV_VBURST_END_F3_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_V_CTL_7
|
||||
* @{
|
||||
*/
|
||||
#define TV_V_CTL_7 0x68054
|
||||
/**
|
||||
* Offset to start of vertical colorburst, measured in one less than the
|
||||
* number of lines from vertical start.
|
||||
*/
|
||||
# define TV_VBURST_START_F4_MASK 0x003f0000
|
||||
# define TV_VBURST_START_F4_SHIFT 16
|
||||
/**
|
||||
* Offset to the end of vertical colorburst, measured in one less than the
|
||||
* number of lines from the start of NBR.
|
||||
*/
|
||||
# define TV_VBURST_END_F4_MASK 0x000000ff
|
||||
# define TV_VBURST_END_F4_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_SC_CTL_1
|
||||
* @{
|
||||
*/
|
||||
#define TV_SC_CTL_1 0x68060
|
||||
/** Turns on the first subcarrier phase generation DDA */
|
||||
# define TV_SC_DDA1_EN (1 << 31)
|
||||
/** Turns on the first subcarrier phase generation DDA */
|
||||
# define TV_SC_DDA2_EN (2 << 31)
|
||||
/** Turns on the first subcarrier phase generation DDA */
|
||||
# define TV_SC_DDA3_EN (3 << 31)
|
||||
/** Sets the subcarrier DDA to reset frequency every other field */
|
||||
# define TV_SC_RESET_EVERY_2 (0 << 24)
|
||||
/** Sets the subcarrier DDA to reset frequency every fourth field */
|
||||
# define TV_SC_RESET_EVERY_4 (1 << 24)
|
||||
/** Sets the subcarrier DDA to reset frequency every eighth field */
|
||||
# define TV_SC_RESET_EVERY_8 (2 << 24)
|
||||
/** Sets the subcarrier DDA to never reset the frequency */
|
||||
# define TV_SC_RESET_NEVER (3 << 24)
|
||||
/** Sets the peak amplitude of the colorburst.*/
|
||||
# define TV_BURST_LEVEL_MASK 0x00ff0000
|
||||
# define TV_BURST_LEVEL_SHIFT 16
|
||||
/** Sets the increment of the first subcarrier phase generation DDA */
|
||||
# define TV_SCDDA1_INC_MASK 0x00000fff
|
||||
# define TV_SCDDA1_INC_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_SC_CTL_2
|
||||
* @{
|
||||
*/
|
||||
#define TV_SC_CTL_2 0x68068
|
||||
/** Sets the rollover for the second subcarrier phase generation DDA */
|
||||
# define TV_SCDDA2_SIZE_MASK 0x7fff0000
|
||||
# define TV_SCDDA2_SIZE_SHIFT 16
|
||||
/** Sets the increent of the second subcarrier phase generation DDA */
|
||||
# define TV_SCDDA2_INC_MASK 0x00007fff
|
||||
# define TV_SCDDA2_INC_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_SC_CTL_3
|
||||
* @{
|
||||
*/
|
||||
#define TV_SC_CTL_3 0x68068
|
||||
/** Sets the rollover for the third subcarrier phase generation DDA */
|
||||
# define TV_SCDDA3_SIZE_MASK 0x7fff0000
|
||||
# define TV_SCDDA3_SIZE_SHIFT 16
|
||||
/** Sets the increent of the third subcarrier phase generation DDA */
|
||||
# define TV_SCDDA3_INC_MASK 0x00007fff
|
||||
# define TV_SCDDA3_INC_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_WIN_POS
|
||||
* @{
|
||||
*/
|
||||
#define TV_WIN_POS 0x68070
|
||||
/** X coordinate of the display from the start of horizontal active */
|
||||
# define TV_XPOS_MASK 0x1fff0000
|
||||
# define TV_XPOS_SHIFT 16
|
||||
/** Y coordinate of the display from the start of vertical active (NBR) */
|
||||
# define TV_YPOS_MASK 0x00000fff
|
||||
# define TV_YPOS_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_WIN_SIZE
|
||||
* @{
|
||||
*/
|
||||
#define TV_WIN_SIZE 0x68074
|
||||
/** Horizontal size of the display window, measured in pixels*/
|
||||
# define TV_XSIZE_MASK 0x1fff0000
|
||||
# define TV_XSIZE_SHIFT 16
|
||||
/**
|
||||
* Vertical size of the display window, measured in pixels.
|
||||
*
|
||||
* Must be even for interlaced modes.
|
||||
*/
|
||||
# define TV_YSIZE_MASK 0x00000fff
|
||||
# define TV_YSIZE_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_FILTER_CTL_1
|
||||
* @{
|
||||
*/
|
||||
#define TV_FILTER_CTL_1 0x68080
|
||||
/**
|
||||
* Enables automatic scaling calculation.
|
||||
*
|
||||
* If set, the rest of the registers are ignored, and the calculated values can
|
||||
* be read back from the register.
|
||||
*/
|
||||
# define TV_AUTO_SCALE (1 << 31)
|
||||
/**
|
||||
* Disables the vertical filter.
|
||||
*
|
||||
* This is required on modes more than 1024 pixels wide */
|
||||
# define TV_V_FILTER_BYPASS (1 << 29)
|
||||
/** Enables adaptive vertical filtering */
|
||||
# define TV_VADAPT (1 << 28)
|
||||
# define TV_VADAPT_MODE_MASK (3 << 26)
|
||||
/** Selects the least adaptive vertical filtering mode */
|
||||
# define TV_VADAPT_MODE_LEAST (0 << 26)
|
||||
/** Selects the moderately adaptive vertical filtering mode */
|
||||
# define TV_VADAPT_MODE_MODERATE (1 << 26)
|
||||
/** Selects the most adaptive vertical filtering mode */
|
||||
# define TV_VADAPT_MODE_MOST (3 << 26)
|
||||
/**
|
||||
* Sets the horizontal scaling factor.
|
||||
*
|
||||
* This should be the fractional part of the horizontal scaling factor divided
|
||||
* by the oversampling rate. TV_HSCALE should be less than 1, and set to:
|
||||
*
|
||||
* (src width - 1) / ((oversample * dest width) - 1)
|
||||
*/
|
||||
# define TV_HSCALE_FRAC_MASK 0x00003fff
|
||||
# define TV_HSCALE_FRAC_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_FILTER_CTL_2
|
||||
* @{
|
||||
*/
|
||||
#define TV_FILTER_CTL_2 0x68084
|
||||
/**
|
||||
* Sets the integer part of the 3.15 fixed-point vertical scaling factor.
|
||||
*
|
||||
* TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
|
||||
*/
|
||||
# define TV_VSCALE_INT_MASK 0x00038000
|
||||
# define TV_VSCALE_INT_SHIFT 15
|
||||
/**
|
||||
* Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
|
||||
*
|
||||
* \sa TV_VSCALE_INT_MASK
|
||||
*/
|
||||
# define TV_VSCALE_FRAC_MASK 0x00007fff
|
||||
# define TV_VSCALE_FRAC_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_FILTER_CTL_3
|
||||
* @{
|
||||
*/
|
||||
#define TV_FILTER_CTL_3 0x68088
|
||||
/**
|
||||
* Sets the integer part of the 3.15 fixed-point vertical scaling factor.
|
||||
*
|
||||
* TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
|
||||
*
|
||||
* For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
|
||||
*/
|
||||
# define TV_VSCALE_IP_INT_MASK 0x00038000
|
||||
# define TV_VSCALE_IP_INT_SHIFT 15
|
||||
/**
|
||||
* Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
|
||||
*
|
||||
* For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
|
||||
*
|
||||
* \sa TV_VSCALE_IP_INT_MASK
|
||||
*/
|
||||
# define TV_VSCALE_IP_FRAC_MASK 0x00007fff
|
||||
# define TV_VSCALE_IP_FRAC_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_CC_CONTROL
|
||||
* @{
|
||||
*/
|
||||
#define TV_CC_CONTROL 0x68090
|
||||
# define TV_CC_ENABLE (1 << 31)
|
||||
/**
|
||||
* Specifies which field to send the CC data in.
|
||||
*
|
||||
* CC data is usually sent in field 0.
|
||||
*/
|
||||
# define TV_CC_FID_MASK (1 << 27)
|
||||
# define TV_CC_FID_SHIFT 27
|
||||
/** Sets the horizontal position of the CC data. Usually 135. */
|
||||
# define TV_CC_HOFF_MASK 0x03ff0000
|
||||
# define TV_CC_HOFF_SHIFT 16
|
||||
/** Sets the vertical position of the CC data. Usually 21 */
|
||||
# define TV_CC_LINE_MASK 0x0000003f
|
||||
# define TV_CC_LINE_SHIFT 0
|
||||
/** @} */
|
||||
|
||||
/** @defgroup TV_CC_DATA
|
||||
* @{
|
||||
*/
|
||||
#define TV_CC_DATA 0x68094
|
||||
# define TV_CC_RDY (1 << 31)
|
||||
/** Second word of CC data to be transmitted. */
|
||||
# define TV_CC_DATA_2_MASK 0x007f0000
|
||||
# define TV_CC_DATA_2_SHIFT 16
|
||||
/** First word of CC data to be transmitted. */
|
||||
# define TV_CC_DATA_1_MASK 0x0000007f
|
||||
# define TV_CC_DATA_1_SHIFT 0
|
||||
/** @}
|
||||
*/
|
||||
|
||||
/** @{ */
|
||||
#define TV_H_LUMA_0 0x68100
|
||||
#define TV_H_LUMA_59 0x681ec
|
||||
#define TV_H_CHROMA_0 0x68200
|
||||
#define TV_H_CHROMA_59 0x682ec
|
||||
/** @} */
|
||||
|
||||
#define PIPEACONF 0x70008
|
||||
#define PIPEACONF_ENABLE (1<<31)
|
||||
#define PIPEACONF_DISABLE 0
|
||||
|
|
|
|||
70
src/i830.h
70
src/i830.h
|
|
@ -69,6 +69,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include "i830_dri.h"
|
||||
#endif
|
||||
|
||||
typedef struct _I830OutputRec I830OutputRec, *I830OutputPtr;
|
||||
|
||||
#include "common.h"
|
||||
#include "i830_sdvo.h"
|
||||
#include "i2c_vid.h"
|
||||
|
|
@ -209,6 +211,9 @@ typedef struct _I830SDVODriver {
|
|||
CARD32 output_device; /* SDVOB or SDVOC */
|
||||
|
||||
i830_sdvo_caps caps;
|
||||
|
||||
CARD16 pixel_clock_min, pixel_clock_max;
|
||||
|
||||
int save_sdvo_mult;
|
||||
Bool save_sdvo_active_1, save_sdvo_active_2;
|
||||
i830_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
|
||||
|
|
@ -220,13 +225,62 @@ extern const char *i830_output_type_names[];
|
|||
|
||||
struct _I830OutputRec {
|
||||
int type;
|
||||
/* int pipe;
|
||||
int flags;*/
|
||||
int pipe;
|
||||
Bool disabled;
|
||||
|
||||
/**
|
||||
* Turns the output on/off, or sets intermediate power levels if available.
|
||||
*
|
||||
* Unsupported intermediate modes drop to the lower power setting. If the
|
||||
* mode is DPMSModeOff, the output must be disabled, as the DPLL may be
|
||||
* disabled afterwards.
|
||||
*/
|
||||
void (*dpms)(ScrnInfoPtr pScrn, I830OutputPtr output, int mode);
|
||||
|
||||
/**
|
||||
* Saves the output's state for restoration on VT switch.
|
||||
*/
|
||||
void (*save)(ScrnInfoPtr pScrn, I830OutputPtr output);
|
||||
|
||||
/**
|
||||
* Restore's the output's state at VT switch.
|
||||
*/
|
||||
void (*restore)(ScrnInfoPtr pScrn, I830OutputPtr output);
|
||||
|
||||
/**
|
||||
* Callback for testing a video mode for a given output.
|
||||
*
|
||||
* This function should only check for cases where a mode can't be supported
|
||||
* on the pipe specifically, and not represent generic CRTC limitations.
|
||||
*
|
||||
* \return MODE_OK if the mode is valid, or another MODE_* otherwise.
|
||||
*/
|
||||
int (*mode_valid)(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode);
|
||||
|
||||
/**
|
||||
* Callback for setting up a video mode before any pipe/dpll changes.
|
||||
*
|
||||
* \param pMode the mode that will be set, or NULL if the mode to be set is
|
||||
* unknown (such as the restore path of VT switching).
|
||||
*/
|
||||
void (*pre_set_mode)(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode);
|
||||
|
||||
/**
|
||||
* Callback for setting up a video mode after the DPLL update but before
|
||||
* the plane is enabled.
|
||||
*/
|
||||
void (*post_set_mode)(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode);
|
||||
|
||||
xf86MonPtr MonInfo;
|
||||
I2CBusPtr pI2CBus;
|
||||
I2CBusPtr pDDCBus;
|
||||
struct _I830DVODriver *i2c_drv;
|
||||
I830SDVOPtr sdvo_drv;
|
||||
/** Output-private structure. Should replace i2c_drv and sdvo_drv */
|
||||
void *dev_priv;
|
||||
};
|
||||
|
||||
typedef struct _I830Rec {
|
||||
|
|
@ -613,9 +667,14 @@ extern Bool I830FixOffset(ScrnInfoPtr pScrn, I830MemRange *mem);
|
|||
extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg,
|
||||
char *name);
|
||||
|
||||
/* i830_crt.c */
|
||||
void i830_crt_init(ScrnInfoPtr pScrn);
|
||||
|
||||
/* i830_dvo.c */
|
||||
Bool I830I2CDetectDVOControllers(ScrnInfoPtr pScrn, I2CBusPtr pI2CBus,
|
||||
struct _I830DVODriver **retdrv);
|
||||
void i830_dvo_init(ScrnInfoPtr pScrn);
|
||||
|
||||
/* i830_lvds.c */
|
||||
void i830_lvds_init(ScrnInfoPtr pScrn);
|
||||
|
||||
/* i830_memory.c */
|
||||
Bool I830BindAGPMemory(ScrnInfoPtr pScrn);
|
||||
|
|
@ -636,6 +695,9 @@ Bool I830RandRSetConfig(ScreenPtr pScreen, Rotation rotation, int rate,
|
|||
Rotation I830GetRotation(ScreenPtr pScreen);
|
||||
void I830GetOriginalVirtualSize(ScrnInfoPtr pScrn, int *x, int *y);
|
||||
|
||||
/* i830_tv.c */
|
||||
void i830_tv_init(ScrnInfoPtr pScrn);
|
||||
|
||||
/*
|
||||
* 12288 is set as the maximum, chosen because it is enough for
|
||||
* 1920x1440@32bpp with a 2048 pixel line pitch with some to spare.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "xf86.h"
|
||||
#include "i830.h"
|
||||
|
||||
static void
|
||||
i830_crt_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD32 temp;
|
||||
|
||||
temp = INREG(ADPA);
|
||||
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
switch(mode) {
|
||||
case DPMSModeOn:
|
||||
temp |= ADPA_DAC_ENABLE;
|
||||
break;
|
||||
case DPMSModeStandby:
|
||||
temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
case DPMSModeSuspend:
|
||||
temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
case DPMSModeOff:
|
||||
temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
}
|
||||
|
||||
OUTREG(ADPA, temp);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_crt_save(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
pI830->saveADPA = INREG(ADPA);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_crt_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
OUTREG(ADPA, pI830->saveADPA);
|
||||
}
|
||||
|
||||
static int
|
||||
i830_crt_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
i830_crt_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
i830_crt_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
CARD32 adpa;
|
||||
|
||||
adpa = ADPA_DAC_ENABLE;
|
||||
|
||||
if (pMode->Flags & V_PHSYNC)
|
||||
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
|
||||
if (pMode->Flags & V_PVSYNC)
|
||||
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
if (output->pipe == 0)
|
||||
adpa |= ADPA_PIPE_A_SELECT;
|
||||
else
|
||||
adpa |= ADPA_PIPE_B_SELECT;
|
||||
|
||||
OUTREG(ADPA, adpa);
|
||||
}
|
||||
|
||||
void
|
||||
i830_crt_init(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
pI830->output[pI830->num_outputs].type = I830_OUTPUT_ANALOG;
|
||||
pI830->output[pI830->num_outputs].dpms = i830_crt_dpms;
|
||||
pI830->output[pI830->num_outputs].save = i830_crt_save;
|
||||
pI830->output[pI830->num_outputs].restore = i830_crt_restore;
|
||||
pI830->output[pI830->num_outputs].mode_valid = i830_crt_mode_valid;
|
||||
pI830->output[pI830->num_outputs].pre_set_mode = i830_crt_pre_set_mode;
|
||||
pI830->output[pI830->num_outputs].post_set_mode = i830_crt_post_set_mode;
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus,
|
||||
GPIOA, "CRTDDC_A");
|
||||
|
||||
pI830->num_outputs++;
|
||||
}
|
||||
|
|
@ -226,7 +226,7 @@ i830FindBestPLL(ScrnInfoPtr pScrn, int outputs, int target, int refclk,
|
|||
return (err != target);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
i830WaitForVblank(ScrnInfoPtr pScreen)
|
||||
{
|
||||
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
||||
|
|
@ -259,6 +259,91 @@ i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y)
|
|||
pI830->pipeY[pipe] = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* In the current world order, there is a list of per-pipe modes, 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.
|
||||
*/
|
||||
static DisplayModePtr
|
||||
i830PipeFindClosestMode(ScrnInfoPtr pScrn, int pipe, DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
DisplayModePtr pBest = NULL, pScan;
|
||||
|
||||
/* If the pipe doesn't have any detected modes, just let the system try to
|
||||
* spam the desired mode in.
|
||||
*/
|
||||
if (pI830->pipeMon[pipe] == NULL) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
|
||||
"No pipe mode list for pipe %d,"
|
||||
"continuing with desired mode\n", pipe);
|
||||
return pMode;
|
||||
}
|
||||
|
||||
assert(pScan->VRefresh != 0.0);
|
||||
for (pScan = pI830->pipeMon[pipe]->Modes; pScan != NULL;
|
||||
pScan = pScan->next) {
|
||||
/* If there's an exact match, we're done. */
|
||||
if (I830ModesEqual(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 (!I830ModesEqual(pBest, pMode)) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
|
||||
"Choosing pipe %d's mode %dx%d@%.1f instead of xf86 "
|
||||
"mode %dx%d@%.1f\n", pipe,
|
||||
pBest->HDisplay, pBest->VDisplay, pBest->VRefresh,
|
||||
pMode->HDisplay, pMode->VDisplay, pMode->VRefresh);
|
||||
pMode = pBest;
|
||||
}
|
||||
return pMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given video mode on the given pipe. Assumes that plane A feeds
|
||||
* pipe A, and plane B feeds pipe B. Should not affect the other planes/pipes.
|
||||
|
|
@ -270,119 +355,76 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
|
|||
int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
|
||||
CARD32 dpll = 0, fp = 0, temp;
|
||||
CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
|
||||
CARD32 pipesrc, dspsize, adpa;
|
||||
CARD32 sdvob = 0, sdvoc = 0, dvo = 0;
|
||||
Bool ok, is_sdvo, is_dvo;
|
||||
int refclk, pixel_clock, sdvo_pixel_multiply;
|
||||
int outputs;
|
||||
DisplayModePtr pMasterMode = pMode;
|
||||
CARD32 pipesrc, dspsize;
|
||||
Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
|
||||
Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
|
||||
int refclk, pixel_clock;
|
||||
int outputs, i;
|
||||
int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
|
||||
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
|
||||
int fp_reg = (pipe == 0) ? FPA0 : FPB0;
|
||||
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
|
||||
int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
|
||||
int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
|
||||
int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
|
||||
int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
|
||||
int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
|
||||
int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
|
||||
int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
|
||||
int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
|
||||
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
|
||||
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
|
||||
|
||||
assert(pMode->VRefresh != 0.0);
|
||||
/* If we've got a list of modes probed for the device, find the best match
|
||||
* in there to the requested mode.
|
||||
*/
|
||||
if (pI830->pipeMon[pipe] != NULL) {
|
||||
DisplayModePtr pBest = NULL, pScan;
|
||||
|
||||
assert(pScan->VRefresh != 0.0);
|
||||
for (pScan = pI830->pipeMon[pipe]->Modes; pScan != NULL;
|
||||
pScan = pScan->next)
|
||||
{
|
||||
/* If there's an exact match, we're done. */
|
||||
if (I830ModesEqual(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_ERROR,
|
||||
"Choosing pipe %d's mode %dx%d@%.1f instead of xf86 "
|
||||
"mode %dx%d@%.1f\n", pipe,
|
||||
pBest->HDisplay, pBest->VDisplay, pBest->VRefresh,
|
||||
pMode->HDisplay, pMode->VDisplay, pMode->VRefresh);
|
||||
pMode = pBest;
|
||||
}
|
||||
}
|
||||
if (pipe == 0)
|
||||
outputs = pI830->operatingDevices & 0xff;
|
||||
else
|
||||
outputs = (pI830->operatingDevices >> 8) & 0xff;
|
||||
|
||||
if (outputs & PIPE_LCD_ACTIVE) {
|
||||
if (I830ModesEqual(&pI830->pipeCurMode[pipe], pMasterMode))
|
||||
return TRUE;
|
||||
} else {
|
||||
if (I830ModesEqual(&pI830->pipeCurMode[pipe], pMode))
|
||||
return TRUE;
|
||||
}
|
||||
if (I830ModesEqual(&pI830->pipeCurMode[pipe], pMode))
|
||||
return TRUE;
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested pix clock: %d\n",
|
||||
pMode->Clock);
|
||||
|
||||
if ((outputs & PIPE_LCD_ACTIVE) && (outputs & ~PIPE_LCD_ACTIVE)) {
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].pipe != pipe || pI830->output[i].disabled)
|
||||
continue;
|
||||
|
||||
switch (pI830->output[i].type) {
|
||||
case I830_OUTPUT_LVDS:
|
||||
is_lvds = TRUE;
|
||||
break;
|
||||
case I830_OUTPUT_SDVO:
|
||||
is_sdvo = TRUE;
|
||||
break;
|
||||
case I830_OUTPUT_DVO:
|
||||
is_dvo = TRUE;
|
||||
break;
|
||||
case I830_OUTPUT_TVOUT:
|
||||
is_tv = TRUE;
|
||||
break;
|
||||
case I830_OUTPUT_ANALOG:
|
||||
is_crt = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_lvds && (is_sdvo || is_dvo || is_tv || is_crt)) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
"Can't enable LVDS and non-LVDS on the same pipe\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (((outputs & PIPE_TV_ACTIVE) && (outputs & ~PIPE_TV_ACTIVE)) ||
|
||||
((outputs & PIPE_TV2_ACTIVE) && (outputs & ~PIPE_TV2_ACTIVE))) {
|
||||
if (is_tv && (is_sdvo || is_dvo || is_crt || is_lvds)) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
"Can't enable a TV and any other output on the same pipe\n");
|
||||
"Can't enable a TV and any other output on the same "
|
||||
"pipe\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (pipe == 0 && (outputs & PIPE_LCD_ACTIVE)) {
|
||||
if (pipe == 0 && is_lvds) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
"Can't support LVDS on pipe A\n");
|
||||
return FALSE;
|
||||
}
|
||||
if ((outputs & PIPE_DFP_ACTIVE) || (outputs & PIPE_DFP2_ACTIVE)) {
|
||||
/* We'll change how we control outputs soon, but to get the SDVO code up
|
||||
* and running, just check for these two possibilities.
|
||||
*/
|
||||
if (IS_I9XX(pI830)) {
|
||||
is_sdvo = TRUE;
|
||||
is_dvo = FALSE;
|
||||
} else {
|
||||
is_dvo = TRUE;
|
||||
is_sdvo = FALSE;
|
||||
}
|
||||
} else {
|
||||
is_sdvo = FALSE;
|
||||
is_dvo = FALSE;
|
||||
}
|
||||
|
||||
htot = (pMode->CrtcHDisplay - 1) | ((pMode->CrtcHTotal - 1) << 16);
|
||||
hblank = (pMode->CrtcHBlankStart - 1) | ((pMode->CrtcHBlankEnd - 1) << 16);
|
||||
|
|
@ -393,8 +435,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
|
|||
pipesrc = ((pMode->HDisplay - 1) << 16) | (pMode->VDisplay - 1);
|
||||
dspsize = ((pMode->VDisplay - 1) << 16) | (pMode->HDisplay - 1);
|
||||
pixel_clock = pMode->Clock;
|
||||
if (outputs & PIPE_LCD_ACTIVE && pI830->panel_fixed_hactive != 0)
|
||||
{
|
||||
|
||||
if (is_lvds && pI830->panel_fixed_hactive != 0) {
|
||||
/* To enable panel fitting, we need to set the pipe timings to that of
|
||||
* the screen at its full resolution. So, drop the timings from the
|
||||
* BIOS VBT tables here.
|
||||
|
|
@ -420,30 +462,24 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
|
|||
pI830->panel_fixed_vsyncwidth - 1) << 16);
|
||||
pixel_clock = pI830->panel_fixed_clock;
|
||||
|
||||
if (pMasterMode->HDisplay <= pI830->panel_fixed_hactive &&
|
||||
pMasterMode->HDisplay <= pI830->panel_fixed_vactive)
|
||||
if (pMode->HDisplay <= pI830->panel_fixed_hactive &&
|
||||
pMode->HDisplay <= pI830->panel_fixed_vactive)
|
||||
{
|
||||
pipesrc = ((pMasterMode->HDisplay - 1) << 16) |
|
||||
(pMasterMode->VDisplay - 1);
|
||||
dspsize = ((pMasterMode->VDisplay - 1) << 16) |
|
||||
(pMasterMode->HDisplay - 1);
|
||||
pipesrc = ((pMode->HDisplay - 1) << 16) |
|
||||
(pMode->VDisplay - 1);
|
||||
dspsize = ((pMode->VDisplay - 1) << 16) |
|
||||
(pMode->HDisplay - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (pMode->Clock >= 100000)
|
||||
sdvo_pixel_multiply = 1;
|
||||
else if (pMode->Clock >= 50000)
|
||||
sdvo_pixel_multiply = 2;
|
||||
else
|
||||
sdvo_pixel_multiply = 4;
|
||||
|
||||
/* In SDVO, we need to keep the clock on the bus between 1Ghz and 2Ghz.
|
||||
* The clock on the bus is 10 times the pixel clock normally. If that
|
||||
* would be too low, we run the DPLL at a multiple of the pixel clock, and
|
||||
* tell the SDVO device the multiplier so it can throw away the dummy bytes.
|
||||
* tell the SDVO device the multiplier so it can throw away the dummy
|
||||
* bytes.
|
||||
*/
|
||||
if (is_sdvo) {
|
||||
pixel_clock *= sdvo_pixel_multiply;
|
||||
pixel_clock *= i830_sdvo_get_pixel_multiplier(pMode);
|
||||
}
|
||||
|
||||
if (IS_I9XX(pI830)) {
|
||||
|
|
@ -461,7 +497,7 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
|
|||
|
||||
dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS;
|
||||
if (IS_I9XX(pI830)) {
|
||||
if (outputs & PIPE_LCD_ACTIVE)
|
||||
if (is_lvds)
|
||||
dpll |= DPLLB_MODE_LVDS;
|
||||
else
|
||||
dpll |= DPLLB_MODE_DAC_SERIAL;
|
||||
|
|
@ -486,55 +522,15 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
|
|||
dpll |= PLL_P2_DIVIDE_BY_4;
|
||||
}
|
||||
|
||||
if (outputs & (PIPE_TV_ACTIVE | PIPE_TV2_ACTIVE))
|
||||
if (is_tv)
|
||||
dpll |= PLL_REF_INPUT_TVCLKINBC;
|
||||
#if 0
|
||||
else if (outputs & (PIPE_LCD_ACTIVE))
|
||||
else if (is_lvds)
|
||||
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
|
||||
#endif
|
||||
else
|
||||
dpll |= PLL_REF_INPUT_DREFCLK;
|
||||
|
||||
if (is_dvo) {
|
||||
dpll |= DPLL_DVO_HIGH_SPEED;
|
||||
|
||||
/* Save the data order, since I don't know what it should be set to. */
|
||||
dvo = INREG(DVOC) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
|
||||
dvo |= DVO_ENABLE;
|
||||
dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH;
|
||||
|
||||
if (pipe == 1)
|
||||
dvo |= DVO_PIPE_B_SELECT;
|
||||
|
||||
if (pMode->Flags & V_PHSYNC)
|
||||
dvo |= DVO_HSYNC_ACTIVE_HIGH;
|
||||
if (pMode->Flags & V_PVSYNC)
|
||||
dvo |= DVO_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
OUTREG(DVOC, dvo & ~DVO_ENABLE);
|
||||
}
|
||||
|
||||
if (is_sdvo) {
|
||||
dpll |= DPLL_DVO_HIGH_SPEED;
|
||||
|
||||
ErrorF("DVOB: %08x\nDVOC: %08x\n", (int)INREG(SDVOB), (int)INREG(SDVOC));
|
||||
|
||||
sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK;
|
||||
sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK;
|
||||
sdvob |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE;
|
||||
sdvoc |= 9 << 19;
|
||||
if (pipe == 1)
|
||||
sdvob |= SDVO_PIPE_B_SELECT;
|
||||
|
||||
if (IS_I945G(pI830) || IS_I945GM(pI830))
|
||||
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
|
||||
else
|
||||
sdvob |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
|
||||
|
||||
OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE);
|
||||
OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE);
|
||||
}
|
||||
|
||||
fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
|
||||
|
||||
#if 1
|
||||
|
|
@ -576,150 +572,53 @@ i830PipeSetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode, int pipe)
|
|||
dspcntr |= DISPPLANE_GAMMA_ENABLE;
|
||||
}
|
||||
|
||||
if (is_sdvo)
|
||||
adpa = ADPA_DAC_DISABLE;
|
||||
else
|
||||
adpa = ADPA_DAC_ENABLE;
|
||||
if (pMode->Flags & V_PHSYNC)
|
||||
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
|
||||
if (pMode->Flags & V_PVSYNC)
|
||||
adpa |= ADPA_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
if (pipe == 0) {
|
||||
if (pipe == 0)
|
||||
dspcntr |= DISPPLANE_SEL_PIPE_A;
|
||||
adpa |= ADPA_PIPE_A_SELECT;
|
||||
} else {
|
||||
else
|
||||
dspcntr |= DISPPLANE_SEL_PIPE_B;
|
||||
adpa |= ADPA_PIPE_B_SELECT;
|
||||
}
|
||||
|
||||
OUTREG(VGACNTRL, VGA_DISP_DISABLE);
|
||||
|
||||
/* Set up display timings and PLLs for the pipe. */
|
||||
if (pipe == 0) {
|
||||
/* First, disable display planes */
|
||||
temp = INREG(DSPACNTR);
|
||||
OUTREG(DSPACNTR, temp & ~DISPLAY_PLANE_ENABLE);
|
||||
/* Finally, set the mode. */
|
||||
/* First, disable display planes */
|
||||
temp = INREG(dspcntr_reg);
|
||||
OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
|
||||
|
||||
/* Wait for vblank for the disable to take effect */
|
||||
i830WaitForVblank(pScrn);
|
||||
/* Wait for vblank for the disable to take effect */
|
||||
i830WaitForVblank(pScrn);
|
||||
|
||||
/* Next, disable display pipes */
|
||||
temp = INREG(PIPEACONF);
|
||||
OUTREG(PIPEACONF, temp & ~PIPEACONF_ENABLE);
|
||||
/* Next, disable display pipes */
|
||||
temp = INREG(pipeconf_reg);
|
||||
OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
|
||||
|
||||
OUTREG(FPA0, fp);
|
||||
OUTREG(DPLL_A, dpll);
|
||||
OUTREG(fp_reg, fp);
|
||||
OUTREG(dpll_reg, dpll);
|
||||
|
||||
OUTREG(HTOTAL_A, htot);
|
||||
OUTREG(HBLANK_A, hblank);
|
||||
OUTREG(HSYNC_A, hsync);
|
||||
OUTREG(VTOTAL_A, vtot);
|
||||
OUTREG(VBLANK_A, vblank);
|
||||
OUTREG(VSYNC_A, vsync);
|
||||
OUTREG(DSPASTRIDE, pScrn->displayWidth * pI830->cpp);
|
||||
OUTREG(DSPASIZE, dspsize);
|
||||
OUTREG(DSPAPOS, 0);
|
||||
i830PipeSetBase(pScrn, pipe, pI830->pipeX[pipe], pI830->pipeX[pipe]);
|
||||
OUTREG(PIPEASRC, pipesrc);
|
||||
|
||||
/* Then, turn the pipe on first */
|
||||
temp = INREG(PIPEACONF);
|
||||
OUTREG(PIPEACONF, temp | PIPEACONF_ENABLE);
|
||||
|
||||
/* And then turn the plane on */
|
||||
OUTREG(DSPACNTR, dspcntr);
|
||||
} else {
|
||||
/* Always make sure the LVDS is off before we play with DPLLs and pipe
|
||||
* configuration.
|
||||
*/
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
|
||||
/* First, disable display planes */
|
||||
temp = INREG(DSPBCNTR);
|
||||
OUTREG(DSPBCNTR, temp & ~DISPLAY_PLANE_ENABLE);
|
||||
|
||||
/* Wait for vblank for the disable to take effect */
|
||||
i830WaitForVblank(pScrn);
|
||||
|
||||
/* Next, disable display pipes */
|
||||
temp = INREG(PIPEBCONF);
|
||||
OUTREG(PIPEBCONF, temp & ~PIPEBCONF_ENABLE);
|
||||
|
||||
if (outputs & PIPE_LCD_ACTIVE) {
|
||||
/* Disable the PLL before messing with LVDS enable */
|
||||
OUTREG(FPB0, fp & ~DPLL_VCO_ENABLE);
|
||||
|
||||
/* LVDS must be powered on before PLL is enabled and before power
|
||||
* sequencing the panel.
|
||||
*/
|
||||
temp = INREG(LVDS);
|
||||
OUTREG(LVDS, temp | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
|
||||
}
|
||||
|
||||
OUTREG(FPB0, fp);
|
||||
OUTREG(DPLL_B, dpll);
|
||||
OUTREG(HTOTAL_B, htot);
|
||||
OUTREG(HBLANK_B, hblank);
|
||||
OUTREG(HSYNC_B, hsync);
|
||||
OUTREG(VTOTAL_B, vtot);
|
||||
OUTREG(VBLANK_B, vblank);
|
||||
OUTREG(VSYNC_B, vsync);
|
||||
OUTREG(DSPBSTRIDE, pScrn->displayWidth * pI830->cpp);
|
||||
OUTREG(DSPBSIZE, dspsize);
|
||||
OUTREG(DSPBPOS, 0);
|
||||
i830PipeSetBase(pScrn, pipe, pI830->pipeX[pipe], pI830->pipeY[pipe]);
|
||||
OUTREG(PIPEBSRC, pipesrc);
|
||||
|
||||
if (outputs & PIPE_LCD_ACTIVE) {
|
||||
CARD32 pfit_control;
|
||||
|
||||
/* Enable automatic panel scaling so that non-native modes fill the
|
||||
* screen.
|
||||
*/
|
||||
/* XXX: Allow (auto-?) enabling of 8-to-6 dithering */
|
||||
pfit_control = (PFIT_ENABLE |
|
||||
VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
|
||||
VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR);
|
||||
if (pI830->panel_wants_dither)
|
||||
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
|
||||
OUTREG(PFIT_CONTROL, pfit_control);
|
||||
}
|
||||
|
||||
/* Then, turn the pipe on first */
|
||||
temp = INREG(PIPEBCONF);
|
||||
OUTREG(PIPEBCONF, temp | PIPEBCONF_ENABLE);
|
||||
|
||||
/* And then turn the plane on */
|
||||
OUTREG(DSPBCNTR, dspcntr);
|
||||
|
||||
if (outputs & PIPE_LCD_ACTIVE) {
|
||||
i830SetLVDSPanelPower(pScrn, TRUE);
|
||||
}
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].pipe == pipe)
|
||||
pI830->output[i].post_set_mode(pScrn, &pI830->output[i], pMode);
|
||||
}
|
||||
|
||||
if (outputs & PIPE_CRT_ACTIVE)
|
||||
OUTREG(ADPA, adpa);
|
||||
OUTREG(htot_reg, htot);
|
||||
OUTREG(hblank_reg, hblank);
|
||||
OUTREG(hsync_reg, hsync);
|
||||
OUTREG(vtot_reg, vtot);
|
||||
OUTREG(vblank_reg, vblank);
|
||||
OUTREG(vsync_reg, vsync);
|
||||
OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
|
||||
OUTREG(dspsize_reg, dspsize);
|
||||
OUTREG(dsppos_reg, 0);
|
||||
i830PipeSetBase(pScrn, pipe, pI830->pipeX[pipe], pI830->pipeX[pipe]);
|
||||
OUTREG(pipesrc_reg, pipesrc);
|
||||
|
||||
if (is_dvo) {
|
||||
/*OUTREG(DVOB_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
|
||||
(pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
|
||||
OUTREG(DVOC_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
|
||||
(pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
|
||||
/*OUTREG(DVOB, dvo);*/
|
||||
OUTREG(DVOC, dvo);
|
||||
}
|
||||
/* Then, turn the pipe on first */
|
||||
temp = INREG(pipeconf_reg);
|
||||
OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
|
||||
|
||||
if (is_sdvo) {
|
||||
OUTREG(SDVOB, sdvob);
|
||||
OUTREG(SDVOC, sdvoc);
|
||||
}
|
||||
/* And then turn the plane on */
|
||||
OUTREG(dspcntr_reg, dspcntr);
|
||||
|
||||
if (outputs & PIPE_LCD_ACTIVE) {
|
||||
pI830->pipeCurMode[pipe] = *pMasterMode;
|
||||
} else {
|
||||
pI830->pipeCurMode[pipe] = *pMode;
|
||||
}
|
||||
pI830->pipeCurMode[pipe] = *pMode;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -728,48 +627,13 @@ void
|
|||
i830DisableUnusedFunctions(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
int outputsA, outputsB;
|
||||
|
||||
outputsA = pI830->operatingDevices & 0xff;
|
||||
outputsB = (pI830->operatingDevices >> 8) & 0xff;
|
||||
int i;
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling unused functions\n");
|
||||
|
||||
/* First, disable the unused outputs */
|
||||
if ((outputsA & PIPE_CRT_ACTIVE) == 0 &&
|
||||
(outputsB & PIPE_CRT_ACTIVE) == 0)
|
||||
{
|
||||
CARD32 adpa = INREG(ADPA);
|
||||
|
||||
if (adpa & ADPA_DAC_ENABLE) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling CRT output\n");
|
||||
OUTREG(ADPA, adpa & ~ADPA_DAC_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
if ((outputsB & PIPE_LCD_ACTIVE) == 0) {
|
||||
CARD32 pp_status = INREG(PP_STATUS);
|
||||
|
||||
if (pp_status & PP_ON) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling LVDS output\n");
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_I9XX(pI830) && ((outputsA & PIPE_DFP_ACTIVE) == 0 &&
|
||||
(outputsB & PIPE_DFP_ACTIVE) == 0))
|
||||
{
|
||||
CARD32 sdvob = INREG(SDVOB);
|
||||
CARD32 sdvoc = INREG(SDVOC);
|
||||
|
||||
if (sdvob & SDVO_ENABLE) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling SDVOB output\n");
|
||||
OUTREG(SDVOB, sdvob & ~SDVO_ENABLE);
|
||||
}
|
||||
if (sdvoc & SDVO_ENABLE) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling SDVOC output\n");
|
||||
OUTREG(SDVOC, sdvoc & ~SDVO_ENABLE);
|
||||
}
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].disabled)
|
||||
pI830->output[i].dpms(pScrn, &pI830->output[i], DPMSModeOff);
|
||||
}
|
||||
|
||||
/* Now, any unused plane, pipe, and DPLL (FIXME: except for DVO, i915
|
||||
|
|
@ -839,7 +703,6 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
|
|||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
Bool ok = TRUE;
|
||||
CARD32 planeA, planeB;
|
||||
#ifdef XF86DRI
|
||||
Bool didLock = FALSE;
|
||||
#endif
|
||||
|
|
@ -864,30 +727,21 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
|
|||
}
|
||||
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
struct _I830OutputRec *output = &pI830->output[i];
|
||||
|
||||
if (output->sdvo_drv)
|
||||
I830SDVOPreSetMode(output->sdvo_drv, pMode);
|
||||
|
||||
if (output->i2c_drv != NULL)
|
||||
output->i2c_drv->vid_rec->Mode(output->i2c_drv->dev_priv,
|
||||
pMode);
|
||||
pI830->output[i].pre_set_mode(pScrn, &pI830->output[i], pMode);
|
||||
}
|
||||
|
||||
if (pI830->planeEnabled[0]) {
|
||||
ok = i830PipeSetMode(pScrn, pMode, 0);
|
||||
ok = i830PipeSetMode(pScrn, i830PipeFindClosestMode(pScrn, 0, pMode),
|
||||
0);
|
||||
if (!ok)
|
||||
goto done;
|
||||
}
|
||||
if (pI830->planeEnabled[1]) {
|
||||
ok = i830PipeSetMode(pScrn, pMode, 1);
|
||||
ok = i830PipeSetMode(pScrn, i830PipeFindClosestMode(pScrn, 1, pMode),
|
||||
1);
|
||||
if (!ok)
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].sdvo_drv)
|
||||
I830SDVOPostSetMode(pI830->output[i].sdvo_drv, pMode);
|
||||
}
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Mode bandwidth is %d Mpixel/s\n",
|
||||
(int)(pMode->HDisplay * pMode->VDisplay *
|
||||
|
|
@ -919,18 +773,7 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode)
|
|||
|
||||
i830DisableUnusedFunctions(pScrn);
|
||||
|
||||
planeA = INREG(DSPACNTR);
|
||||
planeB = INREG(DSPBCNTR);
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Display plane A is now %s and connected to %s.\n",
|
||||
pI830->planeEnabled[0] ? "enabled" : "disabled",
|
||||
planeA & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A");
|
||||
if (pI830->availablePipes == 2)
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Display plane B is now %s and connected to %s.\n",
|
||||
pI830->planeEnabled[1] ? "enabled" : "disabled",
|
||||
planeB & DISPPLANE_SEL_PIPE_MASK ? "Pipe B" : "Pipe A");
|
||||
i830DescribeOutputConfiguration(pScrn);
|
||||
|
||||
#ifdef XF86DRI
|
||||
I830DRISetVBlankInterrupt (pScrn, TRUE);
|
||||
|
|
@ -946,6 +789,52 @@ done:
|
|||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
i830DescribeOutputConfiguration(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
int i;
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Output configuration:\n");
|
||||
|
||||
for (i = 0; i < pI830->availablePipes; i++) {
|
||||
CARD32 dspcntr = INREG(DSPACNTR + (DSPBCNTR - DSPACNTR) * i);
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
" Display plane %c is now %s and connected to pipe %c.\n",
|
||||
'A' + i,
|
||||
pI830->planeEnabled[i] ? "enabled" : "disabled",
|
||||
dspcntr & DISPPLANE_SEL_PIPE_MASK ? 'B' : 'A');
|
||||
}
|
||||
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
const char *name = NULL;
|
||||
|
||||
switch (pI830->output[i].type) {
|
||||
case I830_OUTPUT_ANALOG:
|
||||
name = "CRT";
|
||||
break;
|
||||
case I830_OUTPUT_LVDS:
|
||||
name = "LVDS";
|
||||
break;
|
||||
case I830_OUTPUT_SDVO:
|
||||
name = "SDVO";
|
||||
break;
|
||||
case I830_OUTPUT_DVO:
|
||||
name = "DVO";
|
||||
break;
|
||||
case I830_OUTPUT_TVOUT:
|
||||
name = "TV";
|
||||
break;
|
||||
}
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
" Output %s is %sabled and connected to pipe %c\n",
|
||||
name, pI830->output[i].disabled ? "dis" : "en",
|
||||
pI830->output[i].pipe == 0 ? 'A' : 'B');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
|
||||
*
|
||||
|
|
@ -1092,42 +981,3 @@ i830DetectCRT(ScrnInfoPtr pScrn, Bool allow_disturb)
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the power state for the panel.
|
||||
*/
|
||||
void
|
||||
i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD32 pp_status, pp_control;
|
||||
CARD32 blc_pwm_ctl;
|
||||
int backlight_duty_cycle;
|
||||
|
||||
blc_pwm_ctl = INREG (BLC_PWM_CTL);
|
||||
backlight_duty_cycle = blc_pwm_ctl & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
if (backlight_duty_cycle)
|
||||
pI830->backlight_duty_cycle = backlight_duty_cycle;
|
||||
|
||||
if (on) {
|
||||
OUTREG(PP_STATUS, INREG(PP_STATUS) | PP_ON);
|
||||
OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
|
||||
do {
|
||||
pp_status = INREG(PP_STATUS);
|
||||
pp_control = INREG(PP_CONTROL);
|
||||
} while (!(pp_status & PP_ON) && !(pp_control & POWER_TARGET_ON));
|
||||
OUTREG(BLC_PWM_CTL,
|
||||
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) |
|
||||
pI830->backlight_duty_cycle);
|
||||
} else {
|
||||
OUTREG(BLC_PWM_CTL,
|
||||
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK));
|
||||
|
||||
OUTREG(PP_STATUS, INREG(PP_STATUS) & ~PP_ON);
|
||||
OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
|
||||
do {
|
||||
pp_status = INREG(PP_STATUS);
|
||||
pp_control = INREG(PP_CONTROL);
|
||||
} while ((pp_status & PP_ON) || (pp_control & POWER_TARGET_ON));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ Bool i830SetMode(ScrnInfoPtr pScrn, DisplayModePtr pMode);
|
|||
Bool i830DetectCRT(ScrnInfoPtr pScrn, Bool allow_disturb);
|
||||
void i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on);
|
||||
void i830PipeSetBase(ScrnInfoPtr pScrn, int pipe, int x, int y);
|
||||
void i830WaitForVblank(ScrnInfoPtr pScrn);
|
||||
void i830DescribeOutputConfiguration(ScrnInfoPtr pScrn);
|
||||
|
||||
/* i830_sdvo.c */
|
||||
I830SDVOPtr I830SDVOInit(ScrnInfoPtr pScrn, int output_index,
|
||||
CARD32 output_device);
|
||||
Bool I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode);
|
||||
Bool I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode);
|
||||
|
|
|
|||
|
|
@ -900,56 +900,30 @@ I830UseDDC(ScrnInfoPtr pScrn)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set up the outputs according to what type of chip we are.
|
||||
*
|
||||
* Some outputs may not initialize, due to allocation failure or because a
|
||||
* controller chip isn't found.
|
||||
*/
|
||||
static void
|
||||
I830SetupOutputBusses(ScrnInfoPtr pScrn)
|
||||
I830SetupOutputs(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
int i = 0;
|
||||
Bool ret;
|
||||
|
||||
/* everyone has at least a single analog output */
|
||||
pI830->output[i].type = I830_OUTPUT_ANALOG;
|
||||
i830_crt_init(pScrn);
|
||||
|
||||
/* setup the DDC bus for the analog output */
|
||||
I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOA, "CRTDDC_A");
|
||||
i++;
|
||||
|
||||
if (IS_MOBILE(pI830) && !IS_I830(pI830)) {
|
||||
/* Set up integrated LVDS */
|
||||
pI830->output[i].type = I830_OUTPUT_LVDS;
|
||||
I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOC, "LVDSDDC_C");
|
||||
i++;
|
||||
}
|
||||
/* Set up integrated LVDS */
|
||||
if (IS_MOBILE(pI830) && !IS_I830(pI830))
|
||||
i830_lvds_init(pScrn);
|
||||
|
||||
if (IS_I9XX(pI830)) {
|
||||
/* Set up SDVOB */
|
||||
pI830->output[i].type = I830_OUTPUT_SDVO;
|
||||
I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "SDVOCTRL_E");
|
||||
I830SDVOInit(pScrn, i, SDVOB);
|
||||
i++;
|
||||
|
||||
/* Set up SDVOC */
|
||||
pI830->output[i].type = I830_OUTPUT_SDVO;
|
||||
pI830->output[i].pI2CBus = pI830->output[i-1].pI2CBus;
|
||||
I830SDVOInit(pScrn, i, SDVOC);
|
||||
i++;
|
||||
i830_sdvo_init(pScrn, SDVOB);
|
||||
i830_sdvo_init(pScrn, SDVOC);
|
||||
} else {
|
||||
/* set up DVO */
|
||||
pI830->output[i].type = I830_OUTPUT_DVO;
|
||||
I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOD, "DVODDC_D");
|
||||
I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "DVOI2C_E");
|
||||
|
||||
ret = I830I2CDetectDVOControllers(pScrn, pI830->output[i].pI2CBus,
|
||||
&pI830->output[i].i2c_drv);
|
||||
if (ret == TRUE) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found i2c %s on %08lX\n",
|
||||
pI830->output[i].i2c_drv->modulename,
|
||||
pI830->output[i].pI2CBus->DriverPrivate.uval);
|
||||
}
|
||||
|
||||
i++;
|
||||
i830_dvo_init(pScrn);
|
||||
}
|
||||
pI830->num_outputs = i;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -970,7 +944,7 @@ I830PreInitDDC(ScrnInfoPtr pScrn)
|
|||
if (xf86LoadSubModule(pScrn, "i2c")) {
|
||||
xf86LoaderReqSymLists(I810i2cSymbols, NULL);
|
||||
|
||||
I830SetupOutputBusses(pScrn);
|
||||
I830SetupOutputs(pScrn);
|
||||
|
||||
pI830->ddc2 = TRUE;
|
||||
} else {
|
||||
|
|
@ -1011,14 +985,12 @@ I830DetectMonitors(ScrnInfoPtr pScrn)
|
|||
xf86PrintEDID(pI830->output[i].MonInfo);
|
||||
break;
|
||||
case I830_OUTPUT_SDVO:
|
||||
if (pI830->output[i].sdvo_drv != NULL) {
|
||||
pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
|
||||
pI830->output[i].pDDCBus);
|
||||
pI830->output[i].MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,
|
||||
pI830->output[i].pDDCBus);
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC SDVO %d, %08lX\n", i,
|
||||
pI830->output[i].pDDCBus->DriverPrivate.uval);
|
||||
xf86PrintEDID(pI830->output[i].MonInfo);
|
||||
}
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DDC SDVO %d, %08lX\n", i,
|
||||
pI830->output[i].pDDCBus->DriverPrivate.uval);
|
||||
xf86PrintEDID(pI830->output[i].MonInfo);
|
||||
break;
|
||||
case I830_OUTPUT_UNUSED:
|
||||
break;
|
||||
|
|
@ -1556,7 +1528,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
|
|||
* that we might find early in the list. This hackery will go away when we
|
||||
* start doing independent per-head mode selection.
|
||||
*/
|
||||
for (i = MAX_OUTPUTS - 1; i >= 0; i--) {
|
||||
for (i = pI830->num_outputs - 1; i >= 0; i--) {
|
||||
if (pI830->output[i].MonInfo) {
|
||||
pScrn->monitor->DDC = pI830->output[i].MonInfo;
|
||||
xf86SetDDCproperties(pScrn, pI830->output[i].MonInfo);
|
||||
|
|
@ -1577,8 +1549,7 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
|
|||
|
||||
/* Blacklist machines with known broken BIOSes */
|
||||
if (pI830->PciInfo->chipType == PCI_CHIP_I945_GM) {
|
||||
if ((pI830->PciInfo->subsysVendor == 0xa0a0) &&
|
||||
(pI830->PciInfo->subsysCard == 0x0589)) /* aopen mini pc */
|
||||
if (pI830->PciInfo->subsysVendor == 0xa0a0) /* aopen mini pc */
|
||||
has_lvds = FALSE;
|
||||
|
||||
if ((pI830->PciInfo->subsysVendor == 0x8086) &&
|
||||
|
|
@ -1700,9 +1671,8 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
|
|||
* now. Though really, it's just a name at the moment, since we don't
|
||||
* treat different SDVO outputs differently.
|
||||
*/
|
||||
for (i = 0; i < MAX_OUTPUTS; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO &&
|
||||
pI830->output[i].sdvo_drv != NULL) {
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO) {
|
||||
if (!I830DetectSDVODisplays(pScrn, i))
|
||||
continue;
|
||||
|
||||
|
|
@ -1756,6 +1726,48 @@ I830PreInit(ScrnInfoPtr pScrn, int flags)
|
|||
pI830->Clone = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Perform the pipe assignment of outputs. This code shouldn't exist,
|
||||
* but for now we're supporting the existing MonitorLayout configuration
|
||||
* scheme.
|
||||
*/
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
pI830->output[i].disabled = FALSE;
|
||||
|
||||
switch (pI830->output[i].type) {
|
||||
case I830_OUTPUT_LVDS:
|
||||
if (pI830->MonType1 & PIPE_LFP)
|
||||
pI830->output[i].pipe = 0;
|
||||
else if (pI830->MonType2 & PIPE_LFP)
|
||||
pI830->output[i].pipe = 1;
|
||||
else
|
||||
pI830->output[i].disabled = TRUE;
|
||||
break;
|
||||
case I830_OUTPUT_ANALOG:
|
||||
if (pI830->MonType1 & PIPE_CRT)
|
||||
pI830->output[i].pipe = 0;
|
||||
else if (pI830->MonType2 & PIPE_CRT)
|
||||
pI830->output[i].pipe = 1;
|
||||
else
|
||||
pI830->output[i].disabled = TRUE;
|
||||
break;
|
||||
case I830_OUTPUT_DVO:
|
||||
case I830_OUTPUT_SDVO:
|
||||
if (pI830->MonType1 & PIPE_DFP)
|
||||
pI830->output[i].pipe = 0;
|
||||
else if (pI830->MonType2 & PIPE_DFP)
|
||||
pI830->output[i].pipe = 1;
|
||||
else
|
||||
pI830->output[i].disabled = TRUE;
|
||||
break;
|
||||
default:
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unhandled output type\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pI830->CloneRefresh = 60; /* default to 60Hz */
|
||||
if (xf86GetOptValInteger(pI830->Options, OPTION_CLONE_REFRESH,
|
||||
&(pI830->CloneRefresh))) {
|
||||
|
|
@ -2593,31 +2605,6 @@ SaveHWState(ScrnInfoPtr pScrn)
|
|||
pI830->saveVCLK_POST_DIV = INREG(VCLK_POST_DIV);
|
||||
pI830->saveVGACNTRL = INREG(VGACNTRL);
|
||||
|
||||
pI830->saveADPA = INREG(ADPA);
|
||||
|
||||
pI830->savePFIT_CONTROL = INREG(PFIT_CONTROL);
|
||||
pI830->savePP_ON = INREG(LVDSPP_ON);
|
||||
pI830->savePP_OFF = INREG(LVDSPP_OFF);
|
||||
pI830->saveLVDS = INREG(LVDS);
|
||||
pI830->savePP_CONTROL = INREG(PP_CONTROL);
|
||||
pI830->savePP_CYCLE = INREG(PP_CYCLE);
|
||||
pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
|
||||
pI830->backlight_duty_cycle = (pI830->saveBLC_PWM_CTL &
|
||||
BACKLIGHT_DUTY_CYCLE_MASK);
|
||||
/*
|
||||
* If the light is off at server startup, just make it full brightness
|
||||
*/
|
||||
if (!pI830->backlight_duty_cycle)
|
||||
pI830->backlight_duty_cycle = ((pI830->saveBLC_PWM_CTL &
|
||||
BACKLIGHT_MODULATION_FREQ_MASK) >>
|
||||
BACKLIGHT_MODULATION_FREQ_SHIFT);
|
||||
|
||||
if (!IS_I9XX(pI830)) {
|
||||
pI830->saveDVOA = INREG(DVOA);
|
||||
pI830->saveDVOB = INREG(DVOB);
|
||||
pI830->saveDVOC = INREG(DVOC);
|
||||
}
|
||||
|
||||
for(i = 0; i < 7; i++) {
|
||||
pI830->saveSWF[i] = INREG(SWF0 + (i << 2));
|
||||
pI830->saveSWF[i+7] = INREG(SWF00 + (i << 2));
|
||||
|
|
@ -2627,17 +2614,8 @@ SaveHWState(ScrnInfoPtr pScrn)
|
|||
pI830->saveSWF[16] = INREG(SWF32);
|
||||
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_DVO &&
|
||||
pI830->output[i].i2c_drv != NULL)
|
||||
{
|
||||
pI830->output[i].i2c_drv->vid_rec->SaveRegs(
|
||||
pI830->output[i].i2c_drv->dev_priv);
|
||||
}
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO &&
|
||||
pI830->output[i].sdvo_drv != NULL)
|
||||
{
|
||||
i830SDVOSave(pScrn, i);
|
||||
}
|
||||
if (pI830->output[i].save != NULL)
|
||||
pI830->output[i].save(pScrn, &pI830->output[i]);
|
||||
}
|
||||
|
||||
vgaHWUnlock(hwp);
|
||||
|
|
@ -2675,19 +2653,13 @@ RestoreHWState(ScrnInfoPtr pScrn)
|
|||
temp = INREG(PIPEBCONF);
|
||||
OUTREG(PIPEBCONF, temp & ~PIPEBCONF_ENABLE);
|
||||
|
||||
/* XXX: Wait for a vblank */
|
||||
sleep(1);
|
||||
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
|
||||
/* Disable outputs if necessary */
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO &&
|
||||
pI830->output[i].sdvo_drv != NULL)
|
||||
{
|
||||
i830SDVOPreRestore(pScrn, i);
|
||||
}
|
||||
pI830->output[i].pre_set_mode(pScrn, &pI830->output[i], NULL);
|
||||
}
|
||||
|
||||
i830WaitForVblank(pScrn);
|
||||
|
||||
OUTREG(FPA0, pI830->saveFPA0);
|
||||
OUTREG(FPA1, pI830->saveFPA1);
|
||||
OUTREG(DPLL_A, pI830->saveDPLL_A);
|
||||
|
|
@ -2726,17 +2698,15 @@ RestoreHWState(ScrnInfoPtr pScrn)
|
|||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
pI830->output[i].restore(pScrn, &pI830->output[i]);
|
||||
}
|
||||
|
||||
if (IS_I965G(pI830)) {
|
||||
OUTREG(DSPASURF, pI830->saveDSPABASE);
|
||||
OUTREG(DSPBSURF, pI830->saveDSPBBASE);
|
||||
}
|
||||
|
||||
OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL);
|
||||
OUTREG(LVDSPP_ON, pI830->savePP_ON);
|
||||
OUTREG(LVDSPP_OFF, pI830->savePP_OFF);
|
||||
OUTREG(PP_CYCLE, pI830->savePP_CYCLE);
|
||||
OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
|
||||
|
||||
OUTREG(VCLK_DIVISOR_VGA0, pI830->saveVCLK_DIVISOR_VGA0);
|
||||
OUTREG(VCLK_DIVISOR_VGA1, pI830->saveVCLK_DIVISOR_VGA1);
|
||||
OUTREG(VCLK_POST_DIV, pI830->saveVCLK_POST_DIV);
|
||||
|
|
@ -2748,30 +2718,6 @@ RestoreHWState(ScrnInfoPtr pScrn)
|
|||
OUTREG(DSPACNTR, pI830->saveDSPACNTR);
|
||||
OUTREG(DSPBCNTR, pI830->saveDSPBCNTR);
|
||||
|
||||
OUTREG(ADPA, pI830->saveADPA);
|
||||
OUTREG(LVDS, pI830->saveLVDS);
|
||||
if (!IS_I9XX(pI830)) {
|
||||
OUTREG(DVOA, pI830->saveDVOA);
|
||||
OUTREG(DVOB, pI830->saveDVOB);
|
||||
OUTREG(DVOC, pI830->saveDVOC);
|
||||
}
|
||||
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_DVO &&
|
||||
pI830->output[i].i2c_drv != NULL)
|
||||
{
|
||||
pI830->output[i].i2c_drv->vid_rec->RestoreRegs(
|
||||
pI830->output[i].i2c_drv->dev_priv);
|
||||
}
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO &&
|
||||
pI830->output[i].sdvo_drv != NULL)
|
||||
{
|
||||
i830SDVOPostRestore(pScrn, i);
|
||||
}
|
||||
}
|
||||
|
||||
OUTREG(PP_CONTROL, pI830->savePP_CONTROL);
|
||||
|
||||
for(i = 0; i < 7; i++) {
|
||||
OUTREG(SWF0 + (i << 2), pI830->saveSWF[i]);
|
||||
OUTREG(SWF00 + (i << 2), pI830->saveSWF[i+7]);
|
||||
|
|
@ -4197,39 +4143,6 @@ I830SaveScreen(ScreenPtr pScreen, int mode)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
I830DPMSCRT(ScrnInfoPtr pScrn, int mode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD32 temp;
|
||||
|
||||
temp = INREG(ADPA);
|
||||
temp &= ~(ADPA_HSYNC_CNTL_DISABLE|ADPA_VSYNC_CNTL_DISABLE);
|
||||
switch(mode) {
|
||||
case DPMSModeOn:
|
||||
break;
|
||||
case DPMSModeStandby:
|
||||
temp |= ADPA_HSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
case DPMSModeSuspend:
|
||||
temp |= ADPA_VSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
case DPMSModeOff:
|
||||
temp |= ADPA_HSYNC_CNTL_DISABLE|ADPA_VSYNC_CNTL_DISABLE;
|
||||
break;
|
||||
}
|
||||
OUTREG(ADPA, temp);
|
||||
}
|
||||
|
||||
static void
|
||||
I830DPMSLVDS(ScrnInfoPtr pScrn, int mode)
|
||||
{
|
||||
if (mode == DPMSModeOn)
|
||||
i830SetLVDSPanelPower(pScrn, TRUE);
|
||||
else
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
}
|
||||
|
||||
/* Use the VBE version when available. */
|
||||
static void
|
||||
I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
|
||||
|
|
@ -4239,6 +4152,10 @@ I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
|
|||
int i;
|
||||
CARD32 temp, ctrl, base;
|
||||
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
pI830->output[i].dpms(pScrn, &pI830->output[i], PowerManagementMode);
|
||||
}
|
||||
|
||||
for (i = 0; i < pI830->availablePipes; i++) {
|
||||
if (i == 0) {
|
||||
ctrl = DSPACNTR;
|
||||
|
|
@ -4260,22 +4177,6 @@ I830DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
|
|||
}
|
||||
}
|
||||
|
||||
if (pI830->operatingDevices & (PIPE_CRT_ACTIVE | (PIPE_CRT_ACTIVE<<8))) {
|
||||
I830DPMSCRT(pScrn, PowerManagementMode);
|
||||
}
|
||||
|
||||
if (pI830->operatingDevices & (PIPE_LCD_ACTIVE | (PIPE_LCD_ACTIVE<<8))) {
|
||||
I830DPMSLVDS(pScrn, PowerManagementMode);
|
||||
}
|
||||
|
||||
if (pI830->operatingDevices & (PIPE_DFP_ACTIVE | (PIPE_DFP_ACTIVE<<8))) {
|
||||
/* TBD */
|
||||
}
|
||||
|
||||
if (pI830->operatingDevices & (PIPE_DFP2_ACTIVE | (PIPE_DFP2_ACTIVE<<8))) {
|
||||
/* TBD */
|
||||
}
|
||||
|
||||
if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) {
|
||||
if (PowerManagementMode == DPMSModeOn)
|
||||
pI830->CursorInfoRec->ShowCursor(pScrn);
|
||||
|
|
@ -4466,14 +4367,11 @@ i830MonitorDetectDebugger(ScrnInfoPtr pScrn)
|
|||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Detected CRT as %s in %dms\n",
|
||||
found_crt ? "connected" : "disconnected", finish - start);
|
||||
|
||||
for (i = 0; i < MAX_OUTPUTS; i++) {
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
Bool found_sdvo = TRUE;
|
||||
|
||||
if (pI830->output[i].type != I830_OUTPUT_SDVO ||
|
||||
pI830->output[i].sdvo_drv == NULL)
|
||||
{
|
||||
if (pI830->output[i].type != I830_OUTPUT_SDVO)
|
||||
continue;
|
||||
}
|
||||
start = GetTimeInMillis();
|
||||
found_sdvo = I830DetectSDVODisplays(pScrn, i);
|
||||
finish = GetTimeInMillis();
|
||||
|
|
|
|||
136
src/i830_dvo.c
136
src/i830_dvo.c
|
|
@ -22,7 +22,8 @@ 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"
|
||||
|
|
@ -30,6 +31,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include "xf86.h"
|
||||
#include "i830.h"
|
||||
#include "i810_reg.h"
|
||||
|
||||
#include "sil164/sil164.h"
|
||||
#include "ch7xxx/ch7xxx.h"
|
||||
|
|
@ -54,7 +56,95 @@ struct _I830DVODriver i830_dvo_drivers[] =
|
|||
|
||||
#define I830_NUM_DVO_DRIVERS (sizeof(i830_dvo_drivers)/sizeof(struct _I830DVODriver))
|
||||
|
||||
Bool
|
||||
static void
|
||||
i830_dvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
|
||||
{
|
||||
if (mode == DPMSModeOn)
|
||||
output->i2c_drv->vid_rec->Power(output->i2c_drv->dev_priv, TRUE);
|
||||
else
|
||||
output->i2c_drv->vid_rec->Power(output->i2c_drv->dev_priv, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_dvo_save(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
/* Each output should probably just save the registers it touches, but for
|
||||
* now, use more overkill.
|
||||
*/
|
||||
pI830->saveDVOA = INREG(DVOA);
|
||||
pI830->saveDVOB = INREG(DVOB);
|
||||
pI830->saveDVOC = INREG(DVOC);
|
||||
|
||||
output->i2c_drv->vid_rec->SaveRegs(output->i2c_drv->dev_priv);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_dvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
OUTREG(DVOA, pI830->saveDVOA);
|
||||
OUTREG(DVOB, pI830->saveDVOB);
|
||||
OUTREG(DVOC, pI830->saveDVOC);
|
||||
|
||||
output->i2c_drv->vid_rec->RestoreRegs(output->i2c_drv->dev_priv);
|
||||
}
|
||||
|
||||
static int
|
||||
i830_dvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
if (output->i2c_drv->vid_rec->ModeValid(output->i2c_drv->dev_priv, pMode))
|
||||
return MODE_OK;
|
||||
else
|
||||
return MODE_BAD;
|
||||
}
|
||||
|
||||
static void
|
||||
i830_dvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
output->i2c_drv->vid_rec->Mode(output->i2c_drv->dev_priv, pMode);
|
||||
|
||||
OUTREG(DVOC, INREG(DVOC) & ~DVO_ENABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_dvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD32 dvo;
|
||||
int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B;
|
||||
|
||||
/* Save the data order, since I don't know what it should be set to. */
|
||||
dvo = INREG(DVOC) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
|
||||
dvo |= DVO_ENABLE;
|
||||
dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH;
|
||||
|
||||
if (output->pipe == 1)
|
||||
dvo |= DVO_PIPE_B_SELECT;
|
||||
|
||||
if (pMode->Flags & V_PHSYNC)
|
||||
dvo |= DVO_HSYNC_ACTIVE_HIGH;
|
||||
if (pMode->Flags & V_PVSYNC)
|
||||
dvo |= DVO_VSYNC_ACTIVE_HIGH;
|
||||
|
||||
OUTREG(dpll_reg, INREG(dpll_reg) | DPLL_DVO_HIGH_SPEED);
|
||||
|
||||
/*OUTREG(DVOB_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
|
||||
(pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
|
||||
OUTREG(DVOC_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
|
||||
(pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
|
||||
/*OUTREG(DVOB, dvo);*/
|
||||
OUTREG(DVOC, dvo);
|
||||
}
|
||||
|
||||
static Bool
|
||||
I830I2CDetectDVOControllers(ScrnInfoPtr pScrn, I2CBusPtr pI2CBus,
|
||||
struct _I830DVODriver **retdrv)
|
||||
{
|
||||
|
|
@ -84,3 +174,45 @@ I830I2CDetectDVOControllers(ScrnInfoPtr pScrn, I2CBusPtr pI2CBus,
|
|||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
i830_dvo_init(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
Bool ret;
|
||||
int i = pI830->num_outputs;
|
||||
|
||||
pI830->output[i].type = I830_OUTPUT_DVO;
|
||||
pI830->output[i].dpms = i830_dvo_dpms;
|
||||
pI830->output[i].save = i830_dvo_save;
|
||||
pI830->output[i].restore = i830_dvo_restore;
|
||||
pI830->output[i].mode_valid = i830_dvo_mode_valid;
|
||||
pI830->output[i].pre_set_mode = i830_dvo_pre_set_mode;
|
||||
pI830->output[i].post_set_mode = i830_dvo_post_set_mode;
|
||||
|
||||
/* Set up the I2C and DDC buses */
|
||||
ret = I830I2CInit(pScrn, &pI830->output[i].pI2CBus, GPIOE, "DVOI2C_E");
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
ret = I830I2CInit(pScrn, &pI830->output[i].pDDCBus, GPIOD, "DVODDC_D");
|
||||
if (!ret) {
|
||||
xf86DestroyI2CBusRec(pI830->output[i].pI2CBus, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, try to find a controller */
|
||||
ret = I830I2CDetectDVOControllers(pScrn, pI830->output[i].pI2CBus,
|
||||
&pI830->output[i].i2c_drv);
|
||||
if (ret) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Found i2c %s on %08lX\n",
|
||||
pI830->output[i].i2c_drv->modulename,
|
||||
pI830->output[i].pI2CBus->DriverPrivate.uval);
|
||||
} else {
|
||||
xf86DestroyI2CBusRec(pI830->output[i].pI2CBus, TRUE, TRUE);
|
||||
xf86DestroyI2CBusRec(pI830->output[i].pDDCBus, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
pI830->num_outputs++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "xf86.h"
|
||||
#include "i830.h"
|
||||
|
||||
/**
|
||||
* Sets the power state for the panel.
|
||||
*/
|
||||
static void
|
||||
i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD32 pp_status, pp_control;
|
||||
CARD32 blc_pwm_ctl;
|
||||
int backlight_duty_cycle;
|
||||
|
||||
blc_pwm_ctl = INREG (BLC_PWM_CTL);
|
||||
backlight_duty_cycle = blc_pwm_ctl & BACKLIGHT_DUTY_CYCLE_MASK;
|
||||
if (backlight_duty_cycle)
|
||||
pI830->backlight_duty_cycle = backlight_duty_cycle;
|
||||
|
||||
if (on) {
|
||||
OUTREG(PP_STATUS, INREG(PP_STATUS) | PP_ON);
|
||||
OUTREG(PP_CONTROL, INREG(PP_CONTROL) | POWER_TARGET_ON);
|
||||
do {
|
||||
pp_status = INREG(PP_STATUS);
|
||||
pp_control = INREG(PP_CONTROL);
|
||||
} while (!(pp_status & PP_ON) && !(pp_control & POWER_TARGET_ON));
|
||||
OUTREG(BLC_PWM_CTL,
|
||||
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK) |
|
||||
pI830->backlight_duty_cycle);
|
||||
} else {
|
||||
OUTREG(BLC_PWM_CTL,
|
||||
(blc_pwm_ctl & ~BACKLIGHT_DUTY_CYCLE_MASK));
|
||||
|
||||
OUTREG(PP_STATUS, INREG(PP_STATUS) & ~PP_ON);
|
||||
OUTREG(PP_CONTROL, INREG(PP_CONTROL) & ~POWER_TARGET_ON);
|
||||
do {
|
||||
pp_status = INREG(PP_STATUS);
|
||||
pp_control = INREG(PP_CONTROL);
|
||||
} while ((pp_status & PP_ON) || (pp_control & POWER_TARGET_ON));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
i830_lvds_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
|
||||
{
|
||||
if (mode == DPMSModeOn)
|
||||
i830SetLVDSPanelPower(pScrn, TRUE);
|
||||
else
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_lvds_save(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
pI830->savePFIT_CONTROL = INREG(PFIT_CONTROL);
|
||||
pI830->savePP_ON = INREG(LVDSPP_ON);
|
||||
pI830->savePP_OFF = INREG(LVDSPP_OFF);
|
||||
pI830->saveLVDS = INREG(LVDS);
|
||||
pI830->savePP_CONTROL = INREG(PP_CONTROL);
|
||||
pI830->savePP_CYCLE = INREG(PP_CYCLE);
|
||||
pI830->saveBLC_PWM_CTL = INREG(BLC_PWM_CTL);
|
||||
pI830->backlight_duty_cycle = (pI830->saveBLC_PWM_CTL &
|
||||
BACKLIGHT_DUTY_CYCLE_MASK);
|
||||
|
||||
/*
|
||||
* If the light is off at server startup, just make it full brightness
|
||||
*/
|
||||
if (pI830->backlight_duty_cycle == 0) {
|
||||
pI830->backlight_duty_cycle =
|
||||
(pI830->saveBLC_PWM_CTL & BACKLIGHT_MODULATION_FREQ_MASK) >>
|
||||
BACKLIGHT_MODULATION_FREQ_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
i830_lvds_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
OUTREG(BLC_PWM_CTL, pI830->saveBLC_PWM_CTL);
|
||||
OUTREG(LVDSPP_ON, pI830->savePP_ON);
|
||||
OUTREG(LVDSPP_OFF, pI830->savePP_OFF);
|
||||
OUTREG(PP_CYCLE, pI830->savePP_CYCLE);
|
||||
OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
|
||||
OUTREG(LVDS, pI830->saveLVDS);
|
||||
OUTREG(PP_CONTROL, pI830->savePP_CONTROL);
|
||||
if (pI830->savePP_CONTROL & POWER_TARGET_ON)
|
||||
i830SetLVDSPanelPower(pScrn, TRUE);
|
||||
else
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
}
|
||||
|
||||
static int
|
||||
i830_lvds_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
i830_lvds_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
/* Always make sure the LVDS is off before we play with DPLLs and pipe
|
||||
* configuration. We can skip this in some cases (for example, going
|
||||
* between hi-res modes with automatic panel scaling are fine), but be
|
||||
* conservative for now.
|
||||
*/
|
||||
i830SetLVDSPanelPower(pScrn, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_lvds_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD32 pfit_control;
|
||||
|
||||
/* Enable automatic panel scaling so that non-native modes fill the
|
||||
* screen. Should be enabled before the pipe is enabled, according to
|
||||
* register description.
|
||||
*/
|
||||
pfit_control = (PFIT_ENABLE |
|
||||
VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
|
||||
VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR);
|
||||
|
||||
if (pI830->panel_wants_dither)
|
||||
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
|
||||
|
||||
OUTREG(PFIT_CONTROL, pfit_control);
|
||||
|
||||
/* Disable the PLL before messing with LVDS enable */
|
||||
OUTREG(FPB0, INREG(FPB0) & ~DPLL_VCO_ENABLE);
|
||||
|
||||
/* LVDS must be powered on before PLL is enabled and before power
|
||||
* sequencing the panel.
|
||||
*/
|
||||
OUTREG(LVDS, INREG(LVDS) | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
|
||||
|
||||
/* Re-enable the PLL */
|
||||
OUTREG(FPB0, INREG(FPB0) | DPLL_VCO_ENABLE);
|
||||
|
||||
i830SetLVDSPanelPower(pScrn, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
i830_lvds_init(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
pI830->output[pI830->num_outputs].type = I830_OUTPUT_LVDS;
|
||||
pI830->output[pI830->num_outputs].dpms = i830_lvds_dpms;
|
||||
pI830->output[pI830->num_outputs].save = i830_lvds_save;
|
||||
pI830->output[pI830->num_outputs].restore = i830_lvds_restore;
|
||||
pI830->output[pI830->num_outputs].mode_valid = i830_lvds_mode_valid;
|
||||
pI830->output[pI830->num_outputs].pre_set_mode = i830_lvds_pre_set_mode;
|
||||
pI830->output[pI830->num_outputs].post_set_mode = i830_lvds_post_set_mode;
|
||||
|
||||
/* Set up the LVDS DDC channel. Most panels won't support it, but it can
|
||||
* be useful if available.
|
||||
*/
|
||||
I830I2CInit(pScrn, &pI830->output[pI830->num_outputs].pDDCBus,
|
||||
GPIOC, "LVDSDDC_C");
|
||||
|
||||
pI830->num_outputs++;
|
||||
}
|
||||
|
|
@ -766,7 +766,7 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe)
|
|||
else
|
||||
outputs = (pI830->operatingDevices >> 8) & 0xff;
|
||||
|
||||
for (i = 0; i < MAX_OUTPUTS; i++) {
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
switch (pI830->output[i].type) {
|
||||
case I830_OUTPUT_ANALOG:
|
||||
if (outputs & PIPE_CRT) {
|
||||
|
|
@ -779,14 +779,12 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe)
|
|||
}
|
||||
break;
|
||||
case I830_OUTPUT_DVO:
|
||||
if (outputs & PIPE_DFP && pI830->output[i].i2c_drv != NULL) {
|
||||
if (outputs & PIPE_DFP) {
|
||||
output_index = i;
|
||||
}
|
||||
break;
|
||||
case I830_OUTPUT_SDVO:
|
||||
if (outputs & PIPE_DFP &&
|
||||
pI830->output[i].sdvo_drv != NULL)
|
||||
{
|
||||
if (outputs & PIPE_DFP) {
|
||||
output_index = i;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
339
src/i830_sdvo.c
339
src/i830_sdvo.c
|
|
@ -34,6 +34,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include "compiler.h"
|
||||
#include "i830.h"
|
||||
#include "i830_display.h"
|
||||
#include "i810_reg.h"
|
||||
#include "i830_sdvo_regs.h"
|
||||
|
||||
CARD16 curr_table[6];
|
||||
|
|
@ -169,6 +170,17 @@ I830SDVOReadInputRegs(I830SDVOPtr s)
|
|||
ErrorF("\n");
|
||||
}
|
||||
|
||||
int
|
||||
i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode)
|
||||
{
|
||||
if (pMode->Clock >= 100000)
|
||||
return 1;
|
||||
else if (pMode->Clock >= 50000)
|
||||
return 2;
|
||||
else
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* Sets the control bus switch to either point at one of the DDC buses or the
|
||||
* PROM. It resets from the DDC bus back to internal registers at the next I2C
|
||||
* STOP. PROM access is terminated by accessing an internal register.
|
||||
|
|
@ -520,9 +532,11 @@ I830SDVOSetClockRateMult(I830SDVOPtr s, CARD8 val)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
Bool
|
||||
I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
|
||||
static void
|
||||
i830_sdvo_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr mode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
CARD16 clock = mode->Clock/10, width = mode->CrtcHDisplay;
|
||||
CARD16 height = mode->CrtcVDisplay;
|
||||
CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
|
||||
|
|
@ -531,8 +545,8 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
|
|||
CARD8 c16a[8];
|
||||
CARD8 c17a[8];
|
||||
CARD16 out_timings[6];
|
||||
CARD16 clock_min, clock_max;
|
||||
Bool out1, out2;
|
||||
I830SDVOPtr s = output->sdvo_drv;
|
||||
|
||||
/* do some mode translations */
|
||||
h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart;
|
||||
|
|
@ -573,8 +587,6 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
|
|||
out_timings[5] = c17a[3] | ((short)c17a[2] << 8);
|
||||
|
||||
I830SDVOSetTargetInput(s, FALSE, FALSE);
|
||||
I830SDVOGetInputPixelClockRange(s, &clock_min, &clock_max);
|
||||
ErrorF("clock min/max: %d %d\n", clock_min, clock_max);
|
||||
|
||||
I830SDVOGetActiveOutputs(s, &out1, &out2);
|
||||
|
||||
|
|
@ -600,22 +612,34 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode)
|
|||
out_timings[5]);
|
||||
|
||||
I830SDVOSetTargetInput (s, FALSE, FALSE);
|
||||
|
||||
if (clock >= 10000)
|
||||
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_1X);
|
||||
else if (clock >= 5000)
|
||||
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_2X);
|
||||
else
|
||||
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_4X);
|
||||
|
||||
return TRUE;
|
||||
switch (i830_sdvo_get_pixel_multiplier(mode)) {
|
||||
case 1:
|
||||
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_1X);
|
||||
break;
|
||||
case 2:
|
||||
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_2X);
|
||||
break;
|
||||
case 4:
|
||||
I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_4X);
|
||||
break;
|
||||
}
|
||||
|
||||
OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE);
|
||||
OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE);
|
||||
}
|
||||
|
||||
Bool
|
||||
I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode)
|
||||
static void
|
||||
i830_sdvo_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr mode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
Bool ret = TRUE;
|
||||
Bool out1, out2;
|
||||
CARD32 dpll, sdvob, sdvoc;
|
||||
int dpll_reg = (output->pipe == 0) ? DPLL_A : DPLL_B;
|
||||
int sdvo_pixel_multiply;
|
||||
I830SDVOPtr s = output->sdvo_drv;
|
||||
|
||||
/* the BIOS writes out 6 commands post mode set */
|
||||
/* two 03s, 04 05, 10, 1d */
|
||||
|
|
@ -636,14 +660,48 @@ I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode)
|
|||
I830SDVOSetActiveOutputs(s, TRUE, FALSE);
|
||||
I830SDVOSetTargetInput (s, FALSE, FALSE);
|
||||
|
||||
return ret;
|
||||
/* Set the SDVO control regs. */
|
||||
sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK;
|
||||
sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK;
|
||||
sdvob |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE;
|
||||
sdvoc |= 9 << 19;
|
||||
if (output->pipe == 1)
|
||||
sdvob |= SDVO_PIPE_B_SELECT;
|
||||
|
||||
dpll = INREG(dpll_reg);
|
||||
|
||||
sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(mode);
|
||||
if (IS_I945G(pI830) || IS_I945GM(pI830))
|
||||
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
|
||||
else
|
||||
sdvob |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
|
||||
|
||||
OUTREG(dpll_reg, dpll | DPLL_DVO_HIGH_SPEED);
|
||||
|
||||
OUTREG(SDVOB, sdvob);
|
||||
OUTREG(SDVOC, sdvoc);
|
||||
}
|
||||
|
||||
void
|
||||
i830SDVOSave(ScrnInfoPtr pScrn, int output_index)
|
||||
static void
|
||||
i830_sdvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr sdvo = pI830->output[output_index].sdvo_drv;
|
||||
I830SDVOPtr sdvo = output->sdvo_drv;
|
||||
|
||||
if (mode != DPMSModeOn) {
|
||||
I830SDVOSetActiveOutputs(sdvo, FALSE, FALSE);
|
||||
OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE);
|
||||
} else {
|
||||
I830SDVOSetActiveOutputs(sdvo, TRUE, FALSE);
|
||||
OUTREG(SDVOB, INREG(SDVOB) | SDVO_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
i830_sdvo_save(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr sdvo = output->sdvo_drv;
|
||||
|
||||
sdvo->save_sdvo_mult = I830SDVOGetClockRateMult(sdvo);
|
||||
I830SDVOGetActiveOutputs(sdvo, &sdvo->save_sdvo_active_1,
|
||||
|
|
@ -676,20 +734,11 @@ i830SDVOSave(ScrnInfoPtr pScrn, int output_index)
|
|||
sdvo->save_SDVOX = INREG(sdvo->output_device);
|
||||
}
|
||||
|
||||
void
|
||||
i830SDVOPreRestore(ScrnInfoPtr pScrn, int output_index)
|
||||
static void
|
||||
i830_sdvo_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr sdvo = pI830->output[output_index].sdvo_drv;
|
||||
|
||||
I830SDVOSetActiveOutputs(sdvo, FALSE, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
i830SDVOPostRestore(ScrnInfoPtr pScrn, int output_index)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr sdvo = pI830->output[output_index].sdvo_drv;
|
||||
I830SDVOPtr sdvo = output->sdvo_drv;
|
||||
|
||||
if (sdvo->caps.caps & 0x1) {
|
||||
I830SDVOSetTargetInput(sdvo, FALSE, FALSE);
|
||||
|
|
@ -723,6 +772,21 @@ i830SDVOPostRestore(ScrnInfoPtr pScrn, int output_index)
|
|||
sdvo->save_sdvo_active_2);
|
||||
}
|
||||
|
||||
static int
|
||||
i830_sdvo_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830SDVOPtr sdvo = output->sdvo_drv;
|
||||
|
||||
if (sdvo->pixel_clock_min > pMode->Clock)
|
||||
return MODE_CLOCK_HIGH;
|
||||
|
||||
if (sdvo->pixel_clock_max < pMode->Clock)
|
||||
return MODE_CLOCK_LOW;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
I830SDVOGetCapabilities(I830SDVOPtr s, i830_sdvo_caps *caps)
|
||||
{
|
||||
|
|
@ -815,95 +879,6 @@ I830SDVODDCI2CAddress(I2CDevPtr d, I2CSlaveAddr addr)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
I830SDVOPtr
|
||||
I830SDVOInit(ScrnInfoPtr pScrn, int output_index, CARD32 output_device)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr sdvo;
|
||||
int i;
|
||||
unsigned char ch[0x40];
|
||||
I2CBusPtr i2cbus, ddcbus;
|
||||
|
||||
i2cbus = pI830->output[output_index].pI2CBus;
|
||||
|
||||
sdvo = xcalloc(1, sizeof(I830SDVORec));
|
||||
if (sdvo == NULL)
|
||||
return NULL;
|
||||
|
||||
if (output_device == SDVOB) {
|
||||
sdvo->d.DevName = "SDVO Controller B";
|
||||
sdvo->d.SlaveAddr = 0x70;
|
||||
} else {
|
||||
sdvo->d.DevName = "SDVO Controller C";
|
||||
sdvo->d.SlaveAddr = 0x72;
|
||||
}
|
||||
sdvo->d.pI2CBus = i2cbus;
|
||||
sdvo->d.DriverPrivate.ptr = sdvo;
|
||||
sdvo->output_device = output_device;
|
||||
|
||||
if (!xf86I2CDevInit(&sdvo->d)) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
"Failed to initialize SDVO I2C device %s\n",
|
||||
output_device == SDVOB ? "SDVOB" : "SDVOC");
|
||||
xfree(sdvo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up our wrapper I2C bus for DDC. It acts just like the regular I2C
|
||||
* bus, except that it does the control bus switch to DDC mode before every
|
||||
* Start. While we only need to do it at Start after every Stop after a
|
||||
* Start, extra attempts should be harmless.
|
||||
*/
|
||||
ddcbus = xf86CreateI2CBusRec();
|
||||
if (ddcbus == NULL) {
|
||||
xf86DestroyI2CDevRec(&sdvo->d, 0);
|
||||
xfree(sdvo);
|
||||
return NULL;
|
||||
}
|
||||
if (output_device == SDVOB)
|
||||
ddcbus->BusName = "SDVOB DDC Bus";
|
||||
else
|
||||
ddcbus->BusName = "SDVOC DDC Bus";
|
||||
ddcbus->scrnIndex = i2cbus->scrnIndex;
|
||||
ddcbus->I2CGetByte = I830SDVODDCI2CGetByte;
|
||||
ddcbus->I2CPutByte = I830SDVODDCI2CPutByte;
|
||||
ddcbus->I2CStart = I830SDVODDCI2CStart;
|
||||
ddcbus->I2CStop = I830SDVODDCI2CStop;
|
||||
ddcbus->I2CAddress = I830SDVODDCI2CAddress;
|
||||
ddcbus->DriverPrivate.ptr = sdvo;
|
||||
if (!xf86I2CBusInit(ddcbus)) {
|
||||
xf86DestroyI2CDevRec(&sdvo->d, 0);
|
||||
xfree(sdvo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pI830->output[output_index].pDDCBus = ddcbus;
|
||||
|
||||
/* Read the regs to test if we can talk to the device */
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
if (!sReadByte(sdvo, i, &ch[i])) {
|
||||
xf86DestroyI2CBusRec(pI830->output[output_index].pDDCBus, FALSE,
|
||||
FALSE);
|
||||
xf86DestroyI2CDevRec(&sdvo->d, 0);
|
||||
xfree(sdvo);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pI830->output[output_index].sdvo_drv = sdvo;
|
||||
|
||||
I830SDVOGetCapabilities(sdvo, &sdvo->caps);
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"SDVO device VID/DID: %02X:%02X.%02X, %02X, output 1: %c, output 2: %c\n",
|
||||
sdvo->caps.vendor_id, sdvo->caps.device_id,
|
||||
sdvo->caps.device_rev_id, sdvo->caps.caps,
|
||||
sdvo->caps.output_0_supported ? 'Y' : 'N',
|
||||
sdvo->caps.output_1_supported ? 'Y' : 'N');
|
||||
|
||||
return sdvo;
|
||||
}
|
||||
|
||||
static void
|
||||
I830DumpSDVOCmd (I830SDVOPtr s, int opcode)
|
||||
{
|
||||
|
|
@ -944,13 +919,11 @@ void
|
|||
I830DumpSDVO (ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr s;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
s = pI830->output[i].sdvo_drv;
|
||||
if (s)
|
||||
I830DumpOneSDVO (s);
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO)
|
||||
I830DumpOneSDVO (pI830->output[i].sdvo_drv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -979,3 +952,119 @@ I830DetectSDVODisplays(ScrnInfoPtr pScrn, int output_index)
|
|||
return (s->sdvo_regs[SDVO_I2C_RETURN_0] != 0 ||
|
||||
s->sdvo_regs[SDVO_I2C_RETURN_1] != 0);
|
||||
}
|
||||
|
||||
void
|
||||
i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
I830SDVOPtr sdvo;
|
||||
int i;
|
||||
unsigned char ch[0x40];
|
||||
I2CBusPtr i2cbus = NULL, ddcbus;
|
||||
|
||||
pI830->output[pI830->num_outputs].type = I830_OUTPUT_SDVO;
|
||||
pI830->output[pI830->num_outputs].dpms = i830_sdvo_dpms;
|
||||
pI830->output[pI830->num_outputs].save = i830_sdvo_save;
|
||||
pI830->output[pI830->num_outputs].restore = i830_sdvo_restore;
|
||||
pI830->output[pI830->num_outputs].mode_valid = i830_sdvo_mode_valid;
|
||||
pI830->output[pI830->num_outputs].pre_set_mode = i830_sdvo_pre_set_mode;
|
||||
pI830->output[pI830->num_outputs].post_set_mode = i830_sdvo_post_set_mode;
|
||||
|
||||
/* Find an existing SDVO I2CBus from another output, or allocate it. */
|
||||
for (i = 0; i < pI830->num_outputs; i++) {
|
||||
if (pI830->output[i].type == I830_OUTPUT_SDVO)
|
||||
i2cbus = pI830->output[i].pI2CBus;
|
||||
}
|
||||
if (i2cbus == NULL)
|
||||
I830I2CInit(pScrn, &i2cbus, GPIOE, "SDVOCTRL_E");
|
||||
if (i2cbus == NULL)
|
||||
return;
|
||||
|
||||
/* Allocate the SDVO output private data */
|
||||
sdvo = xcalloc(1, sizeof(I830SDVORec));
|
||||
if (sdvo == NULL) {
|
||||
xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (output_device == SDVOB) {
|
||||
sdvo->d.DevName = "SDVO Controller B";
|
||||
sdvo->d.SlaveAddr = 0x70;
|
||||
} else {
|
||||
sdvo->d.DevName = "SDVO Controller C";
|
||||
sdvo->d.SlaveAddr = 0x72;
|
||||
}
|
||||
sdvo->d.pI2CBus = i2cbus;
|
||||
sdvo->d.DriverPrivate.ptr = sdvo;
|
||||
sdvo->output_device = output_device;
|
||||
|
||||
if (!xf86I2CDevInit(&sdvo->d)) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
|
||||
"Failed to initialize SDVO I2C device %s\n",
|
||||
output_device == SDVOB ? "SDVOB" : "SDVOC");
|
||||
xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE);
|
||||
xfree(sdvo);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up our wrapper I2C bus for DDC. It acts just like the regular I2C
|
||||
* bus, except that it does the control bus switch to DDC mode before every
|
||||
* Start. While we only need to do it at Start after every Stop after a
|
||||
* Start, extra attempts should be harmless.
|
||||
*/
|
||||
ddcbus = xf86CreateI2CBusRec();
|
||||
if (ddcbus == NULL) {
|
||||
xf86DestroyI2CDevRec(&sdvo->d, FALSE);
|
||||
xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE);
|
||||
xfree(sdvo);
|
||||
return;
|
||||
}
|
||||
if (output_device == SDVOB)
|
||||
ddcbus->BusName = "SDVOB DDC Bus";
|
||||
else
|
||||
ddcbus->BusName = "SDVOC DDC Bus";
|
||||
ddcbus->scrnIndex = i2cbus->scrnIndex;
|
||||
ddcbus->I2CGetByte = I830SDVODDCI2CGetByte;
|
||||
ddcbus->I2CPutByte = I830SDVODDCI2CPutByte;
|
||||
ddcbus->I2CStart = I830SDVODDCI2CStart;
|
||||
ddcbus->I2CStop = I830SDVODDCI2CStop;
|
||||
ddcbus->I2CAddress = I830SDVODDCI2CAddress;
|
||||
ddcbus->DriverPrivate.ptr = sdvo;
|
||||
if (!xf86I2CBusInit(ddcbus)) {
|
||||
xf86DestroyI2CDevRec(&sdvo->d, FALSE);
|
||||
xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE);
|
||||
xfree(sdvo);
|
||||
return;
|
||||
}
|
||||
|
||||
pI830->output[pI830->num_outputs].pI2CBus = i2cbus;
|
||||
pI830->output[pI830->num_outputs].pDDCBus = ddcbus;
|
||||
pI830->output[pI830->num_outputs].sdvo_drv = sdvo;
|
||||
|
||||
/* Read the regs to test if we can talk to the device */
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
if (!sReadByte(sdvo, i, &ch[i])) {
|
||||
xf86DestroyI2CBusRec(pI830->output[pI830->num_outputs].pDDCBus,
|
||||
FALSE, FALSE);
|
||||
xf86DestroyI2CDevRec(&sdvo->d, FALSE);
|
||||
xf86DestroyI2CBusRec(i2cbus, TRUE, TRUE);
|
||||
xfree(sdvo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
I830SDVOGetCapabilities(sdvo, &sdvo->caps);
|
||||
|
||||
I830SDVOGetInputPixelClockRange(sdvo, &sdvo->pixel_clock_min,
|
||||
&sdvo->pixel_clock_max);
|
||||
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"SDVO device VID/DID: %02X:%02X.%02X, %02X,"
|
||||
"output 1: %c, output 2: %c\n",
|
||||
sdvo->caps.vendor_id, sdvo->caps.device_id,
|
||||
sdvo->caps.device_rev_id, sdvo->caps.caps,
|
||||
sdvo->caps.output_0_supported ? 'Y' : 'N',
|
||||
sdvo->caps.output_1_supported ? 'Y' : 'N');
|
||||
|
||||
pI830->num_outputs++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,13 +56,10 @@ typedef struct _i830_sdvo_dtd {
|
|||
} __attribute__((packed)) i830_sdvo_dtd;
|
||||
|
||||
void
|
||||
i830SDVOSave(ScrnInfoPtr pScrn, int output_index);
|
||||
i830_sdvo_init(ScrnInfoPtr pScrn, int output_device);
|
||||
|
||||
void
|
||||
i830SDVOPreRestore(ScrnInfoPtr pScrn, int output_index);
|
||||
|
||||
void
|
||||
i830SDVOPostRestore(ScrnInfoPtr pScrn, int output_index);
|
||||
int
|
||||
i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode);
|
||||
|
||||
Bool
|
||||
I830DetectSDVODisplays(ScrnInfoPtr pScrn, int output_index);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright © 2006 Intel Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Eric Anholt <eric@anholt.net>
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* Integrated TV-out support for the 915GM and 945GM.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "xf86.h"
|
||||
#include "i830.h"
|
||||
#include "i830_display.h"
|
||||
|
||||
enum tv_type {
|
||||
TV_TYPE_UNKNOWN,
|
||||
TV_TYPE_COMPOSITE,
|
||||
TV_TYPE_SVIDEO,
|
||||
TV_TYPE_COMPONENT
|
||||
};
|
||||
|
||||
/** Private structure for the integrated TV support */
|
||||
struct i830_tv_priv {
|
||||
CARD32 save_TV_H_CTL_1;
|
||||
CARD32 save_TV_H_CTL_2;
|
||||
CARD32 save_TV_H_CTL_3;
|
||||
CARD32 save_TV_V_CTL_1;
|
||||
CARD32 save_TV_V_CTL_2;
|
||||
CARD32 save_TV_V_CTL_3;
|
||||
CARD32 save_TV_V_CTL_4;
|
||||
CARD32 save_TV_V_CTL_5;
|
||||
CARD32 save_TV_V_CTL_6;
|
||||
CARD32 save_TV_V_CTL_7;
|
||||
CARD32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
|
||||
CARD32 save_TV_DAC;
|
||||
CARD32 save_TV_CTL;
|
||||
};
|
||||
|
||||
enum burst_modes {
|
||||
TV_SC_NTSC_MJ,
|
||||
TV_SC_PAL,
|
||||
TV_SC_PAL_NC,
|
||||
TV_SC_PAL_M,
|
||||
TV_SC_NTSC_443
|
||||
};
|
||||
|
||||
const struct tv_sc_mode {
|
||||
char *name;
|
||||
int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
|
||||
CARD32 sc_reset;
|
||||
Bool pal_burst;
|
||||
} tv_sc_modes[] = {
|
||||
[TV_SC_NTSC_MJ] = {
|
||||
"NTSC M/J",
|
||||
27456, 0, 135, 20800, 0,
|
||||
TV_SC_RESET_EVERY_4,
|
||||
FALSE
|
||||
},
|
||||
[TV_SC_PAL] = {
|
||||
"PAL",
|
||||
27648, 625, 168, 4122, 67,
|
||||
TV_SC_RESET_EVERY_8,
|
||||
TRUE
|
||||
},
|
||||
[TV_SC_PAL_NC] = {
|
||||
"PAL Nc",
|
||||
27648, 625, 135, 23578, 134,
|
||||
TV_SC_RESET_EVERY_8,
|
||||
TRUE
|
||||
},
|
||||
[TV_SC_PAL_M] = {
|
||||
"PAL M",
|
||||
27456, 0, 135, 16704, 0,
|
||||
TV_SC_RESET_EVERY_8,
|
||||
TRUE
|
||||
},
|
||||
[TV_SC_NTSC_443] = {
|
||||
"NTSC-4.43",
|
||||
27456, 525, 168, 4093, 310,
|
||||
TV_SC_RESET_NEVER,
|
||||
FALSE
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Register programming values for TV modes.
|
||||
*
|
||||
* These values account for -1s required.
|
||||
*/
|
||||
const struct tv_mode {
|
||||
char *name;
|
||||
CARD32 oversample;
|
||||
int hsync_end, hblank_end, hblank_start, htotal;
|
||||
Bool progressive;
|
||||
int vsync_start_f1, vsync_start_f2, vsync_len;
|
||||
Bool veq_ena;
|
||||
int veq_start_f1, veq_start_f2, veq_len;
|
||||
int vi_end_f1, vi_end_f2, nbr_end;
|
||||
Bool burst_ena;
|
||||
int hburst_start, hburst_len;
|
||||
int vburst_start_f1, vburst_end_f1;
|
||||
int vburst_start_f2, vburst_end_f2;
|
||||
int vburst_start_f3, vburst_end_f3;
|
||||
int vburst_start_f4, vburst_end_f4;
|
||||
} tv_modes[] = {
|
||||
{
|
||||
"480i",
|
||||
TV_OVERSAMPLE_8X,
|
||||
64, 124, 836, 857,
|
||||
FALSE,
|
||||
6, 7, 6,
|
||||
TRUE, 0, 1, 18,
|
||||
20, 21, 240,
|
||||
TRUE,
|
||||
72, 34, 9, 240, 10, 240, 9, 240, 10, 240
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
i830_tv_detect_type(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
CARD32 save_tv_ctl, save_tv_dac;
|
||||
CARD32 tv_ctl, tv_dac;
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
save_tv_ctl = INREG(TV_CTL);
|
||||
save_tv_dac = INREG(TV_DAC);
|
||||
|
||||
/* First, we have to disable the encoder but source from the right pipe,
|
||||
* which is already enabled.
|
||||
*/
|
||||
tv_ctl = INREG(TV_CTL) & ~(TV_ENC_ENABLE | TV_ENC_PIPEB_SELECT);
|
||||
if (output->pipe == 1)
|
||||
tv_ctl |= TV_ENC_PIPEB_SELECT;
|
||||
OUTREG(TV_CTL, tv_ctl);
|
||||
|
||||
/* Then set the voltage overrides. */
|
||||
tv_dac = DAC_CTL_OVERRIDE | DAC_A_0_7_V | DAC_B_0_7_V | DAC_C_0_7_V;
|
||||
OUTREG(TV_DAC, tv_dac);
|
||||
|
||||
/* Enable sensing of the load. */
|
||||
tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
|
||||
OUTREG(TV_CTL, tv_ctl);
|
||||
|
||||
tv_dac |= TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL | TVDAC_B_SENSE_CTL |
|
||||
TVDAC_C_SENSE_CTL;
|
||||
OUTREG(TV_DAC, tv_dac);
|
||||
|
||||
/* Wait for things to take effect. */
|
||||
i830WaitForVblank(pScrn);
|
||||
|
||||
tv_dac = INREG(TV_DAC);
|
||||
|
||||
OUTREG(TV_DAC, save_tv_dac);
|
||||
OUTREG(TV_CTL, save_tv_ctl);
|
||||
|
||||
if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Detected Composite TV connection\n");
|
||||
return TV_TYPE_COMPOSITE;
|
||||
} else if ((tv_dac & TVDAC_SENSE_MASK) == TVDAC_A_SENSE) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Detected S-Video TV connection\n");
|
||||
return TV_TYPE_SVIDEO;
|
||||
} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Detected Component TV connection\n");
|
||||
return TV_TYPE_COMPONENT;
|
||||
} else {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
|
||||
"Couldn't detect TV connection\n");
|
||||
return TV_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
i830_tv_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
switch(mode) {
|
||||
case DPMSModeOn:
|
||||
OUTREG(TV_CTL, INREG(TV_CTL) | TV_ENC_ENABLE);
|
||||
break;
|
||||
case DPMSModeStandby:
|
||||
case DPMSModeSuspend:
|
||||
case DPMSModeOff:
|
||||
OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
i830_tv_save(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
struct i830_tv_priv *dev_priv = output->dev_priv;
|
||||
|
||||
dev_priv->save_TV_H_CTL_1 = INREG(TV_H_CTL_1);
|
||||
dev_priv->save_TV_H_CTL_2 = INREG(TV_H_CTL_2);
|
||||
dev_priv->save_TV_H_CTL_3 = INREG(TV_H_CTL_3);
|
||||
dev_priv->save_TV_V_CTL_1 = INREG(TV_V_CTL_1);
|
||||
dev_priv->save_TV_V_CTL_2 = INREG(TV_V_CTL_2);
|
||||
dev_priv->save_TV_V_CTL_3 = INREG(TV_V_CTL_3);
|
||||
dev_priv->save_TV_V_CTL_4 = INREG(TV_V_CTL_4);
|
||||
dev_priv->save_TV_V_CTL_5 = INREG(TV_V_CTL_5);
|
||||
dev_priv->save_TV_V_CTL_6 = INREG(TV_V_CTL_6);
|
||||
dev_priv->save_TV_V_CTL_7 = INREG(TV_V_CTL_7);
|
||||
dev_priv->save_TV_SC_CTL_1 = INREG(TV_SC_CTL_1);
|
||||
dev_priv->save_TV_SC_CTL_2 = INREG(TV_SC_CTL_2);
|
||||
dev_priv->save_TV_SC_CTL_3 = INREG(TV_SC_CTL_3);
|
||||
|
||||
dev_priv->save_TV_DAC = INREG(TV_DAC);
|
||||
dev_priv->save_TV_CTL = INREG(TV_CTL);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_tv_restore(ScrnInfoPtr pScrn, I830OutputPtr output)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
struct i830_tv_priv *dev_priv = output->dev_priv;
|
||||
|
||||
OUTREG(TV_H_CTL_1, dev_priv->save_TV_H_CTL_1);
|
||||
OUTREG(TV_H_CTL_2, dev_priv->save_TV_H_CTL_2);
|
||||
OUTREG(TV_H_CTL_3, dev_priv->save_TV_H_CTL_3);
|
||||
OUTREG(TV_V_CTL_1, dev_priv->save_TV_V_CTL_1);
|
||||
OUTREG(TV_V_CTL_2, dev_priv->save_TV_V_CTL_2);
|
||||
OUTREG(TV_V_CTL_3, dev_priv->save_TV_V_CTL_3);
|
||||
OUTREG(TV_V_CTL_4, dev_priv->save_TV_V_CTL_4);
|
||||
OUTREG(TV_V_CTL_5, dev_priv->save_TV_V_CTL_5);
|
||||
OUTREG(TV_V_CTL_6, dev_priv->save_TV_V_CTL_6);
|
||||
OUTREG(TV_V_CTL_7, dev_priv->save_TV_V_CTL_7);
|
||||
OUTREG(TV_SC_CTL_1, dev_priv->save_TV_SC_CTL_1);
|
||||
OUTREG(TV_SC_CTL_2, dev_priv->save_TV_SC_CTL_2);
|
||||
OUTREG(TV_SC_CTL_3, dev_priv->save_TV_SC_CTL_3);
|
||||
|
||||
OUTREG(TV_DAC, dev_priv->save_TV_DAC);
|
||||
OUTREG(TV_CTL, dev_priv->save_TV_CTL);
|
||||
}
|
||||
|
||||
static int
|
||||
i830_tv_mode_valid(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
i830_tv_pre_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
/* Disable the encoder while we set up the pipe. */
|
||||
OUTREG(TV_CTL, INREG(TV_CTL) & ~TV_ENC_ENABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
i830_tv_post_set_mode(ScrnInfoPtr pScrn, I830OutputPtr output,
|
||||
DisplayModePtr pMode)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
enum tv_type type;
|
||||
const struct tv_mode *tv_mode;
|
||||
const struct tv_sc_mode *sc_mode;
|
||||
CARD32 tv_ctl, tv_filter_ctl;
|
||||
CARD32 hctl1, hctl2, hctl3;
|
||||
CARD32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
|
||||
CARD32 scctl1, scctl2, scctl3;
|
||||
|
||||
/* Need to actually choose or construct the appropriate
|
||||
* mode. For now, just set the first one in the list, with
|
||||
* NTSC format.
|
||||
*/
|
||||
tv_mode = &tv_modes[0];
|
||||
sc_mode = &tv_sc_modes[TV_SC_NTSC_MJ];
|
||||
|
||||
type = i830_tv_detect_type(pScrn, output);
|
||||
if (type == TV_TYPE_UNKNOWN) {
|
||||
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Defaulting TV to SVIDEO\n");
|
||||
type = TV_TYPE_SVIDEO;
|
||||
}
|
||||
|
||||
hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
|
||||
(tv_mode->htotal << TV_HTOTAL_SHIFT);
|
||||
|
||||
hctl2 = (tv_mode->hburst_start << 16) |
|
||||
(tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
|
||||
if (tv_mode->burst_ena)
|
||||
hctl2 |= TV_BURST_ENA;
|
||||
|
||||
hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
|
||||
(tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
|
||||
|
||||
vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
|
||||
(tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
|
||||
(tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
|
||||
|
||||
vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
|
||||
(tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
|
||||
(tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
|
||||
|
||||
vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
|
||||
(tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
|
||||
(tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
|
||||
if (tv_mode->veq_ena)
|
||||
vctl3 |= TV_EQUAL_ENA;
|
||||
|
||||
vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
|
||||
(tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
|
||||
|
||||
vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
|
||||
(tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
|
||||
|
||||
vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
|
||||
(tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
|
||||
|
||||
vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
|
||||
(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
|
||||
|
||||
tv_ctl = TV_ENC_ENABLE;
|
||||
if (output->pipe == 1)
|
||||
tv_ctl |= TV_ENC_PIPEB_SELECT;
|
||||
|
||||
switch (type) {
|
||||
case TV_TYPE_COMPOSITE:
|
||||
tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
|
||||
break;
|
||||
case TV_TYPE_COMPONENT:
|
||||
tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
|
||||
break;
|
||||
default:
|
||||
case TV_TYPE_SVIDEO:
|
||||
tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
|
||||
break;
|
||||
}
|
||||
tv_ctl |= tv_mode->oversample;
|
||||
if (tv_mode->progressive)
|
||||
tv_ctl |= TV_PROGRESSIVE;
|
||||
if (sc_mode->pal_burst)
|
||||
tv_ctl |= TV_PAL_BURST;
|
||||
|
||||
scctl1 = TV_SC_DDA1_EN | TV_SC_DDA1_EN;
|
||||
if (sc_mode->dda3_size != 0)
|
||||
scctl1 |= TV_SC_DDA3_EN;
|
||||
scctl1 |= sc_mode->sc_reset;
|
||||
/* XXX: set the burst level */
|
||||
scctl1 |= sc_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
|
||||
|
||||
scctl2 = sc_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
|
||||
sc_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
|
||||
|
||||
scctl3 = sc_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
|
||||
sc_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
|
||||
|
||||
/* Enable two fixes for the chips that need them. */
|
||||
if (pI830->PciInfo->chipType < PCI_CHIP_I945_G)
|
||||
tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
|
||||
|
||||
tv_filter_ctl = TV_AUTO_SCALE;
|
||||
if (pMode->HDisplay > 1024)
|
||||
tv_ctl |= TV_V_FILTER_BYPASS;
|
||||
|
||||
OUTREG(TV_H_CTL_1, hctl1);
|
||||
OUTREG(TV_H_CTL_2, hctl2);
|
||||
OUTREG(TV_H_CTL_3, hctl3);
|
||||
OUTREG(TV_V_CTL_1, vctl1);
|
||||
OUTREG(TV_V_CTL_2, vctl2);
|
||||
OUTREG(TV_V_CTL_3, vctl3);
|
||||
OUTREG(TV_V_CTL_4, vctl4);
|
||||
OUTREG(TV_V_CTL_5, vctl5);
|
||||
OUTREG(TV_V_CTL_6, vctl6);
|
||||
OUTREG(TV_V_CTL_7, vctl7);
|
||||
OUTREG(TV_SC_CTL_1, scctl1);
|
||||
OUTREG(TV_SC_CTL_2, scctl2);
|
||||
OUTREG(TV_SC_CTL_3, scctl3);
|
||||
|
||||
OUTREG(TV_DAC, 0);
|
||||
OUTREG(TV_CTL, tv_ctl);
|
||||
}
|
||||
|
||||
void
|
||||
i830_tv_init(ScrnInfoPtr pScrn)
|
||||
{
|
||||
I830Ptr pI830 = I830PTR(pScrn);
|
||||
|
||||
if ((INREG(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
|
||||
return;
|
||||
|
||||
pI830->output[pI830->num_outputs].dev_priv =
|
||||
malloc(sizeof(struct i830_tv_priv));
|
||||
if (pI830->output[pI830->num_outputs].dev_priv == NULL)
|
||||
return;
|
||||
|
||||
pI830->output[pI830->num_outputs].type = I830_OUTPUT_ANALOG;
|
||||
pI830->output[pI830->num_outputs].dpms = i830_tv_dpms;
|
||||
pI830->output[pI830->num_outputs].save = i830_tv_save;
|
||||
pI830->output[pI830->num_outputs].restore = i830_tv_restore;
|
||||
pI830->output[pI830->num_outputs].mode_valid = i830_tv_mode_valid;
|
||||
pI830->output[pI830->num_outputs].pre_set_mode = i830_tv_pre_set_mode;
|
||||
pI830->output[pI830->num_outputs].post_set_mode = i830_tv_post_set_mode;
|
||||
|
||||
pI830->num_outputs++;
|
||||
}
|
||||
Loading…
Reference in New Issue