drm/i915/bxt: add display initialize/uninitialize sequence (PHY)
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@intel.com> (v2) Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
f8437dd1b5
commit
5c6706e564
3 changed files with 223 additions and 0 deletions
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue