diff mbox

drm/i915: Enable VLV to work in BIOS-less system

Message ID 1379044785-13193-1-git-send-email-chon.ming.lee@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Chon Ming Lee Sept. 13, 2013, 3:59 a.m. UTC
In non PC system, such as IVI, may not use BIOS, instead it uses boot
loader with only minimal system initialization.  Most of the time, boot
loader doesn't come with VBIOS, and depends on device driver to fully
initialize the display controller and GPU.

For Valleyview, without VBIOS, i915 fails to work.  The patch add some
missing init code, such as doing a DPIO CMNRESET and program the GMBUS
frequency.

Signed-off-by: Chon Ming Lee <chon.ming.lee@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h      |    8 +++++
 drivers/gpu/drm/i915/intel_display.c |   51 ++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 0 deletions(-)

Comments

Daniel Vetter Sept. 12, 2013, 4:30 p.m. UTC | #1
On Fri, Sep 13, 2013 at 5:59 AM, Chon Ming Lee <chon.ming.lee@intel.com> wrote:
> In non PC system, such as IVI, may not use BIOS, instead it uses boot
> loader with only minimal system initialization.  Most of the time, boot
> loader doesn't come with VBIOS, and depends on device driver to fully
> initialize the display controller and GPU.
>
> For Valleyview, without VBIOS, i915 fails to work.  The patch add some
> missing init code, such as doing a DPIO CMNRESET and program the GMBUS
> frequency.
>
> Signed-off-by: Chon Ming Lee <chon.ming.lee@intel.com>

Generally I prefer patches with tighter topics, grouped into a series.
For this one I'd split it up into the gmbus setup and the dpio reset,
so 2 patches.

> ---
>  drivers/gpu/drm/i915/i915_reg.h      |    8 +++++
>  drivers/gpu/drm/i915/intel_display.c |   51 ++++++++++++++++++++++++++++++++++
>  2 files changed, 59 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index bcee89b..8ddf58a 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -382,6 +382,8 @@
>  #define   FB_FMAX_VMIN_FREQ_LO_MASK            0xf8000000
>
>  /* vlv2 north clock has */
> +#define CCK_FUSE_REG                           0x8
> +#define  CCK_FUSE_HPLL_FREQ_MASK               0x3
>  #define CCK_REG_DSI_PLL_FUSE                   0x44
>  #define CCK_REG_DSI_PLL_CONTROL                        0x48
>  #define  DSI_PLL_VCO_EN                                (1 << 31)
> @@ -1424,6 +1426,12 @@
>
>  #define MI_ARB_VLV             (VLV_DISPLAY_BASE + 0x6504)
>
> +#define CZCLK_CDCLK_FREQ_RATIO (dev_priv->info->display_mmio_offset + 0x6508)
> +#define   CDCLK_FREQ_SHIFT     4
> +#define   CDCLK_FREQ_MASK      0x1f
> +#define   CZCLK_FREQ_MASK      0xf
> +#define GMBUS_FREQ             (dev_priv->info->display_mmio_offset + 0x6510)
> +
>  /*
>   * Palette regs
>   */
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 3c0e0cf..9ef1d28 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -9497,6 +9497,31 @@ static bool has_edp_a(struct drm_device *dev)
>         return true;
>  }
>
> +static void gmbus_set_freq(struct drm_i915_private *dev_priv, u32 hpll_freq)
> +{
> +       int cdclk_ratio[] = { 10, 15, 20, 25, 30, 0, 40, 45, 50, 0,
> +                       60, 0, 0, 75, 80, 0, 90, 0, 100, 0,
> +                       0, 0, 120, 0, 0, 0, 0, 0, 150, 0, 160 };
> +       int vco_freq[] = { 800, 1600, 2000, 2400 };
> +       int gmbus_freq = 0, cdclk;
> +       u32 reg_val;
> +
> +       BUG_ON(hpll_freq > ARRAY_SIZE(vco_freq));
> +
> +       reg_val = I915_READ(CZCLK_CDCLK_FREQ_RATIO);
> +
> +       cdclk = ((reg_val >> CDCLK_FREQ_SHIFT) & CDCLK_FREQ_MASK) - 1;
> +
> +       if (cdclk_ratio[cdclk])
> +               gmbus_freq = vco_freq[hpll_freq] / cdclk_ratio[cdclk] * 10;
> +
> +       WARN_ON(gmbus_freq == 0);
> +
> +       if (gmbus_freq != 0)
> +               I915_WRITE(GMBUS_FREQ, gmbus_freq);
> +
> +}
> +
>  static void intel_setup_outputs(struct drm_device *dev)
>  {
>         struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -9555,6 +9580,32 @@ static void intel_setup_outputs(struct drm_device *dev)

Doing this in setup_outputs feels like hiding stuff ;-) I know that
there's already the pch refclock setup here, but I've just submitted a
patch to get it out of there.

