@@ -3398,6 +3398,7 @@ extern void intel_i2c_reset(struct drm_device *dev);
/* intel_bios.c */
int intel_bios_init(struct drm_i915_private *dev_priv);
bool intel_bios_is_valid_vbt(const void *buf, size_t size);
+bool intel_bios_is_port_hpd_inverted(struct drm_device *dev, enum port port);
/* intel_opregion.c */
#ifdef CONFIG_ACPI
@@ -36,6 +36,7 @@
#include "i915_drv.h"
#include "i915_trace.h"
#include "intel_drv.h"
+#include "intel_bios.h"
/**
* DOC: interrupt handling
@@ -3506,6 +3507,26 @@ static void bxt_hpd_irq_setup(struct drm_device *dev)
hotplug = I915_READ(PCH_PORT_HOTPLUG);
hotplug |= PORTC_HOTPLUG_ENABLE | PORTB_HOTPLUG_ENABLE |
PORTA_HOTPLUG_ENABLE;
+
+ DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x val:%x\n",
+ hotplug, enabled_irqs, val);
+ hotplug &= ~BXT_DDI_HPD_INVERT_MASK;
+
+ /*
+ * For BXT invert bit has to be set based on AOB design
+ * for HPD detection logic, update it based on VBT fields.
+ */
+
+ if ((enabled_irqs & BXT_DE_PORT_HP_DDIA) &&
+ intel_bios_is_port_hpd_inverted(dev, PORT_A))
+ hotplug |= BXT_DDIA_HPD_INVERT;
+ if ((enabled_irqs & BXT_DE_PORT_HP_DDIB) &&
+ intel_bios_is_port_hpd_inverted(dev, PORT_B))
+ hotplug |= BXT_DDIB_HPD_INVERT;
+ if ((enabled_irqs & BXT_DE_PORT_HP_DDIC) &&
+ intel_bios_is_port_hpd_inverted(dev, PORT_C))
+ hotplug |= BXT_DDIC_HPD_INVERT;
+
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
}
@@ -6212,6 +6212,14 @@ enum skl_disp_power_wells {
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTB_HOTPLUG_LONG_DETECT (2 << 0)
+/* BXT hotplug control */
+#define BXT_DDIA_HPD_INVERT (1 << 27)
+#define BXT_DDIC_HPD_INVERT (1 << 11)
+#define BXT_DDIB_HPD_INVERT (1 << 3)
+#define BXT_DDI_HPD_INVERT_MASK (BXT_DDIA_HPD_INVERT | \
+ BXT_DDIB_HPD_INVERT | \
+ BXT_DDIC_HPD_INVERT)
+
#define PCH_PORT_HOTPLUG2 _MMIO(0xc403C) /* SHOTPLUG_CTL2 SPT+ */
#define PORTE_HOTPLUG_ENABLE (1 << 4)
#define PORTE_HOTPLUG_STATUS_MASK (3 << 0)
@@ -105,6 +105,46 @@ find_section(const void *_bdb, int section_id)
return NULL;
}
+bool
+intel_bios_is_port_hpd_inverted(struct drm_device *dev, enum port port)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+
+ if (!IS_BROXTON(dev)) {
+ DRM_ERROR("Bit inversion is not required in this platform\n");
+ return false;
+ }
+
+ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+
+ if (dev_priv->vbt.child_dev[i].common.hpd_invert == 1) {
+
+ switch (dev_priv->vbt.child_dev[i].common.dvo_port) {
+ case DVO_PORT_DPA:
+ case DVO_PORT_HDMIA:
+ if (port == PORT_A)
+ return true;
+ break;
+ case DVO_PORT_DPB:
+ case DVO_PORT_HDMIB:
+ if (port == PORT_B)
+ return true;
+ break;
+ case DVO_PORT_DPC:
+ case DVO_PORT_HDMIC:
+ if (port == PORT_C)
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
const struct lvds_dvo_timing *dvo_timing)