aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Zanoni <paulo.r.zanoni@intel.com>2013-09-12 16:06:24 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-10-01 01:45:04 -0400
commit6acab15a7b0d2722924c5d671cb29974791beece (patch)
tree5188dbc50100d835c23a9de44d64313c5a2cf5e5
parent768f69c9fe601af39dfeb377f45909896f201444 (diff)
drm/i915: use the HDMI DDI buffer translations from VBT
We currently use the recommended values from BSpec, but the VBT specifies the correct value to use for the hardware we have, so use it. We also fall back to the recommended value in case we can't find the VBT. In addition, this code also provides some infrastructure to parse more information about the DDI ports. There's a lot more information we could extract and use in the future. v2: - Move some code to init_vbt_defaults. v3: - Rebase - Clarify the "DVO Port" matching code v4: - Use I915_MAX_PORTS - Change the HAS_DDI checks - Replace DRM_ERROR with DRM_DEBUG_KMS Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h6
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c77
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h13
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c24
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
1060struct ddi_vbt_port_info {
1061 uint8_t hdmi_level_shift;
1062};
1063
1060struct intel_vbt_data { 1064struct 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
1096enum intel_ddb_partitioning { 1102enum 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
586static 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
637static 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
586static void 656static void
587parse_device_mapping(struct drm_i915_private *dev_priv, 657parse_device_mapping(struct drm_i915_private *dev_priv,
588 struct bdb_header *bdb) 658 struct bdb_header *bdb)
@@ -652,6 +722,7 @@ static void
652init_vbt_defaults(struct drm_i915_private *dev_priv) 722init_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
675static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) 751static 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 */
652struct bdb_mipi { 665struct 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
48static const u32 hsw_ddi_translations_fdi[] = { 47static 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
59static 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
61enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) 75enum 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