Skip to content

Commit 77961eb

Browse files
ideakdanvet
authored andcommitted
drm/i915: power domains: add vlv power wells
Based on an early draft from Jesse. Add support for powering on/off the dynamic power wells on VLV by registering its display and dpio dynamic power wells with the power domain framework. For now power on all PHY TX lanes regardless of the actual lane configuration. Later this can be optimized when the PHY side setup enables only the required lanes. Atm, it enables all lanes in all cases. v2: - undef function local COND macro after its last use (Ville) - Take dev_priv->irq_lock around the whole sequence of intel_set_cpu_fifo_underrun_reporting_nolock() and valleyview_disable_display_irqs(). They are short and releasing the lock in between only makes proving correctness more difficult. - sanitize local var names in vlv_power_well_enabled() v3: - rebase on latest -nightly Signed-off-by: Imre Deak <[email protected]> Reviewed-by: Jesse Barnes <[email protected]> [danvet: Resolve conflict due to my changes in the previous patch. Also throw in an assert_spin_locked for safety. And finally appease checkpatch.] Signed-off-by: Daniel Vetter <[email protected]>
1 parent f88d42f commit 77961eb

File tree

6 files changed

+242
-2
lines changed

6 files changed

+242
-2
lines changed

drivers/gpu/drm/i915/i915_dma.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1672,7 +1672,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
16721672
goto out_mtrrfree;
16731673
}
16741674

1675-
dev_priv->display_irqs_enabled = true;
16761675
intel_irq_init(dev);
16771676
intel_uncore_sanitize(dev);
16781677

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,7 @@ struct i915_power_well {
10621062
/* power well enable/disable usage count */
10631063
int count;
10641064
unsigned long domains;
1065-
void *data;
1065+
unsigned long data;
10661066
const struct i915_power_well_ops *ops;
10671067
};
10681068

drivers/gpu/drm/i915/i915_irq.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
395395
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
396396
bool ret;
397397

398+
assert_spin_locked(&dev_priv->irq_lock);
399+
398400
ret = !intel_crtc->cpu_fifo_underrun_disabled;
399401

400402
if (enable == ret)

drivers/gpu/drm/i915/intel_display.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4229,6 +4229,7 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
42294229

42304230
if (req_cdclk != cur_cdclk)
42314231
valleyview_set_cdclk(dev, req_cdclk);
4232+
modeset_update_crtc_power_domains(dev);
42324233
}
42334234

42344235
static void valleyview_crtc_enable(struct drm_crtc *crtc)

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
609609
/* i915_irq.c */
610610
bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
611611
enum pipe pipe, bool enable);
612+
bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
613+
enum pipe pipe, bool enable);
612614
bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
613615
enum transcoder pch_transcoder,
614616
bool enable);

drivers/gpu/drm/i915/intel_pm.c

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5411,6 +5411,140 @@ static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
54115411
return true;
54125412
}
54135413

