mirror of https://gitee.com/openkylin/linux.git
drm/i915/bxt: Define bxt DDI PLLs and implement enable/disable sequence
Plug bxt PLL code into existing shared DPLL framework. v2: (imre) - squash in Satheeshakrishna's "Define BXT clock registers" and "Add state variables for bxt clock registers" patches - squash in Vandanas's "Change grp access to lane access for PLL" - fix group vs. lane access in bxt_ddi_pll_get_hw_state - add code comment why we read from lane registers while writing to group registers - clean up register macros - use BXT_PORT_PLL_* macros instead of open-coding the same - check if BXT_PORT_PCS_DW12_LN01 matches BXT_PORT_PCS_DW12_LN23 during hardware state readout - add missing LANESTAGGER_STRAP_OVRD masking - add note about missing step according to the latest BUN for PORT_PLL_9/lockthresh Signed-off-by: Satheeshakrishna M <satheeshakrishna.m@intel.com> (v1) Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
ff6d9f55fe
commit
dfb8240847
|
@ -303,6 +303,9 @@ struct intel_dpll_hw_state {
|
|||
uint32_t ctrl1;
|
||||
/* HDMI only, 0 when used for DP */
|
||||
uint32_t cfgcr1, cfgcr2;
|
||||
|
||||
/* bxt */
|
||||
uint32_t ebb0, pll0, pll1, pll2, pll3, pll6, pll8, pcsdw12;
|
||||
};
|
||||
|
||||
struct intel_shared_dpll_config {
|
||||
|
|
|
@ -1136,6 +1136,60 @@ enum skl_disp_power_wells {
|
|||
#define BXT_PHY_CTL_FAMILY(phy) _BXT_PHY((phy), _PHY_CTL_FAMILY_DDI, \
|
||||
_PHY_CTL_FAMILY_EDP)
|
||||
|
||||
/* BXT PHY PLL registers */
|
||||
#define _PORT_PLL_A 0x46074
|
||||
#define _PORT_PLL_B 0x46078
|
||||
#define _PORT_PLL_C 0x4607c
|
||||
#define PORT_PLL_ENABLE (1 << 31)
|
||||
#define PORT_PLL_LOCK (1 << 30)
|
||||
#define PORT_PLL_REF_SEL (1 << 27)
|
||||
#define BXT_PORT_PLL_ENABLE(port) _PORT(port, _PORT_PLL_A, _PORT_PLL_B)
|
||||
|
||||
#define _PORT_PLL_EBB_0_A 0x162034
|
||||
#define _PORT_PLL_EBB_0_B 0x6C034
|
||||
#define _PORT_PLL_EBB_0_C 0x6C340
|
||||
#define PORT_PLL_P1_MASK (0x07 << 13)
|
||||
#define PORT_PLL_P1(x) ((x) << 13)
|
||||
#define PORT_PLL_P2_MASK (0x1f << 8)
|
||||
#define PORT_PLL_P2(x) ((x) << 8)
|
||||
#define BXT_PORT_PLL_EBB_0(port) _PORT3(port, _PORT_PLL_EBB_0_A, \
|
||||
_PORT_PLL_EBB_0_B, \
|
||||
_PORT_PLL_EBB_0_C)
|
||||
|
||||
#define _PORT_PLL_EBB_4_A 0x162038
|
||||
#define _PORT_PLL_EBB_4_B 0x6C038
|
||||
#define _PORT_PLL_EBB_4_C 0x6C344
|
||||
#define PORT_PLL_10BIT_CLK_ENABLE (1 << 13)
|
||||
#define PORT_PLL_RECALIBRATE (1 << 14)
|
||||
#define BXT_PORT_PLL_EBB_4(port) _PORT3(port, _PORT_PLL_EBB_4_A, \
|
||||
_PORT_PLL_EBB_4_B, \
|
||||
_PORT_PLL_EBB_4_C)
|
||||
|
||||
#define _PORT_PLL_0_A 0x162100
|
||||
#define _PORT_PLL_0_B 0x6C100
|
||||
#define _PORT_PLL_0_C 0x6C380
|
||||
/* PORT_PLL_0_A */
|
||||
#define PORT_PLL_M2_MASK 0xFF
|
||||
/* PORT_PLL_1_A */
|
||||
#define PORT_PLL_N_MASK (0x0F << 8)
|
||||
#define PORT_PLL_N(x) ((x) << 8)
|
||||
/* PORT_PLL_2_A */
|
||||
#define PORT_PLL_M2_FRAC_MASK 0x3FFFFF
|
||||
/* PORT_PLL_3_A */
|
||||
#define PORT_PLL_M2_FRAC_ENABLE (1 << 16)
|
||||
/* PORT_PLL_6_A */
|
||||
#define PORT_PLL_PROP_COEFF_MASK 0xF
|
||||
#define PORT_PLL_INT_COEFF_MASK (0x1F << 8)
|
||||
#define PORT_PLL_INT_COEFF(x) ((x) << 8)
|
||||
#define PORT_PLL_GAIN_CTL_MASK (0x07 << 16)
|
||||
#define PORT_PLL_GAIN_CTL(x) ((x) << 16)
|
||||
/* PORT_PLL_8_A */
|
||||
#define PORT_PLL_TARGET_CNT_MASK 0x3FF
|
||||
#define _PORT_PLL_BASE(port) _PORT3(port, _PORT_PLL_0_A, \
|
||||
_PORT_PLL_0_B, \
|
||||
_PORT_PLL_0_C)
|
||||
#define BXT_PORT_PLL(port, idx) (_PORT_PLL_BASE(port) + (idx) * 4)
|
||||
|
||||
/* BXT PHY common lane registers */
|
||||
#define _PORT_CL1CM_DW0_A 0x162000
|
||||
#define _PORT_CL1CM_DW0_BC 0x6C000
|
||||
|
@ -1205,6 +1259,28 @@ enum skl_disp_power_wells {
|
|||
#define BXT_PORT_REF_DW8(phy) _BXT_PHY((phy), _PORT_REF_DW8_BC, \
|
||||
_PORT_REF_DW8_A)
|
||||
|
||||
/* BXT PHY PCS registers */
|
||||
#define _PORT_PCS_DW12_LN01_A 0x162430
|
||||
#define _PORT_PCS_DW12_LN01_B 0x6C430
|
||||
#define _PORT_PCS_DW12_LN01_C 0x6C830
|
||||
#define _PORT_PCS_DW12_LN23_A 0x162630
|
||||
#define _PORT_PCS_DW12_LN23_B 0x6C630
|
||||
#define _PORT_PCS_DW12_LN23_C 0x6CA30
|
||||
#define _PORT_PCS_DW12_GRP_A 0x162c30
|
||||
#define _PORT_PCS_DW12_GRP_B 0x6CC30
|
||||
#define _PORT_PCS_DW12_GRP_C 0x6CE30
|
||||
#define LANESTAGGER_STRAP_OVRD (1 << 6)
|
||||
#define LANE_STAGGER_MASK 0x1F
|
||||
#define BXT_PORT_PCS_DW12_LN01(port) _PORT3(port, _PORT_PCS_DW12_LN01_A, \
|
||||
_PORT_PCS_DW12_LN01_B, \
|
||||
_PORT_PCS_DW12_LN01_C)
|
||||
#define BXT_PORT_PCS_DW12_LN23(port) _PORT3(port, _PORT_PCS_DW12_LN23_A, \
|
||||
_PORT_PCS_DW12_LN23_B, \
|
||||
_PORT_PCS_DW12_LN23_C)
|
||||
#define BXT_PORT_PCS_DW12_GRP(port) _PORT3(port, _PORT_PCS_DW12_GRP_A, \
|
||||
_PORT_PCS_DW12_GRP_B, \
|
||||
_PORT_PCS_DW12_GRP_C)
|
||||
|
||||
/* BXT PHY TX registers */
|
||||
#define _BXT_LANE_OFFSET(lane) (((lane) >> 1) * 0x200 + \
|
||||
((lane) & 1) * 0x80)
|
||||
|
|
|
@ -1990,6 +1990,169 @@ void broxton_ddi_phy_uninit(struct drm_device *dev)
|
|||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, 0);
|
||||
}
|
||||
|
||||
static const char * const bxt_ddi_pll_names[] = {
|
||||
"PORT PLL A",
|
||||
"PORT PLL B",
|
||||
"PORT PLL C",
|
||||
};
|
||||
|
||||
static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
uint32_t temp;
|
||||
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
|
||||
|
||||
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
temp &= ~PORT_PLL_REF_SEL;
|
||||
/* Non-SSC reference */
|
||||
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
|
||||
|
||||
/* Disable 10 bit clock */
|
||||
temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
|
||||
temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
|
||||
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
|
||||
|
||||
/* Write P1 & P2 */
|
||||
temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
|
||||
temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
|
||||
temp |= pll->config.hw_state.ebb0;
|
||||
I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
|
||||
|
||||
/* Write M2 integer */
|
||||
temp = I915_READ(BXT_PORT_PLL(port, 0));
|
||||
temp &= ~PORT_PLL_M2_MASK;
|
||||
temp |= pll->config.hw_state.pll0;
|
||||
I915_WRITE(BXT_PORT_PLL(port, 0), temp);
|
||||
|
||||
/* Write N */
|
||||
temp = I915_READ(BXT_PORT_PLL(port, 1));
|
||||
temp &= ~PORT_PLL_N_MASK;
|
||||
temp |= pll->config.hw_state.pll1;
|
||||
I915_WRITE(BXT_PORT_PLL(port, 1), temp);
|
||||
|
||||
/* Write M2 fraction */
|
||||
temp = I915_READ(BXT_PORT_PLL(port, 2));
|
||||
temp &= ~PORT_PLL_M2_FRAC_MASK;
|
||||
temp |= pll->config.hw_state.pll2;
|
||||
I915_WRITE(BXT_PORT_PLL(port, 2), temp);
|
||||
|
||||
/* Write M2 fraction enable */
|
||||
temp = I915_READ(BXT_PORT_PLL(port, 3));
|
||||
temp &= ~PORT_PLL_M2_FRAC_ENABLE;
|
||||
temp |= pll->config.hw_state.pll3;
|
||||
I915_WRITE(BXT_PORT_PLL(port, 3), temp);
|
||||
|
||||
/* Write coeff */
|
||||
temp = I915_READ(BXT_PORT_PLL(port, 6));
|
||||
temp &= ~PORT_PLL_PROP_COEFF_MASK;
|
||||
temp &= ~PORT_PLL_INT_COEFF_MASK;
|
||||
temp &= ~PORT_PLL_GAIN_CTL_MASK;
|
||||
temp |= pll->config.hw_state.pll6;
|
||||
I915_WRITE(BXT_PORT_PLL(port, 6), temp);
|
||||
|
||||
/* Write calibration val */
|
||||
temp = I915_READ(BXT_PORT_PLL(port, 8));
|
||||
temp &= ~PORT_PLL_TARGET_CNT_MASK;
|
||||
temp |= pll->config.hw_state.pll8;
|
||||
I915_WRITE(BXT_PORT_PLL(port, 8), temp);
|
||||
|
||||
/*
|
||||
* FIXME: program PORT_PLL_9/i_lockthresh according to the latest
|
||||
* specification update.
|
||||
*/
|
||||
|
||||
/* Recalibrate with new settings */
|
||||
temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
|
||||
temp |= PORT_PLL_RECALIBRATE;
|
||||
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
|
||||
/* Enable 10 bit clock */
|
||||
temp |= PORT_PLL_10BIT_CLK_ENABLE;
|
||||
I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
|
||||
|
||||
/* Enable PLL */
|
||||
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
temp |= PORT_PLL_ENABLE;
|
||||
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
|
||||
POSTING_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
|
||||
if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
|
||||
PORT_PLL_LOCK), 200))
|
||||
DRM_ERROR("PLL %d not locked\n", port);
|
||||
|
||||
/*
|
||||
* While we write to the group register to program all lanes at once we
|
||||
* can read only lane registers and we pick lanes 0/1 for that.
|
||||
*/
|
||||
temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
|
||||
temp &= ~LANE_STAGGER_MASK;
|
||||
temp &= ~LANESTAGGER_STRAP_OVRD;
|
||||
temp |= pll->config.hw_state.pcsdw12;
|
||||
I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
|
||||
}
|
||||
|
||||
static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
|
||||
uint32_t temp;
|
||||
|
||||
temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
temp &= ~PORT_PLL_ENABLE;
|
||||
I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
|
||||
POSTING_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
}
|
||||
|
||||
static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
|
||||
struct intel_shared_dpll *pll,
|
||||
struct intel_dpll_hw_state *hw_state)
|
||||
{
|
||||
enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
|
||||
uint32_t val;
|
||||
|
||||
if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
|
||||
return false;
|
||||
|
||||
val = I915_READ(BXT_PORT_PLL_ENABLE(port));
|
||||
if (!(val & PORT_PLL_ENABLE))
|
||||
return false;
|
||||
|
||||
hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
|
||||
hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
|
||||
hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
|
||||
hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
|
||||
hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
|
||||
hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
|
||||
hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
|
||||
/*
|
||||
* While we write to the group register to program all lanes at once we
|
||||
* can read only lane registers. We configure all lanes the same way, so
|
||||
* here just read out lanes 0/1 and output a note if lanes 2/3 differ.
|
||||
*/
|
||||
hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
|
||||
if (I915_READ(BXT_PORT_PCS_DW12_LN23(port) != hw_state->pcsdw12))
|
||||
DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
|
||||
hw_state->pcsdw12,
|
||||
I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
dev_priv->num_shared_dpll = 3;
|
||||
|
||||
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
|
||||
dev_priv->shared_dplls[i].id = i;
|
||||
dev_priv->shared_dplls[i].name = bxt_ddi_pll_names[i];
|
||||
dev_priv->shared_dplls[i].disable = bxt_ddi_pll_disable;
|
||||
dev_priv->shared_dplls[i].enable = bxt_ddi_pll_enable;
|
||||
dev_priv->shared_dplls[i].get_hw_state =
|
||||
bxt_ddi_pll_get_hw_state;
|
||||
}
|
||||
}
|
||||
|
||||
void intel_ddi_pll_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -1997,6 +2160,8 @@ void intel_ddi_pll_init(struct drm_device *dev)
|
|||
|
||||
if (IS_SKYLAKE(dev))
|
||||
skl_shared_dplls_init(dev_priv);
|
||||
else if (IS_BROXTON(dev))
|
||||
bxt_shared_dplls_init(dev_priv);
|
||||
else
|
||||
hsw_shared_dplls_init(dev_priv);
|
||||
|
||||
|
|
Loading…
Reference in New Issue