#include <drm/drmP.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
+#include <linux/dmi.h>
#define _INTEL_BIOS_PRIVATE
#include "intel_vbt_defs.h"
bool is_dvi, is_hdmi, is_dp, is_edp, is_crt;
uint8_t aux_channel, ddc_pin;
/* 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. */
+ * so look for all the possible values for each port.
+ */
int dvo_ports[][3] = {
{DVO_PORT_HDMIA, DVO_PORT_DPA, -1},
{DVO_PORT_HDMIB, DVO_PORT_DPB, -1},
{DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE},
};
- /* Find the child device to use, abort if more than one found. */
+ /*
+ * Find the first child device to reference the port, report if more
+ * than one found.
+ */
for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
it = dev_priv->vbt.child_dev + i;
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",
+ DRM_DEBUG_KMS("More than one child device for port %c in VBT, using the first.\n",
port_name(port));
- return;
+ } else {
+ child = it;
}
- child = it;
}
}
}
return;
aux_channel = child->common.aux_channel;
- ddc_pin = child->common.ddc_pin;
is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING;
is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT;
is_hdmi = is_dvi && (child->common.device_type & DEVICE_TYPE_NOT_HDMI_OUTPUT) == 0;
is_edp = is_dp && (child->common.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR);
+ if (port == PORT_A && is_dvi) {
+ DRM_DEBUG_KMS("VBT claims port A supports DVI%s, ignoring\n",
+ is_hdmi ? "/HDMI" : "");
+ is_dvi = false;
+ is_hdmi = false;
+ }
+
info->supports_dvi = is_dvi;
info->supports_hdmi = is_hdmi;
info->supports_dp = is_dp;
DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port));
if (is_dvi) {
- info->alternate_ddc_pin = ddc_pin;
-
- sanitize_ddc_pin(dev_priv, port);
+ ddc_pin = child->common.ddc_pin;
+ if (intel_gmbus_is_valid_pin(dev_priv, ddc_pin)) {
+ info->alternate_ddc_pin = ddc_pin;
+ sanitize_ddc_pin(dev_priv, port);
+ } else {
+ DRM_DEBUG_KMS("Port %c has invalid DDC pin %d, "
+ "sticking to defaults\n",
+ port_name(port), ddc_pin);
+ }
}
if (is_dp) {
{
enum port port;
- if (!HAS_DDI(dev_priv))
+ if (!HAS_DDI(dev_priv) && !IS_CHERRYVIEW(dev_priv))
return;
if (!dev_priv->vbt.child_dev_num)
return NULL;
}
+#define DRM_DMI_PRODUCT_VERSION 0x6
+
+static void parse_product_info(struct drm_i915_private *dev_priv)
+{
+ const char *product_ver = dmi_get_system_info(DRM_DMI_PRODUCT_VERSION);
+ if (!product_ver)
+ return;
+
+ if (!strncmp(product_ver, "ThinkPad X1", 11)) {
+ DRM_DEBUG_KMS("dmi: %s, Bypassing TMDS_OE write\n", product_ver);
+ dev_priv->bypass_tmds_oe = true;
+ }
+
+ return;
+}
+
/**
* intel_bios_init - find VBT and initialize settings from the BIOS
* @dev_priv: i915 device instance
parse_mipi_config(dev_priv, bdb);
parse_mipi_sequence(dev_priv, bdb);
parse_ddi_ports(dev_priv, bdb);
+ parse_product_info(dev_priv);
out:
if (!vbt) {