Skip to content

Commit

Permalink
drm/i915/hsw+: Add support for multiple power well regs
Browse files Browse the repository at this point in the history
Future platforms increase the number of power wells which require
additional control registers. A convenient way to select the correct
register is to use the high bits of the power well ID as index. This
patch only prepares for this, while upcoming platform enabling patches
will add the actual new power well IDs and corresponding power well
control registers.

Cc: Paulo Zanoni <[email protected]>
Cc: Animesh Manna <[email protected]>
Cc: Rakshmi Bhatia <[email protected]>
Signed-off-by: Imre Deak <[email protected]>
Reviewed-by: Animesh Manna <[email protected]>
Reviewed-by: Rakshmi Bhatia <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
ideak committed Aug 15, 2017
1 parent 0a44594 commit 9c3a16c
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 33 deletions.
26 changes: 19 additions & 7 deletions drivers/gpu/drm/i915/gvt/handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2252,10 +2252,17 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
MMIO_D(GEN6_RC6p_THRESHOLD, D_ALL);
MMIO_D(GEN6_RC6pp_THRESHOLD, D_ALL);
MMIO_D(GEN6_PMINTRMSK, D_ALL);
MMIO_DH(HSW_PWR_WELL_BIOS, D_BDW, NULL, power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_DRIVER, D_BDW, NULL, power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_KVMR, D_BDW, NULL, power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_DEBUG, D_BDW, NULL, power_well_ctl_mmio_write);
/*
* Use an arbitrary power well controlled by the PWR_WELL_CTL
* register.
*/
MMIO_DH(HSW_PWR_WELL_CTL_BIOS(HSW_DISP_PW_GLOBAL), D_BDW, NULL,
power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL), D_BDW, NULL,
power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_CTL_KVMR, D_BDW, NULL, power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_CTL_DEBUG(HSW_DISP_PW_GLOBAL), D_BDW, NULL,
power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_CTL5, D_BDW, NULL, power_well_ctl_mmio_write);
MMIO_DH(HSW_PWR_WELL_CTL6, D_BDW, NULL, power_well_ctl_mmio_write);

Expand Down Expand Up @@ -2645,9 +2652,14 @@ static int init_skl_mmio_info(struct intel_gvt *gvt)
MMIO_F(_DPD_AUX_CH_CTL, 6 * 4, 0, 0, 0, D_SKL_PLUS, NULL,
dp_aux_ch_ctl_mmio_write);

MMIO_D(HSW_PWR_WELL_BIOS, D_SKL_PLUS);
MMIO_DH(HSW_PWR_WELL_DRIVER, D_SKL_PLUS, NULL,
skl_power_well_ctl_write);
/*
* Use an arbitrary power well controlled by the PWR_WELL_CTL
* register.
*/
MMIO_D(HSW_PWR_WELL_CTL_BIOS(SKL_DISP_PW_MISC_IO), D_SKL_PLUS);
MMIO_DH(HSW_PWR_WELL_CTL_DRIVER(SKL_DISP_PW_MISC_IO), D_SKL_PLUS, NULL,
skl_power_well_ctl_write);
MMIO_DH(GEN6_PCODE_MAILBOX, D_SKL_PLUS, NULL, mailbox_write);