5414+
static void vlv_set_power_well(struct drm_i915_private *dev_priv,
5415+
struct i915_power_well *power_well, bool enable)
5416+
{
5417+
enum punit_power_well power_well_id = power_well->data;
5418+
u32 mask;
5419+
u32 state;
5420+
u32 ctrl;
5421+
5422+
mask = PUNIT_PWRGT_MASK(power_well_id);
5423+
state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
5424+
PUNIT_PWRGT_PWR_GATE(power_well_id);
5425+
5426+
mutex_lock(&dev_priv->rps.hw_lock);
5427+
5428+
#define COND \
5429+
((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state)
5430+
5431+
if (COND)
5432+
goto out;
5433+
5434+
ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL);
5435+
ctrl &= ~mask;
5436+
ctrl |= state;
5437+
vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, ctrl);
5438+
5439+
if (wait_for(COND, 100))
5440+
DRM_ERROR("timout setting power well state %08x (%08x)\n",
5441+
state,
5442+
vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL));
5443+
5444+
#undef COND
5445+
5446+
out:
5447+
mutex_unlock(&dev_priv->rps.hw_lock);
5448+
}
5449+
5450+
static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
5451+
struct i915_power_well *power_well)
5452+
{
5453+
vlv_set_power_well(dev_priv, power_well, power_well->count > 0);
5454+
}
5455+
5456+
static void vlv_power_well_enable(struct drm_i915_private *dev_priv,
5457+
struct i915_power_well *power_well)
5458+
{
5459+
vlv_set_power_well(dev_priv, power_well, true);
5460+
}
5461+
5462+
static void vlv_power_well_disable(struct drm_i915_private *dev_priv,
5463+
struct i915_power_well *power_well)
5464+
{
5465+
vlv_set_power_well(dev_priv, power_well, false);
5466+
}
5467+
5468+
static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
5469+
struct i915_power_well *power_well)
5470+
{
5471+
int power_well_id = power_well->data;
5472+
bool enabled = false;
5473+
u32 mask;
5474+
u32 state;
5475+
u32 ctrl;
5476+
5477+
mask = PUNIT_PWRGT_MASK(power_well_id);
5478+
ctrl = PUNIT_PWRGT_PWR_ON(power_well_id);
5479+
5480+
mutex_lock(&dev_priv->rps.hw_lock);
5481+
5482+
state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask;
5483+
/*
5484+
* We only ever set the power-on and power-gate states, anything
5485+
* else is unexpected.
5486+
*/
5487+
WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) &&
5488+
state != PUNIT_PWRGT_PWR_GATE(power_well_id));
5489+
if (state == ctrl)
5490+
enabled = true;
5491+
5492+
/*
5493+
* A transient state at this point would mean some unexpected party
5494+
* is poking at the power controls too.
5495+
*/
5496+
ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask;
5497+
WARN_ON(ctrl != state);
5498+
5499+
mutex_unlock(&dev_priv->rps.hw_lock);
5500+
5501+
return enabled;
5502+
}
5503+
5504+
static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
5505+
struct i915_power_well *power_well)
5506+
{
5507+
WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
5508+
5509+
vlv_set_power_well(dev_priv, power_well, true);
5510+
5511+
spin_lock_irq(&dev_priv->irq_lock);
5512+
valleyview_enable_display_irqs(dev_priv);
5513+
spin_unlock_irq(&dev_priv->irq_lock);
5514+
5515+
/*
5516+
* During driver initialization we need to defer enabling hotplug
5517+
* processing until fbdev is set up.
5518+
*/
5519+
if (dev_priv->enable_hotplug_processing)
5520+
intel_hpd_init(dev_priv->dev);
5521+
5522+
i915_redisable_vga_power_on(dev_priv->dev);
5523+
}
5524+
5525+
static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
5526+
struct i915_power_well *power_well)
5527+
{
5528+
struct drm_device *dev = dev_priv->dev;
5529+
enum pipe pipe;
5530+
5531+
WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
5532+
5533+
spin_lock_irq(&dev_priv->irq_lock);
5534+
for_each_pipe(pipe)
5535+
__intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
5536+
5537+
valleyview_disable_display_irqs(dev_priv);
5538+
spin_unlock_irq(&dev_priv->irq_lock);
5539+
5540+
spin_lock_irq(&dev->vbl_lock);
5541+
for_each_pipe(pipe)
5542+
reset_vblank_counter(dev, pipe);
5543+
spin_unlock_irq(&dev->vbl_lock);
5544+
5545+
vlv_set_power_well(dev_priv, power_well, false);
5546+
}
5547+
54145548
static void check_power_well_state(struct drm_i915_private *dev_priv,
54155549
struct i915_power_well *power_well)
54165550
{
@@ -5543,6 +5677,35 @@ EXPORT_SYMBOL_GPL(i915_release_power_well);
55435677
(POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \
55445678
BIT(POWER_DOMAIN_INIT))
55455679

5680+
#define VLV_ALWAYS_ON_POWER_DOMAINS BIT(POWER_DOMAIN_INIT)
5681+
#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK
5682+
5683+
#define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \
5684+
BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
5685+
BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
5686+
BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
5687+
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
5688+
BIT(POWER_DOMAIN_PORT_CRT) | \
5689+
BIT(POWER_DOMAIN_INIT))
5690+
5691+
#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
5692+
BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
5693+
BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
5694+
BIT(POWER_DOMAIN_INIT))
5695+
5696+
#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
5697+
BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
5698+
BIT(POWER_DOMAIN_INIT))
5699+
5700+
#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
5701+
BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
5702+
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
5703+
BIT(POWER_DOMAIN_INIT))
5704+
5705+
#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
5706+
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
5707+
BIT(POWER_DOMAIN_INIT))
5708+
55465709
static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
55475710
.sync_hw = i9xx_always_on_power_well_noop,
55485711
.enable = i9xx_always_on_power_well_noop,
@@ -5594,6 +5757,77 @@ static struct i915_power_well bdw_power_wells[] = {
55945757
},
55955758
};
55965759

