aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-07-02 03:35:43 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-06 01:56:00 -0400
commit50f56119efcb7ad763c14a9b6c2c8e684050cab0 (patch)
tree98e01f82e44419030a89aa8e6dc77ffbc2adcf1d /drivers/gpu/drm/i915/intel_display.c
parent61b77ddda6cf6f1f6f543339cfeee4c623f82784 (diff)
drm/i915: copy&paste drm_crtc_helper_set_config
And the following static functions required by it: drm_encoder_crtc_ok, drm_crtc_helper_disable No changes safe for the s/drm/intel prefix change. Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c314
1 files changed, 313 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 07077b1fcd7b..33a519117e2f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6590,12 +6590,324 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
6590 .disable = intel_crtc_disable, 6590 .disable = intel_crtc_disable,
6591}; 6591};
6592 6592
6593static bool intel_encoder_crtc_ok(struct drm_encoder *encoder,
6594 struct drm_crtc *crtc)
6595{
6596 struct drm_device *dev;
6597 struct drm_crtc *tmp;
6598 int crtc_mask = 1;
6599
6600 WARN(!crtc, "checking null crtc?\n");
6601
6602 dev = crtc->dev;
6603
6604 list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
6605 if (tmp == crtc)
6606 break;
6607 crtc_mask <<= 1;
6608 }
6609
6610 if (encoder->possible_crtcs & crtc_mask)
6611 return true;
6612 return false;
6613}
6614
6615static int
6616intel_crtc_helper_disable(struct drm_crtc *crtc)
6617{
6618 struct drm_device *dev = crtc->dev;
6619 struct drm_connector *connector;
6620 struct drm_encoder *encoder;
6621
6622 /* Decouple all encoders and their attached connectors from this crtc */
6623 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
6624 if (encoder->crtc != crtc)
6625 continue;
6626
6627 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
6628 if (connector->encoder != encoder)
6629 continue;
6630
6631 connector->encoder = NULL;
6632 }
6633 }
6634
6635 drm_helper_disable_unused_functions(dev);
6636 return 0;
6637}
6638
6639static int intel_crtc_set_config(struct drm_mode_set *set)
6640{
6641 struct drm_device *dev;
6642 struct drm_crtc *save_crtcs, *new_crtc, *crtc;
6643 struct drm_encoder *save_encoders, *new_encoder, *encoder;
6644 struct drm_framebuffer *old_fb = NULL;
6645 bool mode_changed = false; /* if true do a full mode set */
6646 bool fb_changed = false; /* if true and !mode_changed just do a flip */
6647 struct drm_connector *save_connectors, *connector;
6648 int count = 0, ro, fail = 0;
6649 struct drm_crtc_helper_funcs *crtc_funcs;
6650 struct drm_mode_set save_set;
6651 int ret;
6652 int i;
6653
6654 DRM_DEBUG_KMS("\n");
6655
6656 if (!set)
6657 return -EINVAL;
6658
6659 if (!set->crtc)
6660 return -EINVAL;
6661
6662 if (!set->crtc->helper_private)
6663 return -EINVAL;
6664
6665 crtc_funcs = set->crtc->helper_private;
6666
6667 if (!set->mode)
6668 set->fb = NULL;
6669
6670 if (set->fb) {
6671 DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",
6672 set->crtc->base.id, set->fb->base.id,
6673 (int)set->num_connectors, set->x, set->y);
6674 } else {
6675 DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);
6676 return intel_crtc_helper_disable(set->crtc);
6677 }
6678
6679 dev = set->crtc->dev;
6680
6681 /* Allocate space for the backup of all (non-pointer) crtc, encoder and
6682 * connector data. */
6683 save_crtcs = kzalloc(dev->mode_config.num_crtc *
6684 sizeof(struct drm_crtc), GFP_KERNEL);
6685 if (!save_crtcs)
6686 return -ENOMEM;
6687
6688 save_encoders = kzalloc(dev->mode_config.num_encoder *
6689 sizeof(struct drm_encoder), GFP_KERNEL);
6690 if (!save_encoders) {
6691 kfree(save_crtcs);
6692 return -ENOMEM;
6693 }
6694
6695 save_connectors = kzalloc(dev->mode_config.num_connector *
6696 sizeof(struct drm_connector), GFP_KERNEL);
6697 if (!save_connectors) {
6698 kfree(save_crtcs);
6699 kfree(save_encoders);
6700 return -ENOMEM;
6701 }
6702
6703 /* Copy data. Note that driver private data is not affected.
6704 * Should anything bad happen only the expected state is
6705 * restored, not the drivers personal bookkeeping.
6706 */
6707 count = 0;
6708 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
6709 save_crtcs[count++] = *crtc;
6710 }
6711
6712 count = 0;
6713 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
6714 save_encoders[count++] = *encoder;
6715 }
6716
6717 count = 0;
6718 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
6719 save_connectors[count++] = *connector;
6720 }
6721
6722 save_set.crtc = set->crtc;
6723 save_set.mode = &set->crtc->mode;
6724 save_set.x = set->crtc->x;
6725 save_set.y = set->crtc->y;
6726 save_set.fb = set->crtc->fb;
6727
6728 /* We should be able to check here if the fb has the same properties
6729 * and then just flip_or_move it */
6730 if (set->crtc->fb != set->fb) {
6731 /* If we have no fb then treat it as a full mode set */
6732 if (set->crtc->fb == NULL) {
6733 DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
6734 mode_changed = true;
6735 } else if (set->fb == NULL) {
6736 mode_changed = true;
6737 } else if (set->fb->depth != set->crtc->fb->depth) {
6738 mode_changed = true;
6739 } else if (set->fb->bits_per_pixel !=
6740 set->crtc->fb->bits_per_pixel) {
6741 mode_changed = true;
6742 } else
6743 fb_changed = true;
6744 }
6745
6746 if (set->x != set->crtc->x || set->y != set->crtc->y)
6747 fb_changed = true;
6748
6749 if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
6750 DRM_DEBUG_KMS("modes are different, full mode set\n");
6751 drm_mode_debug_printmodeline(&set->crtc->mode);
6752 drm_mode_debug_printmodeline(set->mode);
6753 mode_changed = true;
6754 }
6755
6756 /* a) traverse passed in connector list and get encoders for them */
6757 count = 0;
6758 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
6759 struct drm_connector_helper_funcs *connector_funcs =
6760 connector->helper_private;
6761 new_encoder = connector->encoder;
6762 for (ro = 0; ro < set->num_connectors; ro++) {
6763 if (set->connectors[ro] == connector) {
6764 new_encoder = connector_funcs->best_encoder(connector);
6765 /* if we can't get an encoder for a connector
6766 we are setting now - then fail */
6767 if (new_encoder == NULL)
6768 /* don't break so fail path works correct */
6769 fail = 1;
6770 break;
6771 }
6772 }
6773
6774 if (new_encoder != connector->encoder) {
6775 DRM_DEBUG_KMS("encoder changed, full mode switch\n");
6776 mode_changed = true;
6777 /* If the encoder is reused for another connector, then
6778 * the appropriate crtc will be set later.
6779 */
6780 if (connector->encoder)
6781 connector->encoder->crtc = NULL;
6782 connector->encoder = new_encoder;
6783 }
6784 }
6785
6786 if (fail) {
6787 ret = -EINVAL;
6788 goto fail;
6789 }
6790
6791 count = 0;
6792 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
6793 if (!connector->encoder)
6794 continue;
6795
6796 if (connector->encoder->crtc == set->crtc)
6797 new_crtc = NULL;
6798 else
6799 new_crtc = connector->encoder->crtc;
6800
6801 for (ro = 0; ro < set->num_connectors; ro++) {
6802 if (set->connectors[ro] == connector)
6803 new_crtc = set->crtc;
6804 }
6805
6806 /* Make sure the new CRTC will work with the encoder */
6807 if (new_crtc &&
6808 !intel_encoder_crtc_ok(connector->encoder, new_crtc)) {
6809 ret = -EINVAL;
6810 goto fail;
6811 }
6812 if (new_crtc != connector->encoder->crtc) {
6813 DRM_DEBUG_KMS("crtc changed, full mode switch\n");
6814 mode_changed = true;
6815 connector->encoder->crtc = new_crtc;
6816 }
6817 if (new_crtc) {
6818 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
6819 connector->base.id, drm_get_connector_name(connector),
6820 new_crtc->base.id);
6821 } else {
6822 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
6823 connector->base.id, drm_get_connector_name(connector));
6824 }
6825 }
6826
6827 /* mode_set_base is not a required function */
6828 if (fb_changed && !crtc_funcs->mode_set_base)
6829 mode_changed = true;
6830
6831 if (mode_changed) {
6832 set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
6833 if (set->crtc->enabled) {
6834 DRM_DEBUG_KMS("attempting to set mode from"
6835 " userspace\n");
6836 drm_mode_debug_printmodeline(set->mode);
6837 old_fb = set->crtc->fb;
6838 set->crtc->fb = set->fb;
6839 if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
6840 set->x, set->y,
6841 old_fb)) {
6842 DRM_ERROR("failed to set mode on [CRTC:%d]\n",
6843 set->crtc->base.id);
6844 set->crtc->fb = old_fb;
6845 ret = -EINVAL;
6846 goto fail;
6847 }
6848 DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
6849 for (i = 0; i < set->num_connectors; i++) {
6850 DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
6851 drm_get_connector_name(set->connectors[i]));
6852 set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
6853 }
6854 }
6855 drm_helper_disable_unused_functions(dev);
6856 } else if (fb_changed) {
6857 set->crtc->x = set->x;
6858 set->crtc->y = set->y;
6859
6860 old_fb = set->crtc->fb;
6861 if (set->crtc->fb != set->fb)
6862 set->crtc->fb = set->fb;
6863 ret = crtc_funcs->mode_set_base(set->crtc,
6864 set->x, set->y, old_fb);
6865 if (ret != 0) {
6866 set->crtc->fb = old_fb;
6867 goto fail;
6868 }
6869 }
6870
6871 kfree(save_connectors);
6872 kfree(save_encoders);
6873 kfree(save_crtcs);
6874 return 0;
6875
6876fail:
6877 /* Restore all previous data. */
6878 count = 0;
6879 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
6880 *crtc = save_crtcs[count++];
6881 }
6882
6883 count = 0;
6884 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
6885 *encoder = save_encoders[count++];
6886 }
6887
6888 count = 0;
6889 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
6890 *connector = save_connectors[count++];
6891 }
6892
6893 /* Try to restore the config */
6894 if (mode_changed &&
6895 !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x,
6896 save_set.y, save_set.fb))
6897 DRM_ERROR("failed to restore config after modeset failure\n");
6898
6899 kfree(save_connectors);
6900 kfree(save_encoders);
6901 kfree(save_crtcs);
6902 return ret;
6903}
6904
6593static const struct drm_crtc_funcs intel_crtc_funcs = { 6905static const struct drm_crtc_funcs intel_crtc_funcs = {
6594 .reset = intel_crtc_reset, 6906 .reset = intel_crtc_reset,
6595 .cursor_set = intel_crtc_cursor_set, 6907 .cursor_set = intel_crtc_cursor_set,
6596 .cursor_move = intel_crtc_cursor_move, 6908 .cursor_move = intel_crtc_cursor_move,
6597 .gamma_set = intel_crtc_gamma_set, 6909 .gamma_set = intel_crtc_gamma_set,
6598 .set_config = drm_crtc_helper_set_config, 6910 .set_config = intel_crtc_set_config,
6599 .destroy = intel_crtc_destroy, 6911 .destroy = intel_crtc_destroy,
6600 .page_flip = intel_crtc_page_flip, 6912 .page_flip = intel_crtc_page_flip,
6601}; 6913};