@@ -1548,6 +1548,35 @@ static void cnl_cdclk_pll_enable(struct drm_i915_private *dev_priv, int vco)
1548
1548
dev_priv -> cdclk .hw .vco = vco ;
1549
1549
}
1550
1550
1551
+ static bool has_cdclk_crawl (struct drm_i915_private * i915 )
1552
+ {
1553
+ return INTEL_INFO (i915 )-> has_cdclk_crawl ;
1554
+ }
1555
+
1556
+ static void adlp_cdclk_pll_crawl (struct drm_i915_private * dev_priv , int vco )
1557
+ {
1558
+ int ratio = DIV_ROUND_CLOSEST (vco , dev_priv -> cdclk .hw .ref );
1559
+ u32 val ;
1560
+
1561
+ /* Write PLL ratio without disabling */
1562
+ val = CNL_CDCLK_PLL_RATIO (ratio ) | BXT_DE_PLL_PLL_ENABLE ;
1563
+ intel_de_write (dev_priv , BXT_DE_PLL_ENABLE , val );
1564
+
1565
+ /* Submit freq change request */
1566
+ val |= BXT_DE_PLL_FREQ_REQ ;
1567
+ intel_de_write (dev_priv , BXT_DE_PLL_ENABLE , val );
1568
+
1569
+ /* Timeout 200us */
1570
+ if (intel_de_wait_for_set (dev_priv , BXT_DE_PLL_ENABLE ,
1571
+ BXT_DE_PLL_LOCK | BXT_DE_PLL_FREQ_REQ_ACK , 1 ))
1572
+ DRM_ERROR ("timeout waiting for FREQ change request ack\n" );
1573
+
1574
+ val &= ~BXT_DE_PLL_FREQ_REQ ;
1575
+ intel_de_write (dev_priv , BXT_DE_PLL_ENABLE , val );
1576
+
1577
+ dev_priv -> cdclk .hw .vco = vco ;
1578
+ }
1579
+
1551
1580
static u32 bxt_cdclk_cd2x_pipe (struct drm_i915_private * dev_priv , enum pipe pipe )
1552
1581
{
1553
1582
if (DISPLAY_VER (dev_priv ) >= 12 ) {
@@ -1620,14 +1649,16 @@ static void bxt_set_cdclk(struct drm_i915_private *dev_priv,
1620
1649
return ;
1621
1650
}
1622
1651
1623
- if (DISPLAY_VER (dev_priv ) >= 11 || IS_CANNONLAKE (dev_priv )) {
1652
+ if (has_cdclk_crawl (dev_priv ) && dev_priv -> cdclk .hw .vco > 0 && vco > 0 ) {
1653
+ if (dev_priv -> cdclk .hw .vco != vco )
1654
+ adlp_cdclk_pll_crawl (dev_priv , vco );
1655
+ } else if (DISPLAY_VER (dev_priv ) >= 11 || IS_CANNONLAKE (dev_priv )) {
1624
1656
if (dev_priv -> cdclk .hw .vco != 0 &&
1625
1657
dev_priv -> cdclk .hw .vco != vco )
1626
1658
cnl_cdclk_pll_disable (dev_priv );
1627
1659
1628
1660
if (dev_priv -> cdclk .hw .vco != vco )
1629
1661
cnl_cdclk_pll_enable (dev_priv , vco );
1630
-
1631
1662
} else {
1632
1663
if (dev_priv -> cdclk .hw .vco != 0 &&
1633
1664
dev_priv -> cdclk .hw .vco != vco )
@@ -1820,6 +1851,28 @@ void intel_cdclk_uninit_hw(struct drm_i915_private *i915)
1820
1851
skl_cdclk_uninit_hw (i915 );
1821
1852
}
1822
1853
1854
+ static bool intel_cdclk_can_crawl (struct drm_i915_private * dev_priv ,
1855
+ const struct intel_cdclk_config * a ,
1856
+ const struct intel_cdclk_config * b )
1857
+ {
1858
+ int a_div , b_div ;
1859
+
1860
+ if (!has_cdclk_crawl (dev_priv ))
1861
+ return false;
1862
+
1863
+ /*
1864
+ * The vco and cd2x divider will change independently
1865
+ * from each, so we disallow cd2x change when crawling.
1866
+ */
1867
+ a_div = DIV_ROUND_CLOSEST (a -> vco , a -> cdclk );
1868
+ b_div = DIV_ROUND_CLOSEST (b -> vco , b -> cdclk );
1869
+
1870
+ return a -> vco != 0 && b -> vco != 0 &&
1871
+ a -> vco != b -> vco &&
1872
+ a_div == b_div &&
1873
+ a -> ref == b -> ref ;
1874
+ }
1875
+
1823
1876
/**
1824
1877
* intel_cdclk_needs_modeset - Determine if changong between the CDCLK
1825
1878
* configurations requires a modeset on all pipes
@@ -2475,7 +2528,7 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
2475
2528
struct drm_i915_private * dev_priv = to_i915 (state -> base .dev );
2476
2529
const struct intel_cdclk_state * old_cdclk_state ;
2477
2530
struct intel_cdclk_state * new_cdclk_state ;
2478
- enum pipe pipe ;
2531
+ enum pipe pipe = INVALID_PIPE ;
2479
2532
int ret ;
2480
2533
2481
2534
new_cdclk_state = intel_atomic_get_cdclk_state (state );
@@ -2527,15 +2580,18 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
2527
2580
2528
2581
if (drm_atomic_crtc_needs_modeset (& crtc_state -> uapi ))
2529
2582
pipe = INVALID_PIPE ;
2530
- } else {
2531
- pipe = INVALID_PIPE ;
2532
2583
}
2533
2584
2534
- if (pipe != INVALID_PIPE ) {
2585
+ if (intel_cdclk_can_crawl (dev_priv ,
2586
+ & old_cdclk_state -> actual ,
2587
+ & new_cdclk_state -> actual )) {
2588
+ drm_dbg_kms (& dev_priv -> drm ,
2589
+ "Can change cdclk via crawl\n" );
2590
+ } else if (pipe != INVALID_PIPE ) {
2535
2591
new_cdclk_state -> pipe = pipe ;
2536
2592
2537
2593
drm_dbg_kms (& dev_priv -> drm ,
2538
- "Can change cdclk with pipe %c active\n" ,
2594
+ "Can change cdclk cd2x divider with pipe %c active\n" ,
2539
2595
pipe_name (pipe ));
2540
2596
} else if (intel_cdclk_needs_modeset (& old_cdclk_state -> actual ,
2541
2597
& new_cdclk_state -> actual )) {
@@ -2544,8 +2600,6 @@ int intel_modeset_calc_cdclk(struct intel_atomic_state *state)
2544
2600
if (ret )
2545
2601
return ret ;
2546
2602
2547
- new_cdclk_state -> pipe = INVALID_PIPE ;
2548
-
2549
2603
drm_dbg_kms (& dev_priv -> drm ,
2550
2604
"Modeset required for cdclk change\n" );
2551
2605
}
0 commit comments