drm/i915/skl: enable DDI-E hotplug
authorXiong Zhang <xiong.y.zhang@intel.com>
Mon, 17 Aug 2015 07:55:50 +0000 (15:55 +0800)
committerJani Nikula <jani.nikula@intel.com>
Wed, 26 Aug 2015 07:24:25 +0000 (10:24 +0300)
v2: fix one error found by checkpath.pl
v3: Add one ignored break for switch-case. DDI-E hotplug
    function doesn't work after updating drm-intel tree,
    I checked the code and found this missing which isn't
    the root cause for broke DDI-E hp.  The broken
    DDI-E hp function is fixed by "Adding DDI_E power
    well domain".

Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Tested-by: Timo Aaltonen <timo.aaltonen@canonical.com>
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_hotplug.c

index 599441beea17e539f13a122ea398923101b1764b..089459b39771195ae91d197fd9da9d81fe174ac4 100644 (file)
@@ -214,6 +214,7 @@ enum hpd_pin {
        HPD_PORT_B,
        HPD_PORT_C,
        HPD_PORT_D,
+       HPD_PORT_E,
        HPD_NUM_PINS
 };
 
index 1118c39281f98cc272b23bcbded120c7ecdd4502..d94c92d842fb9edfc0549257ea1fafb67aa1a820 100644 (file)
@@ -61,6 +61,13 @@ static const u32 hpd_cpt[HPD_NUM_PINS] = {
        [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
 };
 
+static const u32 hpd_spt[HPD_NUM_PINS] = {
+       [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
+       [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
+       [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
+       [HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT
+};
+
 static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_EN,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
@@ -1252,6 +1259,8 @@ static bool pch_port_hotplug_long_detect(enum port port, u32 val)
                return val & PORTC_HOTPLUG_LONG_DETECT;
        case PORT_D:
                return val & PORTD_HOTPLUG_LONG_DETECT;
+       case PORT_E:
+               return val & PORTE_HOTPLUG_LONG_DETECT;
        default:
                return false;
        }
@@ -1752,7 +1761,12 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
-       u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
+       u32 hotplug_trigger;
+
+       if (HAS_PCH_SPT(dev))
+               hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT;
+       else
+               hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
        if (hotplug_trigger) {
                u32 dig_hotplug_reg, pin_mask, long_mask;
@@ -1760,9 +1774,23 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
                dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
                I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
 
-               intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
-                                  dig_hotplug_reg, hpd_cpt,
-                                  pch_port_hotplug_long_detect);
+               if (HAS_PCH_SPT(dev)) {
+                       intel_get_hpd_pins(&pin_mask, &long_mask,
+                                          hotplug_trigger,
+                                          dig_hotplug_reg, hpd_spt,
+                                          pch_port_hotplug_long_detect);
+
+                       /* detect PORTE HP event */
+                       dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
+                       if (pch_port_hotplug_long_detect(PORT_E,
+                                                        dig_hotplug_reg))
+                               long_mask |= 1 << HPD_PORT_E;
+               } else
+                       intel_get_hpd_pins(&pin_mask, &long_mask,
+                                          hotplug_trigger,
+                                          dig_hotplug_reg, hpd_cpt,
+                                          pch_port_hotplug_long_detect);
+
                intel_hpd_irq_handler(dev, pin_mask, long_mask);
        }
 
@@ -2984,6 +3012,11 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
                for_each_intel_encoder(dev, intel_encoder)
                        if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED)
                                enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin];
+       } else if (HAS_PCH_SPT(dev)) {
+               hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
+               for_each_intel_encoder(dev, intel_encoder)
+                       if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED)
+                               enabled_irqs |= hpd_spt[intel_encoder->hpd_pin];
        } else {
                hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
                for_each_intel_encoder(dev, intel_encoder)
@@ -3005,6 +3038,13 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
        hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
        hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
        I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
+
+       /* enable SPT PORTE hot plug */
+       if (HAS_PCH_SPT(dev)) {
+               hotplug = I915_READ(PCH_PORT_HOTPLUG2);
+               hotplug |= PORTE_HOTPLUG_ENABLE;
+               I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
+       }
 }
 
 static void bxt_hpd_irq_setup(struct drm_device *dev)
