From b2891eb2531e5e0d251febd0a395d758111790d4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 11 Jul 2017 23:42:35 +0300 Subject: [PATCH] drm/i915/hsw+: Add has_fuses power well attribute The pattern of a power well backing a set of fuses whose initialization we need to wait for during power well enabling is common to all GEN9+ platforms. Adding support for this to the HSW power well enable helper allows us to use the HSW/BDW power well code for GEN9+ as well in a follow-up patch. v2: - Use an enum for power gates instead of raw numbers. (Ville) Signed-off-by: Imre Deak Reviewed-by: Arkadiusz Hiler Link: https://patchwork.freedesktop.org/patch/msgid/20170711204236.5618-6-imre.deak@intel.com Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/gvt/display.c | 6 ++-- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_reg.h | 14 ++++++--- drivers/gpu/drm/i915/intel_runtime_pm.c | 41 ++++++++++++++++++++----- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/display.c b/drivers/gpu/drm/i915/gvt/display.c index 2deb05f618fb..24cc4b012e93 100644 --- a/drivers/gpu/drm/i915/gvt/display.c +++ b/drivers/gpu/drm/i915/gvt/display.c @@ -178,9 +178,9 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu) SDE_PORTE_HOTPLUG_SPT); vgpu_vreg(vgpu, SKL_FUSE_STATUS) |= SKL_FUSE_DOWNLOAD_STATUS | - SKL_FUSE_PG0_DIST_STATUS | - SKL_FUSE_PG1_DIST_STATUS | - SKL_FUSE_PG2_DIST_STATUS; + SKL_FUSE_PG_DIST_STATUS(SKL_PG0) | + SKL_FUSE_PG_DIST_STATUS(SKL_PG1) | + SKL_FUSE_PG_DIST_STATUS(SKL_PG2); vgpu_vreg(vgpu, LCPLL1_CTL) |= LCPLL_PLL_ENABLE | LCPLL_PLL_LOCK; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1a43adb22162..0ac66a4c361f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1397,6 +1397,7 @@ struct i915_power_well { u8 irq_pipe_mask; /* The pw is backing the VGA functionality */ bool has_vga:1; + bool has_fuses:1; } hsw; }; const struct i915_power_well_ops *ops; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d7241a25a929..c83f1095cb21 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8023,11 +8023,17 @@ enum { #define HSW_PWR_WELL_CTL6 _MMIO(0x45414) /* SKL Fuse Status */ +enum skl_power_gate { + SKL_PG0, + SKL_PG1, + SKL_PG2, +}; + #define SKL_FUSE_STATUS _MMIO(0x42000) -#define SKL_FUSE_DOWNLOAD_STATUS (1<<31) -#define SKL_FUSE_PG0_DIST_STATUS (1<<27) -#define SKL_FUSE_PG1_DIST_STATUS (1<<26) -#define SKL_FUSE_PG2_DIST_STATUS (1<<25) +#define SKL_FUSE_DOWNLOAD_STATUS (1<<31) +/* PG0 (HW control->no power well ID), PG1..PG2 (SKL_DISP_PW1..SKL_DISP_PW2) */ +#define SKL_PW_TO_PG(pw) ((pw) - SKL_DISP_PW_1 + SKL_PG1) +#define SKL_FUSE_PG_DIST_STATUS(pg) (1 << (27 - (pg))) /* Per-pipe DDI Function Control */ #define _TRANS_DDI_FUNC_CTL_A 0x60400 diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index d1289be907d9..3992de3c9f01 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -400,16 +400,43 @@ static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv, !!(reqs & 1), !!(reqs & 2), !!(reqs & 4), !!(reqs & 8)); } +static void gen9_wait_for_power_well_fuses(struct drm_i915_private *dev_priv, + enum skl_power_gate pg) +{ + /* Timeout 5us for PG#0, for other PGs 1us */ + WARN_ON(intel_wait_for_register(dev_priv, SKL_FUSE_STATUS, + SKL_FUSE_PG_DIST_STATUS(pg), + SKL_FUSE_PG_DIST_STATUS(pg), 1)); +} + static void hsw_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { enum i915_power_well_id id = power_well->id; + bool wait_fuses = power_well->hsw.has_fuses; + enum skl_power_gate pg; u32 val; + if (wait_fuses) { + pg = SKL_PW_TO_PG(id); + /* + * For PW1 we have to wait both for the PW0/PG0 fuse state + * before enabling the power well and PW1/PG1's own fuse + * state after the enabling. For all other power wells with + * fuses we only have to wait for that PW/PG's fuse state + * after the enabling. + */ + if (pg == SKL_PG1) + gen9_wait_for_power_well_fuses(dev_priv, SKL_PG0); + } + val = I915_READ(HSW_PWR_WELL_DRIVER); I915_WRITE(HSW_PWR_WELL_DRIVER, val | HSW_PWR_WELL_CTL_REQ(id)); hsw_wait_for_power_well_enable(dev_priv, power_well); + if (wait_fuses) + gen9_wait_for_power_well_fuses(dev_priv, pg); + hsw_power_well_post_enable(dev_priv, power_well->hsw.irq_pipe_mask, power_well->hsw.has_vga); } @@ -810,15 +837,15 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, case SKL_DISP_PW_1: if (intel_wait_for_register(dev_priv, SKL_FUSE_STATUS, - SKL_FUSE_PG0_DIST_STATUS, - SKL_FUSE_PG0_DIST_STATUS, + SKL_FUSE_PG_DIST_STATUS(SKL_PG0), + SKL_FUSE_PG_DIST_STATUS(SKL_PG0), 1)) { DRM_ERROR("PG0 not enabled\n"); return; } break; case SKL_DISP_PW_2: - if (!(fuse_status & SKL_FUSE_PG1_DIST_STATUS)) { + if (!(fuse_status & SKL_FUSE_PG_DIST_STATUS(SKL_PG1))) { DRM_ERROR("PG1 in disabled state\n"); return; } @@ -863,15 +890,15 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, if (power_well->id == SKL_DISP_PW_1) { if (intel_wait_for_register(dev_priv, SKL_FUSE_STATUS, - SKL_FUSE_PG1_DIST_STATUS, - SKL_FUSE_PG1_DIST_STATUS, + SKL_FUSE_PG_DIST_STATUS(SKL_PG1), + SKL_FUSE_PG_DIST_STATUS(SKL_PG1), 1)) DRM_ERROR("PG1 distributing status timeout\n"); } else if (power_well->id == SKL_DISP_PW_2) { if (intel_wait_for_register(dev_priv, SKL_FUSE_STATUS, - SKL_FUSE_PG2_DIST_STATUS, - SKL_FUSE_PG2_DIST_STATUS, + SKL_FUSE_PG_DIST_STATUS(SKL_PG2), + SKL_FUSE_PG_DIST_STATUS(SKL_PG2), 1)) DRM_ERROR("PG2 distributing status timeout\n"); } -- 2.20.1