aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-08-25 05:05:17 -0400
committerChris Wilson <chris@chris-wilson.co.uk>2010-09-08 05:23:27 -0400
commit6c9547ff354d867318d78094aa8e9cf5218851e2 (patch)
tree88907cc36767faa27ea8ea9171d4febac1216de6 /drivers/gpu/drm
parent57cd6508da65adabcb14be6ba3b9370d750b647d (diff)
drm/i915/sdvo: Preserve pixel-multiplier
Store the pixel-multiplier on the adjusted mode and avoid modifying the requested mode. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c25
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h18
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c99
3 files changed, 75 insertions, 67 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index adce19304eee..120a9c0c2da6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3519,7 +3519,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
3519 int trans_dpll_sel = (pipe == 0) ? 0 : 1; 3519 int trans_dpll_sel = (pipe == 0) ? 0 : 1;
3520 int lvds_reg = LVDS; 3520 int lvds_reg = LVDS;
3521 u32 temp; 3521 u32 temp;
3522 int sdvo_pixel_multiply;
3523 int target_clock; 3522 int target_clock;
3524 3523
3525 drm_vblank_pre_modeset(dev, pipe); 3524 drm_vblank_pre_modeset(dev, pipe);
@@ -3770,12 +3769,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
3770 else 3769 else
3771 dpll |= DPLLB_MODE_DAC_SERIAL; 3770 dpll |= DPLLB_MODE_DAC_SERIAL;
3772 if (is_sdvo) { 3771 if (is_sdvo) {
3772 int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
3773 if (pixel_multiplier > 1) {
3774 if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
3775 dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
3776 else if (HAS_PCH_SPLIT(dev))
3777 dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
3778 }
3773 dpll |= DPLL_DVO_HIGH_SPEED; 3779 dpll |= DPLL_DVO_HIGH_SPEED;
3774 sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
3775 if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
3776 dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
3777 else if (HAS_PCH_SPLIT(dev))
3778 dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
3779 } 3780 }
3780 if (is_dp) 3781 if (is_dp)
3781 dpll |= DPLL_DVO_HIGH_SPEED; 3782 dpll |= DPLL_DVO_HIGH_SPEED;
@@ -3982,9 +3983,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
3982 3983
3983 if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) { 3984 if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
3984 if (is_sdvo) { 3985 if (is_sdvo) {
3985 sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; 3986 int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
3986 I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | 3987 if (pixel_multiplier > 1)
3987 ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); 3988 pixel_multiplier = (pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
3989 else
3990 pixel_multiplier = 0;
3991
3992 I915_WRITE(dpll_md_reg,
3993 (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
3994 pixel_multiplier);
3988 } else 3995 } else
3989 I915_WRITE(dpll_md_reg, 0); 3996 I915_WRITE(dpll_md_reg, 0);
3990 } else { 3997 } else {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1ca3c9e2667a..64a7c87817d7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -99,6 +99,24 @@
99#define INTEL_DVO_CHIP_TMDS 2 99#define INTEL_DVO_CHIP_TMDS 2
100#define INTEL_DVO_CHIP_TVOUT 4 100#define INTEL_DVO_CHIP_TVOUT 4
101 101
102/* drm_display_mode->private_flags */
103#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
104#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
105
106static inline void
107intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
108 int multiplier)
109{
110 mode->clock *= multiplier;
111 mode->private_flags |= multiplier;
112}
113
114static inline int
115intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
116{
117 return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
118}
119
102struct intel_i2c_chan { 120struct intel_i2c_chan {
103 struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */ 121 struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
104 u32 reg; /* GPIO reg */ 122 u32 reg; /* GPIO reg */
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index e3b7a7ee39cb..1c1aeea81e56 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -106,16 +106,12 @@ struct intel_sdvo {
106 bool is_hdmi; 106 bool is_hdmi;
107 107
108 /** 108 /**
109 * This is set if we detect output of sdvo device as LVDS. 109 * This is set if we detect output of sdvo device as LVDS and
110 * have a valid fixed mode to use with the panel.
110 */ 111 */
111 bool is_lvds; 112 bool is_lvds;
112 113
113 /** 114 /**
114 * This is sdvo flags for input timing.
115 */
116 uint8_t sdvo_flags;
117
118 /**
119 * This is sdvo fixed pannel mode pointer 115 * This is sdvo fixed pannel mode pointer
120 */ 116 */
121 struct drm_display_mode *sdvo_lvds_fixed_mode; 117 struct drm_display_mode *sdvo_lvds_fixed_mode;
@@ -132,6 +128,8 @@ struct intel_sdvo {
132 /* Mac mini hack -- use the same DDC as the analog connector */ 128 /* Mac mini hack -- use the same DDC as the analog connector */
133 struct i2c_adapter *analog_ddc_bus; 129 struct i2c_adapter *analog_ddc_bus;
134 130
131 /* Input timings for adjusted_mode */
132 struct intel_sdvo_dtd input_dtd;
135}; 133};
136 134
137struct intel_sdvo_connector { 135struct intel_sdvo_connector {
@@ -1022,8 +1020,6 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
1022 struct drm_display_mode *mode, 1020 struct drm_display_mode *mode,
1023 struct drm_display_mode *adjusted_mode) 1021 struct drm_display_mode *adjusted_mode)
1024{ 1022{
1025 struct intel_sdvo_dtd input_dtd;
1026
1027 /* Reset the input timing to the screen. Assume always input 0. */ 1023 /* Reset the input timing to the screen. Assume always input 0. */
1028 if (!intel_sdvo_set_target_input(intel_sdvo)) 1024 if (!intel_sdvo_set_target_input(intel_sdvo))
1029 return false; 1025 return false;
@@ -1035,14 +1031,12 @@ intel_sdvo_set_input_timings_for_mode(struct intel_sdvo *intel_sdvo,
1035 return false; 1031 return false;
1036 1032
1037 if (!intel_sdvo_get_preferred_input_timing(intel_sdvo, 1033 if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
1038 &input_dtd)) 1034 &intel_sdvo->input_dtd))
1039 return false; 1035 return false;
1040 1036
1041 intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); 1037 intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
1042 intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
1043 1038
1044 drm_mode_set_crtcinfo(adjusted_mode, 0); 1039 drm_mode_set_crtcinfo(adjusted_mode, 0);
1045 mode->clock = adjusted_mode->clock;
1046 return true; 1040 return true;
1047} 1041}
1048 1042
@@ -1051,6 +1045,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
1051 struct drm_display_mode *adjusted_mode) 1045 struct drm_display_mode *adjusted_mode)
1052{ 1046{
1053 struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); 1047 struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
1048 int multiplier;
1054 1049
1055 /* We need to construct preferred input timings based on our 1050 /* We need to construct preferred input timings based on our
1056 * output timings. To do that, we have to set the output 1051 * output timings. To do that, we have to set the output
@@ -1065,10 +1060,8 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
1065 mode, 1060 mode,
1066 adjusted_mode); 1061 adjusted_mode);
1067 } else if (intel_sdvo->is_lvds) { 1062 } else if (intel_sdvo->is_lvds) {
1068 drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);
1069
1070 if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, 1063 if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
1071 intel_sdvo->sdvo_lvds_fixed_mode)) 1064 intel_sdvo->sdvo_lvds_fixed_mode))
1072 return false; 1065 return false;
1073 1066
1074 (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo, 1067 (void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
@@ -1077,9 +1070,10 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
1077 } 1070 }
1078 1071
1079 /* Make the CRTC code factor in the SDVO pixel multiplier. The 1072 /* Make the CRTC code factor in the SDVO pixel multiplier. The
1080 * SDVO device will be told of the multiplier during mode_set. 1073 * SDVO device will factor out the multiplier during mode_set.
1081 */ 1074 */
1082 adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); 1075 multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
1076 intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
1083 1077
1084 return true; 1078 return true;
1085} 1079}
@@ -1093,10 +1087,11 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
1093 struct drm_crtc *crtc = encoder->crtc; 1087 struct drm_crtc *crtc = encoder->crtc;
1094 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 1088 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1095 struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder); 1089 struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
1096 u32 sdvox = 0; 1090 u32 sdvox;
1097 int sdvo_pixel_multiply, rate;
1098 struct intel_sdvo_in_out_map in_out; 1091 struct intel_sdvo_in_out_map in_out;
1099 struct intel_sdvo_dtd input_dtd; 1092 struct intel_sdvo_dtd input_dtd;
1093 int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
1094 int rate;
1100 1095
1101 if (!mode) 1096 if (!mode)
1102 return; 1097 return;
@@ -1114,28 +1109,23 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
1114 SDVO_CMD_SET_IN_OUT_MAP, 1109 SDVO_CMD_SET_IN_OUT_MAP,
1115 &in_out, sizeof(in_out)); 1110 &in_out, sizeof(in_out));
1116 1111
1117 if (intel_sdvo->is_hdmi) { 1112 /* Set the output timings to the screen */
1118 if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode)) 1113 if (!intel_sdvo_set_target_output(intel_sdvo,
1119 return; 1114 intel_sdvo->attached_output))
1120 1115 return;
1121 sdvox |= SDVO_AUDIO_ENABLE;
1122 }
1123 1116
1124 /* We have tried to get input timing in mode_fixup, and filled into 1117 /* We have tried to get input timing in mode_fixup, and filled into
1125 adjusted_mode */ 1118 * adjusted_mode.
1126 intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
1127 if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
1128 input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;
1129
1130 /* If it's a TV, we already set the output timing in mode_fixup.
1131 * Otherwise, the output timing is equal to the input timing.
1132 */ 1119 */
1133 if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) { 1120 if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
1121 input_dtd = intel_sdvo->input_dtd;
1122 } else {
1134 /* Set the output timing to the screen */ 1123 /* Set the output timing to the screen */
1135 if (!intel_sdvo_set_target_output(intel_sdvo, 1124 if (!intel_sdvo_set_target_output(intel_sdvo,
1136 intel_sdvo->attached_output)) 1125 intel_sdvo->attached_output))
1137 return; 1126 return;
1138 1127
1128 intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
1139 (void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd); 1129 (void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
1140 } 1130 }
1141 1131
@@ -1143,31 +1133,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
1143 if (!intel_sdvo_set_target_input(intel_sdvo)) 1133 if (!intel_sdvo_set_target_input(intel_sdvo))
1144 return; 1134 return;
1145 1135
1146 if (intel_sdvo->is_tv) { 1136 if (intel_sdvo->is_hdmi &&
1147 if (!intel_sdvo_set_tv_format(intel_sdvo)) 1137 !intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
1148 return; 1138 return;
1149 }
1150 1139
1151 /* We would like to use intel_sdvo_create_preferred_input_timing() to 1140 if (intel_sdvo->is_tv &&
1152 * provide the device with a timing it can support, if it supports that 1141 !intel_sdvo_set_tv_format(intel_sdvo))
1153 * feature. However, presumably we would need to adjust the CRTC to 1142 return;
1154 * output the preferred timing, and we don't support that currently.
1155 */
1156#if 0
1157 success = intel_sdvo_create_preferred_input_timing(encoder, clock,
1158 width, height);
1159 if (success) {
1160 struct intel_sdvo_dtd *input_dtd;
1161 1143
1162 intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
1163 intel_sdvo_set_input_timing(encoder, &input_dtd);
1164 }
1165#else
1166 (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd); 1144 (void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
1167#endif
1168 1145
1169 sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); 1146 switch (pixel_multiplier) {
1170 switch (sdvo_pixel_multiply) { 1147 default:
1171 case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break; 1148 case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
1172 case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break; 1149 case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
1173 case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break; 1150 case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1177,13 +1154,13 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
1177 1154
1178 /* Set the SDVO control regs. */ 1155 /* Set the SDVO control regs. */
1179 if (IS_I965G(dev)) { 1156 if (IS_I965G(dev)) {
1180 sdvox |= SDVO_BORDER_ENABLE; 1157 sdvox = SDVO_BORDER_ENABLE;
1181 if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) 1158 if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
1182 sdvox |= SDVO_VSYNC_ACTIVE_HIGH; 1159 sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
1183 if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) 1160 if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
1184 sdvox |= SDVO_HSYNC_ACTIVE_HIGH; 1161 sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
1185 } else { 1162 } else {
1186 sdvox |= I915_READ(intel_sdvo->sdvo_reg); 1163 sdvox = I915_READ(intel_sdvo->sdvo_reg);
1187 switch (intel_sdvo->sdvo_reg) { 1164 switch (intel_sdvo->sdvo_reg) {
1188 case SDVOB: 1165 case SDVOB:
1189 sdvox &= SDVOB_PRESERVE_MASK; 1166 sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1173,18 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
1196 } 1173 }
1197 if (intel_crtc->pipe == 1) 1174 if (intel_crtc->pipe == 1)
1198 sdvox |= SDVO_PIPE_B_SELECT; 1175 sdvox |= SDVO_PIPE_B_SELECT;
1176 if (intel_sdvo->is_hdmi)
1177 sdvox |= SDVO_AUDIO_ENABLE;
1199 1178
1200 if (IS_I965G(dev)) { 1179 if (IS_I965G(dev)) {
1201 /* done in crtc_mode_set as the dpll_md reg must be written early */ 1180 /* done in crtc_mode_set as the dpll_md reg must be written early */
1202 } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) { 1181 } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
1203 /* done in crtc_mode_set as it lives inside the dpll register */ 1182 /* done in crtc_mode_set as it lives inside the dpll register */
1204 } else { 1183 } else {
1205 sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; 1184 sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
1206 } 1185 }
1207 1186
1208 if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL) 1187 if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
1209 sdvox |= SDVO_STALL_SELECT; 1188 sdvox |= SDVO_STALL_SELECT;
1210 intel_sdvo_write_sdvox(intel_sdvo, sdvox); 1189 intel_sdvo_write_sdvox(intel_sdvo, sdvox);
1211} 1190}
@@ -1692,6 +1671,10 @@ end:
1692 if (newmode->type & DRM_MODE_TYPE_PREFERRED) { 1671 if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
1693 intel_sdvo->sdvo_lvds_fixed_mode = 1672 intel_sdvo->sdvo_lvds_fixed_mode =
1694 drm_mode_duplicate(connector->dev, newmode); 1673 drm_mode_duplicate(connector->dev, newmode);
1674
1675 drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
1676 0);
1677
1695 intel_sdvo->is_lvds = true; 1678 intel_sdvo->is_lvds = true;
1696 break; 1679 break;
1697 } 1680 }