aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_sdvo.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-06 16:51:48 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-06 16:52:43 -0400
commita1ceb677518a16903c3656c7079f9611315a0422 (patch)
tree72d5d887bd05689633d7e463d40128ccfcd4ae09 /drivers/gpu/drm/i915/intel_sdvo.c
parent8c3f929b6147e142efc58d5d03dc6fa703b14a5d (diff)
parentb980514c9adf403e3f43ead08196f5ce0e61fd05 (diff)
Merge the modeset-rework, basic conversion into drm-intel-next
As a quick reference I'll detail the motivation and design of the new code a bit here (mostly stitched together from patchbomb announcements and commits introducing the new concepts). The crtc helper code has the fundamental assumption that encoders and crtcs can be enabled/disabled in any order, as long as we take care of depencies (which means that enabled encoders need an enabled crtc to feed them data, essentially). Our hw works differently. We already have tons of ugly cases where crtc code enables encoder hw (or encoder->mode_set enables stuff that should only be enabled in enocder->commit) to work around these issues. But on the disable side we can't pull off similar tricks - there we actually need to rework the modeset sequence that controls all this. And this is also the real motivation why I've finally undertaken this rewrite: eDP on my shiny new Ivybridge Ultrabook is broken, and it's broken due to the wrong disable sequence ... The new code introduces a few interfaces and concepts: - Add new encoder->enable/disable functions which are directly called from the crtc->enable/disable function. This ensures that the encoder's can be enabled/disabled at a very specific in the modeset sequence, controlled by our platform specific code (instead of the crtc helper code calling them at a time it deems convenient). - Rework the dpms code - our code has mostly 1:1 connector:encoder mappings and does support cloning on only a few encoders, so we can simplify things quite a bit. - Also only ever disable/enable the entire output pipeline. This ensures that we obey the right sequence of enabling/disabling things, trying to be clever here mostly just complicates the code and results in bugs. For cloneable encoders this requires a bit of special handling to ensure that outputs can still be disabled individually, but it simplifies the common case. - Add infrastructure to read out the current hw state. No amount of careful ordering will help us if we brick the hw on the initial modeset setup. Which could happen if we just randomly disable things, oblivious to the state set up by the bios. Hence we need to be able to read that out. As a benefit, we grow a few generic functions useful to cross-check our modeset code with actual hw state. With all this in place, we can copy&paste the crtc helper code into the drm/i915 driver and start to rework it: - As detailed above, the new code only disables/enables an entire output pipe. As a preparation for global mode-changes (e.g. reassigning shared resources) it keeps track of which pipes need to be touched by a set of bitmasks. - To ensure that we correctly disable the current display pipes, we need to know the currently active connector/encoder/crtc linking. The old crtc helper simply overwrote these links with the new setup, the new code stages the new links in ->new_* pointers. Those get commited to the real linking pointers once the old output configuration has been torn down, before the ->mode_set callbacks are called. - Finally the code adds tons of self-consistency checks by employing the new hw state readout functions to cross-check the actual hw state with what the datastructure think it should be. These checks are done both after every modeset and after the hw state has been read out and sanitized at boot/resume time. All these checks greatly helped in tracking down regressions and bugs in the new code. With this new basis, a lot of cleanups and improvements to the code are now possible (besides the DP fixes that ultimately made me write this), but not yet done: - I think we should create struct intel_mode and use it as the adjusted mode everywhere to store little pieces like needs_tvclock, pipe dithering values or dp link parameters. That would still be a layering violation, but at least we wouldn't need to recompute these kinds of things in intel_display.c. Especially the port bpc computation needed for selecting the pipe bpc and dithering settings in intel_display.c is rather gross. - In a related rework we could implement ->mode_valid in terms of ->mode_fixup in a generic way - I've hunted down too many bugs where ->mode_valid did the right thing, but ->mode_fixup didn't. Or vice versa, resulting in funny bugs for user-supplied modes. - Ditch the idea to rework the hdp handling in the common crtc helper code and just move things to i915.ko. Which would rid us of the ->detect crtc helper dependencies. - LVDS wire pair and pll enabling is all done in the crtc->mode_set function currently. We should be able to move this to the crtc_enable callbacks (or in the case of the LVDS wire pair enabling, into some encoder callback). Last, but not least, this new code should also help in enabling a few neat features: The hw state readout code prepares (but there are still big pieces missing) for fastboot, i.e. avoiding the inital modeset at boot-up and just taking over the configuration left behind by the bios. We also should be able to extend the configuration checks in the beginning of the modeset sequence and make better decisions about shared resources (which is the entire point behind the atomic/global modeset ioctl). Tested-by: Jani Nikula <jani.nikula@intel.com> Tested-by: Ben Widawsky <ben@bwidawsk.net> Tested-by: Damien Lespiau <damien.lespiau@intel.com> Tested-by: Rodrigo Vivi <rodrigo.vivi@gmail.com> Acked-by: Chris Wilson <chris@chris-wilson.co.uk> Tested-by: Vijay Purushothaman <vijay.a.purushothaman@intel.com> Acked-by: Vijay Purushothaman <vijay.a.purushothaman@intel.com> Tested-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Acked-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Tested-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sdvo.c')
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c164
1 files changed, 128 insertions, 36 deletions
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 6c9a85759bc3..39c319827f91 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -628,6 +628,14 @@ static bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,
628 &outputs, sizeof(outputs)); 628 &outputs, sizeof(outputs));
629} 629}
630 630
631static bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
632 u16 *outputs)
633{
634 return intel_sdvo_get_value(intel_sdvo,
635 SDVO_CMD_GET_ACTIVE_OUTPUTS,
636 outputs, sizeof(*outputs));
637}
638
631static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo, 639static bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
632 int mode) 640 int mode)
633{ 641{
@@ -1142,51 +1150,132 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
1142 intel_sdvo_write_sdvox(intel_sdvo, sdvox); 1150 intel_sdvo_write_sdvox(intel_sdvo, sdvox);
1143} 1151}
1144 1152
1145static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) 1153static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
1146{ 1154{
1147 struct drm_device *dev = encoder->dev; 1155 struct intel_sdvo_connector *intel_sdvo_connector =
1156 to_intel_sdvo_connector(&connector->base);
1157 struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
1158 u16 active_outputs;
1159
1160 intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
1161
1162 if (active_outputs & intel_sdvo_connector->output_flag)
1163 return true;
1164 else
1165 return false;
1166}
1167
1168static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
1169 enum pipe *pipe)
1170{
1171 struct drm_device *dev = encoder->base.dev;
1148 struct drm_i915_private *dev_priv = dev->dev_private; 1172 struct drm_i915_private *dev_priv = dev->dev_private;
1149 struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder); 1173 struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1150 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); 1174 u32 tmp;
1175
1176 tmp = I915_READ(intel_sdvo->sdvo_reg);
1177
1178 if (!(tmp & SDVO_ENABLE))
1179 return false;
1180
1181 if (HAS_PCH_CPT(dev))
1182 *pipe = PORT_TO_PIPE_CPT(tmp);
1183 else
1184 *pipe = PORT_TO_PIPE(tmp);
1185
1186 return true;
1187}
1188
1189static void intel_disable_sdvo(struct intel_encoder *encoder)
1190{
1191 struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
1192 struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1193 u32 temp;
1194
1195 intel_sdvo_set_active_outputs(intel_sdvo, 0);
1196 if (0)
1197 intel_sdvo_set_encoder_power_state(intel_sdvo,
1198 DRM_MODE_DPMS_OFF);
1199
1200 temp = I915_READ(intel_sdvo->sdvo_reg);
1201 if ((temp & SDVO_ENABLE) != 0) {
1202 intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
1203 }
1204}
1205
1206static void intel_enable_sdvo(struct intel_encoder *encoder)
1207{
1208 struct drm_device *dev = encoder->base.dev;
1209 struct drm_i915_private *dev_priv = dev->dev_private;
1210 struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1211 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
1151 u32 temp; 1212 u32 temp;
1213 bool input1, input2;
1214 int i;
1215 u8 status;
1216
1217 temp = I915_READ(intel_sdvo->sdvo_reg);
1218 if ((temp & SDVO_ENABLE) == 0)
1219 intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
1220 for (i = 0; i < 2; i++)
1221 intel_wait_for_vblank(dev, intel_crtc->pipe);
1222
1223 status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
1224 /* Warn if the device reported failure to sync.
1225 * A lot of SDVO devices fail to notify of sync, but it's
1226 * a given it the status is a success, we succeeded.
1227 */
1228 if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
1229 DRM_DEBUG_KMS("First %s output reported failure to "
1230 "sync\n", SDVO_NAME(intel_sdvo));
1231 }
1232
1233 if (0)
1234 intel_sdvo_set_encoder_power_state(intel_sdvo,
1235 DRM_MODE_DPMS_ON);
1236 intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
1237}
1238
1239static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
1240{
1241 struct drm_crtc *crtc;
1242 struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1243
1244 /* dvo supports only 2 dpms states. */
1245 if (mode != DRM_MODE_DPMS_ON)
1246 mode = DRM_MODE_DPMS_OFF;
1247
1248 if (mode == connector->dpms)
1249 return;
1250
1251 connector->dpms = mode;
1252
1253 /* Only need to change hw state when actually enabled */
1254 crtc = intel_sdvo->base.base.crtc;
1255 if (!crtc) {
1256 intel_sdvo->base.connectors_active = false;
1257 return;
1258 }
1152 1259
1153 if (mode != DRM_MODE_DPMS_ON) { 1260 if (mode != DRM_MODE_DPMS_ON) {
1154 intel_sdvo_set_active_outputs(intel_sdvo, 0); 1261 intel_sdvo_set_active_outputs(intel_sdvo, 0);
1155 if (0) 1262 if (0)
1156 intel_sdvo_set_encoder_power_state(intel_sdvo, mode); 1263 intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
1157 1264
1158 if (mode == DRM_MODE_DPMS_OFF) { 1265 intel_sdvo->base.connectors_active = false;
1159 temp = I915_READ(intel_sdvo->sdvo_reg); 1266
1160 if ((temp & SDVO_ENABLE) != 0) { 1267 intel_crtc_update_dpms(crtc);
1161 intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
1162 }
1163 }
1164 } else { 1268 } else {
1165 bool input1, input2; 1269 intel_sdvo->base.connectors_active = true;
1166 int i; 1270
1167 u8 status; 1271 intel_crtc_update_dpms(crtc);
1168
1169 temp = I915_READ(intel_sdvo->sdvo_reg);
1170 if ((temp & SDVO_ENABLE) == 0)
1171 intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
1172 for (i = 0; i < 2; i++)
1173 intel_wait_for_vblank(dev, intel_crtc->pipe);
1174
1175 status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
1176 /* Warn if the device reported failure to sync.
1177 * A lot of SDVO devices fail to notify of sync, but it's
1178 * a given it the status is a success, we succeeded.
1179 */
1180 if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
1181 DRM_DEBUG_KMS("First %s output reported failure to "
1182 "sync\n", SDVO_NAME(intel_sdvo));
1183 }
1184 1272
1185 if (0) 1273 if (0)
1186 intel_sdvo_set_encoder_power_state(intel_sdvo, mode); 1274 intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
1187 intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); 1275 intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
1188 } 1276 }
1189 return; 1277
1278 intel_modeset_check_state(connector->dev);
1190} 1279}
1191 1280
1192static int intel_sdvo_mode_valid(struct drm_connector *connector, 1281static int intel_sdvo_mode_valid(struct drm_connector *connector,
@@ -1838,8 +1927,8 @@ set_value:
1838done: 1927done:
1839 if (intel_sdvo->base.base.crtc) { 1928 if (intel_sdvo->base.base.crtc) {
1840 struct drm_crtc *crtc = intel_sdvo->base.base.crtc; 1929 struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
1841 drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, 1930 intel_set_mode(crtc, &crtc->mode,
1842 crtc->y, crtc->fb); 1931 crtc->x, crtc->y, crtc->fb);
1843 } 1932 }
1844 1933
1845 return 0; 1934 return 0;
@@ -1847,15 +1936,13 @@ done:
1847} 1936}
1848 1937
1849static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { 1938static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
1850 .dpms = intel_sdvo_dpms,
1851 .mode_fixup = intel_sdvo_mode_fixup, 1939 .mode_fixup = intel_sdvo_mode_fixup,
1852 .prepare = intel_encoder_prepare,
1853 .mode_set = intel_sdvo_mode_set, 1940 .mode_set = intel_sdvo_mode_set,
1854 .commit = intel_encoder_commit, 1941 .disable = intel_encoder_noop,
1855}; 1942};
1856 1943
1857static const struct drm_connector_funcs intel_sdvo_connector_funcs = { 1944static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
1858 .dpms = drm_helper_connector_dpms, 1945 .dpms = intel_sdvo_dpms,
1859 .detect = intel_sdvo_detect, 1946 .detect = intel_sdvo_detect,
1860 .fill_modes = drm_helper_probe_single_connector_modes, 1947 .fill_modes = drm_helper_probe_single_connector_modes,
1861 .set_property = intel_sdvo_set_property, 1948 .set_property = intel_sdvo_set_property,
@@ -2027,6 +2114,7 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
2027 connector->base.base.interlace_allowed = 1; 2114 connector->base.base.interlace_allowed = 1;
2028 connector->base.base.doublescan_allowed = 0; 2115 connector->base.base.doublescan_allowed = 0;
2029 connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB; 2116 connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
2117 connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
2030 2118
2031 intel_connector_attach_encoder(&connector->base, &encoder->base); 2119 intel_connector_attach_encoder(&connector->base, &encoder->base);
2032 drm_sysfs_connector_add(&connector->base.base); 2120 drm_sysfs_connector_add(&connector->base.base);
@@ -2578,6 +2666,10 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
2578 2666
2579 drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs); 2667 drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
2580 2668
2669 intel_encoder->disable = intel_disable_sdvo;
2670 intel_encoder->enable = intel_enable_sdvo;
2671 intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
2672
2581 /* In default case sdvo lvds is false */ 2673 /* In default case sdvo lvds is false */
2582 if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) 2674 if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
2583 goto err; 2675 goto err;