The problem is that setup_outputs isn't called on resume, and I
suspect we actually need this.

The dpio reset is probably best stuffed into intel_uncore_sanitize
>                 if (I915_READ(PCH_DP_D) & DP_DETECTED)
>                         intel_dp_init(dev, PCH_DP_D, PORT_D);
>         } else if (IS_VALLEYVIEW(dev)) {
> +               u32 reg_val;
> +
> +               /* Trigger DPIO CMN RESET, require especially in BIOS less
> +                * system
> +                */
> +               reg_val = I915_READ(DPIO_CTL);
> +               if (!(reg_val & 0x1)) {
> +                       I915_WRITE(DPIO_CTL, 0x0);
> +                       I915_WRITE(DPIO_CTL, 0x1);
> +                       POSTING_READ(DPIO_CTL);
> +               }

Atm we don't have a suitable "early platform setup" function which is
called from the right places. I'd shove this into intel_uncore.c:
intel_uncore_sanitize for now, that should work.

Maybe once your patches are in I'll throw a intel_ealy_init_hw
refactoring on top to avoid sprinkling things all over the place
between the driver load and the resume codepaths.

> +
> +               /* In BIOS-less system, program the correct gmbus frequency
> +                * before reading edid.
> +                */
> +
> +               /* Obtain SKU information to determine the correct CDCLK */
> +               mutex_lock(&dev_priv->dpio_lock);
> +               reg_val = vlv_cck_read(dev_priv, CCK_FUSE_REG);
> +               mutex_unlock(&dev_priv->dpio_lock);

I'd move this into the gmbus_freq setup function.

> +
> +               reg_val &= CCK_FUSE_HPLL_FREQ_MASK;
> +
> +               /* Write CDCLK to GMBUS freq for GMBUS clk generation. */
> +               gmbus_set_freq(dev_priv, reg_val);

Imo it's better to move this to intel_i2c.c: intel_i2c_reset. That
function is already called from all the right places.

Cheers, Daniel

> +
>                 /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */
>                 if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) {
>                         intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,
> --
> 1.7.7.6
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Chon Ming Lee Sept. 13, 2013, 3:28 a.m. UTC | #2
On 09/12 18:30, Daniel Vetter wrote:
> On Fri, Sep 13, 2013 at 5:59 AM, Chon Ming Lee <chon.ming.lee@intel.com> wrote:
> > In non PC system, such as IVI, may not use BIOS, instead it uses boot
> > loader with only minimal system initialization.  Most of the time, boot
> > loader doesn't come with VBIOS, and depends on device driver to fully
> > initialize the display controller and GPU.
> >
> > For Valleyview, without VBIOS, i915 fails to work.  The patch add some
> > missing init code, such as doing a DPIO CMNRESET and program the GMBUS
> > frequency.
> >
> > Signed-off-by: Chon Ming Lee <chon.ming.lee@intel.com>
> 
> Generally I prefer patches with tighter topics, grouped into a series.
> For this one I'd split it up into the gmbus setup and the dpio reset,
> so 2 patches.
> 
> > ---
> >  drivers/gpu/drm/i915/i915_reg.h      |    8 +++++
> >  drivers/gpu/drm/i915/intel_display.c |   51 ++++++++++++++++++++++++++++++++++
> >  2 files changed, 59 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> > index bcee89b..8ddf58a 100644
> > --- a/drivers/gpu/drm/i915/i915_reg.h
> > +++ b/drivers/gpu/drm/i915/i915_reg.h
> > @@ -382,6 +382,8 @@
> >  #define   FB_FMAX_VMIN_FREQ_LO_MASK            0xf8000000
> >
> >  /* vlv2 north clock has */
> > +#define CCK_FUSE_REG                           0x8
> > +#define  CCK_FUSE_HPLL_FREQ_MASK               0x3
> >  #define CCK_REG_DSI_PLL_FUSE                   0x44
> >  #define CCK_REG_DSI_PLL_CONTROL                        0x48
> >  #define  DSI_PLL_VCO_EN                                (1 << 31)
> > @@ -1424,6 +1426,12 @@
> >
> >  #define MI_ARB_VLV             (VLV_DISPLAY_BASE + 0x6504)
> >
> > +#define CZCLK_CDCLK_FREQ_RATIO (dev_priv->info->display_mmio_offset + 0x6508)
> > +#define   CDCLK_FREQ_SHIFT     4
> > +#define   CDCLK_FREQ_MASK      0x1f
> > +#define   CZCLK_FREQ_MASK      0xf
> > +#define GMBUS_FREQ             (dev_priv->info->display_mmio_offset + 0x6510)
> > +
> >  /*
> >   * Palette regs
> >   */
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 3c0e0cf..9ef1d28 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -9497,6 +9497,31 @@ static bool has_edp_a(struct drm_device *dev)
> >         return true;
> >  }
> >
> > +static void gmbus_set_freq(struct drm_i915_private *dev_priv, u32 hpll_freq)
> > +{
> > +       int cdclk_ratio[] = { 10, 15, 20, 25, 30, 0, 40, 45, 50, 0,
> > +                       60, 0, 0, 75, 80, 0, 90, 0, 100, 0,
> > +                       0, 0, 120, 0, 0, 0, 0, 0, 150, 0, 160 };
> > +       int vco_freq[] = { 800, 1600, 2000, 2400 };
> > +       int gmbus_freq = 0, cdclk;
> > +       u32 reg_val;
> > +
> > +       BUG_ON(hpll_freq > ARRAY_SIZE(vco_freq));
> > +
> > +       reg_val = I915_READ(CZCLK_CDCLK_FREQ_RATIO);
> > +
> > +       cdclk = ((reg_val >> CDCLK_FREQ_SHIFT) & CDCLK_FREQ_MASK) - 1;
> > +
> > +       if (cdclk_ratio[cdclk])
> > +               gmbus_freq = vco_freq[hpll_freq] / cdclk_ratio[cdclk] * 10;
> > +
> > +       WARN_ON(gmbus_freq == 0);
> > +
> > +       if (gmbus_freq != 0)
> > +               I915_WRITE(GMBUS_FREQ, gmbus_freq);
> > +
> > +}
> > +
> >  static void intel_setup_outputs(struct drm_device *dev)
> >  {
> >         struct drm_i915_private *dev_priv = dev->dev_private;
> > @@ -9555,6 +9580,32 @@ static void intel_setup_outputs(struct drm_device *dev)
> 
> Doing this in setup_outputs feels like hiding stuff ;-) I know that
> there's already the pch refclock setup here, but I've just submitted a
> patch to get it out of there.
> 
> The problem is that setup_outputs isn't called on resume, and I
> suspect we actually need this.
> 
> The dpio reset is probably best stuffed into intel_uncore_sanitize
> >                 if (I915_READ(PCH_DP_D) & DP_DETECTED)
> >                         intel_dp_init(dev, PCH_DP_D, PORT_D);
> >         } else if (IS_VALLEYVIEW(dev)) {
> > +               u32 reg_val;
> > +
> > +               /* Trigger DPIO CMN RESET, require especially in BIOS less
> > +                * system
> > +                */
> > +               reg_val = I915_READ(DPIO_CTL);
> > +               if (!(reg_val & 0x1)) {
> > +                       I915_WRITE(DPIO_CTL, 0x0);
> > +                       I915_WRITE(DPIO_CTL, 0x1);
> > +                       POSTING_READ(DPIO_CTL);
> > +               }
> 
> Atm we don't have a suitable "early platform setup" function which is
> called from the right places. I'd shove this into intel_uncore.c:
> intel_uncore_sanitize for now, that should work.
> 
> Maybe once your patches are in I'll throw a intel_ealy_init_hw
> refactoring on top to avoid sprinkling things all over the place
> between the driver load and the resume codepaths.
> 
I have moved according what you suggest.  Now, the system resume is able to work now.
Will send out the revise patch.
> > +
> > +               /* In BIOS-less system, program the correct gmbus frequency
> > +                * before reading edid.
> > +                */
> > +
> > +               /* Obtain SKU information to determine the correct CDCLK */
> > +               mutex_lock(&dev_priv->dpio_lock);
> > +               reg_val = vlv_cck_read(dev_priv, CCK_FUSE_REG);
> > +               mutex_unlock(&dev_priv->dpio_lock);
> 
> I'd move this into the gmbus_freq setup function.
> 
> > +
> > +               reg_val &= CCK_FUSE_HPLL_FREQ_MASK;
> > +
> > +               /* Write CDCLK to GMBUS freq for GMBUS clk generation. */
> > +               gmbus_set_freq(dev_priv, reg_val);
> 
> Imo it's better to move this to intel_i2c.c: intel_i2c_reset. That
> function is already called from all the right places.
> 
> Cheers, Daniel
> 
> > +
> >                 /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */
> >                 if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) {
> >                         intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,
> > --
> > 1.7.7.6
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index bcee89b..8ddf58a 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -382,6 +382,8 @@ 
 #define   FB_FMAX_VMIN_FREQ_LO_MASK		0xf8000000
 
 /* vlv2 north clock has */
+#define CCK_FUSE_REG				0x8
+#define  CCK_FUSE_HPLL_FREQ_MASK		0x3
 #define CCK_REG_DSI_PLL_FUSE			0x44
 #define CCK_REG_DSI_PLL_CONTROL			0x48
 #define  DSI_PLL_VCO_EN				(1 << 31)
@@ -1424,6 +1426,12 @@ 
 
 #define MI_ARB_VLV		(VLV_DISPLAY_BASE + 0x6504)
 
+#define CZCLK_CDCLK_FREQ_RATIO	(dev_priv->info->display_mmio_offset + 0x6508)
+#define   CDCLK_FREQ_SHIFT	4
+#define   CDCLK_FREQ_MASK	0x1f
+#define   CZCLK_FREQ_MASK	0xf
+#define GMBUS_FREQ		(dev_priv->info->display_mmio_offset + 0x6510)
+
 /*
  * Palette regs
  */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3c0e0cf..9ef1d28 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9497,6 +9497,31 @@  static bool has_edp_a(struct drm_device *dev)
 	return true;
 }
 
+static void gmbus_set_freq(struct drm_i915_private *dev_priv, u32 hpll_freq)
+{
+	int cdclk_ratio[] = { 10, 15, 20, 25, 30, 0, 40, 45, 50, 0,
+			60, 0, 0, 75, 80, 0, 90, 0, 100, 0,
+			0, 0, 120, 0, 0, 0, 0, 0, 150, 0, 160 };
+	int vco_freq[] = { 800, 1600, 2000, 2400 };
+	int gmbus_freq = 0, cdclk;
+	u32 reg_val;
+
+	BUG_ON(hpll_freq > ARRAY_SIZE(vco_freq));
+
+	reg_val = I915_READ(CZCLK_CDCLK_FREQ_RATIO);
+
+	cdclk = ((reg_val >> CDCLK_FREQ_SHIFT) & CDCLK_FREQ_MASK) - 1;
+
+	if (cdclk_ratio[cdclk])
+		gmbus_freq = vco_freq[hpll_freq] / cdclk_ratio[cdclk] * 10;
+
+	WARN_ON(gmbus_freq == 0);
+
+	if (gmbus_freq != 0)
+		I915_WRITE(GMBUS_FREQ, gmbus_freq);
+
+}
+
 static void intel_setup_outputs(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -9555,6 +9580,32 @@  static void intel_setup_outputs(struct drm_device *dev)
 		if (I915_READ(PCH_DP_D) & DP_DETECTED)
 			intel_dp_init(dev, PCH_DP_D, PORT_D);
 	} else if (IS_VALLEYVIEW(dev)) {
+		u32 reg_val;
+
+		/* Trigger DPIO CMN RESET, require especially in BIOS less
+		 * system
+		 */
+		reg_val = I915_READ(DPIO_CTL);
+		if (!(reg_val & 0x1)) {
+			I915_WRITE(DPIO_CTL, 0x0);
+			I915_WRITE(DPIO_CTL, 0x1);
+			POSTING_READ(DPIO_CTL);
+		}
+
+		/* In BIOS-less system, program the correct gmbus frequency
+		 * before reading edid.
+		 */
+
+		/* Obtain SKU information to determine the correct CDCLK */
+		mutex_lock(&dev_priv->dpio_lock);
+		reg_val = vlv_cck_read(dev_priv, CCK_FUSE_REG);
+		mutex_unlock(&dev_priv->dpio_lock);
+
+		reg_val &= CCK_FUSE_HPLL_FREQ_MASK;
+
+		/* Write CDCLK to GMBUS freq for GMBUS clk generation. */
+		gmbus_set_freq(dev_priv, reg_val);
+
 		/* Check for built-in panel first. Shares lanes with HDMI on SDVOC */
 		if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED) {
 			intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,