aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-07-05 16:34:27 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-06 02:02:57 -0400
commit9a935856992d68b9194f825ce6e115df7ecc5bca (patch)
treed8e207abfb1c9c5baef03e6b209d4b75eb2213ae /drivers/gpu
parent1aa4b628ee63f55db96c7e820257b6e4948abb74 (diff)
drm/i915: stage modeset output changes
This is the core of the new modeset logic. The current code which is based upon the crtc helper code first updates all the link of the new display pipeline and then calls the lower-level set_mode function to execute the required callbacks to get there. The issue with this approach is that for disabling we need to know the _current_ display pipe state, not the new one. Hence we need to stage the new state of the display pipe and only update it once we have disabled the current configuration and before we start to update the hw registers with the new configuration. This patch here just prepares the ground by switching the new output state computation to these staging pointers. To make it clearer, rename the old update_output_state function to stage_output_state. A few peculiarities: - We're also calling the set_mode function at various places to update properties. Hence after a successfule modeset we need to stage the current configuration (for otherwise we might fall back again). This happens automatically because as part of the (successful) modeset we need to copy the staged state to the real one. But for the hw readout code we need to make sure that this happens, too. - Teach the new staged output state computation code the required smarts to handle the disabling of outputs. The current code handles this in a special case, but to better handle global modeset changes covering more than one crtc, we want to do this all in the same low-level modeset code. - The actual modeset code is still a bit ugly and wants to know the new crtc->enabled state a bit early. Follow-on patches will clean that up, for now we have to apply the staged output configuration early, outside of the set_mode functions. - Improve/add comments in stage_output_state. Essentially all that is left to do now is move the disabling code into set_mode and then move the staged state update code also into set_mode, at the right place between disabling things and calling the mode_set callbacks for the new configuration. v2: Disabling a crtc works by passing in a NULL mode or fb, userspace doesn't hand in the list of connectors. We therefore need to detect this case manually and tear down all the output links. v3: Properly update the output staging pointers after having read out the hw state. v4: Simplify the code, add more DRM_DEBUG_KMS output and check a few assumptions with WARN_ON. Essentially all things that I've noticed while debugging issues in other places of the code. v4: Correctly disable the old set of connectors when enabling an already enabled crtc on a new set of crtc. Reported by Paulo Zanoni. Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c174
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h16
2 files changed, 146 insertions, 44 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a2ce117aa794..5031e0c4a02e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6619,6 +6619,51 @@ intel_crtc_prepare_encoders(struct drm_device *dev)
6619 } 6619 }
6620} 6620}
6621 6621
6622/**
6623 * intel_modeset_update_staged_output_state
6624 *
6625 * Updates the staged output configuration state, e.g. after we've read out the
6626 * current hw state.
6627 */
6628static void intel_modeset_update_staged_output_state(struct drm_device *dev)
6629{
6630 struct intel_encoder *encoder;
6631 struct intel_connector *connector;
6632
6633 list_for_each_entry(connector, &dev->mode_config.connector_list,
6634 base.head) {
6635 connector->new_encoder =
6636 to_intel_encoder(connector->base.encoder);
6637 }
6638
6639 list_for_each_entry(encoder, &dev->mode_config.encoder_list,
6640 base.head) {
6641 encoder->new_crtc =
6642 to_intel_crtc(encoder->base.crtc);
6643 }
6644}
6645
6646/**
6647 * intel_modeset_commit_output_state
6648 *
6649 * This function copies the stage display pipe configuration to the real one.
6650 */
6651static void intel_modeset_commit_output_state(struct drm_device *dev)
6652{
6653 struct intel_encoder *encoder;
6654 struct intel_connector *connector;
6655
6656 list_for_each_entry(connector, &dev->mode_config.connector_list,
6657 base.head) {
6658 connector->base.encoder = &connector->new_encoder->base;
6659 }
6660
6661 list_for_each_entry(encoder, &dev->mode_config.encoder_list,
6662 base.head) {
6663 encoder->base.crtc = &encoder->new_crtc->base;
6664 }
6665}
6666
6622bool intel_set_mode(struct drm_crtc *crtc, 6667bool intel_set_mode(struct drm_crtc *crtc,
6623 struct drm_display_mode *mode, 6668 struct drm_display_mode *mode,
6624 int x, int y, struct drm_framebuffer *old_fb) 6669 int x, int y, struct drm_framebuffer *old_fb)
@@ -6785,8 +6830,8 @@ static void intel_set_config_restore_state(struct drm_device *dev,
6785 struct intel_set_config *config) 6830 struct intel_set_config *config)
6786{ 6831{
6787 struct drm_crtc *crtc; 6832 struct drm_crtc *crtc;
6788 struct drm_encoder *encoder; 6833 struct intel_encoder *encoder;
6789 struct drm_connector *connector; 6834 struct intel_connector *connector;
6790 int count; 6835 int count;
6791 6836
6792 count = 0; 6837 count = 0;
@@ -6795,13 +6840,15 @@ static void intel_set_config_restore_state(struct drm_device *dev,
6795 } 6840 }
6796 6841
6797 count = 0; 6842 count = 0;
6798 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 6843 list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
6799 encoder->crtc = config->save_encoder_crtcs[count++]; 6844 encoder->new_crtc =
6845 to_intel_crtc(config->save_encoder_crtcs[count++]);
6800 } 6846 }
6801 6847
6802 count = 0; 6848 count = 0;
6803 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 6849 list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
6804 connector->encoder = config->save_connector_encoders[count++]; 6850 connector->new_encoder =
6851 to_intel_encoder(config->save_connector_encoders[count++]);
6805 } 6852 }
6806} 6853}
6807 6854
@@ -6840,73 +6887,106 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
6840} 6887}
6841 6888
6842static int 6889static int
6843intel_set_config_update_output_state(struct drm_device *dev, 6890intel_modeset_stage_output_state(struct drm_device *dev,
6844 struct drm_mode_set *set, 6891 struct drm_mode_set *set,
6845 struct intel_set_config *config) 6892 struct intel_set_config *config)
6846{ 6893{
6847 struct drm_crtc *new_crtc; 6894 struct drm_crtc *new_crtc;
6848 struct drm_encoder *new_encoder; 6895 struct intel_connector *connector;
6849 struct drm_connector *connector; 6896 struct intel_encoder *encoder;
6850 int count, ro; 6897 int count, ro;
6851 6898
6852 /* a) traverse passed in connector list and get encoders for them */ 6899 /* The upper layers ensure that we either disabl a crtc or have a list
6900 * of connectors. For paranoia, double-check this. */
6901 WARN_ON(!set->fb && (set->num_connectors != 0));
6902 WARN_ON(set->fb && (set->num_connectors == 0));
6903
6853 count = 0; 6904 count = 0;
6854 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 6905 list_for_each_entry(connector, &dev->mode_config.connector_list,
6855 new_encoder = connector->encoder; 6906 base.head) {
6907 /* Otherwise traverse passed in connector list and get encoders
6908 * for them. */
6856 for (ro = 0; ro < set->num_connectors; ro++) { 6909 for (ro = 0; ro < set->num_connectors; ro++) {
6857 if (set->connectors[ro] == connector) { 6910 if (set->connectors[ro] == &connector->base) {
6858 new_encoder = 6911 connector->new_encoder = connector->encoder;
6859 &intel_attached_encoder(connector)->base;
6860 break; 6912 break;
6861 } 6913 }
6862 } 6914 }
6863 6915
6864 if (new_encoder != connector->encoder) { 6916 /* If we disable the crtc, disable all its connectors. Also, if
6917 * the connector is on the changing crtc but not on the new
6918 * connector list, disable it. */
6919 if ((!set->fb || ro == set->num_connectors) &&
6920 connector->base.encoder &&
6921 connector->base.encoder->crtc == set->crtc) {
6922 connector->new_encoder = NULL;
6923
6924 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
6925 connector->base.base.id,
6926 drm_get_connector_name(&connector->base));
6927 }
6928
6929
6930 if (&connector->new_encoder->base != connector->base.encoder) {
6865 DRM_DEBUG_KMS("encoder changed, full mode switch\n"); 6931 DRM_DEBUG_KMS("encoder changed, full mode switch\n");
6866 config->mode_changed = true; 6932 config->mode_changed = true;
6867 /* If the encoder is reused for another connector, then
6868 * the appropriate crtc will be set later.
6869 */
6870 if (connector->encoder)
6871 connector->encoder->crtc = NULL;
6872 connector->encoder = new_encoder;
6873 } 6933 }
6934
6935 /* Disable all disconnected encoders. */
6936 if (connector->base.status == connector_status_disconnected)
6937 connector->new_encoder = NULL;
6874 } 6938 }
6939 /* connector->new_encoder is now updated for all connectors. */
6875 6940
6941 /* Update crtc of enabled connectors. */
6876 count = 0; 6942 count = 0;
6877 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 6943 list_for_each_entry(connector, &dev->mode_config.connector_list,
6878 if (!connector->encoder) 6944 base.head) {
6945 if (!connector->new_encoder)
6879 continue; 6946 continue;
6880 6947
6881 if (connector->encoder->crtc == set->crtc) 6948 new_crtc = connector->new_encoder->base.crtc;
6882 new_crtc = NULL;
6883 else
6884 new_crtc = connector->encoder->crtc;
6885 6949
6886 for (ro = 0; ro < set->num_connectors; ro++) { 6950 for (ro = 0; ro < set->num_connectors; ro++) {
6887 if (set->connectors[ro] == connector) 6951 if (set->connectors[ro] == &connector->base)
6888 new_crtc = set->crtc; 6952 new_crtc = set->crtc;
6889 } 6953 }
6890 6954
6891 /* Make sure the new CRTC will work with the encoder */ 6955 /* Make sure the new CRTC will work with the encoder */
6892 if (new_crtc && 6956 if (!intel_encoder_crtc_ok(&connector->new_encoder->base,
6893 !intel_encoder_crtc_ok(connector->encoder, new_crtc)) { 6957 new_crtc)) {
6894 return -EINVAL; 6958 return -EINVAL;
6895 } 6959 }
6896 if (new_crtc != connector->encoder->crtc) { 6960 connector->encoder->new_crtc = to_intel_crtc(new_crtc);
6961
6962 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
6963 connector->base.base.id,
6964 drm_get_connector_name(&connector->base),
6965 new_crtc->base.id);
6966 }
6967
6968 /* Check for any encoders that needs to be disabled. */
6969 list_for_each_entry(encoder, &dev->mode_config.encoder_list,
6970 base.head) {
6971 list_for_each_entry(connector,
6972 &dev->mode_config.connector_list,
6973 base.head) {
6974 if (connector->new_encoder == encoder) {
6975 WARN_ON(!connector->new_encoder->new_crtc);
6976
6977 goto next_encoder;
6978 }
6979 }
6980 encoder->new_crtc = NULL;
6981next_encoder:
6982 /* Only now check for crtc changes so we don't miss encoders
6983 * that will be disabled. */
6984 if (&encoder->new_crtc->base != encoder->base.crtc) {
6897 DRM_DEBUG_KMS("crtc changed, full mode switch\n"); 6985 DRM_DEBUG_KMS("crtc changed, full mode switch\n");
6898 config->mode_changed = true; 6986 config->mode_changed = true;
6899 connector->encoder->crtc = new_crtc;
6900 }
6901 if (new_crtc) {
6902 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
6903 connector->base.id, drm_get_connector_name(connector),
6904 new_crtc->base.id);
6905 } else {
6906 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
6907 connector->base.id, drm_get_connector_name(connector));
6908 } 6987 }
6909 } 6988 }
6989 /* Now we've also updated encoder->new_crtc for all encoders. */
6910 6990
6911 return 0; 6991 return 0;
6912} 6992}
@@ -6965,11 +7045,13 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
6965 * such cases. */ 7045 * such cases. */
6966 intel_set_config_compute_mode_changes(set, config); 7046 intel_set_config_compute_mode_changes(set, config);
6967 7047
6968 ret = intel_set_config_update_output_state(dev, set, config); 7048 ret = intel_modeset_stage_output_state(dev, set, config);
6969 if (ret) 7049 if (ret)
6970 goto fail; 7050 goto fail;
6971 7051
6972 if (config->mode_changed) { 7052 if (config->mode_changed) {
7053 intel_modeset_commit_output_state(dev);
7054
6973 set->crtc->enabled = drm_helper_crtc_in_use(set->crtc); 7055 set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
6974 if (set->crtc->enabled) { 7056 if (set->crtc->enabled) {
6975 DRM_DEBUG_KMS("attempting to set mode from" 7057 DRM_DEBUG_KMS("attempting to set mode from"
@@ -7015,6 +7097,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
7015fail: 7097fail:
7016 intel_set_config_restore_state(dev, config); 7098 intel_set_config_restore_state(dev, config);
7017 7099
7100 intel_modeset_commit_output_state(dev);
7101
7018 /* Try to restore the config */ 7102 /* Try to restore the config */
7019 if (config->mode_changed && 7103 if (config->mode_changed &&
7020 !intel_set_mode(save_set.crtc, save_set.mode, 7104 !intel_set_mode(save_set.crtc, save_set.mode,
@@ -7888,6 +7972,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev)
7888 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); 7972 crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
7889 intel_sanitize_crtc(crtc); 7973 intel_sanitize_crtc(crtc);
7890 } 7974 }
7975
7976 intel_modeset_update_staged_output_state(dev);
7891} 7977}
7892 7978
7893void intel_modeset_gem_init(struct drm_device *dev) 7979void intel_modeset_gem_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4946282bd324..ae807afc5fbf 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -133,6 +133,12 @@ struct intel_fbdev {
133 133
134struct intel_encoder { 134struct intel_encoder {
135 struct drm_encoder base; 135 struct drm_encoder base;
136 /*
137 * The new crtc this encoder will be driven from. Only differs from
138 * base->crtc while a modeset is in progress.
139 */
140 struct intel_crtc *new_crtc;
141
136 int type; 142 int type;
137 bool needs_tv_clock; 143 bool needs_tv_clock;
138 /* 144 /*
@@ -153,7 +159,17 @@ struct intel_encoder {
153 159
154struct intel_connector { 160struct intel_connector {
155 struct drm_connector base; 161 struct drm_connector base;
162 /*
163 * The fixed encoder this connector is connected to.
164 */
156 struct intel_encoder *encoder; 165 struct intel_encoder *encoder;
166
167 /*
168 * The new encoder this connector will be driven. Only differs from
169 * encoder while a modeset is in progress.
170 */
171 struct intel_encoder *new_encoder;
172
157 /* Reads out the current hw, returning true if the connector is enabled 173 /* Reads out the current hw, returning true if the connector is enabled
158 * and active (i.e. dpms ON state). */ 174 * and active (i.e. dpms ON state). */
159 bool (*get_hw_state)(struct intel_connector *); 175 bool (*get_hw_state)(struct intel_connector *);