Commit 77961eb984c7e5394bd29cc7be2ab0bf0cc7e7b1

Authored by Imre Deak
Committed by Daniel Vetter
1 parent f88d42f1d0

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 <imre.deak@intel.com>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
[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 <daniel.vetter@ffwll.ch>

Showing 6 changed files with 242 additions and 2 deletions Side-by-side Diff

drivers/gpu/drm/i915/i915_dma.c
... ... @@ -1672,7 +1672,6 @@
1672 1672 goto out_mtrrfree;
1673 1673 }
1674 1674  
1675   - dev_priv->display_irqs_enabled = true;
1676 1675 intel_irq_init(dev);
1677 1676 intel_uncore_sanitize(dev);
1678 1677  
drivers/gpu/drm/i915/i915_drv.h
... ... @@ -1062,7 +1062,7 @@
1062 1062 /* power well enable/disable usage count */
1063 1063 int count;
1064 1064 unsigned long domains;
1065   - void *data;
  1065 + unsigned long data;
1066 1066 const struct i915_power_well_ops *ops;
1067 1067 };
1068 1068  
drivers/gpu/drm/i915/i915_irq.c
... ... @@ -395,6 +395,8 @@
395 395 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
396 396 bool ret;
397 397  
  398 + assert_spin_locked(&dev_priv->irq_lock);
  399 +
398 400 ret = !intel_crtc->cpu_fifo_underrun_disabled;
399 401  
400 402 if (enable == ret)
drivers/gpu/drm/i915/intel_display.c
... ... @@ -4229,6 +4229,7 @@
4229 4229  
4230 4230 if (req_cdclk != cur_cdclk)
4231 4231 valleyview_set_cdclk(dev, req_cdclk);
  4232 + modeset_update_crtc_power_domains(dev);
4232 4233 }
4233 4234  
4234 4235 static void valleyview_crtc_enable(struct drm_crtc *crtc)
drivers/gpu/drm/i915/intel_drv.h
... ... @@ -609,6 +609,8 @@
609 609 /* i915_irq.c */
610 610 bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
611 611 enum pipe pipe, bool enable);
  612 +bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
  613 + enum pipe pipe, bool enable);
612 614 bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
613 615 enum transcoder pch_transcoder,
614 616 bool enable);
drivers/gpu/drm/i915/intel_pm.c
... ... @@ -5411,6 +5411,140 @@
5411 5411 return true;
5412 5412 }
5413 5413  
  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 +
5414 5548 static void check_power_well_state(struct drm_i915_private *dev_priv,
5415 5549 struct i915_power_well *power_well)
5416 5550 {
... ... @@ -5543,6 +5677,35 @@
5543 5677 (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \
5544 5678 BIT(POWER_DOMAIN_INIT))
5545 5679  
  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 +
5546 5709 static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
5547 5710 .sync_hw = i9xx_always_on_power_well_noop,
5548 5711 .enable = i9xx_always_on_power_well_noop,
... ... @@ -5594,6 +5757,77 @@
5594 5757 },
5595 5758 };
5596 5759  
  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 +
5597 5831 #define set_power_wells(power_domains, __power_wells) ({ \
5598 5832 (power_domains)->power_wells = (__power_wells); \
5599 5833 (power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
... ... @@ -5615,6 +5849,8 @@
5615 5849 } else if (IS_BROADWELL(dev_priv->dev)) {
5616 5850 set_power_wells(power_domains, bdw_power_wells);
5617 5851 hsw_pwr = power_domains;
  5852 + } else if (IS_VALLEYVIEW(dev_priv->dev)) {
  5853 + set_power_wells(power_domains, vlv_power_wells);
5618 5854 } else {
5619 5855 set_power_wells(power_domains, i9xx_always_on_power_well);
5620 5856 }