drm/i915/gvt: Fix virtual display setup for BXT/APL
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / gvt / display.c
index 5b5c71a0b4af5c8bc96e33703e6a88d7a67b28af..5c1fcac260d3b396a298942fb124ab145c6a3b63 100644 (file)
@@ -173,22 +173,162 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
        int pipe;
 
        if (IS_BROXTON(dev_priv)) {
+               enum transcoder trans;
+               enum port port;
+
+               /* Clear PIPE, DDI, PHY, HPD before setting new */
                vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
                        ~(GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) |
                          GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) |
                          GEN8_DE_PORT_HOTPLUG(HPD_PORT_C));
 
+               for_each_pipe(dev_priv, pipe) {
+                       vgpu_vreg_t(vgpu, PIPECONF(pipe)) &=
+                               ~(PIPECONF_ENABLE | I965_PIPECONF_ACTIVE);
+                       vgpu_vreg_t(vgpu, DSPCNTR(pipe)) &= ~DISPLAY_PLANE_ENABLE;
+                       vgpu_vreg_t(vgpu, SPRCTL(pipe)) &= ~SPRITE_ENABLE;
+                       vgpu_vreg_t(vgpu, CURCNTR(pipe)) &= ~MCURSOR_MODE;
+                       vgpu_vreg_t(vgpu, CURCNTR(pipe)) |= MCURSOR_MODE_DISABLE;
+               }
+
+               for (trans = TRANSCODER_A; trans <= TRANSCODER_EDP; trans++) {
+                       vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(trans)) &=
+                               ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
+                                 TRANS_DDI_PORT_MASK | TRANS_DDI_FUNC_ENABLE);
+               }
+               vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) &=
+                       ~(TRANS_DDI_BPC_MASK | TRANS_DDI_MODE_SELECT_MASK |
+                         TRANS_DDI_PORT_MASK);
+
+               for (port = PORT_A; port <= PORT_C; port++) {
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) &=
+                               ~BXT_PHY_LANE_ENABLED;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(port)) |=
+                               (BXT_PHY_CMNLANE_POWERDOWN_ACK |
+                                BXT_PHY_LANE_POWERDOWN_ACK);
+
+                       vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(port)) &=
+                               ~(PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+                                 PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+                                 PORT_PLL_ENABLE);
+
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) &=
+                               ~(DDI_INIT_DISPLAY_DETECTED |
+                                 DDI_BUF_CTL_ENABLE);
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(port)) |= DDI_BUF_IS_IDLE;
+               }
+
+               vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) &= ~(BIT(0) | BIT(1));
+               vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) &=
+                       ~PHY_POWER_GOOD;
+               vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) &=
+                       ~PHY_POWER_GOOD;
+               vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) &= ~BIT(30);
+               vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) &= ~BIT(30);
+
+               vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIB_DETECTED;
+               vgpu_vreg_t(vgpu, SFUSE_STRAP) &= ~SFUSE_STRAP_DDIC_DETECTED;
+
+               /*
+                * Only 1 PIPE enabled in current vGPU display and PIPE_A is
+                *  tied to TRANSCODER_A in HW, so it's safe to assume PIPE_A,
+                *   TRANSCODER_A can be enabled. PORT_x depends on the input of
+                *   setup_virtual_dp_monitor.
+                */
+               vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE;
+               vgpu_vreg_t(vgpu, PIPECONF(PIPE_A)) |= I965_PIPECONF_ACTIVE;
+
+               /*
+                * Golden M/N are calculated based on:
+                *   24 bpp, 4 lanes, 154000 pixel clk (from virtual EDID),
+                *   DP link clk 1620 MHz and non-constant_n.
+                * TODO: calculate DP link symbol clk and stream clk m/n.
+                */
+               vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) = 63 << TU_SIZE_SHIFT;
+               vgpu_vreg_t(vgpu, PIPE_DATA_M1(TRANSCODER_A)) |= 0x5b425e;
+               vgpu_vreg_t(vgpu, PIPE_DATA_N1(TRANSCODER_A)) = 0x800000;
+               vgpu_vreg_t(vgpu, PIPE_LINK_M1(TRANSCODER_A)) = 0x3cd6e;
+               vgpu_vreg_t(vgpu, PIPE_LINK_N1(TRANSCODER_A)) = 0x80000;
+
+               /* Enable per-DDI/PORT vreg */
                if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+                       vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(1);
+                       vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY1)) |=
+                               PHY_POWER_GOOD;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY1)) |=
+                               BIT(30);
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) |=
+                               BXT_PHY_LANE_ENABLED;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_A)) &=
+                               ~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+                                 BXT_PHY_LANE_POWERDOWN_ACK);
+                       vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_A)) |=
+                               (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+                                PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+                                PORT_PLL_ENABLE);
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) |=
+                               (DDI_BUF_CTL_ENABLE | DDI_INIT_DISPLAY_DETECTED);
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_A)) &=
+                               ~DDI_BUF_IS_IDLE;
+                       vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)) |=
+                               (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+                                TRANS_DDI_FUNC_ENABLE);
                        vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
                                GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
                }
 
                if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+                       vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIB_DETECTED;
+                       vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0);
+                       vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |=
+                               PHY_POWER_GOOD;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |=
+                               BIT(30);
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) |=
+                               BXT_PHY_LANE_ENABLED;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_B)) &=
+                               ~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+                                 BXT_PHY_LANE_POWERDOWN_ACK);
+                       vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_B)) |=
+                               (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+                                PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+                                PORT_PLL_ENABLE);
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) |=
+                               DDI_BUF_CTL_ENABLE;
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_B)) &=
+                               ~DDI_BUF_IS_IDLE;
+                       vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
+                               (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+                                (PORT_B << TRANS_DDI_PORT_SHIFT) |
+                                TRANS_DDI_FUNC_ENABLE);
                        vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
                                GEN8_DE_PORT_HOTPLUG(HPD_PORT_B);
                }
 
                if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+                       vgpu_vreg_t(vgpu, SFUSE_STRAP) |= SFUSE_STRAP_DDIC_DETECTED;
+                       vgpu_vreg_t(vgpu, BXT_P_CR_GT_DISP_PWRON) |= BIT(0);
+                       vgpu_vreg_t(vgpu, BXT_PORT_CL1CM_DW0(DPIO_PHY0)) |=
+                               PHY_POWER_GOOD;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL_FAMILY(DPIO_PHY0)) |=
+                               BIT(30);
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) |=
+                               BXT_PHY_LANE_ENABLED;
+                       vgpu_vreg_t(vgpu, BXT_PHY_CTL(PORT_C)) &=
+                               ~(BXT_PHY_CMNLANE_POWERDOWN_ACK |
+                                 BXT_PHY_LANE_POWERDOWN_ACK);
+                       vgpu_vreg_t(vgpu, BXT_PORT_PLL_ENABLE(PORT_C)) |=
+                               (PORT_PLL_POWER_STATE | PORT_PLL_POWER_ENABLE |
+                                PORT_PLL_REF_SEL | PORT_PLL_LOCK |
+                                PORT_PLL_ENABLE);
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) |=
+                               DDI_BUF_CTL_ENABLE;
+                       vgpu_vreg_t(vgpu, DDI_BUF_CTL(PORT_C)) &=
+                               ~DDI_BUF_IS_IDLE;
+                       vgpu_vreg_t(vgpu, TRANS_DDI_FUNC_CTL(TRANSCODER_A)) |=
+                               (TRANS_DDI_BPC_8 | TRANS_DDI_MODE_SELECT_DP_SST |
+                                (PORT_B << TRANS_DDI_PORT_SHIFT) |
+                                TRANS_DDI_FUNC_ENABLE);
                        vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
                                GEN8_DE_PORT_HOTPLUG(HPD_PORT_C);
                }
@@ -520,6 +660,45 @@ void intel_vgpu_emulate_hotplug(struct intel_vgpu *vgpu, bool connected)
                vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
                                PORTD_HOTPLUG_STATUS_MASK;
                intel_vgpu_trigger_virtual_event(vgpu, DP_D_HOTPLUG);
+       } else if (IS_BROXTON(i915)) {
+               if (connected) {
+                       if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+                               vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+                                       GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
+                       }
+                       if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+                               vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
+                                       SFUSE_STRAP_DDIB_DETECTED;
+                               vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+                                       GEN8_DE_PORT_HOTPLUG(HPD_PORT_B);
+                       }
+                       if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+                               vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
+                                       SFUSE_STRAP_DDIC_DETECTED;
+                               vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) |=
+                                       GEN8_DE_PORT_HOTPLUG(HPD_PORT_C);
+                       }
+               } else {
+                       if (intel_vgpu_has_monitor_on_port(vgpu, PORT_A)) {
+                               vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+                                       ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_A);
+                       }
+                       if (intel_vgpu_has_monitor_on_port(vgpu, PORT_B)) {
+                               vgpu_vreg_t(vgpu, SFUSE_STRAP) &=
+                                       ~SFUSE_STRAP_DDIB_DETECTED;
+                               vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+                                       ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_B);
+                       }
+                       if (intel_vgpu_has_monitor_on_port(vgpu, PORT_C)) {
+                               vgpu_vreg_t(vgpu, SFUSE_STRAP) &=
+                                       ~SFUSE_STRAP_DDIC_DETECTED;
+                               vgpu_vreg_t(vgpu, GEN8_DE_PORT_ISR) &=
+                                       ~GEN8_DE_PORT_HOTPLUG(HPD_PORT_C);
+                       }
+               }
+               vgpu_vreg_t(vgpu, PCH_PORT_HOTPLUG) |=
+                       PORTB_HOTPLUG_STATUS_MASK;
+               intel_vgpu_trigger_virtual_event(vgpu, DP_B_HOTPLUG);
        }
 }