MMIO_D(0xa210, D_SKL_PLUS);
MMIO_D(GEN9_MEDIA_PG_IDLE_HYSTERESIS, D_SKL_PLUS);
Expand Down
32 changes: 25 additions & 7 deletions drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1254,13 +1254,13 @@ enum i915_power_well_id {

/*
* HSW/BDW
* - HSW_PWR_WELL_DRIVER (status bit: id*2, req bit: id*2+1)
* - HSW_PWR_WELL_CTL_DRIVER(0) (status bit: id*2, req bit: id*2+1)
*/
HSW_DISP_PW_GLOBAL = 15,

/*
* GEN9+
* - HSW_PWR_WELL_DRIVER (status bit: id*2, req bit: id*2+1)
* - HSW_PWR_WELL_CTL_DRIVER(0) (status bit: id*2, req bit: id*2+1)
*/
SKL_DISP_PW_MISC_IO = 0,
SKL_DISP_PW_DDI_A_E,
Expand Down Expand Up @@ -8189,11 +8189,29 @@ enum {
#define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15)

/* HSW Power Wells */
#define HSW_PWR_WELL_BIOS _MMIO(0x45400) /* CTL1 */
#define HSW_PWR_WELL_DRIVER _MMIO(0x45404) /* CTL2 */
#define HSW_PWR_WELL_KVMR _MMIO(0x45408) /* CTL3 */
#define HSW_PWR_WELL_DEBUG _MMIO(0x4540C) /* CTL4 */
#define _HSW_PW_SHIFT(pw) ((pw) * 2)
#define _HSW_PWR_WELL_CTL1 0x45400
#define _HSW_PWR_WELL_CTL2 0x45404
#define _HSW_PWR_WELL_CTL3 0x45408
#define _HSW_PWR_WELL_CTL4 0x4540C

/*
* Each power well control register contains up to 16 (request, status) HW
* flag tuples. The register index and HW flag shift is determined by the
* power well ID (see i915_power_well_id). There are 4 possible sources of
* power well requests each source having its own set of control registers:
* BIOS, DRIVER, KVMR, DEBUG.
*/
#define _HSW_PW_REG_IDX(pw) ((pw) >> 4)
#define _HSW_PW_SHIFT(pw) (((pw) & 0xf) * 2)
/* TODO: Add all PWR_WELL_CTL registers below for new platforms */
#define HSW_PWR_WELL_CTL_BIOS(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \
_HSW_PWR_WELL_CTL1))
#define HSW_PWR_WELL_CTL_DRIVER(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \
_HSW_PWR_WELL_CTL2))
#define HSW_PWR_WELL_CTL_KVMR _MMIO(_HSW_PWR_WELL_CTL3)
#define HSW_PWR_WELL_CTL_DEBUG(pw) _MMIO(_PICK(_HSW_PW_REG_IDX(pw), \
_HSW_PWR_WELL_CTL4))

#define HSW_PWR_WELL_CTL_REQ(pw) (1 << (_HSW_PW_SHIFT(pw) + 1))
#define HSW_PWR_WELL_CTL_STATE(pw) (1 << _HSW_PW_SHIFT(pw))
#define HSW_PWR_WELL_CTL5 _MMIO(0x45410)
Expand Down
6 changes: 4 additions & 2 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -8783,7 +8783,8 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
pipe_name(crtc->pipe));

I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
I915_STATE_WARN(I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL)),
"Display power well on\n");
I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
Expand Down Expand Up @@ -15348,7 +15349,8 @@ intel_display_capture_error_state(struct drm_i915_private *dev_priv)
return NULL;

if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
error->power_well_driver =
I915_READ(HSW_PWR_WELL_CTL_DRIVER(HSW_DISP_PW_GLOBAL));

