diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_i2c.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_i2c.c | 62 |
1 files changed, 55 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d1c1e0f7f26..d33b61d0dd3 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -34,6 +34,11 @@ #include <drm/i915_drm.h> #include "i915_drv.h" +enum disp_clk { + CDCLK, + CZCLK +}; + struct gmbus_port { const char *name; int reg; @@ -58,10 +63,60 @@ to_intel_gmbus(struct i2c_adapter *i2c) return container_of(i2c, struct intel_gmbus, adapter); } +static int get_disp_clk_div(struct drm_i915_private *dev_priv, + enum disp_clk clk) +{ + u32 reg_val; + int clk_ratio; + + reg_val = I915_READ(CZCLK_CDCLK_FREQ_RATIO); + + if (clk == CDCLK) + clk_ratio = + ((reg_val & CDCLK_FREQ_MASK) >> CDCLK_FREQ_SHIFT) + 1; + else + clk_ratio = (reg_val & CZCLK_FREQ_MASK) + 1; + + return clk_ratio; +} + +static void gmbus_set_freq(struct drm_i915_private *dev_priv) +{ + int vco, gmbus_freq = 0, cdclk_div; + + BUG_ON(!IS_VALLEYVIEW(dev_priv->dev)); + + vco = valleyview_get_vco(dev_priv); + + /* Get the CDCLK divide ratio */ + cdclk_div = get_disp_clk_div(dev_priv, CDCLK); + + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + if (cdclk_div) + gmbus_freq = (vco << 1) / cdclk_div; + + if (WARN_ON(gmbus_freq == 0)) + return; + + I915_WRITE(GMBUSFREQ_VLV, gmbus_freq); +} + void intel_i2c_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * In BIOS-less system, program the correct gmbus frequency + * before reading edid. + */ + if (IS_VALLEYVIEW(dev)) + gmbus_set_freq(dev_priv); + I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0); } @@ -203,13 +258,6 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) algo->data = bus; } -/* - * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI - * mode. This results in spurious interrupt warnings if the legacy irq no. is - * shared with another device. The kernel then disables that interrupt source - * and so prevents the other device from working properly. - */ -#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) static int gmbus_wait_hw_status(struct drm_i915_private *dev_priv, u32 gmbus2_status, |