5760+
static const struct i915_power_well_ops vlv_display_power_well_ops = {
5761+
.sync_hw = vlv_power_well_sync_hw,
5762+
.enable = vlv_display_power_well_enable,
5763+
.disable = vlv_display_power_well_disable,
5764+
.is_enabled = vlv_power_well_enabled,
5765+
};
5766+
5767+
static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
5768+
.sync_hw = vlv_power_well_sync_hw,
5769+
.enable = vlv_power_well_enable,
5770+
.disable = vlv_power_well_disable,
5771+
.is_enabled = vlv_power_well_enabled,
5772+
};
5773+
5774+
static struct i915_power_well vlv_power_wells[] = {
5775+
{
5776+
.name = "always-on",
5777+
.always_on = 1,
5778+
.domains = VLV_ALWAYS_ON_POWER_DOMAINS,
5779+
.ops = &i9xx_always_on_power_well_ops,
5780+
},
5781+
{
5782+
.name = "display",
5783+
.domains = VLV_DISPLAY_POWER_DOMAINS,
5784+
.data = PUNIT_POWER_WELL_DISP2D,
5785+
.ops = &vlv_display_power_well_ops,
5786+
},
5787+
{
5788+
.name = "dpio-common",
5789+
.domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
5790+
.data = PUNIT_POWER_WELL_DPIO_CMN_BC,
5791+
.ops = &vlv_dpio_power_well_ops,
5792+
},
5793+
{
5794+
.name = "dpio-tx-b-01",
5795+
.domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
5796+
VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
5797+
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
5798+
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
5799+
.ops = &vlv_dpio_power_well_ops,
5800+
.data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
5801+
},
5802+
{
5803+
.name = "dpio-tx-b-23",
5804+
.domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
5805+
VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
5806+
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
5807+
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
5808+
.ops = &vlv_dpio_power_well_ops,
5809+
.data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
5810+
},
5811+
{
5812+
.name = "dpio-tx-c-01",
5813+
.domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
5814+
VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
5815+
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
5816+
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
5817+
.ops = &vlv_dpio_power_well_ops,
5818+
.data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
5819+
},
5820+
{
5821+
.name = "dpio-tx-c-23",
5822+
.domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
5823+
VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
5824+
VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
5825+
VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
5826+
.ops = &vlv_dpio_power_well_ops,
5827+
.data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
5828+
},
5829+
};
5830+
55975831
#define set_power_wells(power_domains, __power_wells) ({ \
55985832
(power_domains)->power_wells = (__power_wells); \
55995833
(power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
@@ -5615,6 +5849,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
56155849
} else if (IS_BROADWELL(dev_priv->dev)) {
56165850
set_power_wells(power_domains, bdw_power_wells);
56175851
hsw_pwr = power_domains;
5852+
} else if (IS_VALLEYVIEW(dev_priv->dev)) {
5853+
set_power_wells(power_domains, vlv_power_wells);
56185854
} else {
56195855
set_power_wells(power_domains, i9xx_always_on_power_well);
56205856
}

0 commit comments

Comments
 (0)