mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-02 02:56:40 +07:00
drm/i915: Move broxton phy code to intel_dpio_phy.c
The phy in broxton is also a dpio phy, similar to cherryview but with programming through MMIO. So move the code together with the other similar phys. Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> Reviewed-by: Imre Deak <imre.deak@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/d611de6d256593cf904172db7ff27f164480c228.1475770848.git-series.ander.conselvan.de.oliveira@intel.com
This commit is contained in:
parent
b284eedaf7
commit
47a6bc61b8
@ -3761,6 +3761,18 @@ u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg);
|
||||
void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
|
||||
|
||||
/* intel_dpio_phy.c */
|
||||
void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy);
|
||||
void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy);
|
||||
bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy);
|
||||
bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy);
|
||||
uint8_t bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
|
||||
uint8_t lane_count);
|
||||
void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
|
||||
uint8_t lane_lat_optim_mask);
|
||||
uint8_t bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder);
|
||||
|
||||
void chv_set_phy_signal_level(struct intel_encoder *encoder,
|
||||
u32 deemph_reg_value, u32 margin_reg_value,
|
||||
bool uniq_trans_scale);
|
||||
|
@ -1923,332 +1923,14 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder,
|
||||
}
|
||||
}
|
||||
|
||||
bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
enum port port;
|
||||
|
||||
if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & GT_DISPLAY_POWER_ON(phy)))
|
||||
return false;
|
||||
|
||||
if ((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
|
||||
(PHY_POWER_GOOD | PHY_RESERVED)) != PHY_POWER_GOOD) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d powered, but power hasn't settled\n",
|
||||
phy);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (phy == DPIO_PHY1 &&
|
||||
!(I915_READ(BXT_PORT_REF_DW3(DPIO_PHY1)) & GRC_DONE)) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY 1 powered, but GRC isn't done\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(I915_READ(BXT_PHY_CTL_FAMILY(phy)) & COMMON_RESET_DIS)) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d powered, but still in reset\n",
|
||||
phy);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for_each_port_masked(port,
|
||||
phy == DPIO_PHY0 ? BIT(PORT_B) | BIT(PORT_C) :
|
||||
BIT(PORT_A)) {
|
||||
u32 tmp = I915_READ(BXT_PHY_CTL(port));
|
||||
|
||||
if (tmp & BXT_PHY_CMNLANE_POWERDOWN_ACK) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d powered, but common lane "
|
||||
"for port %c powered down "
|
||||
"(PHY_CTL %08x)\n",
|
||||
phy, port_name(port), tmp);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 bxt_get_grc(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
u32 val = I915_READ(BXT_PORT_REF_DW6(phy));
|
||||
|
||||
return (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
|
||||
}
|
||||
|
||||
static void bxt_phy_wait_grc_done(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
if (intel_wait_for_register(dev_priv,
|
||||
BXT_PORT_REF_DW3(phy),
|
||||
GRC_DONE, GRC_DONE,
|
||||
10))
|
||||
DRM_ERROR("timeout waiting for PHY%d GRC\n", phy);
|
||||
}
|
||||
|
||||
void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
|
||||
/* Still read out the GRC value for state verification */
|
||||
if (phy == DPIO_PHY0)
|
||||
dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy);
|
||||
|
||||
if (bxt_ddi_phy_verify_state(dev_priv, phy)) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d already enabled, "
|
||||
"won't reprogram it\n", phy);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d enabled with invalid state, "
|
||||
"force reprogramming it\n", phy);
|
||||
}
|
||||
|
||||
val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
|
||||
val |= GT_DISPLAY_POWER_ON(phy);
|
||||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
|
||||
|
||||
/*
|
||||
* The PHY registers start out inaccessible and respond to reads with
|
||||
* all 1s. Eventually they become accessible as they power up, then
|
||||
* the reserved bit will give the default 0. Poll on the reserved bit
|
||||
* becoming 0 to find when the PHY is accessible.
|
||||
* HW team confirmed that the time to reach phypowergood status is
|
||||
* anywhere between 50 us and 100us.
|
||||
*/
|
||||
if (wait_for_us(((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
|
||||
(PHY_RESERVED | PHY_POWER_GOOD)) == PHY_POWER_GOOD), 100)) {
|
||||
DRM_ERROR("timeout during PHY%d power on\n", phy);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*
|
||||
* FIXME: Clarify programming of the following, the register is
|
||||
* read-only with bit 6 fixed at 0 at least in stepping A.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, DPIO_PHY1);
|
||||
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);
|
||||
|
||||
if (phy == DPIO_PHY1)
|
||||
bxt_phy_wait_grc_done(dev_priv, DPIO_PHY1);
|
||||
}
|
||||
|
||||
void bxt_ddi_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);
|
||||
|
||||
val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
|
||||
val &= ~GT_DISPLAY_POWER_ON(phy);
|
||||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
|
||||
}
|
||||
|
||||
static bool __printf(6, 7)
|
||||
__phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy,
|
||||
i915_reg_t reg, u32 mask, u32 expected,
|
||||
const char *reg_fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
u32 val;
|
||||
|
||||
val = I915_READ(reg);
|
||||
if ((val & mask) == expected)
|
||||
return true;
|
||||
|
||||
va_start(args, reg_fmt);
|
||||
vaf.fmt = reg_fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d reg %pV [%08x] state mismatch: "
|
||||
"current %08x, expected %08x (mask %08x)\n",
|
||||
phy, &vaf, reg.reg, val, (val & ~mask) | expected,
|
||||
mask);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
uint32_t mask;
|
||||
bool ok;
|
||||
|
||||
#define _CHK(reg, mask, exp, fmt, ...) \
|
||||
__phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt, \
|
||||
## __VA_ARGS__)
|
||||
|
||||
if (!bxt_ddi_phy_is_enabled(dev_priv, phy))
|
||||
return false;
|
||||
|
||||
ok = true;
|
||||
|
||||
/* PLL Rcomp code offset */
|
||||
ok &= _CHK(BXT_PORT_CL1CM_DW9(phy),
|
||||
IREF0RC_OFFSET_MASK, 0xe4 << IREF0RC_OFFSET_SHIFT,
|
||||
"BXT_PORT_CL1CM_DW9(%d)", phy);
|
||||
ok &= _CHK(BXT_PORT_CL1CM_DW10(phy),
|
||||
IREF1RC_OFFSET_MASK, 0xe4 << IREF1RC_OFFSET_SHIFT,
|
||||
"BXT_PORT_CL1CM_DW10(%d)", phy);
|
||||
|
||||
/* Power gating */
|
||||
mask = OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | SUS_CLK_CONFIG;
|
||||
ok &= _CHK(BXT_PORT_CL1CM_DW28(phy), mask, mask,
|
||||
"BXT_PORT_CL1CM_DW28(%d)", phy);
|
||||
|
||||
if (phy == DPIO_PHY0)
|
||||
ok &= _CHK(BXT_PORT_CL2CM_DW6_BC,
|
||||
DW6_OLDO_DYN_PWR_DOWN_EN, DW6_OLDO_DYN_PWR_DOWN_EN,
|
||||
"BXT_PORT_CL2CM_DW6_BC");
|
||||
|
||||
/*
|
||||
* TODO: Verify BXT_PORT_CL1CM_DW30 bit OCL2_LDOFUSE_PWR_DIS,
|
||||
* at least on stepping A this bit is read-only and fixed at 0.
|
||||
*/
|
||||
|
||||
if (phy == DPIO_PHY0) {
|
||||
u32 grc_code = dev_priv->bxt_phy_grc;
|
||||
|
||||
grc_code = grc_code << GRC_CODE_FAST_SHIFT |
|
||||
grc_code << GRC_CODE_SLOW_SHIFT |
|
||||
grc_code;
|
||||
mask = GRC_CODE_FAST_MASK | GRC_CODE_SLOW_MASK |
|
||||
GRC_CODE_NOM_MASK;
|
||||
ok &= _CHK(BXT_PORT_REF_DW6(DPIO_PHY0), mask, grc_code,
|
||||
"BXT_PORT_REF_DW6(%d)", DPIO_PHY0);
|
||||
|
||||
mask = GRC_DIS | GRC_RDY_OVRD;
|
||||
ok &= _CHK(BXT_PORT_REF_DW8(DPIO_PHY0), mask, mask,
|
||||
"BXT_PORT_REF_DW8(%d)", DPIO_PHY0);
|
||||
}
|
||||
|
||||
return ok;
|
||||
#undef _CHK
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
|
||||
uint8_t lane_count)
|
||||
{
|
||||
switch (lane_count) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return BIT(2) | BIT(0);
|
||||
case 4:
|
||||
return BIT(3) | BIT(2) | BIT(0);
|
||||
default:
|
||||
MISSING_CASE(lane_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
|
||||
enum port port = dport->port;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
int lane;
|
||||
uint8_t mask = intel_crtc->config->lane_lat_optim_mask;
|
||||
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
u32 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 (intel_crtc->config->lane_lat_optim_mask & BIT(lane))
|
||||
val |= LATENCY_OPTIM;
|
||||
|
||||
I915_WRITE(BXT_PORT_TX_DW14_LN(port, lane), val);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
|
||||
enum port port = dport->port;
|
||||
int lane;
|
||||
uint8_t mask;
|
||||
|
||||
mask = 0;
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
u32 val = I915_READ(BXT_PORT_TX_DW14_LN(port, lane));
|
||||
|
||||
if (val & LATENCY_OPTIM)
|
||||
mask |= BIT(lane);
|
||||
}
|
||||
|
||||
return mask;
|
||||
bxt_ddi_phy_set_lane_optim_mask(encoder, mask);
|
||||
}
|
||||
|
||||
void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
|
||||
|
@ -23,6 +23,333 @@
|
||||
|
||||
#include "intel_drv.h"
|
||||
|
||||
bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
enum port port;
|
||||
|
||||
if (!(I915_READ(BXT_P_CR_GT_DISP_PWRON) & GT_DISPLAY_POWER_ON(phy)))
|
||||
return false;
|
||||
|
||||
if ((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
|
||||
(PHY_POWER_GOOD | PHY_RESERVED)) != PHY_POWER_GOOD) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d powered, but power hasn't settled\n",
|
||||
phy);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (phy == DPIO_PHY1 &&
|
||||
!(I915_READ(BXT_PORT_REF_DW3(DPIO_PHY1)) & GRC_DONE)) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY 1 powered, but GRC isn't done\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(I915_READ(BXT_PHY_CTL_FAMILY(phy)) & COMMON_RESET_DIS)) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d powered, but still in reset\n",
|
||||
phy);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for_each_port_masked(port,
|
||||
phy == DPIO_PHY0 ? BIT(PORT_B) | BIT(PORT_C) :
|
||||
BIT(PORT_A)) {
|
||||
u32 tmp = I915_READ(BXT_PHY_CTL(port));
|
||||
|
||||
if (tmp & BXT_PHY_CMNLANE_POWERDOWN_ACK) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d powered, but common lane "
|
||||
"for port %c powered down "
|
||||
"(PHY_CTL %08x)\n",
|
||||
phy, port_name(port), tmp);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 bxt_get_grc(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
u32 val = I915_READ(BXT_PORT_REF_DW6(phy));
|
||||
|
||||
return (val & GRC_CODE_MASK) >> GRC_CODE_SHIFT;
|
||||
}
|
||||
|
||||
static void bxt_phy_wait_grc_done(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
if (intel_wait_for_register(dev_priv,
|
||||
BXT_PORT_REF_DW3(phy),
|
||||
GRC_DONE, GRC_DONE,
|
||||
10))
|
||||
DRM_ERROR("timeout waiting for PHY%d GRC\n", phy);
|
||||
}
|
||||
|
||||
void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (bxt_ddi_phy_is_enabled(dev_priv, phy)) {
|
||||
/* Still read out the GRC value for state verification */
|
||||
if (phy == DPIO_PHY0)
|
||||
dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, phy);
|
||||
|
||||
if (bxt_ddi_phy_verify_state(dev_priv, phy)) {
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d already enabled, "
|
||||
"won't reprogram it\n", phy);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d enabled with invalid state, "
|
||||
"force reprogramming it\n", phy);
|
||||
}
|
||||
|
||||
val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
|
||||
val |= GT_DISPLAY_POWER_ON(phy);
|
||||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
|
||||
|
||||
/*
|
||||
* The PHY registers start out inaccessible and respond to reads with
|
||||
* all 1s. Eventually they become accessible as they power up, then
|
||||
* the reserved bit will give the default 0. Poll on the reserved bit
|
||||
* becoming 0 to find when the PHY is accessible.
|
||||
* HW team confirmed that the time to reach phypowergood status is
|
||||
* anywhere between 50 us and 100us.
|
||||
*/
|
||||
if (wait_for_us(((I915_READ(BXT_PORT_CL1CM_DW0(phy)) &
|
||||
(PHY_RESERVED | PHY_POWER_GOOD)) == PHY_POWER_GOOD), 100)) {
|
||||
DRM_ERROR("timeout during PHY%d power on\n", phy);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*
|
||||
* FIXME: Clarify programming of the following, the register is
|
||||
* read-only with bit 6 fixed at 0 at least in stepping A.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
val = dev_priv->bxt_phy_grc = bxt_get_grc(dev_priv, DPIO_PHY1);
|
||||
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);
|
||||
|
||||
if (phy == DPIO_PHY1)
|
||||
bxt_phy_wait_grc_done(dev_priv, DPIO_PHY1);
|
||||
}
|
||||
|
||||
void bxt_ddi_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);
|
||||
|
||||
val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
|
||||
val &= ~GT_DISPLAY_POWER_ON(phy);
|
||||
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, val);
|
||||
}
|
||||
|
||||
static bool __printf(6, 7)
|
||||
__phy_reg_verify_state(struct drm_i915_private *dev_priv, enum dpio_phy phy,
|
||||
i915_reg_t reg, u32 mask, u32 expected,
|
||||
const char *reg_fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
u32 val;
|
||||
|
||||
val = I915_READ(reg);
|
||||
if ((val & mask) == expected)
|
||||
return true;
|
||||
|
||||
va_start(args, reg_fmt);
|
||||
vaf.fmt = reg_fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
DRM_DEBUG_DRIVER("DDI PHY %d reg %pV [%08x] state mismatch: "
|
||||
"current %08x, expected %08x (mask %08x)\n",
|
||||
phy, &vaf, reg.reg, val, (val & ~mask) | expected,
|
||||
mask);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy)
|
||||
{
|
||||
uint32_t mask;
|
||||
bool ok;
|
||||
|
||||
#define _CHK(reg, mask, exp, fmt, ...) \
|
||||
__phy_reg_verify_state(dev_priv, phy, reg, mask, exp, fmt, \
|
||||
## __VA_ARGS__)
|
||||
|
||||
if (!bxt_ddi_phy_is_enabled(dev_priv, phy))
|
||||
return false;
|
||||
|
||||
ok = true;
|
||||
|
||||
/* PLL Rcomp code offset */
|
||||
ok &= _CHK(BXT_PORT_CL1CM_DW9(phy),
|
||||
IREF0RC_OFFSET_MASK, 0xe4 << IREF0RC_OFFSET_SHIFT,
|
||||
"BXT_PORT_CL1CM_DW9(%d)", phy);
|
||||
ok &= _CHK(BXT_PORT_CL1CM_DW10(phy),
|
||||
IREF1RC_OFFSET_MASK, 0xe4 << IREF1RC_OFFSET_SHIFT,
|
||||
"BXT_PORT_CL1CM_DW10(%d)", phy);
|
||||
|
||||
/* Power gating */
|
||||
mask = OCL1_POWER_DOWN_EN | DW28_OLDO_DYN_PWR_DOWN_EN | SUS_CLK_CONFIG;
|
||||
ok &= _CHK(BXT_PORT_CL1CM_DW28(phy), mask, mask,
|
||||
"BXT_PORT_CL1CM_DW28(%d)", phy);
|
||||
|
||||
if (phy == DPIO_PHY0)
|
||||
ok &= _CHK(BXT_PORT_CL2CM_DW6_BC,
|
||||
DW6_OLDO_DYN_PWR_DOWN_EN, DW6_OLDO_DYN_PWR_DOWN_EN,
|
||||
"BXT_PORT_CL2CM_DW6_BC");
|
||||
|
||||
/*
|
||||
* TODO: Verify BXT_PORT_CL1CM_DW30 bit OCL2_LDOFUSE_PWR_DIS,
|
||||
* at least on stepping A this bit is read-only and fixed at 0.
|
||||
*/
|
||||
|
||||
if (phy == DPIO_PHY0) {
|
||||
u32 grc_code = dev_priv->bxt_phy_grc;
|
||||
|
||||
grc_code = grc_code << GRC_CODE_FAST_SHIFT |
|
||||
grc_code << GRC_CODE_SLOW_SHIFT |
|
||||
grc_code;
|
||||
mask = GRC_CODE_FAST_MASK | GRC_CODE_SLOW_MASK |
|
||||
GRC_CODE_NOM_MASK;
|
||||
ok &= _CHK(BXT_PORT_REF_DW6(DPIO_PHY0), mask, grc_code,
|
||||
"BXT_PORT_REF_DW6(%d)", DPIO_PHY0);
|
||||
|
||||
mask = GRC_DIS | GRC_RDY_OVRD;
|
||||
ok &= _CHK(BXT_PORT_REF_DW8(DPIO_PHY0), mask, mask,
|
||||
"BXT_PORT_REF_DW8(%d)", DPIO_PHY0);
|
||||
}
|
||||
|
||||
return ok;
|
||||
#undef _CHK
|
||||
}
|
||||
|
||||
uint8_t
|
||||
bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
|
||||
uint8_t lane_count)
|
||||
{
|
||||
switch (lane_count) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return BIT(2) | BIT(0);
|
||||
case 4:
|
||||
return BIT(3) | BIT(2) | BIT(0);
|
||||
default:
|
||||
MISSING_CASE(lane_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bxt_ddi_phy_set_lane_optim_mask(struct intel_encoder *encoder,
|
||||
uint8_t lane_lat_optim_mask)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
|
||||
enum port port = dport->port;
|
||||
int lane;
|
||||
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
u32 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_lat_optim_mask & BIT(lane))
|
||||
val |= LATENCY_OPTIM;
|
||||
|
||||
I915_WRITE(BXT_PORT_TX_DW14_LN(port, lane), val);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t
|
||||
bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
|
||||
enum port port = dport->port;
|
||||
int lane;
|
||||
uint8_t mask;
|
||||
|
||||
mask = 0;
|
||||
for (lane = 0; lane < 4; lane++) {
|
||||
u32 val = I915_READ(BXT_PORT_TX_DW14_LN(port, lane));
|
||||
|
||||
if (val & LATENCY_OPTIM)
|
||||
mask |= BIT(lane);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
void chv_set_phy_signal_level(struct intel_encoder *encoder,
|
||||
u32 deemph_reg_value, u32 margin_reg_value,
|
||||
bool uniq_trans_scale)
|
||||
|
@ -1351,12 +1351,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv);
|
||||
void hsw_disable_pc8(struct drm_i915_private *dev_priv);
|
||||
void bxt_init_cdclk(struct drm_i915_private *dev_priv);
|
||||
void bxt_uninit_cdclk(struct drm_i915_private *dev_priv);
|
||||
void bxt_ddi_phy_init(struct drm_i915_private *dev_priv, enum dpio_phy phy);
|
||||
void bxt_ddi_phy_uninit(struct drm_i915_private *dev_priv, enum dpio_phy phy);
|
||||
bool bxt_ddi_phy_is_enabled(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy);
|
||||
bool bxt_ddi_phy_verify_state(struct drm_i915_private *dev_priv,
|
||||
enum dpio_phy phy);
|
||||
void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv);
|
||||
void bxt_enable_dc9(struct drm_i915_private *dev_priv);
|
||||
void bxt_disable_dc9(struct drm_i915_private *dev_priv);
|
||||
|
Loading…
Reference in New Issue
Block a user