From: Paulo Zanoni <przanoni@gmail.com>
To: intel-gfx@lists.freedesktop.org
Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Subject: [PATCH 2/5] drm/i915: use the HDMI DDI buffer translations from VBT
Date: Thu, 12 Sep 2013 17:06:24 -0300 [thread overview]
Message-ID: <1379016384-1573-1-git-send-email-przanoni@gmail.com> (raw)
In-Reply-To: <CA+gsUGT_4Ds7f5DeMjVGSh3vNtNd31BZz0LwRrUtY5bxpv_9Tw@mail.gmail.com>
From: Paulo Zanoni <paulo.r.zanoni@intel.com>
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>
---
drivers/gpu/drm/i915/i915_drv.h | 6 +++
drivers/gpu/drm/i915/intel_bios.c | 77 +++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_bios.h | 13 +++++++
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 ca8856a..f159df0 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1052,6 +1052,10 @@ enum modeset_restore {
MODESET_SUSPENDED,
};
+struct ddi_vbt_port_info {
+ uint8_t hdmi_level_shift;
+};
+
struct intel_vbt_data {
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -1086,6 +1090,8 @@ struct intel_vbt_data {
int child_dev_num;
union child_device_config *child_dev;
+
+ struct ddi_vbt_port_info ddi_port_info[I915_MAX_PORTS];
};
enum intel_ddb_partitioning {
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 33003b9..2f43429 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)
dev_priv->vbt.dsi.panel_id = mipi->panel_id;
}
+static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
+ struct bdb_header *bdb)
+{
+ union child_device_config *it, *child = NULL;
+ struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port];
+ uint8_t hdmi_level_shift;
+ int i, j;
+ /* Each DDI port can have more than one value on the "DVO Port" field,
+ * so look for all the possible values for each port and abort if more
+ * than one is found. */
+ int dvo_ports[][2] = {
+ {DVO_PORT_HDMIA, DVO_PORT_DPA},
+ {DVO_PORT_HDMIB, DVO_PORT_DPB},
+ {DVO_PORT_HDMIC, DVO_PORT_DPC},
+ {DVO_PORT_HDMID, DVO_PORT_DPD},
+ {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ },
+ };
+
+ /* Find the child device to use, abort if more than one found. */
+ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+ it = dev_priv->vbt.child_dev + i;
+
+ for (j = 0; j < 2; j++) {
+ if (dvo_ports[port][j] == -1)
+ break;
+
+ if (it->common.dvo_port == dvo_ports[port][j]) {
+ if (child) {
+ DRM_DEBUG_KMS("More than one child device for port %c in VBT.\n",
+ port_name(port));
+ return;
+ }
+ child = it;
+ }
+ }
+ }
+ if (!child)
+ return;
+
+ if (bdb->version >= 158) {
+ /* The VBT HDMI level shift values match the table we have. */
+ hdmi_level_shift = child->raw[7] & 0xF;
+ if (hdmi_level_shift < 0xC) {
+ DRM_DEBUG_KMS("VBT HDMI level shift for port %c: %d\n",
+ port_name(port),
+ hdmi_level_shift);
+ info->hdmi_level_shift = hdmi_level_shift;
+ }
+ }
+}
+
+static void parse_ddi_ports(struct drm_i915_private *dev_priv,
+ struct bdb_header *bdb)
+{
+ struct drm_device *dev = dev_priv->dev;
+ enum port port;
+
+ if (!HAS_DDI(dev))
+ return;
+
+ if (!dev_priv->vbt.child_dev_num)
+ return;
+
+ if (bdb->version < 155)
+ return;
+
+ for (port = PORT_A; port < I915_MAX_PORTS; port++)
+ parse_ddi_port(dev_priv, port, bdb);
+}
+
static void
parse_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
@@ -652,6 +722,7 @@ static void
init_vbt_defaults(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
+ enum port port;
dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC;
@@ -670,6 +741,11 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
dev_priv->vbt.lvds_use_ssc = 1;
dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq);
+
+ for (port = PORT_A; port < I915_MAX_PORTS; port++) {
+ /* Recommended BSpec default: 800mV 0dB. */
+ dev_priv->vbt.ddi_port_info[port].hdmi_level_shift = 6;
+ }
}
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)
parse_driver_features(dev_priv, bdb);
parse_edp(dev_priv, bdb);
parse_mipi(dev_priv, bdb);
+ parse_ddi_ports(dev_priv, bdb);
if (bios)
pci_unmap_rom(pdev, bios);
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 1da2bf2..287cc5a 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);
#define PORT_IDPC 8
#define PORT_IDPD 9
+/* Possible values for the "DVO Port" field for versions >= 155: */
+#define DVO_PORT_HDMIA 0
+#define DVO_PORT_HDMIB 1
+#define DVO_PORT_HDMIC 2
+#define DVO_PORT_HDMID 3
+#define DVO_PORT_LVDS 4
+#define DVO_PORT_TV 5
+#define DVO_PORT_CRT 6
+#define DVO_PORT_DPB 7
+#define DVO_PORT_DPC 8
+#define DVO_PORT_DPD 9
+#define DVO_PORT_DPA 10
+
/* MIPI DSI panel info */
struct bdb_mipi {
u16 panel_id;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 6082ab2..a9887eb 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[] = {
0x80C30FFF, 0x000B0000,
0x00FFFFFF, 0x00040006,
0x80D75FFF, 0x000B0000,
- 0x00FFFFFF, 0x00040006 /* HDMI parameters */
};
static const u32 hsw_ddi_translations_fdi[] = {
@@ -55,7 +54,22 @@ static const u32 hsw_ddi_translations_fdi[] = {
0x00C30FFF, 0x001E0000,
0x00FFFFFF, 0x00060006,
0x00D75FFF, 0x001E0000,
- 0x00FFFFFF, 0x00040006 /* HDMI parameters */
+};
+
+static const u32 hsw_ddi_translations_hdmi[] = {
+ /* Idx NT mV diff T mV diff db */
+ 0x00FFFFFF, 0x0006000E, /* 0: 400 400 0 */
+ 0x00E79FFF, 0x000E000C, /* 1: 400 500 2 */
+ 0x00D75FFF, 0x0005000A, /* 2: 400 600 3.5 */
+ 0x00FFFFFF, 0x0005000A, /* 3: 600 600 0 */
+ 0x00E79FFF, 0x001D0007, /* 4: 600 750 2 */
+ 0x00D75FFF, 0x000C0004, /* 5: 600 900 3.5 */
+ 0x00FFFFFF, 0x00040006, /* 6: 800 800 0 */
+ 0x80E79FFF, 0x00030002, /* 7: 800 1000 2 */
+ 0x00FFFFFF, 0x00140005, /* 8: 850 850 0 */
+ 0x00FFFFFF, 0x000C0004, /* 9: 900 900 0 */
+ 0x00FFFFFF, 0x001C0003, /* 10: 950 950 0 */
+ 0x80FFFFFF, 0x00030002, /* 11: 1000 1000 0 */
};
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)
const u32 *ddi_translations = (port == PORT_E) ?
hsw_ddi_translations_fdi :
hsw_ddi_translations_dp;
+ int hdmi_level = dev_priv->vbt.ddi_port_info[port].hdmi_level_shift;
for (i = 0, reg = DDI_BUF_TRANS(port);
i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
I915_WRITE(reg, ddi_translations[i]);
reg += 4;
}
+ /* Entry 9 is for HDMI: */
+ for (i = 0; i < 2; i++) {
+ I915_WRITE(reg, hsw_ddi_translations_hdmi[hdmi_level * 2 + i]);
+ reg += 4;
+ }
}
/* Program DDI buffers translations for DP. By default, program ports A-D in DP
--
1.8.3.1
next prev parent reply other threads:[~2013-09-12 20:06 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-11 21:02 [PATCH 1/5] drm/i915: VBT's child_device_config changes over time Paulo Zanoni
2013-09-11 21:02 ` [PATCH 2/5] drm/i915: use the HDMI DDI buffer translations from VBT Paulo Zanoni
2013-09-11 21:33 ` Chris Wilson
2013-09-12 17:14 ` Paulo Zanoni
2013-09-12 20:06 ` Paulo Zanoni [this message]
2013-09-11 21:02 ` [PATCH 3/5] drm/i915: check the DDC and AUX bits of the VBT on DDI machines Paulo Zanoni
2013-09-11 21:22 ` Chris Wilson
2013-09-12 20:07 ` Paulo Zanoni
2013-09-11 21:02 ` [PATCH 4/5] drm/i915: add some assertions about VBT DDI port types Paulo Zanoni
2013-09-11 21:23 ` Chris Wilson
2013-09-12 20:10 ` Paulo Zanoni
2013-09-11 21:02 ` [PATCH 5/5] drm/i915: don't init DP or HDMI when not supported by DDI port Paulo Zanoni
2013-09-11 21:19 ` Chris Wilson
2013-09-12 20:12 ` Paulo Zanoni
2013-09-20 22:45 ` Daniel Vetter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1379016384-1573-1-git-send-email-przanoni@gmail.com \
--to=przanoni@gmail.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=paulo.r.zanoni@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox