@@ -3393,6 +3393,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
@@ -3424,6 +3425,47 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
}
+/*
+ * For BXT invert bit has to be set based on AOB design
+ * for HPD detection logic, update it based on VBT fields.
+ */
+static void bxt_hpd_set_invert(struct drm_device *dev, u32 hotplug_port)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int reg_val, val = 0;
+ enum port port;
+
+ for (port = PORT_A; port <= PORT_C; port++) {
+
+ /* Proceed only if invert bit is set */
+ if (intel_bios_is_port_hpd_inverted(dev, port)) {
+ switch (port) {
+ case PORT_A:
+ if (hotplug_port & BXT_DE_PORT_HP_DDIA)
+ val |= BXT_DDIA_HPD_INVERT;
+ break;
+ case PORT_B:
+ if (hotplug_port & BXT_DE_PORT_HP_DDIB)
+ val |= BXT_DDIB_HPD_INVERT;
+ break;
+ case PORT_C:
+ if (hotplug_port & BXT_DE_PORT_HP_DDIC)
+ val |= BXT_DDIC_HPD_INVERT;
+ break;
+ default:
+ DRM_ERROR("HPD invert set for invalid port %d\n",
+ port);
+ break;
+ }
+ }
+ }
+ reg_val = I915_READ(BXT_HOTPLUG_CTL);
+ DRM_DEBUG_KMS("Invert bit setting: hp_ctl:%x hp_port:%x val:%x\n",
+ reg_val, hotplug_port, val);
+ reg_val &= ~BXT_DDI_HPD_INVERT_MASK;
+ I915_WRITE(BXT_HOTPLUG_CTL, reg_val | val);
+}
+
static void spt_hpd_irq_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3494,6 +3536,7 @@ static void bxt_hpd_irq_setup(struct drm_device *dev)
hotplug |= PORTC_HOTPLUG_ENABLE | PORTB_HOTPLUG_ENABLE |
PORTA_HOTPLUG_ENABLE;
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
+ bxt_hpd_set_invert(dev, enabled_irqs);
}
static void ibx_irq_postinstall(struct drm_device *dev)
@@ -5940,6 +5940,15 @@ enum skl_disp_power_wells {
#define GEN8_PCU_IIR _MMIO(0x444e8)
#define GEN8_PCU_IER _MMIO(0x444ec)
+/* BXT hotplug control */
+#define BXT_HOTPLUG_CTL _MMIO(0xC4030)
+#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 ILK_DISPLAY_CHICKEN2 _MMIO(0x42004)
/* Required on all Ironlake and Sandybridge according to the B-Spec. */
#define ILK_ELPIN_409_SELECT (1 << 25)
@@ -105,6 +105,48 @@ 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:
+ DRM_DEBUG_KMS("This dvo port %d doesn't need invert\n",
+ dev_priv->vbt.child_dev[i].common.dvo_port);
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
const struct lvds_dvo_timing *dvo_timing)