diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo.c | 114 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_sdvo_regs.h | 1 |
2 files changed, 103 insertions, 12 deletions
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index f03473779feb..4f0c30948bc4 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -68,12 +68,23 @@ struct intel_sdvo_priv { | |||
68 | * This is set if we treat the device as HDMI, instead of DVI. | 68 | * This is set if we treat the device as HDMI, instead of DVI. |
69 | */ | 69 | */ |
70 | bool is_hdmi; | 70 | bool is_hdmi; |
71 | |||
71 | /** | 72 | /** |
72 | * This is set if we detect output of sdvo device as LVDS. | 73 | * This is set if we detect output of sdvo device as LVDS. |
73 | */ | 74 | */ |
74 | bool is_lvds; | 75 | bool is_lvds; |
75 | 76 | ||
76 | /** | 77 | /** |
78 | * This is sdvo flags for input timing. | ||
79 | */ | ||
80 | uint8_t sdvo_flags; | ||
81 | |||
82 | /** | ||
83 | * This is sdvo fixed pannel mode pointer | ||
84 | */ | ||
85 | struct drm_display_mode *sdvo_lvds_fixed_mode; | ||
86 | |||
87 | /** | ||
77 | * Returned SDTV resolutions allowed for the current format, if the | 88 | * Returned SDTV resolutions allowed for the current format, if the |
78 | * device reported it. | 89 | * device reported it. |
79 | */ | 90 | */ |
@@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output, | |||
592 | uint16_t height) | 603 | uint16_t height) |
593 | { | 604 | { |
594 | struct intel_sdvo_preferred_input_timing_args args; | 605 | struct intel_sdvo_preferred_input_timing_args args; |
606 | struct intel_sdvo_priv *sdvo_priv = output->dev_priv; | ||
595 | uint8_t status; | 607 | uint8_t status; |
596 | 608 | ||
597 | memset(&args, 0, sizeof(args)); | 609 | memset(&args, 0, sizeof(args)); |
@@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output, | |||
599 | args.width = width; | 611 | args.width = width; |
600 | args.height = height; | 612 | args.height = height; |
601 | args.interlace = 0; | 613 | args.interlace = 0; |
602 | args.scaled = 0; | 614 | |
615 | if (sdvo_priv->is_lvds && | ||
616 | (sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width || | ||
617 | sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height)) | ||
618 | args.scaled = 1; | ||
619 | |||
603 | intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, | 620 | intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, |
604 | &args, sizeof(args)); | 621 | &args, sizeof(args)); |
605 | status = intel_sdvo_read_response(output, NULL, 0); | 622 | status = intel_sdvo_read_response(output, NULL, 0); |
@@ -944,12 +961,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, | |||
944 | struct intel_output *output = enc_to_intel_output(encoder); | 961 | struct intel_output *output = enc_to_intel_output(encoder); |
945 | struct intel_sdvo_priv *dev_priv = output->dev_priv; | 962 | struct intel_sdvo_priv *dev_priv = output->dev_priv; |
946 | 963 | ||
947 | if (!dev_priv->is_tv) { | 964 | if (dev_priv->is_tv) { |
948 | /* Make the CRTC code factor in the SDVO pixel multiplier. The | ||
949 | * SDVO device will be told of the multiplier during mode_set. | ||
950 | */ | ||
951 | adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); | ||
952 | } else { | ||
953 | struct intel_sdvo_dtd output_dtd; | 965 | struct intel_sdvo_dtd output_dtd; |
954 | bool success; | 966 | bool success; |
955 | 967 | ||
@@ -980,6 +992,47 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, | |||
980 | intel_sdvo_get_preferred_input_timing(output, | 992 | intel_sdvo_get_preferred_input_timing(output, |
981 | &input_dtd); | 993 | &input_dtd); |
982 | intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); | 994 | intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); |
995 | dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; | ||
996 | |||
997 | drm_mode_set_crtcinfo(adjusted_mode, 0); | ||
998 | |||
999 | mode->clock = adjusted_mode->clock; | ||
1000 | |||
1001 | adjusted_mode->clock *= | ||
1002 | intel_sdvo_get_pixel_multiplier(mode); | ||
1003 | } else { | ||
1004 | return false; | ||
1005 | } | ||
1006 | } else if (dev_priv->is_lvds) { | ||
1007 | struct intel_sdvo_dtd output_dtd; | ||
1008 | bool success; | ||
1009 | |||
1010 | drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0); | ||
1011 | /* Set output timings */ | ||
1012 | intel_sdvo_get_dtd_from_mode(&output_dtd, | ||
1013 | dev_priv->sdvo_lvds_fixed_mode); | ||
1014 | |||
1015 | intel_sdvo_set_target_output(output, | ||
1016 | dev_priv->controlled_output); | ||
1017 | intel_sdvo_set_output_timing(output, &output_dtd); | ||
1018 | |||
1019 | /* Set the input timing to the screen. Assume always input 0. */ | ||
1020 | intel_sdvo_set_target_input(output, true, false); | ||
1021 | |||
1022 | |||
1023 | success = intel_sdvo_create_preferred_input_timing( | ||
1024 | output, | ||
1025 | mode->clock / 10, | ||
1026 | mode->hdisplay, | ||
1027 | mode->vdisplay); | ||
1028 | |||
1029 | if (success) { | ||
1030 | struct intel_sdvo_dtd input_dtd; | ||
1031 | |||
1032 | intel_sdvo_get_preferred_input_timing(output, | ||
1033 | &input_dtd); | ||
1034 | intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); | ||
1035 | dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags; | ||
983 | 1036 | ||
984 | drm_mode_set_crtcinfo(adjusted_mode, 0); | 1037 | drm_mode_set_crtcinfo(adjusted_mode, 0); |
985 | 1038 | ||
@@ -990,6 +1043,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, | |||
990 | } else { | 1043 | } else { |
991 | return false; | 1044 | return false; |
992 | } | 1045 | } |
1046 | |||
1047 | } else { | ||
1048 | /* Make the CRTC code factor in the SDVO pixel multiplier. The | ||
1049 | * SDVO device will be told of the multiplier during mode_set. | ||
1050 | */ | ||
1051 | adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); | ||
993 | } | 1052 | } |
994 | return true; | 1053 | return true; |
995 | } | 1054 | } |
@@ -1033,15 +1092,16 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, | |||
1033 | 1092 | ||
1034 | /* We have tried to get input timing in mode_fixup, and filled into | 1093 | /* We have tried to get input timing in mode_fixup, and filled into |
1035 | adjusted_mode */ | 1094 | adjusted_mode */ |
1036 | if (sdvo_priv->is_tv) | 1095 | if (sdvo_priv->is_tv || sdvo_priv->is_lvds) { |
1037 | intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); | 1096 | intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); |
1038 | else | 1097 | input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags; |
1098 | } else | ||
1039 | intel_sdvo_get_dtd_from_mode(&input_dtd, mode); | 1099 | intel_sdvo_get_dtd_from_mode(&input_dtd, mode); |
1040 | 1100 | ||
1041 | /* If it's a TV, we already set the output timing in mode_fixup. | 1101 | /* If it's a TV, we already set the output timing in mode_fixup. |
1042 | * Otherwise, the output timing is equal to the input timing. | 1102 | * Otherwise, the output timing is equal to the input timing. |
1043 | */ | 1103 | */ |
1044 | if (!sdvo_priv->is_tv) { | 1104 | if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) { |
1045 | /* Set the output timing to the screen */ | 1105 | /* Set the output timing to the screen */ |
1046 | intel_sdvo_set_target_output(output, | 1106 | intel_sdvo_set_target_output(output, |
1047 | sdvo_priv->controlled_output); | 1107 | sdvo_priv->controlled_output); |
@@ -1116,6 +1176,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, | |||
1116 | sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; | 1176 | sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; |
1117 | } | 1177 | } |
1118 | 1178 | ||
1179 | if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL) | ||
1180 | sdvox |= SDVO_STALL_SELECT; | ||
1119 | intel_sdvo_write_sdvox(output, sdvox); | 1181 | intel_sdvo_write_sdvox(output, sdvox); |
1120 | } | 1182 | } |
1121 | 1183 | ||
@@ -1276,6 +1338,17 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, | |||
1276 | if (sdvo_priv->pixel_clock_max < mode->clock) | 1338 | if (sdvo_priv->pixel_clock_max < mode->clock) |
1277 | return MODE_CLOCK_HIGH; | 1339 | return MODE_CLOCK_HIGH; |
1278 | 1340 | ||
1341 | if (sdvo_priv->is_lvds == true) { | ||
1342 | if (sdvo_priv->sdvo_lvds_fixed_mode == NULL) | ||
1343 | return MODE_PANEL; | ||
1344 | |||
1345 | if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay) | ||
1346 | return MODE_PANEL; | ||
1347 | |||
1348 | if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay) | ||
1349 | return MODE_PANEL; | ||
1350 | } | ||
1351 | |||
1279 | return MODE_OK; | 1352 | return MODE_OK; |
1280 | } | 1353 | } |
1281 | 1354 | ||
@@ -1549,6 +1622,8 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) | |||
1549 | { | 1622 | { |
1550 | struct intel_output *intel_output = to_intel_output(connector); | 1623 | struct intel_output *intel_output = to_intel_output(connector); |
1551 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | 1624 | struct drm_i915_private *dev_priv = connector->dev->dev_private; |
1625 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
1626 | struct drm_display_mode *newmode; | ||
1552 | 1627 | ||
1553 | /* | 1628 | /* |
1554 | * Attempt to get the mode list from DDC. | 1629 | * Attempt to get the mode list from DDC. |
@@ -1557,11 +1632,10 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) | |||
1557 | */ | 1632 | */ |
1558 | intel_ddc_get_modes(intel_output); | 1633 | intel_ddc_get_modes(intel_output); |
1559 | if (list_empty(&connector->probed_modes) == false) | 1634 | if (list_empty(&connector->probed_modes) == false) |
1560 | return; | 1635 | goto end; |
1561 | 1636 | ||
1562 | /* Fetch modes from VBT */ | 1637 | /* Fetch modes from VBT */ |
1563 | if (dev_priv->sdvo_lvds_vbt_mode != NULL) { | 1638 | if (dev_priv->sdvo_lvds_vbt_mode != NULL) { |
1564 | struct drm_display_mode *newmode; | ||
1565 | newmode = drm_mode_duplicate(connector->dev, | 1639 | newmode = drm_mode_duplicate(connector->dev, |
1566 | dev_priv->sdvo_lvds_vbt_mode); | 1640 | dev_priv->sdvo_lvds_vbt_mode); |
1567 | if (newmode != NULL) { | 1641 | if (newmode != NULL) { |
@@ -1571,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) | |||
1571 | drm_mode_probed_add(connector, newmode); | 1645 | drm_mode_probed_add(connector, newmode); |
1572 | } | 1646 | } |
1573 | } | 1647 | } |
1648 | |||
1649 | end: | ||
1650 | list_for_each_entry(newmode, &connector->probed_modes, head) { | ||
1651 | if (newmode->type & DRM_MODE_TYPE_PREFERRED) { | ||
1652 | sdvo_priv->sdvo_lvds_fixed_mode = | ||
1653 | drm_mode_duplicate(connector->dev, newmode); | ||
1654 | break; | ||
1655 | } | ||
1656 | } | ||
1657 | |||
1574 | } | 1658 | } |
1575 | 1659 | ||
1576 | static int intel_sdvo_get_modes(struct drm_connector *connector) | 1660 | static int intel_sdvo_get_modes(struct drm_connector *connector) |
@@ -1593,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) | |||
1593 | static void intel_sdvo_destroy(struct drm_connector *connector) | 1677 | static void intel_sdvo_destroy(struct drm_connector *connector) |
1594 | { | 1678 | { |
1595 | struct intel_output *intel_output = to_intel_output(connector); | 1679 | struct intel_output *intel_output = to_intel_output(connector); |
1680 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
1596 | 1681 | ||
1597 | if (intel_output->i2c_bus) | 1682 | if (intel_output->i2c_bus) |
1598 | intel_i2c_destroy(intel_output->i2c_bus); | 1683 | intel_i2c_destroy(intel_output->i2c_bus); |
1599 | if (intel_output->ddc_bus) | 1684 | if (intel_output->ddc_bus) |
1600 | intel_i2c_destroy(intel_output->ddc_bus); | 1685 | intel_i2c_destroy(intel_output->ddc_bus); |
1601 | 1686 | ||
1687 | if (sdvo_priv->sdvo_lvds_fixed_mode != NULL) | ||
1688 | drm_mode_destroy(connector->dev, | ||
1689 | sdvo_priv->sdvo_lvds_fixed_mode); | ||
1690 | |||
1602 | drm_sysfs_connector_remove(connector); | 1691 | drm_sysfs_connector_remove(connector); |
1603 | drm_connector_cleanup(connector); | 1692 | drm_connector_cleanup(connector); |
1693 | |||
1604 | kfree(intel_output); | 1694 | kfree(intel_output); |
1605 | } | 1695 | } |
1606 | 1696 | ||
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 193938b7d7f9..ba5cdf8ae40b 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h | |||
@@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg { | |||
715 | #define SDVO_HBUF_TX_ONCE (2 << 6) | 715 | #define SDVO_HBUF_TX_ONCE (2 << 6) |
716 | #define SDVO_HBUF_TX_VSYNC (3 << 6) | 716 | #define SDVO_HBUF_TX_VSYNC (3 << 6) |
717 | #define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c | 717 | #define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c |
718 | #define SDVO_NEED_TO_STALL (1 << 7) | ||
718 | 719 | ||
719 | struct intel_sdvo_encode{ | 720 | struct intel_sdvo_encode{ |
720 | u8 dvi_rev; | 721 | u8 dvi_rev; |