Commit d1999e9e authored by Rodrigo Vivi's avatar Rodrigo Vivi

drm/i915/cnl: Allow dynamic cdclk changes on CNL

All the low level cdclk bits are present, so let's add the required
hooks to reconfigure cdclk on the fly.

Cannonlake also needs to adjust the minimal pixel rate
as gen9 platforms. Specially for the Azalia audio case.

v2: Rebase due to cnl_sanitize_cdclk()
v3: Rebased by Rodrigo on top of Ville's cdclk rework.
v4: Rebase moving cnl_calc_cdclk up to follow same order
    as previous platforms.
v2: Squash drm/i915/cnl: Adjust min pixel rate. to address
    the current limitation where CDCLK cannot be set to 168MHz
    if audio is used with 96MHz. (Imre)
v3: adjust some of the clock limits within
    bdw_adjust_min_pipe_pixel_rate. (Ville/DK/Imre).
    Fix commit message messed by squash.

Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Cc: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: default avatarImre Deak <imre.deak@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1497047175-27250-4-git-send-email-rodrigo.vivi@intel.com
parent d8d4a512
......@@ -1400,6 +1400,16 @@ void bxt_uninit_cdclk(struct drm_i915_private *dev_priv)
bxt_set_cdclk(dev_priv, &cdclk_state);
}
static int cnl_calc_cdclk(int max_pixclk)
{
if (max_pixclk > 336000)
return 528000;
else if (max_pixclk > 168000)
return 336000;
else
return 168000;
}
static void cnl_cdclk_pll_update(struct drm_i915_private *dev_priv,
struct intel_cdclk_state *cdclk_state)
{
......@@ -1641,7 +1651,7 @@ void cnl_init_cdclk(struct drm_i915_private *dev_priv)
cdclk_state = dev_priv->cdclk.hw;
cdclk_state.cdclk = 168000;
cdclk_state.cdclk = cnl_calc_cdclk(0);
cdclk_state.vco = cnl_cdclk_pll_vco(dev_priv, cdclk_state.cdclk);
cnl_set_cdclk(dev_priv, &cdclk_state);
......@@ -1722,7 +1732,9 @@ static int bdw_adjust_min_pipe_pixel_rate(struct intel_crtc_state *crtc_state,
crtc_state->has_audio &&
crtc_state->port_clock >= 540000 &&
crtc_state->lane_count == 4) {
if (IS_GEMINILAKE(dev_priv))
if (IS_CANNONLAKE(dev_priv))
pixel_rate = max(316800, pixel_rate);
else if (IS_GEMINILAKE(dev_priv))
pixel_rate = max(2 * 316800, pixel_rate);
else
pixel_rate = max(432000, pixel_rate);
......@@ -1768,7 +1780,7 @@ static int intel_max_pixel_rate(struct drm_atomic_state *state)
pixel_rate = crtc_state->pixel_rate;
if (IS_BROADWELL(dev_priv) || IS_GEN9(dev_priv))
if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9)
pixel_rate =
bdw_adjust_min_pipe_pixel_rate(crtc_state,
pixel_rate);
......@@ -1929,6 +1941,40 @@ static int bxt_modeset_calc_cdclk(struct drm_atomic_state *state)
return 0;
}
static int cnl_modeset_calc_cdclk(struct drm_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->dev);
struct intel_atomic_state *intel_state =
to_intel_atomic_state(state);
int max_pixclk = intel_max_pixel_rate(state);
int cdclk, vco;
cdclk = cnl_calc_cdclk(max_pixclk);
vco = cnl_cdclk_pll_vco(dev_priv, cdclk);
if (cdclk > dev_priv->max_cdclk_freq) {
DRM_DEBUG_KMS("requested cdclk (%d kHz) exceeds max (%d kHz)\n",
cdclk, dev_priv->max_cdclk_freq);
return -EINVAL;
}
intel_state->cdclk.logical.vco = vco;
intel_state->cdclk.logical.cdclk = cdclk;
if (!intel_state->active_crtcs) {
cdclk = cnl_calc_cdclk(0);
vco = cnl_cdclk_pll_vco(dev_priv, cdclk);
intel_state->cdclk.actual.vco = vco;
intel_state->cdclk.actual.cdclk = cdclk;
} else {
intel_state->cdclk.actual =
intel_state->cdclk.logical;
}
return 0;
}
static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
{
int max_cdclk_freq = dev_priv->max_cdclk_freq;
......@@ -1960,7 +2006,9 @@ static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
*/
void intel_update_max_cdclk(struct drm_i915_private *dev_priv)
{
if (IS_GEN9_BC(dev_priv)) {
if (IS_CANNONLAKE(dev_priv)) {
dev_priv->max_cdclk_freq = 528000;
} else if (IS_GEN9_BC(dev_priv)) {
u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK;
int max_cdclk, vco;
......@@ -2157,6 +2205,10 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
dev_priv->display.set_cdclk = skl_set_cdclk;
dev_priv->display.modeset_calc_cdclk =
skl_modeset_calc_cdclk;
} else if (IS_CANNONLAKE(dev_priv)) {
dev_priv->display.set_cdclk = cnl_set_cdclk;
dev_priv->display.modeset_calc_cdclk =
cnl_modeset_calc_cdclk;
}
if (IS_CANNONLAKE(dev_priv))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment