diff options
author | Eric Anholt <eric@anholt.net> | 2006-10-09 11:49:18 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2006-10-09 11:49:37 -0700 |
commit | 317cc119c575650c1aa8bf992a0f42bdfffcd7ba (patch) | |
tree | 6b7c3ad7b7b44c507ee10d0295d5767f11a2787b /src/i830_sdvo.c | |
parent | 9bb7736ab36f172db58703c4664bb1b0cd7f80c3 (diff) |
Move per-output mode setting code to per-output methods.
This is not a very clean interface, as a number of outputs require tweaks to
the DPLL registers. When possible, the DPLLs are just adjusted in the
per-output post_set_mode, which happens just after the DPLL is enabled.
However, this seems better than the previous method of having all outputs
programmed in the same function.
Diffstat (limited to 'src/i830_sdvo.c')
-rw-r--r-- | src/i830_sdvo.c | 86 |
1 files changed, 68 insertions, 18 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index dc17af0e..9a1e1550 100644 --- a/src/i830_sdvo.c +++ b/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; @@ -533,6 +547,7 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode) 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; @@ -600,22 +615,34 @@ I830SDVOPreSetMode(I830SDVOPtr s, DisplayModePtr mode) out_timings[5]); I830SDVOSetTargetInput (s, FALSE, FALSE); - - if (clock >= 10000) + + switch (i830_sdvo_get_pixel_multiplier(mode)) { + case 1: I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_1X); - else if (clock >= 5000) + break; + case 2: I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_2X); - else + break; + case 4: I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_4X); + break; + } - return TRUE; + 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,18 +663,41 @@ 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); } static void i830_sdvo_dpms(ScrnInfoPtr pScrn, I830OutputPtr output, int mode) { + I830Ptr pI830 = I830PTR(pScrn); I830SDVOPtr sdvo = output->sdvo_drv; - if (mode != DPMSModeOn) + if (mode != DPMSModeOn) { I830SDVOSetActiveOutputs(sdvo, FALSE, FALSE); - else + OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE); + } else { I830SDVOSetActiveOutputs(sdvo, TRUE, FALSE); + OUTREG(SDVOB, INREG(SDVOB) | SDVO_ENABLE); + } } static void @@ -857,13 +907,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); } } @@ -906,6 +954,8 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) 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].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++) { @@ -974,7 +1024,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) return; } - pI830->output[pI830->num_outputs].pI2CBus = ddcbus; + pI830->output[pI830->num_outputs].pI2CBus = i2cbus; pI830->output[pI830->num_outputs].pDDCBus = ddcbus; pI830->output[pI830->num_outputs].sdvo_drv = sdvo; |