|
@@ -5411,6 +5411,140 @@ static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static void vlv_set_power_well(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well, bool enable)
|
|
|
+{
|
|
|
+ enum punit_power_well power_well_id = power_well->data;
|
|
|
+ u32 mask;
|
|
|
+ u32 state;
|
|
|
+ u32 ctrl;
|
|
|
+
|
|
|
+ mask = PUNIT_PWRGT_MASK(power_well_id);
|
|
|
+ state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
|
|
|
+ PUNIT_PWRGT_PWR_GATE(power_well_id);
|
|
|
+
|
|
|
+ mutex_lock(&dev_priv->rps.hw_lock);
|
|
|
+
|
|
|
+#define COND \
|
|
|
+ ((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state)
|
|
|
+
|
|
|
+ if (COND)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL);
|
|
|
+ ctrl &= ~mask;
|
|
|
+ ctrl |= state;
|
|
|
+ vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, ctrl);
|
|
|
+
|
|
|
+ if (wait_for(COND, 100))
|
|
|
+ DRM_ERROR("timout setting power well state %08x (%08x)\n",
|
|
|
+ state,
|
|
|
+ vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL));
|
|
|
+
|
|
|
+#undef COND
|
|
|
+
|
|
|
+out:
|
|
|
+ mutex_unlock(&dev_priv->rps.hw_lock);
|
|
|
+}
|
|
|
+
|
|
|
+static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well)
|
|
|
+{
|
|
|
+ vlv_set_power_well(dev_priv, power_well, power_well->count > 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void vlv_power_well_enable(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well)
|
|
|
+{
|
|
|
+ vlv_set_power_well(dev_priv, power_well, true);
|
|
|
+}
|
|
|
+
|
|
|
+static void vlv_power_well_disable(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well)
|
|
|
+{
|
|
|
+ vlv_set_power_well(dev_priv, power_well, false);
|
|
|
+}
|
|
|
+
|
|
|
+static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well)
|
|
|
+{
|
|
|
+ int power_well_id = power_well->data;
|
|
|
+ bool enabled = false;
|
|
|
+ u32 mask;
|
|
|
+ u32 state;
|
|
|
+ u32 ctrl;
|
|
|
+
|
|
|
+ mask = PUNIT_PWRGT_MASK(power_well_id);
|
|
|
+ ctrl = PUNIT_PWRGT_PWR_ON(power_well_id);
|
|
|
+
|
|
|
+ mutex_lock(&dev_priv->rps.hw_lock);
|
|
|
+
|
|
|
+ state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask;
|
|
|
+ /*
|
|
|
+ * We only ever set the power-on and power-gate states, anything
|
|
|
+ * else is unexpected.
|
|
|
+ */
|
|
|
+ WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) &&
|
|
|
+ state != PUNIT_PWRGT_PWR_GATE(power_well_id));
|
|
|
+ if (state == ctrl)
|
|
|
+ enabled = true;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A transient state at this point would mean some unexpected party
|
|
|
+ * is poking at the power controls too.
|
|
|
+ */
|
|
|
+ ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask;
|
|
|
+ WARN_ON(ctrl != state);
|
|
|
+
|
|
|
+ mutex_unlock(&dev_priv->rps.hw_lock);
|
|
|
+
|
|
|
+ return enabled;
|
|
|
+}
|
|
|
+
|
|
|
+static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well)
|
|
|
+{
|
|
|
+ WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
|
|
|
+
|
|
|
+ vlv_set_power_well(dev_priv, power_well, true);
|
|
|
+
|
|
|
+ spin_lock_irq(&dev_priv->irq_lock);
|
|
|
+ valleyview_enable_display_irqs(dev_priv);
|
|
|
+ spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * During driver initialization we need to defer enabling hotplug
|
|
|
+ * processing until fbdev is set up.
|
|
|
+ */
|
|
|
+ if (dev_priv->enable_hotplug_processing)
|
|
|
+ intel_hpd_init(dev_priv->dev);
|
|
|
+
|
|
|
+ i915_redisable_vga_power_on(dev_priv->dev);
|
|
|
+}
|
|
|
+
|
|
|
+static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
|
|
|
+ struct i915_power_well *power_well)
|
|
|
+{
|
|
|
+ struct drm_device *dev = dev_priv->dev;
|
|
|
+ enum pipe pipe;
|
|
|
+
|
|
|
+ WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
|
|
|
+
|
|
|
+ spin_lock_irq(&dev_priv->irq_lock);
|
|
|
+ for_each_pipe(pipe)
|
|
|
+ __intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
|
|
|
+
|
|
|
+ valleyview_disable_display_irqs(dev_priv);
|
|
|
+ spin_unlock_irq(&dev_priv->irq_lock);
|
|
|
+
|
|
|
+ spin_lock_irq(&dev->vbl_lock);
|
|
|
+ for_each_pipe(pipe)
|
|
|
+ reset_vblank_counter(dev, pipe);
|
|
|
+ spin_unlock_irq(&dev->vbl_lock);
|
|
|
+
|
|
|
+ vlv_set_power_well(dev_priv, power_well, false);
|
|
|
+}
|
|
|
+
|
|
|
static void check_power_well_state(struct drm_i915_private *dev_priv,
|
|
|
struct i915_power_well *power_well)
|
|
|
{
|
|
@@ -5543,6 +5677,35 @@ EXPORT_SYMBOL_GPL(i915_release_power_well);
|
|
|
(POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) | \
|
|
|
BIT(POWER_DOMAIN_INIT))
|
|
|
|
|
|
+#define VLV_ALWAYS_ON_POWER_DOMAINS BIT(POWER_DOMAIN_INIT)
|
|
|
+#define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK
|
|
|
+
|
|
|
+#define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_PORT_CRT) | \
|
|
|
+ BIT(POWER_DOMAIN_INIT))
|
|
|
+
|
|
|
+#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_INIT))
|
|
|
+
|
|
|
+#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_INIT))
|
|
|
+
|
|
|
+#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_INIT))
|
|
|
+
|
|
|
+#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
|
|
|
+ BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
|
|
|
+ BIT(POWER_DOMAIN_INIT))
|
|
|
+
|
|
|
static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
|
|
|
.sync_hw = i9xx_always_on_power_well_noop,
|
|
|
.enable = i9xx_always_on_power_well_noop,
|
|
@@ -5594,6 +5757,77 @@ static struct i915_power_well bdw_power_wells[] = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+static const struct i915_power_well_ops vlv_display_power_well_ops = {
|
|
|
+ .sync_hw = vlv_power_well_sync_hw,
|
|
|
+ .enable = vlv_display_power_well_enable,
|
|
|
+ .disable = vlv_display_power_well_disable,
|
|
|
+ .is_enabled = vlv_power_well_enabled,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
|
|
|
+ .sync_hw = vlv_power_well_sync_hw,
|
|
|
+ .enable = vlv_power_well_enable,
|
|
|
+ .disable = vlv_power_well_disable,
|
|
|
+ .is_enabled = vlv_power_well_enabled,
|
|
|
+};
|
|
|
+
|
|
|
+static struct i915_power_well vlv_power_wells[] = {
|
|
|
+ {
|
|
|
+ .name = "always-on",
|
|
|
+ .always_on = 1,
|
|
|
+ .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
|
|
|
+ .ops = &i9xx_always_on_power_well_ops,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "display",
|
|
|
+ .domains = VLV_DISPLAY_POWER_DOMAINS,
|
|
|
+ .data = PUNIT_POWER_WELL_DISP2D,
|
|
|
+ .ops = &vlv_display_power_well_ops,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "dpio-common",
|
|
|
+ .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
|
|
|
+ .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
|
|
|
+ .ops = &vlv_dpio_power_well_ops,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "dpio-tx-b-01",
|
|
|
+ .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
|
|
|
+ .ops = &vlv_dpio_power_well_ops,
|
|
|
+ .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "dpio-tx-b-23",
|
|
|
+ .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
|
|
|
+ .ops = &vlv_dpio_power_well_ops,
|
|
|
+ .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "dpio-tx-c-01",
|
|
|
+ .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
|
|
|
+ .ops = &vlv_dpio_power_well_ops,
|
|
|
+ .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "dpio-tx-c-23",
|
|
|
+ .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
|
|
|
+ VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
|
|
|
+ .ops = &vlv_dpio_power_well_ops,
|
|
|
+ .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
#define set_power_wells(power_domains, __power_wells) ({ \
|
|
|
(power_domains)->power_wells = (__power_wells); \
|
|
|
(power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
|
|
@@ -5615,6 +5849,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
|
|
|
} else if (IS_BROADWELL(dev_priv->dev)) {
|
|
|
set_power_wells(power_domains, bdw_power_wells);
|
|
|
hsw_pwr = power_domains;
|
|
|
+ } else if (IS_VALLEYVIEW(dev_priv->dev)) {
|
|
|
+ set_power_wells(power_domains, vlv_power_wells);
|
|
|
} else {
|
|
|
set_power_wells(power_domains, i9xx_always_on_power_well);
|
|
|
}
|