for_each_pipe(dev_priv, i) {
error->pipe[i].power_domain_on =
Expand Down
37 changes: 20 additions & 17 deletions drivers/gpu/drm/i915/intel_runtime_pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ static void hsw_wait_for_power_well_enable(struct drm_i915_private *dev_priv,

/* Timeout for PW1:10 us, AUX:not specified, other PWs:20 us. */
WARN_ON(intel_wait_for_register(dev_priv,
HSW_PWR_WELL_DRIVER,
HSW_PWR_WELL_CTL_DRIVER(id),
HSW_PWR_WELL_CTL_STATE(id),
HSW_PWR_WELL_CTL_STATE(id),
1));
Expand All @@ -319,10 +319,10 @@ static u32 hsw_power_well_requesters(struct drm_i915_private *dev_priv,
u32 req_mask = HSW_PWR_WELL_CTL_REQ(id);
u32 ret;

ret = I915_READ(HSW_PWR_WELL_BIOS) & req_mask ? 1 : 0;
ret |= I915_READ(HSW_PWR_WELL_DRIVER) & req_mask ? 2 : 0;
ret |= I915_READ(HSW_PWR_WELL_KVMR) & req_mask ? 4 : 0;
ret |= I915_READ(HSW_PWR_WELL_DEBUG) & req_mask ? 8 : 0;
ret = I915_READ(HSW_PWR_WELL_CTL_BIOS(id)) & req_mask ? 1 : 0;
ret |= I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & req_mask ? 2 : 0;
ret |= I915_READ(HSW_PWR_WELL_CTL_KVMR) & req_mask ? 4 : 0;
ret |= I915_READ(HSW_PWR_WELL_CTL_DEBUG(id)) & req_mask ? 8 : 0;

return ret;
}
Expand All @@ -343,7 +343,7 @@ static void hsw_wait_for_power_well_disable(struct drm_i915_private *dev_priv,
* Skip the wait in case any of the request bits are set and print a
* diagnostic message.
*/
wait_for((disabled = !(I915_READ(HSW_PWR_WELL_DRIVER) &
wait_for((disabled = !(I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) &
HSW_PWR_WELL_CTL_STATE(id))) ||
(reqs = hsw_power_well_requesters(dev_priv, id)), 1);
if (disabled)
Expand Down Expand Up @@ -384,8 +384,8 @@ static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
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));
val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), val | HSW_PWR_WELL_CTL_REQ(id));
hsw_wait_for_power_well_enable(dev_priv, power_well);

if (wait_fuses)
Expand All @@ -403,8 +403,9 @@ static void hsw_power_well_disable(struct drm_i915_private *dev_priv,

hsw_power_well_pre_disable(dev_priv, power_well->hsw.irq_pipe_mask);

val = I915_READ(HSW_PWR_WELL_DRIVER);
I915_WRITE(HSW_PWR_WELL_DRIVER, val & ~HSW_PWR_WELL_CTL_REQ(id));
val = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));
I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id),
val & ~HSW_PWR_WELL_CTL_REQ(id));
hsw_wait_for_power_well_disable(dev_priv, power_well);
}

Expand All @@ -419,17 +420,19 @@ static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
enum i915_power_well_id id = power_well->id;
u32 mask = HSW_PWR_WELL_CTL_REQ(id) | HSW_PWR_WELL_CTL_STATE(id);

return (I915_READ(HSW_PWR_WELL_DRIVER) & mask) == mask;
return (I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) & mask) == mask;
}

static void assert_can_enable_dc9(struct drm_i915_private *dev_priv)
{
enum i915_power_well_id id = SKL_DISP_PW_2;

WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9),
"DC9 already programmed to be enabled.\n");
WARN_ONCE(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5,
"DC5 still not disabled to enable DC9.\n");
WARN_ONCE(I915_READ(HSW_PWR_WELL_DRIVER) &
HSW_PWR_WELL_CTL_REQ(SKL_DISP_PW_2),
WARN_ONCE(I915_READ(HSW_PWR_WELL_CTL_DRIVER(id)) &
HSW_PWR_WELL_CTL_REQ(id),
"Power well 2 on.\n");
WARN_ONCE(intel_irqs_enabled(dev_priv),
"Interrupts not disabled yet.\n");
Expand Down Expand Up @@ -630,15 +633,15 @@ static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
{
enum i915_power_well_id id = power_well->id;
u32 mask = HSW_PWR_WELL_CTL_REQ(id);
u32 bios_req = I915_READ(HSW_PWR_WELL_BIOS);
u32 bios_req = I915_READ(HSW_PWR_WELL_CTL_BIOS(id));

/* Take over the request bit if set by BIOS. */
if (bios_req & mask) {
u32 drv_req = I915_READ(HSW_PWR_WELL_DRIVER);
u32 drv_req = I915_READ(HSW_PWR_WELL_CTL_DRIVER(id));

if (!(drv_req & mask))
I915_WRITE(HSW_PWR_WELL_DRIVER, drv_req | mask);
I915_WRITE(HSW_PWR_WELL_BIOS, bios_req & ~mask);
I915_WRITE(HSW_PWR_WELL_CTL_DRIVER(id), drv_req | mask);
I915_WRITE(HSW_PWR_WELL_CTL_BIOS(id), bios_req & ~mask);
}
}

Expand Down

0 comments on commit 9c3a16c

Please sign in to comment.