• Damien Lespiau's avatar
    drm/i915/skl: Deinit/init the display at suspend/resume · 5d96d8af
    Damien Lespiau authored
    We need to re-init the display hardware when going out of suspend. This
    includes:
    
      - Hooking the PCH to the reset logic
      - Restoring CDCDLK
      - Enabling the DDB power
    
    Among those, only the CDCDLK one is a bit tricky. There's some
    complexity in that:
    
      - DPLL0 (which is the source for CDCLK) has two VCOs, each with a set
        of supported frequencies. As eDP also uses DPLL0 for its link rate,
        once DPLL0 is on, we restrict the possible eDP link rates the chosen
        VCO.
      - CDCLK also limits the bandwidth available to push pixels.
    
    So, as a first step, this commit restore what the BIOS set, until I can
    do more testing.
    
    In case that's of interest for the reviewer, I've unit tested the
    function that derives the decimal frequency field:
    
      #include <stdio.h>
      #include <stdint.h>
      #include <assert.h>
    
      #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
    
      static const struct dpll_freq {
              unsigned int freq;
              unsigned int decimal;
      } freqs[] = {
              { .freq = 308570, .decimal = 0b01001100111},
              { .freq = 337500, .decimal = 0b01010100001},
              { .freq = 432000, .decimal = 0b01101011110},
              { .freq = 450000, .decimal = 0b01110000010},
              { .freq = 540000, .decimal = 0b10000110110},
              { .freq = 617140, .decimal = 0b10011010000},
              { .freq = 675000, .decimal = 0b10101000100},
      };
    
      static void intbits(unsigned int v)
      {
              int i;
    
              for(i = 10; i >= 0; i--)
                      putchar('0' + ((v >> i) & 1));
      }
    
      static unsigned int freq_decimal(unsigned int freq /* in kHz */)
      {
              return (freq - 1000) / 500;
      }
    
      static void test_freq(const struct dpll_freq *entry)
      {
              unsigned int decimal = freq_decimal(entry->freq);
    
              printf("freq: %d, expected: ", entry->freq);
              intbits(entry->decimal);
              printf(", got: ");
              intbits(decimal);
              putchar('\n');
    
              assert(decimal == entry->decimal);
      }
    
      int main(int argc, char **argv)
      {
              int i;
    
              for (i = 0; i < ARRAY_SIZE(freqs); i++)
                      test_freq(&freqs[i]);
    
              return 0;
      }
    
    v2:
      - Rebase on top of -nightly
      - Use (freq - 1000) / 500 for the decimal frequency (Ville)
      - Fix setting the enable bit of HSW_NDE_RSTWRN_OPT (Ville)
      - Rename skl_display_{resume,suspend} to skl_{init,uninit}_cdclk to
        be consistent with the BXT code (Ville)
      - Store boot CDCLK in ddi_pll_init (Ville)
      - Merge dev_priv's skl_boot_cdclk into cdclk_freq
      - Use LCPLL_PLL_LOCK instead of (1 << 30) (Ville)
      - Replace various '0' by SKL_DPLL0 to be a bit more explicit that
        we're programming DPLL0
      - Busy poll the PCU before doing the frequency change. It takes about
        3/4 cycles, each separated by 10us, to get the ACK from the CPU
        (Ville)
    
    v3:
      - Restore dev_priv->skl_boot_cdclk, leaving unification with
        dev_priv->cdclk_freq for a later patch (Daniel, Ville)
    Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
    Signed-off-by: default avatarDamien Lespiau <damien.lespiau@intel.com>
    Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
    5d96d8af
i915_drv.c 49.3 KB