diff options
author | Keith Packard <keithp@keithp.com> | 2009-04-07 19:16:42 -0400 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2009-06-18 18:54:07 -0400 |
commit | a4fc5ed69817c73e32571ad7837bb707f9890009 (patch) | |
tree | 1a54e8ca9917330359118c1709895c80d74c15af /drivers/gpu/drm/i915/intel_display.c | |
parent | c31c4ba3437d98efa19710e30d694a1cfdf87aa5 (diff) |
drm/i915: Add Display Port support
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 107 |
1 files changed, 102 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3e1c78162119..5af55aa0d7a6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "intel_drv.h" | 29 | #include "intel_drv.h" |
30 | #include "i915_drm.h" | 30 | #include "i915_drm.h" |
31 | #include "i915_drv.h" | 31 | #include "i915_drv.h" |
32 | #include "intel_dp.h" | ||
32 | 33 | ||
33 | #include "drm_crtc_helper.h" | 34 | #include "drm_crtc_helper.h" |
34 | 35 | ||
@@ -135,10 +136,11 @@ struct intel_limit { | |||
135 | #define INTEL_LIMIT_G4X_HDMI_DAC 5 | 136 | #define INTEL_LIMIT_G4X_HDMI_DAC 5 |
136 | #define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6 | 137 | #define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6 |
137 | #define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7 | 138 | #define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7 |
138 | #define INTEL_LIMIT_IGD_SDVO_DAC 8 | 139 | #define INTEL_LIMIT_G4X_DISPLAY_PORT 8 |
139 | #define INTEL_LIMIT_IGD_LVDS 9 | 140 | #define INTEL_LIMIT_IGD_SDVO_DAC 9 |
140 | #define INTEL_LIMIT_IGDNG_SDVO_DAC 10 | 141 | #define INTEL_LIMIT_IGD_LVDS 10 |
141 | #define INTEL_LIMIT_IGDNG_LVDS 11 | 142 | #define INTEL_LIMIT_IGDNG_SDVO_DAC 11 |
143 | #define INTEL_LIMIT_IGDNG_LVDS 12 | ||
142 | 144 | ||
143 | /*The parameter is for SDVO on G4x platform*/ | 145 | /*The parameter is for SDVO on G4x platform*/ |
144 | #define G4X_DOT_SDVO_MIN 25000 | 146 | #define G4X_DOT_SDVO_MIN 25000 |
@@ -218,6 +220,25 @@ struct intel_limit { | |||
218 | #define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7 | 220 | #define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7 |
219 | #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0 | 221 | #define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0 |
220 | 222 | ||
223 | /*The parameter is for DISPLAY PORT on G4x platform*/ | ||
224 | #define G4X_DOT_DISPLAY_PORT_MIN 161670 | ||
225 | #define G4X_DOT_DISPLAY_PORT_MAX 227000 | ||
226 | #define G4X_N_DISPLAY_PORT_MIN 1 | ||
227 | #define G4X_N_DISPLAY_PORT_MAX 2 | ||
228 | #define G4X_M_DISPLAY_PORT_MIN 97 | ||
229 | #define G4X_M_DISPLAY_PORT_MAX 108 | ||
230 | #define G4X_M1_DISPLAY_PORT_MIN 0x10 | ||
231 | #define G4X_M1_DISPLAY_PORT_MAX 0x12 | ||
232 | #define G4X_M2_DISPLAY_PORT_MIN 0x05 | ||
233 | #define G4X_M2_DISPLAY_PORT_MAX 0x06 | ||
234 | #define G4X_P_DISPLAY_PORT_MIN 10 | ||
235 | #define G4X_P_DISPLAY_PORT_MAX 20 | ||
236 | #define G4X_P1_DISPLAY_PORT_MIN 1 | ||
237 | #define G4X_P1_DISPLAY_PORT_MAX 2 | ||
238 | #define G4X_P2_DISPLAY_PORT_SLOW 10 | ||
239 | #define G4X_P2_DISPLAY_PORT_FAST 10 | ||
240 | #define G4X_P2_DISPLAY_PORT_LIMIT 0 | ||
241 | |||
221 | /* IGDNG */ | 242 | /* IGDNG */ |
222 | /* as we calculate clock using (register_value + 2) for | 243 | /* as we calculate clock using (register_value + 2) for |
223 | N/M1/M2, so here the range value for them is (actual_value-2). | 244 | N/M1/M2, so here the range value for them is (actual_value-2). |
@@ -256,6 +277,10 @@ static bool | |||
256 | intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, | 277 | intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, |
257 | int target, int refclk, intel_clock_t *best_clock); | 278 | int target, int refclk, intel_clock_t *best_clock); |
258 | 279 | ||
280 | static bool | ||
281 | intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, | ||
282 | int target, int refclk, intel_clock_t *best_clock); | ||
283 | |||
259 | static const intel_limit_t intel_limits[] = { | 284 | static const intel_limit_t intel_limits[] = { |
260 | { /* INTEL_LIMIT_I8XX_DVO_DAC */ | 285 | { /* INTEL_LIMIT_I8XX_DVO_DAC */ |
261 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, | 286 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, |
@@ -389,6 +414,28 @@ static const intel_limit_t intel_limits[] = { | |||
389 | }, | 414 | }, |
390 | .find_pll = intel_g4x_find_best_PLL, | 415 | .find_pll = intel_g4x_find_best_PLL, |
391 | }, | 416 | }, |
417 | { /* INTEL_LIMIT_G4X_DISPLAY_PORT */ | ||
418 | .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN, | ||
419 | .max = G4X_DOT_DISPLAY_PORT_MAX }, | ||
420 | .vco = { .min = G4X_VCO_MIN, | ||
421 | .max = G4X_VCO_MAX}, | ||
422 | .n = { .min = G4X_N_DISPLAY_PORT_MIN, | ||
423 | .max = G4X_N_DISPLAY_PORT_MAX }, | ||
424 | .m = { .min = G4X_M_DISPLAY_PORT_MIN, | ||
425 | .max = G4X_M_DISPLAY_PORT_MAX }, | ||
426 | .m1 = { .min = G4X_M1_DISPLAY_PORT_MIN, | ||
427 | .max = G4X_M1_DISPLAY_PORT_MAX }, | ||
428 | .m2 = { .min = G4X_M2_DISPLAY_PORT_MIN, | ||
429 | .max = G4X_M2_DISPLAY_PORT_MAX }, | ||
430 | .p = { .min = G4X_P_DISPLAY_PORT_MIN, | ||
431 | .max = G4X_P_DISPLAY_PORT_MAX }, | ||
432 | .p1 = { .min = G4X_P1_DISPLAY_PORT_MIN, | ||
433 | .max = G4X_P1_DISPLAY_PORT_MAX}, | ||
434 | .p2 = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT, | ||
435 | .p2_slow = G4X_P2_DISPLAY_PORT_SLOW, | ||
436 | .p2_fast = G4X_P2_DISPLAY_PORT_FAST }, | ||
437 | .find_pll = intel_find_pll_g4x_dp, | ||
438 | }, | ||
392 | { /* INTEL_LIMIT_IGD_SDVO */ | 439 | { /* INTEL_LIMIT_IGD_SDVO */ |
393 | .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, | 440 | .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX}, |
394 | .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX }, | 441 | .vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX }, |
@@ -478,6 +525,8 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) | |||
478 | limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC]; | 525 | limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC]; |
479 | } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { | 526 | } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) { |
480 | limit = &intel_limits[INTEL_LIMIT_G4X_SDVO]; | 527 | limit = &intel_limits[INTEL_LIMIT_G4X_SDVO]; |
528 | } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) { | ||
529 | limit = &intel_limits[INTEL_LIMIT_G4X_DISPLAY_PORT]; | ||
481 | } else /* The option is for other outputs */ | 530 | } else /* The option is for other outputs */ |
482 | limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; | 531 | limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; |
483 | 532 | ||
@@ -764,6 +813,35 @@ out: | |||
764 | return found; | 813 | return found; |
765 | } | 814 | } |
766 | 815 | ||
816 | /* DisplayPort has only two frequencies, 162MHz and 270MHz */ | ||
817 | static bool | ||
818 | intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc, | ||
819 | int target, int refclk, intel_clock_t *best_clock) | ||
820 | { | ||
821 | intel_clock_t clock; | ||
822 | if (target < 200000) { | ||
823 | clock.dot = 161670; | ||
824 | clock.p = 20; | ||
825 | clock.p1 = 2; | ||
826 | clock.p2 = 10; | ||
827 | clock.n = 0x01; | ||
828 | clock.m = 97; | ||
829 | clock.m1 = 0x10; | ||
830 | clock.m2 = 0x05; | ||
831 | } else { | ||
832 | clock.dot = 270000; | ||
833 | clock.p = 10; | ||
834 | clock.p1 = 1; | ||
835 | clock.p2 = 10; | ||
836 | clock.n = 0x02; | ||
837 | clock.m = 108; | ||
838 | clock.m1 = 0x12; | ||
839 | clock.m2 = 0x06; | ||
840 | } | ||
841 | memcpy(best_clock, &clock, sizeof(intel_clock_t)); | ||
842 | return true; | ||
843 | } | ||
844 | |||
767 | void | 845 | void |
768 | intel_wait_for_vblank(struct drm_device *dev) | 846 | intel_wait_for_vblank(struct drm_device *dev) |
769 | { | 847 | { |
@@ -1541,7 +1619,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
1541 | intel_clock_t clock; | 1619 | intel_clock_t clock; |
1542 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; | 1620 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; |
1543 | bool ok, is_sdvo = false, is_dvo = false; | 1621 | bool ok, is_sdvo = false, is_dvo = false; |
1544 | bool is_crt = false, is_lvds = false, is_tv = false; | 1622 | bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; |
1545 | struct drm_mode_config *mode_config = &dev->mode_config; | 1623 | struct drm_mode_config *mode_config = &dev->mode_config; |
1546 | struct drm_connector *connector; | 1624 | struct drm_connector *connector; |
1547 | const intel_limit_t *limit; | 1625 | const intel_limit_t *limit; |
@@ -1585,6 +1663,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
1585 | case INTEL_OUTPUT_ANALOG: | 1663 | case INTEL_OUTPUT_ANALOG: |
1586 | is_crt = true; | 1664 | is_crt = true; |
1587 | break; | 1665 | break; |
1666 | case INTEL_OUTPUT_DISPLAYPORT: | ||
1667 | is_dp = true; | ||
1668 | break; | ||
1588 | } | 1669 | } |
1589 | 1670 | ||
1590 | num_outputs++; | 1671 | num_outputs++; |
@@ -1600,6 +1681,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
1600 | } else { | 1681 | } else { |
1601 | refclk = 48000; | 1682 | refclk = 48000; |
1602 | } | 1683 | } |
1684 | |||
1603 | 1685 | ||
1604 | /* | 1686 | /* |
1605 | * Returns a set of divisors for the desired target clock with the given | 1687 | * Returns a set of divisors for the desired target clock with the given |
@@ -1662,6 +1744,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
1662 | else if (IS_IGDNG(dev)) | 1744 | else if (IS_IGDNG(dev)) |
1663 | dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; | 1745 | dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; |
1664 | } | 1746 | } |
1747 | if (is_dp) | ||
1748 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
1665 | 1749 | ||
1666 | /* compute bitmask from p1 value */ | 1750 | /* compute bitmask from p1 value */ |
1667 | if (IS_IGD(dev)) | 1751 | if (IS_IGD(dev)) |
@@ -1809,6 +1893,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
1809 | I915_WRITE(lvds_reg, lvds); | 1893 | I915_WRITE(lvds_reg, lvds); |
1810 | I915_READ(lvds_reg); | 1894 | I915_READ(lvds_reg); |
1811 | } | 1895 | } |
1896 | if (is_dp) | ||
1897 | intel_dp_set_m_n(crtc, mode, adjusted_mode); | ||
1812 | 1898 | ||
1813 | I915_WRITE(fp_reg, fp); | 1899 | I915_WRITE(fp_reg, fp); |
1814 | I915_WRITE(dpll_reg, dpll); | 1900 | I915_WRITE(dpll_reg, dpll); |
@@ -2475,6 +2561,8 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
2475 | found = intel_sdvo_init(dev, SDVOB); | 2561 | found = intel_sdvo_init(dev, SDVOB); |
2476 | if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) | 2562 | if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) |
2477 | intel_hdmi_init(dev, SDVOB); | 2563 | intel_hdmi_init(dev, SDVOB); |
2564 | if (!found && SUPPORTS_INTEGRATED_DP(dev)) | ||
2565 | intel_dp_init(dev, DP_B); | ||
2478 | } | 2566 | } |
2479 | 2567 | ||
2480 | /* Before G4X SDVOC doesn't have its own detect register */ | 2568 | /* Before G4X SDVOC doesn't have its own detect register */ |
@@ -2487,7 +2575,11 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
2487 | found = intel_sdvo_init(dev, SDVOC); | 2575 | found = intel_sdvo_init(dev, SDVOC); |
2488 | if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) | 2576 | if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) |
2489 | intel_hdmi_init(dev, SDVOC); | 2577 | intel_hdmi_init(dev, SDVOC); |
2578 | if (!found && SUPPORTS_INTEGRATED_DP(dev)) | ||
2579 | intel_dp_init(dev, DP_C); | ||
2490 | } | 2580 | } |
2581 | if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) | ||
2582 | intel_dp_init(dev, DP_D); | ||
2491 | } else | 2583 | } else |
2492 | intel_dvo_init(dev); | 2584 | intel_dvo_init(dev); |
2493 | 2585 | ||
@@ -2530,6 +2622,11 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
2530 | (1 << 1)); | 2622 | (1 << 1)); |
2531 | clone_mask = (1 << INTEL_OUTPUT_TVOUT); | 2623 | clone_mask = (1 << INTEL_OUTPUT_TVOUT); |
2532 | break; | 2624 | break; |
2625 | case INTEL_OUTPUT_DISPLAYPORT: | ||
2626 | crtc_mask = ((1 << 0) | | ||
2627 | (1 << 1)); | ||
2628 | clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT); | ||
2629 | break; | ||
2533 | } | 2630 | } |
2534 | encoder->possible_crtcs = crtc_mask; | 2631 | encoder->possible_crtcs = crtc_mask; |
2535 | encoder->possible_clones = intel_connector_clones(dev, clone_mask); | 2632 | encoder->possible_clones = intel_connector_clones(dev, clone_mask); |