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: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1497047175-27250-4-git-send-email-rodrigo.vivi@intel.com
diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c
index 35a1432..b8914db 100644
--- a/drivers/gpu/drm/i915/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/intel_cdclk.c
@@ -1400,6 +1400,16 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 @@
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))