On Wed, Apr 15, 2015 at 04:42:57PM +0300, Imre Deak wrote: > From: Vandana Kannan <vandana.kannan@xxxxxxxxx> > > Add PHY specific display initialization sequence as per BSpec. > > Note that the PHY initialization/uninitialization are done > at their current place only for simplicity, in a future patch - when more > of the runtime PM features will be enabled - these will be moved to > power well#1 and modeset encoder enabling/disabling hooks respectively. > > The call to uninitialize the PHY during system/runtime suspend will be > added later in this patchset. > > v1: Added function definitions in header files > v2: Imre's review comments addressed > - Moved CDCLK related definitions to i915_reg.h > - Removed defintions for CDCLK frequency > - Split uninit_cdclk() by adding a phy_uninit function > - Calculate freq and decimal based on input frequency > - Program SSA precharge based on input frequency > - Use wait_for 1ms instead 200us udelay for DE PLL locking > - Removed initial value for divider, freq, decimal, ratio. > - Replaced polling loops with wait_for > - Parameterized latency optim setting > - Fix the parts where DE PLL has to be disabled. > - Call CDCLK selection from mode set > > v3: (imre) > - add note about the plan to move the cdclk/phy init to a better place > - take rps.hw_lock around pcode access > - fix DDI PHY timeout value > - squash in Vandana's "PORT_CL2CM_DW6_A BUN fix", > "DDI PHY programming register defn", "Do ddi_phy_init always", > - move PHY register macros next to the corresponding CHV/VLV macros > - move DE PLL register macros here from another patch since they are > used here first > - add BXT_ prefix to CDCLK flags > - s/COMMON_RESET/COMMON_RESET_DIS/ and clarify related code comments > - fix incorrect read value for the RMW of BXT_PHY_CTL_FAMILY_DDI > - fix using GT_DISPLAY_EDP_POWER_ON vs. GT_DISPLAY_DDI_POWER_ON > when powering on DDI ports > - fix incorrect port when setting BXT_PORT_TX_DW14_LN for DDI ports > - add missing masking when programming CDCLK_FREQ_DECIMAL > - add missing powering on for DDI-C port, rename OCL2_LDOFUSE_PWR_EN > to OCL2_LDOFUSE_PWR_DIS to reduce confusion > - add note about mismatch with bspec in the PORT_REF_DW6 fields > - factor out PHY init code to a new function, so we can call it for > PHY1 and PHY0, instead of open-coding the same > > v4: (ville) > - split the CDCLK/PHY parts into two patches, update commit message > accordingly > - use the existing dpio_phy enum instead of adding a new one for the > same purpose > - flip the meaning of PHYs so that PHY_A is PHY1 and PHY_BC is PHY0 to > better match CHV > - s/BXT_PHY/_BXT_PHY/ > - use _PIPE for _BXT_PHY instead of open-coding it > - drop _0_2_0_GTTMMADR suffix from BXT_P_CR_GT_DISP_PWRON > - define GT_DISPLAY_POWER_ON in a more standard way > - make a note that the CHV ConfigDB also disagrees about GRC_CODE field > definitions > - fix lane optimization refactoring fumble from v3 > - add per PHY uninit functions to match the init counterparts > > Signed-off-by: Vandana Kannan <vandana.kannan@xxxxxxxxx> (v2) > Signed-off-by: Imre Deak <imre.deak@xxxxxxxxx> Looking OK. Stuffing some/all of it into a power well and/or into the port enable/disable code may be the right thing to do later, but this should at least get it up and running for now. Reviewed-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/i915_reg.h | 96 ++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/intel_ddi.c | 125 +++++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/intel_drv.h | 2 + > 3 files changed, 223 insertions(+) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index c79bf8d..1903e37 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -1117,6 +1117,102 @@ enum skl_disp_power_wells { > #define DPIO_FRC_LATENCY_SHFIT 8 > #define CHV_TX_DW14(ch, lane) _TXLANE(ch, lane, 0xb8) > #define DPIO_UPAR_SHIFT 30 > + > +/* BXT PHY registers */ > +#define _BXT_PHY(phy, a, b) _PIPE((phy), (a), (b)) > + > +#define BXT_P_CR_GT_DISP_PWRON 0x138090 > +#define GT_DISPLAY_POWER_ON(phy) (1 << (phy)) > + > +#define _PHY_CTL_FAMILY_EDP 0x64C80 > +#define _PHY_CTL_FAMILY_DDI 0x64C90 > +#define COMMON_RESET_DIS (1 << 31) > +#define BXT_PHY_CTL_FAMILY(phy) _BXT_PHY((phy), _PHY_CTL_FAMILY_DDI, \ > + _PHY_CTL_FAMILY_EDP) > + > +/* BXT PHY common lane registers */ > +#define _PORT_CL1CM_DW0_A 0x162000 > +#define _PORT_CL1CM_DW0_BC 0x6C000 > +#define PHY_POWER_GOOD (1 << 16) > +#define BXT_PORT_CL1CM_DW0(phy) _BXT_PHY((phy), _PORT_CL1CM_DW0_BC, \ > + _PORT_CL1CM_DW0_A) > + > +#define _PORT_CL1CM_DW9_A 0x162024 > +#define _PORT_CL1CM_DW9_BC 0x6C024 > +#define IREF0RC_OFFSET_SHIFT 8 > +#define IREF0RC_OFFSET_MASK (0xFF << IREF0RC_OFFSET_SHIFT) > +#define BXT_PORT_CL1CM_DW9(phy) _BXT_PHY((phy), _PORT_CL1CM_DW9_BC, \ > + _PORT_CL1CM_DW9_A) > + > +#define _PORT_CL1CM_DW10_A 0x162028 > +#define _PORT_CL1CM_DW10_BC 0x6C028 > +#define IREF1RC_OFFSET_SHIFT 8 > +#define IREF1RC_OFFSET_MASK (0xFF << IREF1RC_OFFSET_SHIFT) > +#define BXT_PORT_CL1CM_DW10(phy) _BXT_PHY((phy), _PORT_CL1CM_DW10_BC, \ > + _PORT_CL1CM_DW10_A) > + > +#define _PORT_CL1CM_DW28_A 0x162070 > +#define _PORT_CL1CM_DW28_BC 0x6C070 > +#define OCL1_POWER_DOWN_EN (1 << 23) > +#define DW28_OLDO_DYN_PWR_DOWN_EN (1 << 22) > +#define SUS_CLK_CONFIG 0x3 > +#define BXT_PORT_CL1CM_DW28(phy) _BXT_PHY((phy), _PORT_CL1CM_DW28_BC, \ > + _PORT_CL1CM_DW28_A) > + > +#define _PORT_CL1CM_DW30_A 0x162078 > +#define _PORT_CL1CM_DW30_BC 0x6C078 > +#define OCL2_LDOFUSE_PWR_DIS (1 << 6) > +#define BXT_PORT_CL1CM_DW30(phy) _BXT_PHY((phy), _PORT_CL1CM_DW30_BC, \ > + _PORT_CL1CM_DW30_A) > + > +/* Defined for PHY0 only */ > +#define BXT_PORT_CL2CM_DW6_BC 0x6C358 > +#define DW6_OLDO_DYN_PWR_DOWN_EN (1 << 28) > + > +/* BXT PHY Ref registers */ > +#define _PORT_REF_DW3_A 0x16218C > +#define _PORT_REF_DW3_BC 0x6C18C > +#define GRC_DONE (1 << 22) > +#define BXT_PORT_REF_DW3(phy) _BXT_PHY((phy), _PORT_REF_DW3_BC, \ > + _PORT_REF_DW3_A) > + > +#define _PORT_REF_DW6_A 0x162198 > +#define _PORT_REF_DW6_BC 0x6C198 > +/* > + * FIXME: BSpec/CHV ConfigDB disagrees on the following two fields, fix them > + * after testing. > + */ > +#define GRC_CODE_SHIFT 23 > +#define GRC_CODE_MASK (0x1FF << GRC_CODE_SHIFT) > +#define GRC_CODE_FAST_SHIFT 16 > +#define GRC_CODE_FAST_MASK (0x7F << GRC_CODE_FAST_SHIFT) > +#define GRC_CODE_SLOW_SHIFT 8 > +#define GRC_CODE_SLOW_MASK (0xFF << GRC_CODE_SLOW_SHIFT) > +#define GRC_CODE_NOM_MASK 0xFF > +#define BXT_PORT_REF_DW6(phy) _BXT_PHY((phy), _PORT_REF_DW6_BC, \ > + _PORT_REF_DW6_A) > + > +#define _PORT_REF_DW8_A 0x1621A0 > +#define _PORT_REF_DW8_BC 0x6C1A0 > +#define GRC_DIS (1 << 15) > +#define GRC_RDY_OVRD (1 << 1) > +#define BXT_PORT_REF_DW8(phy) _BXT_PHY((phy), _PORT_REF_DW8_BC, \ > + _PORT_REF_DW8_A) > + > +/* BXT PHY TX registers */ > +#define _BXT_LANE_OFFSET(lane) (((lane) >> 1) * 0x200 + \ > + ((lane) & 1) * 0x80) > + > +#define _PORT_TX_DW14_LN0_A 0x162538 > +#define _PORT_TX_DW14_LN0_B 0x6C538 > +#define _PORT_TX_DW14_LN0_C 0x6C938 > +#define LATENCY_OPTIM_SHIFT 30 > +#define LATENCY_OPTIM (1 << LATENCY_OPTIM_SHIFT) > +#define BXT_PORT_TX_DW14_LN(port, lane) (_PORT3((port), _PORT_TX_DW14_LN0_A, \ > + _PORT_TX_DW14_LN0_B, \ > + _PORT_TX_DW14_LN0_C) + \ > + _BXT_LANE_OFFSET(lane)) > + > /* > * Fence registers > */ > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c > index 25d697b..31cadb8 100644 > --- a/drivers/gpu/drm/i915/intel_ddi.c > +++ b/drivers/gpu/drm/i915/intel_ddi.c > @@ -1864,6 +1864,130 @@ static void skl_shared_dplls_init(struct drm_i915_private *dev_priv) > } > } > > +static void broxton_phy_init(struct drm_i915_private *dev_priv, > + enum dpio_phy phy) > +{ > + enum port port; > + uint32_t val; > + > + val = I915_READ(BXT_P_CR_GT_DISP_PWRON); > + val |= GT_DISPLAY_POWER_ON(phy); > + I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val); > + > + /* Considering 10ms timeout until BSpec is updated */ > + if (wait_for(I915_READ(BXT_PORT_CL1CM_DW0(phy)) & PHY_POWER_GOOD, 10)) > + DRM_ERROR("timeout during PHY%d power on\n", phy); > + > + for (port = (phy == DPIO_PHY0 ? PORT_B : PORT_A); > + port <= (phy == DPIO_PHY0 ? PORT_C : PORT_A); port++) { > + int lane; > + > + for (lane = 0; lane < 4; lane++) { > + val = I915_READ(BXT_PORT_TX_DW14_LN(port, lane)); > + /* > + * Note that on CHV this flag is called UPAR, but has > + * the same function. > + */ > + val &= ~LATENCY_OPTIM; > + if (lane != 1) > + val |= LATENCY_OPTIM; > + > + I915_WRITE(BXT_PORT_TX_DW14_LN(port, lane), val); > + } > + } > + > + /* Program PLL Rcomp code offset */ > + val = I915_READ(BXT_PORT_CL1CM_DW9(phy)); > + val &= ~IREF0RC_OFFSET_MASK; > + val |= 0xE4 << IREF0RC_OFFSET_SHIFT; > + I915_WRITE(BXT_PORT_CL1CM_DW9(phy), val); > + > + val = I915_READ(BXT_PORT_CL1CM_DW10(phy)); > + val &= ~IREF1RC_OFFSET_MASK; > + val |= 0xE4 << IREF1RC_OFFSET_SHIFT; > + I915_WRITE(BXT_PORT_CL1CM_DW10(phy), val); > + > + /* Program power gating */ > + val = I915_READ(BXT_PORT_CL1CM_DW28(phy)); > + val |= OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | > + SUS_CLK_CONFIG; > + I915_WRITE(BXT_PORT_CL1CM_DW28(phy), val); > + > + if (phy == DPIO_PHY0) { > + val = I915_READ(BXT_PORT_CL2CM_DW6_BC); > + val |= DW6_OLDO_DYN_PWR_DOWN_EN; > + I915_WRITE(BXT_PORT_CL2CM_DW6_BC, val); > + } > + > + val = I915_READ(BXT_PORT_CL1CM_DW30(phy)); > + val &= ~OCL2_LDOFUSE_PWR_DIS; > + /* > + * On PHY1 disable power on the second channel, since no port is > + * connected there. On PHY0 both channels have a port, so leave it > + * enabled. > + * TODO: port C is only connected on BXT-P, so on BXT0/1 we should > + * power down the second channel on PHY0 as well. > + */ > + if (phy == DPIO_PHY1) > + val |= OCL2_LDOFUSE_PWR_DIS; > + I915_WRITE(BXT_PORT_CL1CM_DW30(phy), val); > + > + if (phy == DPIO_PHY0) { > + uint32_t grc_code; > + /* > + * PHY0 isn't connected to an RCOMP resistor so copy over > + * the corresponding calibrated value from PHY1, and disable > + * the automatic calibration on PHY0. > + */ > + if (wait_for(I915_READ(BXT_PORT_REF_DW3(DPIO_PHY1)) & GRC_DONE, > + 10)) > + DRM_ERROR("timeout waiting for PHY1 GRC\n"); > + > + val = I915_READ(BXT_PORT_REF_DW6(DPIO_PHY1)); > + val = (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT; > + grc_code = val << GRC_CODE_FAST_SHIFT | > + val << GRC_CODE_SLOW_SHIFT | > + val; > + I915_WRITE(BXT_PORT_REF_DW6(DPIO_PHY0), grc_code); > + > + val = I915_READ(BXT_PORT_REF_DW8(DPIO_PHY0)); > + val |= GRC_DIS | GRC_RDY_OVRD; > + I915_WRITE(BXT_PORT_REF_DW8(DPIO_PHY0), val); > + } > + > + val = I915_READ(BXT_PHY_CTL_FAMILY(phy)); > + val |= COMMON_RESET_DIS; > + I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val); > +} > + > +void broxton_ddi_phy_init(struct drm_device *dev) > +{ > + /* Enable PHY1 first since it provides Rcomp for PHY0 */ > + broxton_phy_init(dev->dev_private, DPIO_PHY1); > + broxton_phy_init(dev->dev_private, DPIO_PHY0); > +} > + > +static void broxton_phy_uninit(struct drm_i915_private *dev_priv, > + enum dpio_phy phy) > +{ > + uint32_t val; > + > + val = I915_READ(BXT_PHY_CTL_FAMILY(phy)); > + val &= ~COMMON_RESET_DIS; > + I915_WRITE(BXT_PHY_CTL_FAMILY(phy), val); > +} > + > +void broxton_ddi_phy_uninit(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + broxton_phy_uninit(dev_priv, DPIO_PHY1); > + broxton_phy_uninit(dev_priv, DPIO_PHY0); > + > + /* FIXME: do this in broxton_phy_uninit per phy */ > + I915_WRITE(BXT_P_CR_GT_DISP_PWRON, 0); > +} > + > void intel_ddi_pll_init(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > @@ -1882,6 +2006,7 @@ void intel_ddi_pll_init(struct drm_device *dev) > DRM_ERROR("LCPLL1 is disabled\n"); > } else if (IS_BROXTON(dev)) { > broxton_init_cdclk(dev); > + broxton_ddi_phy_init(dev); > } else { > /* > * The LCPLL register should be turned on by the BIOS. For now > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 5ba88eb..5266985 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -1115,6 +1115,8 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv); > void broxton_init_cdclk(struct drm_device *dev); > void broxton_uninit_cdclk(struct drm_device *dev); > void broxton_set_cdclk(struct drm_device *dev, int frequency); > +void broxton_ddi_phy_init(struct drm_device *dev); > +void broxton_ddi_phy_uninit(struct drm_device *dev); > void intel_dp_get_m_n(struct intel_crtc *crtc, > struct intel_crtc_state *pipe_config); > void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n); > -- > 2.1.0 -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx