diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_bios.c | 77 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_bios.h | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 24 |
4 files changed, 118 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9868a66ef59c..2eca286b57ff 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -1057,6 +1057,10 @@ enum modeset_restore { | |||
1057 | MODESET_SUSPENDED, | 1057 | MODESET_SUSPENDED, |
1058 | }; | 1058 | }; |
1059 | 1059 | ||
1060 | struct ddi_vbt_port_info { | ||
1061 | uint8_t hdmi_level_shift; | ||
1062 | }; | ||
1063 | |||
1060 | struct intel_vbt_data { | 1064 | struct intel_vbt_data { |
1061 | struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ | 1065 | struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ |
1062 | struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ | 1066 | struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ |
@@ -1091,6 +1095,8 @@ struct intel_vbt_data { | |||
1091 | 1095 | ||
1092 | int child_dev_num; | 1096 | int child_dev_num; |
1093 | union child_device_config *child_dev; | 1097 | union child_device_config *child_dev; |
1098 | |||
1099 | struct ddi_vbt_port_info ddi_port_info[I915_MAX_PORTS]; | ||
1094 | }; | 1100 | }; |
1095 | 1101 | ||
1096 | enum intel_ddb_partitioning { | 1102 | enum intel_ddb_partitioning { |
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 33003b97f1f0..2f434297246e 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c | |||
@@ -583,6 +583,76 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | |||
583 | dev_priv->vbt.dsi.panel_id = mipi->panel_id; | 583 | dev_priv->vbt.dsi.panel_id = mipi->panel_id; |
584 | } | 584 | } |
585 | 585 | ||
586 | static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, | ||
587 | struct bdb_header *bdb) | ||
588 | { | ||
589 | union child_device_config *it, *child = NULL; | ||
590 | struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; | ||
591 | uint8_t hdmi_level_shift; | ||
592 | int i, j; | ||
593 | /* Each DDI port can have more than one value on the "DVO Port" field, | ||
594 | * so look for all the possible values for each port and abort if more | ||
595 | * than one is found. */ | ||
596 | int dvo_ports[][2] = { | ||
597 | {DVO_PORT_HDMIA, DVO_PORT_DPA}, | ||
598 | {DVO_PORT_HDMIB, DVO_PORT_DPB}, | ||
599 | {DVO_PORT_HDMIC, DVO_PORT_DPC}, | ||
600 | {DVO_PORT_HDMID, DVO_PORT_DPD}, | ||
601 | {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, | ||
602 | }; | ||
603 | |||
604 | /* Find the child device to use, abort if more than one found. */ | ||
605 | for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { | ||
606 | it = dev_priv->vbt.child_dev + i; | ||
607 | |||
608 | for (j = 0; j < 2; j++) { | ||
609 | if (dvo_ports[port][j] == -1) | ||
610 | break; | ||
611 | |||
612 | if (it->common.dvo_port == dvo_ports[port][j]) { | ||
613 | if (child) { | ||
614 | DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n", | ||
615 | port_name(port)); | ||
616 | return; | ||
617 | } | ||
618 | child = it; | ||
619 | } | ||
620 | } | ||
621 | } | ||
622 | if (!child) | ||
623 | return; | ||
624 | |||
625 | if (bdb->version >= 158) { | ||
626 | /* The VBT HDMI level shift values match the table we have. */ | ||
627 | hdmi_level_shift = child->raw[7] & 0xF; | ||
628 | if (hdmi_level_shift < 0xC) { | ||
629 | DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n", | ||
630 | port_name(port), | ||
631 | hdmi_level_shift); | ||
632 | info->hdmi_level_shift = hdmi_level_shift; | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | |||
637 | static void parse_ddi_ports(struct drm_i915_private *dev_priv, | ||
638 | struct bdb_header *bdb) | ||
639 | { | ||
640 | struct drm_device *dev = dev_priv->dev; | ||
641 | enum port port; | ||
642 | |||
643 | if (!HAS_DDI(dev)) | ||
644 | return; | ||
645 | |||
646 | if (!dev_priv->vbt.child_dev_num) | ||
647 | return; | ||
648 | |||
649 | if (bdb->version < 155) | ||
650 | return; | ||
651 | |||
652 | for (port = PORT_A; port < I915_MAX_PORTS; port++) | ||
653 | parse_ddi_port(dev_priv, port, bdb); | ||
654 | } | ||
655 | |||
586 | static void | 656 | static void |
587 | parse_device_mapping(struct drm_i915_private *dev_priv, | 657 | parse_device_mapping(struct drm_i915_private *dev_priv, |
588 | struct bdb_header *bdb) | 658 | struct bdb_header *bdb) |
@@ -652,6 +722,7 @@ static void | |||
652 | init_vbt_defaults(struct drm_i915_private *dev_priv) | 722 | init_vbt_defaults(struct drm_i915_private *dev_priv) |
653 | { | 723 | { |
654 | struct drm_device *dev = dev_priv->dev; | 724 | struct drm_device *dev = dev_priv->dev; |
725 | enum port port; | ||
655 | 726 | ||
656 | dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; | 727 | dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC; |
657 | 728 | ||
@@ -670,6 +741,11 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) | |||
670 | dev_priv->vbt.lvds_use_ssc = 1; | 741 | dev_priv->vbt.lvds_use_ssc = 1; |
671 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); | 742 | dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); |
672 | DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); | 743 | DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); |
744 | |||
745 | for (port = PORT_A; port < I915_MAX_PORTS; port++) { | ||
746 | /* Recommended BSpec default: 800mV 0dB. */ | ||
747 | dev_priv->vbt.ddi_port_info[port].hdmi_level_shift = 6; | ||
748 | } | ||
673 | } | 749 | } |
674 | 750 | ||
675 | static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) | 751 | static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) |
@@ -761,6 +837,7 @@ intel_parse_bios(struct drm_device *dev) | |||
761 | parse_driver_features(dev_priv, bdb); | 837 | parse_driver_features(dev_priv, bdb); |
762 | parse_edp(dev_priv, bdb); | 838 | parse_edp(dev_priv, bdb); |
763 | parse_mipi(dev_priv, bdb); | 839 | parse_mipi(dev_priv, bdb); |
840 | parse_ddi_ports(dev_priv, bdb); | ||
764 | 841 | ||
765 | if (bios) | 842 | if (bios) |
766 | pci_unmap_rom(pdev, bios); | 843 | pci_unmap_rom(pdev, bios); |
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 1da2bf208299..287cc5a21c2e 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h | |||
@@ -648,6 +648,19 @@ int intel_parse_bios(struct drm_device *dev); | |||
648 | #define PORT_IDPC 8 | 648 | #define PORT_IDPC 8 |
649 | #define PORT_IDPD 9 | 649 | #define PORT_IDPD 9 |
650 | 650 | ||
651 | /* Possible values for the "DVO Port" field for versions >= 155: */ | ||
652 | #define DVO_PORT_HDMIA 0 | ||
653 | #define DVO_PORT_HDMIB 1 | ||
654 | #define DVO_PORT_HDMIC 2 | ||
655 | #define DVO_PORT_HDMID 3 | ||
656 | #define DVO_PORT_LVDS 4 | ||
657 | #define DVO_PORT_TV 5 | ||
658 | #define DVO_PORT_CRT 6 | ||
659 | #define DVO_PORT_DPB 7 | ||
660 | #define DVO_PORT_DPC 8 | ||
661 | #define DVO_PORT_DPD 9 | ||
662 | #define DVO_PORT_DPA 10 | ||
663 | |||
651 | /* MIPI DSI panel info */ | 664 | /* MIPI DSI panel info */ |
652 | struct bdb_mipi { | 665 | struct bdb_mipi { |
653 | u16 panel_id; | 666 | u16 panel_id; |
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 351e21a0be07..963245a104e4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c | |||
@@ -42,7 +42,6 @@ static const u32 hsw_ddi_translations_dp[] = { | |||
42 | 0x80C30FFF, 0x000B0000, | 42 | 0x80C30FFF, 0x000B0000, |
43 | 0x00FFFFFF, 0x00040006, | 43 | 0x00FFFFFF, 0x00040006, |
44 | 0x80D75FFF, 0x000B0000, | 44 | 0x80D75FFF, 0x000B0000, |
45 | 0x00FFFFFF, 0x00040006 /* HDMI parameters */ | ||
46 | }; | 45 | }; |
47 | 46 | ||
48 | static const u32 hsw_ddi_translations_fdi[] = { | 47 | static const u32 hsw_ddi_translations_fdi[] = { |
@@ -55,7 +54,22 @@ static const u32 hsw_ddi_translations_fdi[] = { | |||
55 | 0x00C30FFF, 0x001E0000, | 54 | 0x00C30FFF, 0x001E0000, |
56 | 0x00FFFFFF, 0x00060006, | 55 | 0x00FFFFFF, 0x00060006, |
57 | 0x00D75FFF, 0x001E0000, | 56 | 0x00D75FFF, 0x001E0000, |
58 | 0x00FFFFFF, 0x00040006 /* HDMI parameters */ | 57 | }; |
58 | |||
59 | static const u32 hsw_ddi_translations_hdmi[] = { | ||
60 | /* Idx NT mV diff T mV diff db */ | ||
61 | 0x00FFFFFF, 0x0006000E, /* 0: 400 400 0 */ | ||
62 | 0x00E79FFF, 0x000E000C, /* 1: 400 500 2 */ | ||
63 | 0x00D75FFF, 0x0005000A, /* 2: 400 600 3.5 */ | ||
64 | 0x00FFFFFF, 0x0005000A, /* 3: 600 600 0 */ | ||
65 | 0x00E79FFF, 0x001D0007, /* 4: 600 750 2 */ | ||
66 | 0x00D75FFF, 0x000C0004, /* 5: 600 900 3.5 */ | ||
67 | 0x00FFFFFF, 0x00040006, /* 6: 800 800 0 */ | ||
68 | 0x80E79FFF, 0x00030002, /* 7: 800 1000 2 */ | ||
69 | 0x00FFFFFF, 0x00140005, /* 8: 850 850 0 */ | ||
70 | 0x00FFFFFF, 0x000C0004, /* 9: 900 900 0 */ | ||
71 | 0x00FFFFFF, 0x001C0003, /* 10: 950 950 0 */ | ||
72 | 0x80FFFFFF, 0x00030002, /* 11: 1000 1000 0 */ | ||
59 | }; | 73 | }; |
60 | 74 | ||
61 | enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) | 75 | enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) |
@@ -92,12 +106,18 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port) | |||
92 | const u32 *ddi_translations = (port == PORT_E) ? | 106 | const u32 *ddi_translations = (port == PORT_E) ? |
93 | hsw_ddi_translations_fdi : | 107 | hsw_ddi_translations_fdi : |
94 | hsw_ddi_translations_dp; | 108 | hsw_ddi_translations_dp; |
109 | int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift; | ||
95 | 110 | ||
96 | for (i = 0, reg = DDI_BUF_TRANS(port); | 111 | for (i = 0, reg = DDI_BUF_TRANS(port); |
97 | i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { | 112 | i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) { |
98 | I915_WRITE(reg, ddi_translations[i]); | 113 | I915_WRITE(reg, ddi_translations[i]); |
99 | reg += 4; | 114 | reg += 4; |
100 | } | 115 | } |
116 | /* Entry 9 is for HDMI: */ | ||
117 | for (i = 0; i < 2; i++) { | ||
118 | I915_WRITE(reg, hsw_ddi_translations_hdmi[hdmi_level * 2 + i]); | ||
119 | reg += 4; | ||
120 | } | ||
101 | } | 121 | } |
102 | 122 | ||
103 | /* Program DDI buffers translations for DP. By default, program ports A-D in DP | 123 | /* Program DDI buffers translations for DP. By default, program ports A-D in DP |