Message ID | 1432282962-3530-4-git-send-email-mika.kahola@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, May 22, 2015 at 11:22:33AM +0300, Mika Kahola wrote: > From: Ville Syrjälä <ville.syrjala@linux.intel.com> > > Implement cdclk extraction for g33, 965gm and g4x platforms. The details > came from configdb. Sadly there isn't anything there for other gen3/gen4 > chipsets. > > So far I've tested this on one ELK where it gave me a HPLL VCO of 5333 > MHz and cdclk of 444 MHz which seems perfectly sane for this machine. > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> > > v2: Rebased to the latest > v3: Rebased to the latest > > Reviewed-by: Mika Kahola <mika.kahola@intel.com> > > Author: Ville Syrjälä <ville.syrjala@linux.intel.com> Acked-by: Damien Lespiau <damien.lespiau@intel.com> > --- > drivers/gpu/drm/i915/i915_reg.h | 3 + > drivers/gpu/drm/i915/intel_display.c | 183 ++++++++++++++++++++++++++++++++++- > 2 files changed, 185 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 6625fb3..14366c8 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -2491,6 +2491,9 @@ enum skl_disp_power_wells { > #define CLKCFG_MEM_800 (3 << 4) > #define CLKCFG_MEM_MASK (7 << 4) > > +#define HPLLVCO (MCHBAR_MIRROR_BASE + 0xc38) > +#define HPLLVCO_MOBILE (MCHBAR_MIRROR_BASE + 0xc0f) > + > #define TSC1 0x11001 > #define TSE (1<<0) > #define TR1 0x11006 > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index 4b17aad..86c9140 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -6669,6 +6669,175 @@ static int i830_get_display_clock_speed(struct drm_device *dev) > return 133333; > } > > +static unsigned int intel_hpll_vco(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + static const unsigned int blb_vco[8] = { > + [0] = 3200000, > + [1] = 4000000, > + [2] = 5333333, > + [3] = 4800000, > + [4] = 6400000, > + }; > + static const unsigned int pnv_vco[8] = { > + [0] = 3200000, > + [1] = 4000000, > + [2] = 5333333, > + [3] = 4800000, > + [4] = 2666667, > + }; > + static const unsigned int cl_vco[8] = { > + [0] = 3200000, > + [1] = 4000000, > + [2] = 5333333, > + [3] = 6400000, > + [4] = 3333333, > + [5] = 3566667, > + [6] = 4266667, > + }; > + static const unsigned int elk_vco[8] = { > + [0] = 3200000, > + [1] = 4000000, > + [2] = 5333333, > + [3] = 4800000, > + }; > + static const unsigned int ctg_vco[8] = { > + [0] = 3200000, > + [1] = 4000000, > + [2] = 5333333, > + [3] = 6400000, > + [4] = 2666667, > + [5] = 4266667, > + }; > + const unsigned int *vco_table; > + unsigned int vco; > + uint8_t tmp = 0; > + > + /* FIXME other chipsets? */ > + if (IS_GM45(dev)) > + vco_table = ctg_vco; > + else if (IS_G4X(dev)) > + vco_table = elk_vco; > + else if (IS_CRESTLINE(dev)) > + vco_table = cl_vco; > + else if (IS_PINEVIEW(dev)) > + vco_table = pnv_vco; > + else if (IS_G33(dev)) > + vco_table = blb_vco; > + else > + return 0; > + > + tmp = I915_READ(IS_MOBILE(dev) ? HPLLVCO_MOBILE : HPLLVCO); > + > + vco = vco_table[tmp & 0x7]; > + if (vco == 0) > + DRM_ERROR("Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp); > + else > + DRM_DEBUG_KMS("HPLL VCO %u kHz\n", vco); > + > + return vco; > +} > + > +static int gm45_get_display_clock_speed(struct drm_device *dev) > +{ > + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); > + uint16_t tmp = 0; > + > + pci_read_config_word(dev->pdev, GCFGC, &tmp); > + > + cdclk_sel = (tmp >> 12) & 0x1; > + > + switch (vco) { > + case 2666667: > + case 4000000: > + case 5333333: > + return cdclk_sel ? 333333 : 222222; > + case 3200000: > + return cdclk_sel ? 320000 : 228571; > + default: > + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n", vco, tmp); > + return 222222; > + } > +} > + > +static int i965gm_get_display_clock_speed(struct drm_device *dev) > +{ > + static const uint8_t div_3200[] = { 16, 10, 8 }; > + static const uint8_t div_4000[] = { 20, 12, 10 }; > + static const uint8_t div_5333[] = { 24, 16, 14 }; > + const uint8_t *div_table; > + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); > + uint16_t tmp = 0; > + > + pci_read_config_word(dev->pdev, GCFGC, &tmp); > + > + cdclk_sel = ((tmp >> 8) & 0x1f) - 1; > + > + if (cdclk_sel >= ARRAY_SIZE(div_3200)) > + goto fail; > + > + switch (vco) { > + case 3200000: > + div_table = div_3200; > + break; > + case 4000000: > + div_table = div_4000; > + break; > + case 5333333: > + div_table = div_5333; > + break; > + default: > + goto fail; > + } > + > + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); > + > + fail: > + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp); > + return 200000; > +} > + > +static int g33_get_display_clock_speed(struct drm_device *dev) > +{ > + static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 }; > + static const uint8_t div_4000[] = { 14, 12, 10, 8, 6, 20 }; > + static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 }; > + static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 }; > + const uint8_t *div_table; > + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); > + uint16_t tmp = 0; > + > + pci_read_config_word(dev->pdev, GCFGC, &tmp); > + > + cdclk_sel = (tmp >> 4) & 0x7; > + > + if (cdclk_sel >= ARRAY_SIZE(div_3200)) > + goto fail; > + > + switch (vco) { > + case 3200000: > + div_table = div_3200; > + break; > + case 4000000: > + div_table = div_4000; > + break; > + case 4800000: > + div_table = div_4800; > + break; > + case 5333333: > + div_table = div_5333; > + break; > + default: > + goto fail; > + } > + > + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); > + > + fail: > + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp); > + return 190476; > +} > + > static void > intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) > { > @@ -14196,9 +14365,21 @@ static void intel_init_display(struct drm_device *dev) > dev_priv->display.get_display_clock_speed = > ilk_get_display_clock_speed; > else if (IS_I945G(dev) || IS_BROADWATER(dev) || > - IS_GEN6(dev) || IS_IVYBRIDGE(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) > + IS_GEN6(dev) || IS_IVYBRIDGE(dev)) > dev_priv->display.get_display_clock_speed = > i945_get_display_clock_speed; > + else if (IS_GM45(dev)) > + dev_priv->display.get_display_clock_speed = > + gm45_get_display_clock_speed; > + else if (IS_CRESTLINE(dev)) > + dev_priv->display.get_display_clock_speed = > + i965gm_get_display_clock_speed; > + else if (IS_PINEVIEW(dev)) > + dev_priv->display.get_display_clock_speed = > + pnv_get_display_clock_speed; > + else if (IS_G33(dev) || IS_G4X(dev)) > + dev_priv->display.get_display_clock_speed = > + g33_get_display_clock_speed; > else if (IS_I915G(dev)) > dev_priv->display.get_display_clock_speed = > i915_get_display_clock_speed; > -- > 1.9.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6625fb3..14366c8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2491,6 +2491,9 @@ enum skl_disp_power_wells { #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) +#define HPLLVCO (MCHBAR_MIRROR_BASE + 0xc38) +#define HPLLVCO_MOBILE (MCHBAR_MIRROR_BASE + 0xc0f) + #define TSC1 0x11001 #define TSE (1<<0) #define TR1 0x11006 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4b17aad..86c9140 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6669,6 +6669,175 @@ static int i830_get_display_clock_speed(struct drm_device *dev) return 133333; } +static unsigned int intel_hpll_vco(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + static const unsigned int blb_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + [4] = 6400000, + }; + static const unsigned int pnv_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + [4] = 2666667, + }; + static const unsigned int cl_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 6400000, + [4] = 3333333, + [5] = 3566667, + [6] = 4266667, + }; + static const unsigned int elk_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + }; + static const unsigned int ctg_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 6400000, + [4] = 2666667, + [5] = 4266667, + }; + const unsigned int *vco_table; + unsigned int vco; + uint8_t tmp = 0; + + /* FIXME other chipsets? */ + if (IS_GM45(dev)) + vco_table = ctg_vco; + else if (IS_G4X(dev)) + vco_table = elk_vco; + else if (IS_CRESTLINE(dev)) + vco_table = cl_vco; + else if (IS_PINEVIEW(dev)) + vco_table = pnv_vco; + else if (IS_G33(dev)) + vco_table = blb_vco; + else + return 0; + + tmp = I915_READ(IS_MOBILE(dev) ? HPLLVCO_MOBILE : HPLLVCO); + + vco = vco_table[tmp & 0x7]; + if (vco == 0) + DRM_ERROR("Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp); + else + DRM_DEBUG_KMS("HPLL VCO %u kHz\n", vco); + + return vco; +} + +static int gm45_get_display_clock_speed(struct drm_device *dev) +{ + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = (tmp >> 12) & 0x1; + + switch (vco) { + case 2666667: + case 4000000: + case 5333333: + return cdclk_sel ? 333333 : 222222; + case 3200000: + return cdclk_sel ? 320000 : 228571; + default: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n", vco, tmp); + return 222222; + } +} + +static int i965gm_get_display_clock_speed(struct drm_device *dev) +{ + static const uint8_t div_3200[] = { 16, 10, 8 }; + static const uint8_t div_4000[] = { 20, 12, 10 }; + static const uint8_t div_5333[] = { 24, 16, 14 }; + const uint8_t *div_table; + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = ((tmp >> 8) & 0x1f) - 1; + + if (cdclk_sel >= ARRAY_SIZE(div_3200)) + goto fail; + + switch (vco) { + case 3200000: + div_table = div_3200; + break; + case 4000000: + div_table = div_4000; + break; + case 5333333: + div_table = div_5333; + break; + default: + goto fail; + } + + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); + + fail: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp); + return 200000; +} + +static int g33_get_display_clock_speed(struct drm_device *dev) +{ + static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 }; + static const uint8_t div_4000[] = { 14, 12, 10, 8, 6, 20 }; + static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 }; + static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 }; + const uint8_t *div_table; + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = (tmp >> 4) & 0x7; + + if (cdclk_sel >= ARRAY_SIZE(div_3200)) + goto fail; + + switch (vco) { + case 3200000: + div_table = div_3200; + break; + case 4000000: + div_table = div_4000; + break; + case 4800000: + div_table = div_4800; + break; + case 5333333: + div_table = div_5333; + break; + default: + goto fail; + } + + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); + + fail: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp); + return 190476; +} + static void intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) { @@ -14196,9 +14365,21 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = ilk_get_display_clock_speed; else if (IS_I945G(dev) || IS_BROADWATER(dev) || - IS_GEN6(dev) || IS_IVYBRIDGE(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) + IS_GEN6(dev) || IS_IVYBRIDGE(dev)) dev_priv->display.get_display_clock_speed = i945_get_display_clock_speed; + else if (IS_GM45(dev)) + dev_priv->display.get_display_clock_speed = + gm45_get_display_clock_speed; + else if (IS_CRESTLINE(dev)) + dev_priv->display.get_display_clock_speed = + i965gm_get_display_clock_speed; + else if (IS_PINEVIEW(dev)) + dev_priv->display.get_display_clock_speed = + pnv_get_display_clock_speed; + else if (IS_G33(dev) || IS_G4X(dev)) + dev_priv->display.get_display_clock_speed = + g33_get_display_clock_speed; else if (IS_I915G(dev)) dev_priv->display.get_display_clock_speed = i915_get_display_clock_speed;