diff options
author | Zhenyu Wang <zhenyuw@linux.intel.com> | 2009-07-23 13:00:31 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-07-29 18:16:11 -0400 |
commit | 5eb08b69f510fadaba77eb9a1bda0f7299c4ebcc (patch) | |
tree | 107cb7647464fe2f8db7e7fdd652b90494cb2815 /drivers/gpu/drm | |
parent | eebc863e469cd91d96c4e3636450596ae29f0502 (diff) |
drm/i915: enable DisplayPort support on IGDNG
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 102 |
3 files changed, 157 insertions, 21 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 7c77c4c53c52..4518a9489ed1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -1444,6 +1444,7 @@ | |||
1444 | #define DP_CLOCK_OUTPUT_ENABLE (1 << 13) | 1444 | #define DP_CLOCK_OUTPUT_ENABLE (1 << 13) |
1445 | 1445 | ||
1446 | #define DP_SCRAMBLING_DISABLE (1 << 12) | 1446 | #define DP_SCRAMBLING_DISABLE (1 << 12) |
1447 | #define DP_SCRAMBLING_DISABLE_IGDNG (1 << 7) | ||
1447 | 1448 | ||
1448 | /** limit RGB values to avoid confusing TVs */ | 1449 | /** limit RGB values to avoid confusing TVs */ |
1449 | #define DP_COLOR_RANGE_16_235 (1 << 8) | 1450 | #define DP_COLOR_RANGE_16_235 (1 << 8) |
@@ -2210,4 +2211,28 @@ | |||
2210 | #define PCH_PP_OFF_DELAYS 0xc720c | 2211 | #define PCH_PP_OFF_DELAYS 0xc720c |
2211 | #define PCH_PP_DIVISOR 0xc7210 | 2212 | #define PCH_PP_DIVISOR 0xc7210 |
2212 | 2213 | ||
2214 | #define PCH_DP_B 0xe4100 | ||
2215 | #define PCH_DPB_AUX_CH_CTL 0xe4110 | ||
2216 | #define PCH_DPB_AUX_CH_DATA1 0xe4114 | ||
2217 | #define PCH_DPB_AUX_CH_DATA2 0xe4118 | ||
2218 | #define PCH_DPB_AUX_CH_DATA3 0xe411c | ||
2219 | #define PCH_DPB_AUX_CH_DATA4 0xe4120 | ||
2220 | #define PCH_DPB_AUX_CH_DATA5 0xe4124 | ||
2221 | |||
2222 | #define PCH_DP_C 0xe4200 | ||
2223 | #define PCH_DPC_AUX_CH_CTL 0xe4210 | ||
2224 | #define PCH_DPC_AUX_CH_DATA1 0xe4214 | ||
2225 | #define PCH_DPC_AUX_CH_DATA2 0xe4218 | ||
2226 | #define PCH_DPC_AUX_CH_DATA3 0xe421c | ||
2227 | #define PCH_DPC_AUX_CH_DATA4 0xe4220 | ||
2228 | #define PCH_DPC_AUX_CH_DATA5 0xe4224 | ||
2229 | |||
2230 | #define PCH_DP_D 0xe4300 | ||
2231 | #define PCH_DPD_AUX_CH_CTL 0xe4310 | ||
2232 | #define PCH_DPD_AUX_CH_DATA1 0xe4314 | ||
2233 | #define PCH_DPD_AUX_CH_DATA2 0xe4318 | ||
2234 | #define PCH_DPD_AUX_CH_DATA3 0xe431c | ||
2235 | #define PCH_DPD_AUX_CH_DATA4 0xe4320 | ||
2236 | #define PCH_DPD_AUX_CH_DATA5 0xe4324 | ||
2237 | |||
2213 | #endif /* _I915_REG_H_ */ | 2238 | #endif /* _I915_REG_H_ */ |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 15a8c3908acb..34c50460eaa7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -268,6 +268,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, | |||
268 | static bool | 268 | static bool |
269 | intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, | 269 | intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc, |
270 | int target, int refclk, intel_clock_t *best_clock); | 270 | int target, int refclk, intel_clock_t *best_clock); |
271 | static bool | ||
272 | intel_find_pll_igdng_dp(const intel_limit_t *, struct drm_crtc *crtc, | ||
273 | int target, int refclk, intel_clock_t *best_clock); | ||
271 | 274 | ||
272 | static const intel_limit_t intel_limits_i8xx_dvo = { | 275 | static const intel_limit_t intel_limits_i8xx_dvo = { |
273 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, | 276 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, |
@@ -752,6 +755,30 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, | |||
752 | } | 755 | } |
753 | 756 | ||
754 | static bool | 757 | static bool |
758 | intel_find_pll_igdng_dp(const intel_limit_t *limit, struct drm_crtc *crtc, | ||
759 | int target, int refclk, intel_clock_t *best_clock) | ||
760 | { | ||
761 | struct drm_device *dev = crtc->dev; | ||
762 | intel_clock_t clock; | ||
763 | if (target < 200000) { | ||
764 | clock.n = 1; | ||
765 | clock.p1 = 2; | ||
766 | clock.p2 = 10; | ||
767 | clock.m1 = 12; | ||
768 | clock.m2 = 9; | ||
769 | } else { | ||
770 | clock.n = 2; | ||
771 | clock.p1 = 1; | ||
772 | clock.p2 = 10; | ||
773 | clock.m1 = 14; | ||
774 | clock.m2 = 8; | ||
775 | } | ||
776 | intel_clock(dev, refclk, &clock); | ||
777 | memcpy(best_clock, &clock, sizeof(intel_clock_t)); | ||
778 | return true; | ||
779 | } | ||
780 | |||
781 | static bool | ||
755 | intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, | 782 | intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, |
756 | int target, int refclk, intel_clock_t *best_clock) | 783 | int target, int refclk, intel_clock_t *best_clock) |
757 | { | 784 | { |
@@ -763,6 +790,10 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, | |||
763 | int err_most = 47; | 790 | int err_most = 47; |
764 | found = false; | 791 | found = false; |
765 | 792 | ||
793 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) | ||
794 | return intel_find_pll_igdng_dp(limit, crtc, target, | ||
795 | refclk, best_clock); | ||
796 | |||
766 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { | 797 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { |
767 | if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == | 798 | if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == |
768 | LVDS_CLKB_POWER_UP) | 799 | LVDS_CLKB_POWER_UP) |
@@ -2136,6 +2167,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
2136 | int lvds_reg = LVDS; | 2167 | int lvds_reg = LVDS; |
2137 | u32 temp; | 2168 | u32 temp; |
2138 | int sdvo_pixel_multiply; | 2169 | int sdvo_pixel_multiply; |
2170 | int target_clock; | ||
2139 | 2171 | ||
2140 | drm_vblank_pre_modeset(dev, pipe); | 2172 | drm_vblank_pre_modeset(dev, pipe); |
2141 | 2173 | ||
@@ -2218,11 +2250,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, | |||
2218 | } | 2250 | } |
2219 | 2251 | ||
2220 | /* FDI link */ | 2252 | /* FDI link */ |
2221 | if (IS_IGDNG(dev)) | 2253 | if (IS_IGDNG(dev)) { |
2254 | /* DP over FDI requires target mode clock | ||
2255 | instead of link clock */ | ||
2256 | if (is_dp) | ||
2257 | target_clock = mode->clock; | ||
2258 | else | ||
2259 | target_clock = adjusted_mode->clock; | ||
2222 | igdng_compute_m_n(3, 4, /* lane num 4 */ | 2260 | igdng_compute_m_n(3, 4, /* lane num 4 */ |
2223 | adjusted_mode->clock, | 2261 | target_clock, |
2224 | 270000, /* lane clock */ | 2262 | 270000, /* lane clock */ |
2225 | &m_n); | 2263 | &m_n); |
2264 | } | ||
2226 | 2265 | ||
2227 | if (IS_IGD(dev)) | 2266 | if (IS_IGD(dev)) |
2228 | fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; | 2267 | fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; |
@@ -3050,6 +3089,8 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
3050 | found = 0; | 3089 | found = 0; |
3051 | if (!found) | 3090 | if (!found) |
3052 | intel_hdmi_init(dev, HDMIB); | 3091 | intel_hdmi_init(dev, HDMIB); |
3092 | if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) | ||
3093 | intel_dp_init(dev, PCH_DP_B); | ||
3053 | } | 3094 | } |
3054 | 3095 | ||
3055 | if (I915_READ(HDMIC) & PORT_DETECTED) | 3096 | if (I915_READ(HDMIC) & PORT_DETECTED) |
@@ -3058,6 +3099,12 @@ static void intel_setup_outputs(struct drm_device *dev) | |||
3058 | if (I915_READ(HDMID) & PORT_DETECTED) | 3099 | if (I915_READ(HDMID) & PORT_DETECTED) |
3059 | intel_hdmi_init(dev, HDMID); | 3100 | intel_hdmi_init(dev, HDMID); |
3060 | 3101 | ||
3102 | if (I915_READ(PCH_DP_C) & DP_DETECTED) | ||
3103 | intel_dp_init(dev, PCH_DP_C); | ||
3104 | |||
3105 | if (I915_READ(PCH_DP_D) & DP_DETECTED) | ||
3106 | intel_dp_init(dev, PCH_DP_D); | ||
3107 | |||
3061 | } else if (IS_I9XX(dev)) { | 3108 | } else if (IS_I9XX(dev)) { |
3062 | int found; | 3109 | int found; |
3063 | u32 reg; | 3110 | u32 reg; |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index afec65c5ad8a..0715911cbd84 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -206,7 +206,12 @@ intel_dp_aux_ch(struct intel_output *intel_output, | |||
206 | * and would like to run at 2MHz. So, take the | 206 | * and would like to run at 2MHz. So, take the |
207 | * hrawclk value and divide by 2 and use that | 207 | * hrawclk value and divide by 2 and use that |
208 | */ | 208 | */ |
209 | aux_clock_divider = intel_hrawclk(dev) / 2; | 209 | /* IGDNG: input clock fixed at 125Mhz, so aux_bit_clk always 62 */ |
210 | if (IS_IGDNG(dev)) | ||
211 | aux_clock_divider = 62; | ||
212 | else | ||
213 | aux_clock_divider = intel_hrawclk(dev) / 2; | ||
214 | |||
210 | /* Must try at least 3 times according to DP spec */ | 215 | /* Must try at least 3 times according to DP spec */ |
211 | for (try = 0; try < 5; try++) { | 216 | for (try = 0; try < 5; try++) { |
212 | /* Load the send data into the aux channel data registers */ | 217 | /* Load the send data into the aux channel data registers */ |
@@ -493,22 +498,40 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, | |||
493 | intel_dp_compute_m_n(3, lane_count, | 498 | intel_dp_compute_m_n(3, lane_count, |
494 | mode->clock, adjusted_mode->clock, &m_n); | 499 | mode->clock, adjusted_mode->clock, &m_n); |
495 | 500 | ||
496 | if (intel_crtc->pipe == 0) { | 501 | if (IS_IGDNG(dev)) { |
497 | I915_WRITE(PIPEA_GMCH_DATA_M, | 502 | if (intel_crtc->pipe == 0) { |
498 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | | 503 | I915_WRITE(TRANSA_DATA_M1, |
499 | m_n.gmch_m); | 504 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | |
500 | I915_WRITE(PIPEA_GMCH_DATA_N, | 505 | m_n.gmch_m); |
501 | m_n.gmch_n); | 506 | I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n); |
502 | I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); | 507 | I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m); |
503 | I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); | 508 | I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n); |
509 | } else { | ||
510 | I915_WRITE(TRANSB_DATA_M1, | ||
511 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | | ||
512 | m_n.gmch_m); | ||
513 | I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n); | ||
514 | I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m); | ||
515 | I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n); | ||
516 | } | ||
504 | } else { | 517 | } else { |
505 | I915_WRITE(PIPEB_GMCH_DATA_M, | 518 | if (intel_crtc->pipe == 0) { |
506 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | | 519 | I915_WRITE(PIPEA_GMCH_DATA_M, |
507 | m_n.gmch_m); | 520 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | |
508 | I915_WRITE(PIPEB_GMCH_DATA_N, | 521 | m_n.gmch_m); |
509 | m_n.gmch_n); | 522 | I915_WRITE(PIPEA_GMCH_DATA_N, |
510 | I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); | 523 | m_n.gmch_n); |
511 | I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); | 524 | I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m); |
525 | I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n); | ||
526 | } else { | ||
527 | I915_WRITE(PIPEB_GMCH_DATA_M, | ||
528 | ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) | | ||
529 | m_n.gmch_m); | ||
530 | I915_WRITE(PIPEB_GMCH_DATA_N, | ||
531 | m_n.gmch_n); | ||
532 | I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m); | ||
533 | I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n); | ||
534 | } | ||
512 | } | 535 | } |
513 | } | 536 | } |
514 | 537 | ||
@@ -935,6 +958,12 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP) | |||
935 | struct drm_i915_private *dev_priv = dev->dev_private; | 958 | struct drm_i915_private *dev_priv = dev->dev_private; |
936 | struct intel_dp_priv *dp_priv = intel_output->dev_priv; | 959 | struct intel_dp_priv *dp_priv = intel_output->dev_priv; |
937 | 960 | ||
961 | DP &= ~DP_LINK_TRAIN_MASK; | ||
962 | I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE); | ||
963 | POSTING_READ(dp_priv->output_reg); | ||
964 | |||
965 | udelay(17000); | ||
966 | |||
938 | I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); | 967 | I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN); |
939 | POSTING_READ(dp_priv->output_reg); | 968 | POSTING_READ(dp_priv->output_reg); |
940 | } | 969 | } |
@@ -978,6 +1007,24 @@ intel_dp_check_link_status(struct intel_output *intel_output) | |||
978 | intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); | 1007 | intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration); |
979 | } | 1008 | } |
980 | 1009 | ||
1010 | static enum drm_connector_status | ||
1011 | igdng_dp_detect(struct drm_connector *connector) | ||
1012 | { | ||
1013 | struct intel_output *intel_output = to_intel_output(connector); | ||
1014 | struct intel_dp_priv *dp_priv = intel_output->dev_priv; | ||
1015 | enum drm_connector_status status; | ||
1016 | |||
1017 | status = connector_status_disconnected; | ||
1018 | if (intel_dp_aux_native_read(intel_output, | ||
1019 | 0x000, dp_priv->dpcd, | ||
1020 | sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd)) | ||
1021 | { | ||
1022 | if (dp_priv->dpcd[0] != 0) | ||
1023 | status = connector_status_connected; | ||
1024 | } | ||
1025 | return status; | ||
1026 | } | ||
1027 | |||
981 | /** | 1028 | /** |
982 | * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. | 1029 | * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. |
983 | * | 1030 | * |
@@ -996,6 +1043,9 @@ intel_dp_detect(struct drm_connector *connector) | |||
996 | 1043 | ||
997 | dp_priv->has_audio = false; | 1044 | dp_priv->has_audio = false; |
998 | 1045 | ||
1046 | if (IS_IGDNG(dev)) | ||
1047 | return igdng_dp_detect(connector); | ||
1048 | |||
999 | temp = I915_READ(PORT_HOTPLUG_EN); | 1049 | temp = I915_READ(PORT_HOTPLUG_EN); |
1000 | 1050 | ||
1001 | I915_WRITE(PORT_HOTPLUG_EN, | 1051 | I915_WRITE(PORT_HOTPLUG_EN, |
@@ -1106,6 +1156,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) | |||
1106 | struct drm_connector *connector; | 1156 | struct drm_connector *connector; |
1107 | struct intel_output *intel_output; | 1157 | struct intel_output *intel_output; |
1108 | struct intel_dp_priv *dp_priv; | 1158 | struct intel_dp_priv *dp_priv; |
1159 | const char *name = NULL; | ||
1109 | 1160 | ||
1110 | intel_output = kcalloc(sizeof(struct intel_output) + | 1161 | intel_output = kcalloc(sizeof(struct intel_output) + |
1111 | sizeof(struct intel_dp_priv), 1, GFP_KERNEL); | 1162 | sizeof(struct intel_dp_priv), 1, GFP_KERNEL); |
@@ -1139,9 +1190,22 @@ intel_dp_init(struct drm_device *dev, int output_reg) | |||
1139 | drm_sysfs_connector_add(connector); | 1190 | drm_sysfs_connector_add(connector); |
1140 | 1191 | ||
1141 | /* Set up the DDC bus. */ | 1192 | /* Set up the DDC bus. */ |
1142 | intel_dp_i2c_init(intel_output, | 1193 | switch (output_reg) { |
1143 | (output_reg == DP_B) ? "DPDDC-B" : | 1194 | case DP_B: |
1144 | (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D"); | 1195 | case PCH_DP_B: |
1196 | name = "DPDDC-B"; | ||
1197 | break; | ||
1198 | case DP_C: | ||
1199 | case PCH_DP_C: | ||
1200 | name = "DPDDC-C"; | ||
1201 | break; | ||
1202 | case DP_D: | ||
1203 | case PCH_DP_D: | ||
1204 | name = "DPDDC-D"; | ||
1205 | break; | ||
1206 | } | ||
1207 | |||
1208 | intel_dp_i2c_init(intel_output, name); | ||
1145 | intel_output->ddc_bus = &dp_priv->adapter; | 1209 | intel_output->ddc_bus = &dp_priv->adapter; |
1146 | intel_output->hot_plug = intel_dp_hot_plug; | 1210 | intel_output->hot_plug = intel_dp_hot_plug; |
1147 | 1211 | ||