index 8e46c348366bc867c7b81ed9ccdd72d7bc57c2fc..83a0888756d68402af1c4211b51372edba53f19d 100644 (file)
@@ -5949,6 +5949,7 @@ enum skl_disp_power_wells {
 #define SDE_AUXC_CPT           (1 << 26)
 #define SDE_AUXB_CPT           (1 << 25)
 #define SDE_AUX_MASK_CPT       (7 << 25)
+#define SDE_PORTE_HOTPLUG_SPT  (1 << 25)
 #define SDE_PORTD_HOTPLUG_CPT  (1 << 23)
 #define SDE_PORTC_HOTPLUG_CPT  (1 << 22)
 #define SDE_PORTB_HOTPLUG_CPT  (1 << 21)
@@ -5959,6 +5960,10 @@ enum skl_disp_power_wells {
                                 SDE_PORTD_HOTPLUG_CPT |        \
                                 SDE_PORTC_HOTPLUG_CPT |        \
                                 SDE_PORTB_HOTPLUG_CPT)
+#define SDE_HOTPLUG_MASK_SPT   (SDE_PORTE_HOTPLUG_SPT |        \
+                                SDE_PORTD_HOTPLUG_CPT |        \
+                                SDE_PORTC_HOTPLUG_CPT |        \
+                                SDE_PORTB_HOTPLUG_CPT)
 #define SDE_GMBUS_CPT          (1 << 17)
 #define SDE_ERROR_CPT          (1 << 16)
 #define SDE_AUDIO_CP_REQ_C_CPT (1 << 10)
@@ -6030,6 +6035,13 @@ enum skl_disp_power_wells {
 #define  PORTB_HOTPLUG_SHORT_DETECT    (1 << 0)
 #define  PORTB_HOTPLUG_LONG_DETECT     (2 << 0)
 
+#define PCH_PORT_HOTPLUG2        0xc403C               /* SHOTPLUG_CTL2 */
+#define PORTE_HOTPLUG_ENABLE            (1 << 4)
+#define PORTE_HOTPLUG_STATUS_MASK      (0x3 << 0)
+#define  PORTE_HOTPLUG_NO_DETECT       (0 << 0)
+#define  PORTE_HOTPLUG_SHORT_DETECT    (1 << 0)
+#define  PORTE_HOTPLUG_LONG_DETECT     (2 << 0)
+
 #define PCH_GPIOA               0xc5010
 #define PCH_GPIOB               0xc5014
 #define PCH_GPIOC               0xc5018
index 83936403502fb8a768783dbc5e24cf9f22035d61..53f5476bc4bb88625dbbb824eadd78eb15761b31 100644 (file)
@@ -1098,6 +1098,9 @@ bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
                case PORT_D:
                        bit = SDE_PORTD_HOTPLUG_CPT;
                        break;
+               case PORT_E:
+                       bit = SDE_PORTE_HOTPLUG_SPT;
+                       break;
                default:
                        return true;
                }
index 260ff8b084377728cff7ef80c0b30e14be7bb638..3781cd3e358a786829cb39b242059ee6d2d57671 100644 (file)
@@ -5860,6 +5860,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        case PORT_D:
                intel_encoder->hpd_pin = HPD_PORT_D;
                break;
+       case PORT_E:
+               intel_encoder->hpd_pin = HPD_PORT_E;
+               break;
        default:
                BUG();
        }
index 032a0bf75f3b1d4d7fbbfd44025653865f30ac0b..53c0173a39fe182d5d2e50ac2ffc6637f77526fd 100644 (file)
@@ -91,6 +91,9 @@ bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port)
        case HPD_PORT_D:
                *port = PORT_D;
                return true;
+       case HPD_PORT_E:
+               *port = PORT_E;
+               return true;
        default:
                return false;   /* no hpd */
        }