#include <drm/drm_rect.h>
#include <linux/dma_remapping.h>
-/* Primary plane formats supported by all gen */
-#define COMMON_PRIMARY_FORMATS \
- DRM_FORMAT_C8, \
- DRM_FORMAT_RGB565, \
- DRM_FORMAT_XRGB8888, \
- DRM_FORMAT_ARGB8888
-
/* Primary plane formats for gen <= 3 */
-static const uint32_t intel_primary_formats_gen2[] = {
- COMMON_PRIMARY_FORMATS,
+static const uint32_t i8xx_primary_formats[] = {
+ DRM_FORMAT_C8,
+ DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB1555,
- DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_XRGB8888,
};
/* Primary plane formats for gen >= 4 */
-static const uint32_t intel_primary_formats_gen4[] = {
- COMMON_PRIMARY_FORMATS, \
+static const uint32_t i965_primary_formats[] = {
+ DRM_FORMAT_C8,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB2101010,
+ DRM_FORMAT_XBGR2101010,
+};
+
+static const uint32_t skl_primary_formats[] = {
+ DRM_FORMAT_C8,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XRGB8888,
DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_ARGB8888,
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
- DRM_FORMAT_ARGB2101010,
DRM_FORMAT_XBGR2101010,
- DRM_FORMAT_ABGR2101010,
};
/* Cursor formats */
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
-static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *old_fb,
+static int intel_set_mode(struct drm_crtc *crtc,
struct drm_atomic_state *state);
static int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *ifb,
u32 val;
bool cur_state;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
val = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
cur_state = val & DSI_PLL_VCO_EN;
I915_STATE_WARN(cur_state != state,
BUG_ON(!IS_CHERRYVIEW(dev_priv->dev));
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
/* Enable back the 10bit clock to display controller */
tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
tmp |= DPIO_DCLKP_EN;
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp);
+ mutex_unlock(&dev_priv->sb_lock);
+
/*
* Need to wait > 100ns between dclkp clock enable bit and PLL enable.
*/
/* not sure when this should be written */
I915_WRITE(DPLL_MD(pipe), pipe_config->dpll_hw_state.dpll_md);
POSTING_READ(DPLL_MD(pipe));
-
- mutex_unlock(&dev_priv->dpio_lock);
}
static int intel_num_dvo_pipes(struct drm_device *dev)
I915_WRITE(DPLL(pipe), val);
POSTING_READ(DPLL(pipe));
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
/* Disable 10bit clock to display controller */
val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
}
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
}
void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
- struct intel_digital_port *dport)
+ struct intel_digital_port *dport,
+ unsigned int expected_mask)
{
u32 port_mask;
int dpll_reg;
case PORT_C:
port_mask = DPLL_PORTC_READY_MASK;
dpll_reg = DPLL(0);
+ expected_mask <<= 4;
break;
case PORT_D:
port_mask = DPLL_PORTD_READY_MASK;
BUG();
}
- if (wait_for((I915_READ(dpll_reg) & port_mask) == 0, 1000))
- WARN(1, "timed out waiting for port %c ready: 0x%08x\n",
- port_name(dport->port), I915_READ(dpll_reg));
+ if (wait_for((I915_READ(dpll_reg) & port_mask) == expected_mask, 1000))
+ WARN(1, "timed out waiting for port %c ready: got 0x%x, expected 0x%x\n",
+ port_name(dport->port), I915_READ(dpll_reg) & port_mask, expected_mask);
}
static void intel_prepare_shared_dpll(struct intel_crtc *crtc)
intel_wait_for_pipe_off(crtc);
}
-/*
- * Plane regs are double buffered, going from enabled->disabled needs a
- * trigger in order to latch. The display address reg provides this.
- */
-void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
- enum plane plane)
-{
- struct drm_device *dev = dev_priv->dev;
- u32 reg = INTEL_INFO(dev)->gen >= 4 ? DSPSURF(plane) : DSPADDR(plane);
-
- I915_WRITE(reg, I915_READ(reg));
- POSTING_READ(reg);
-}
-
/**
* intel_enable_primary_hw_plane - enable the primary plane on a given pipe
* @plane: plane to be enabled
dspcntr |= DISPPLANE_8BPP;
break;
case DRM_FORMAT_XRGB1555:
- case DRM_FORMAT_ARGB1555:
dspcntr |= DISPPLANE_BGRX555;
break;
case DRM_FORMAT_RGB565:
dspcntr |= DISPPLANE_BGRX565;
break;
case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
dspcntr |= DISPPLANE_BGRX888;
break;
case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_ABGR8888:
dspcntr |= DISPPLANE_RGBX888;
break;
case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010:
dspcntr |= DISPPLANE_BGRX101010;
break;
case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010:
dspcntr |= DISPPLANE_RGBX101010;
break;
default:
dspcntr |= DISPPLANE_BGRX565;
break;
case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
dspcntr |= DISPPLANE_BGRX888;
break;
case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_ABGR8888:
dspcntr |= DISPPLANE_RGBX888;
break;
case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010:
dspcntr |= DISPPLANE_BGRX101010;
break;
case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010:
dspcntr |= DISPPLANE_RGBX101010;
break;
default:
u32 skl_plane_ctl_format(uint32_t pixel_format)
{
- u32 plane_ctl_format = 0;
switch (pixel_format) {
+ case DRM_FORMAT_C8:
+ return PLANE_CTL_FORMAT_INDEXED;
case DRM_FORMAT_RGB565:
- plane_ctl_format = PLANE_CTL_FORMAT_RGB_565;
- break;
+ return PLANE_CTL_FORMAT_RGB_565;
case DRM_FORMAT_XBGR8888:
- plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
- break;
+ return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
case DRM_FORMAT_XRGB8888:
- plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888;
- break;
+ return PLANE_CTL_FORMAT_XRGB_8888;
/*
* XXX: For ARBG/ABGR formats we default to expecting scanout buffers
* to be already pre-multiplied. We need to add a knob (or a different
* DRM_FORMAT) for user-space to configure that.
*/
case DRM_FORMAT_ABGR8888:
- plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX |
+ return PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX |
PLANE_CTL_ALPHA_SW_PREMULTIPLY;
- break;
case DRM_FORMAT_ARGB8888:
- plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888 |
+ return PLANE_CTL_FORMAT_XRGB_8888 |
PLANE_CTL_ALPHA_SW_PREMULTIPLY;
- break;
case DRM_FORMAT_XRGB2101010:
- plane_ctl_format = PLANE_CTL_FORMAT_XRGB_2101010;
- break;
+ return PLANE_CTL_FORMAT_XRGB_2101010;
case DRM_FORMAT_XBGR2101010:
- plane_ctl_format = PLANE_CTL_ORDER_RGBX | PLANE_CTL_FORMAT_XRGB_2101010;
- break;
+ return PLANE_CTL_ORDER_RGBX | PLANE_CTL_FORMAT_XRGB_2101010;
case DRM_FORMAT_YUYV:
- plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV;
- break;
+ return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV;
case DRM_FORMAT_YVYU:
- plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU;
- break;
+ return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU;
case DRM_FORMAT_UYVY:
- plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY;
- break;
+ return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY;
case DRM_FORMAT_VYUY:
- plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY;
- break;
+ return PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY;
default:
- BUG();
+ MISSING_CASE(pixel_format);
}
- return plane_ctl_format;
+
+ return 0;
}
u32 skl_plane_ctl_tiling(uint64_t fb_modifier)
{
- u32 plane_ctl_tiling = 0;
switch (fb_modifier) {
case DRM_FORMAT_MOD_NONE:
break;
case I915_FORMAT_MOD_X_TILED:
- plane_ctl_tiling = PLANE_CTL_TILED_X;
- break;
+ return PLANE_CTL_TILED_X;
case I915_FORMAT_MOD_Y_TILED:
- plane_ctl_tiling = PLANE_CTL_TILED_Y;
- break;
+ return PLANE_CTL_TILED_Y;
case I915_FORMAT_MOD_Yf_TILED:
- plane_ctl_tiling = PLANE_CTL_TILED_YF;
- break;
+ return PLANE_CTL_TILED_YF;
default:
MISSING_CASE(fb_modifier);
}
- return plane_ctl_tiling;
+
+ return 0;
}
u32 skl_plane_ctl_rotation(unsigned int rotation)
{
- u32 plane_ctl_rotation = 0;
switch (rotation) {
case BIT(DRM_ROTATE_0):
break;
+ /*
+ * DRM_ROTATE_ is counter clockwise to stay compatible with Xrandr
+ * while i915 HW rotation is clockwise, thats why this swapping.
+ */
case BIT(DRM_ROTATE_90):
- plane_ctl_rotation = PLANE_CTL_ROTATE_90;
- break;
+ return PLANE_CTL_ROTATE_270;
case BIT(DRM_ROTATE_180):
- plane_ctl_rotation = PLANE_CTL_ROTATE_180;
- break;
+ return PLANE_CTL_ROTATE_180;
case BIT(DRM_ROTATE_270):
- plane_ctl_rotation = PLANE_CTL_ROTATE_270;
- break;
+ return PLANE_CTL_ROTATE_90;
default:
MISSING_CASE(rotation);
}
- return plane_ctl_rotation;
+ return 0;
}
static void skylake_update_primary_plane(struct drm_crtc *crtc,
if (intel_rotation_90_or_270(rotation)) {
/* stride = Surface height in tiles */
- tile_height = intel_tile_height(dev, fb->bits_per_pixel,
+ tile_height = intel_tile_height(dev, fb->pixel_format,
fb->modifier[0]);
stride = DIV_ROUND_UP(fb->height, tile_height);
x_offset = stride * tile_height - y - src_h;
drm_modeset_unlock_all(dev);
}
-static int
+static void
intel_finish_fb(struct drm_framebuffer *old_fb)
{
struct drm_i915_gem_object *obj = intel_fb_obj(old_fb);
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
bool was_interruptible = dev_priv->mm.interruptible;
int ret;
/* Big Hammer, we also need to ensure that any pending
* MI_WAIT_FOR_EVENT inside a user batch buffer on the
* current scanout is retired before unpinning the old
- * framebuffer.
+ * framebuffer. Note that we rely on userspace rendering
+ * into the buffer attached to the pipe they are waiting
+ * on. If not, userspace generates a GPU hang with IPEHR
+ * point to the MI_WAIT_FOR_EVENT.
*
* This should only fail upon a hung GPU, in which case we
* can safely continue.
*/
dev_priv->mm.interruptible = false;
- ret = i915_gem_object_finish_gpu(obj);
+ ret = i915_gem_object_wait_rendering(obj, true);
dev_priv->mm.interruptible = was_interruptible;
- return ret;
+ WARN_ON(ret);
}
static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
u32 divsel, phaseinc, auxdiv, phasedir = 0;
u32 temp;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
/* It is necessary to ungate the pixclk gate prior to programming
* the divisors, and gate it back when it is done.
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
}
static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
temp &= ~(TRANS_DP_PORT_SEL_MASK |
TRANS_DP_SYNC_MASK |
TRANS_DP_BPC_MASK);
- temp |= (TRANS_DP_OUTPUT_ENABLE |
- TRANS_DP_ENH_FRAMING);
+ temp |= TRANS_DP_OUTPUT_ENABLE;
temp |= bpc << 9; /* same format but at 11:9 */
if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
}
/* check colorkey */
- if (intel_plane && intel_plane->ckey.flags != I915_SET_COLORKEY_NONE) {
- DRM_DEBUG_KMS("PLANE:%d scaling with color key not allowed",
- intel_plane->base.base.id);
+ if (WARN_ON(intel_plane &&
+ intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) {
+ DRM_DEBUG_KMS("PLANE:%d scaling %ux%u->%ux%u not allowed with colorkey",
+ intel_plane->base.base.id, src_w, src_h, dst_w, dst_h);
return -EINVAL;
}
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
ironlake_pfit_disable(intel_crtc);
+ if (intel_crtc->config->has_pch_encoder)
+ ironlake_fdi_disable(crtc);
+
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->post_disable)
encoder->post_disable(encoder);
if (intel_crtc->config->has_pch_encoder) {
- ironlake_fdi_disable(crtc);
-
ironlake_disable_pch_transcoder(dev_priv, pipe);
if (HAS_PCH_CPT(dev)) {
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
}
+static const struct skl_cdclk_entry {
+ unsigned int freq;
+ unsigned int vco;
+} skl_cdclk_frequencies[] = {
+ { .freq = 308570, .vco = 8640 },
+ { .freq = 337500, .vco = 8100 },
+ { .freq = 432000, .vco = 8640 },
+ { .freq = 450000, .vco = 8100 },
+ { .freq = 540000, .vco = 8100 },
+ { .freq = 617140, .vco = 8640 },
+ { .freq = 675000, .vco = 8100 },
+};
+
+static unsigned int skl_cdclk_decimal(unsigned int freq)
+{
+ return (freq - 1000) / 500;
+}
+
+static unsigned int skl_cdclk_get_vco(unsigned int freq)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(skl_cdclk_frequencies); i++) {
+ const struct skl_cdclk_entry *e = &skl_cdclk_frequencies[i];
+
+ if (e->freq == freq)
+ return e->vco;
+ }
+
+ return 8100;
+}
+
+static void
+skl_dpll0_enable(struct drm_i915_private *dev_priv, unsigned int required_vco)
+{
+ unsigned int min_freq;
+ u32 val;
+
+ /* select the minimum CDCLK before enabling DPLL 0 */
+ val = I915_READ(CDCLK_CTL);
+ val &= ~CDCLK_FREQ_SEL_MASK | ~CDCLK_FREQ_DECIMAL_MASK;
+ val |= CDCLK_FREQ_337_308;
+
+ if (required_vco == 8640)
+ min_freq = 308570;
+ else
+ min_freq = 337500;
+
+ val = CDCLK_FREQ_337_308 | skl_cdclk_decimal(min_freq);
+
+ I915_WRITE(CDCLK_CTL, val);
+ POSTING_READ(CDCLK_CTL);
+
+ /*
+ * We always enable DPLL0 with the lowest link rate possible, but still
+ * taking into account the VCO required to operate the eDP panel at the
+ * desired frequency. The usual DP link rates operate with a VCO of
+ * 8100 while the eDP 1.4 alternate link rates need a VCO of 8640.
+ * The modeset code is responsible for the selection of the exact link
+ * rate later on, with the constraint of choosing a frequency that
+ * works with required_vco.
+ */
+ val = I915_READ(DPLL_CTRL1);
+
+ val &= ~(DPLL_CTRL1_HDMI_MODE(SKL_DPLL0) | DPLL_CTRL1_SSC(SKL_DPLL0) |
+ DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0));
+ val |= DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
+ if (required_vco == 8640)
+ val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080,
+ SKL_DPLL0);
+ else
+ val |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,
+ SKL_DPLL0);
+
+ I915_WRITE(DPLL_CTRL1, val);
+ POSTING_READ(DPLL_CTRL1);
+
+ I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) | LCPLL_PLL_ENABLE);
+
+ if (wait_for(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK, 5))
+ DRM_ERROR("DPLL0 not locked\n");
+}
+
+static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv)
+{
+ int ret;
+ u32 val;
+
+ /* inform PCU we want to change CDCLK */
+ val = SKL_CDCLK_PREPARE_FOR_CHANGE;
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = sandybridge_pcode_read(dev_priv, SKL_PCODE_CDCLK_CONTROL, &val);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ return ret == 0 && (val & SKL_CDCLK_READY_FOR_CHANGE);
+}
+
+static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv)
+{
+ unsigned int i;
+
+ for (i = 0; i < 15; i++) {
+ if (skl_cdclk_pcu_ready(dev_priv))
+ return true;
+ udelay(10);
+ }
+
+ return false;
+}
+
+static void skl_set_cdclk(struct drm_i915_private *dev_priv, unsigned int freq)
+{
+ u32 freq_select, pcu_ack;
+
+ DRM_DEBUG_DRIVER("Changing CDCLK to %dKHz\n", freq);
+
+ if (!skl_cdclk_wait_for_pcu_ready(dev_priv)) {
+ DRM_ERROR("failed to inform PCU about cdclk change\n");
+ return;
+ }
+
+ /* set CDCLK_CTL */
+ switch(freq) {
+ case 450000:
+ case 432000:
+ freq_select = CDCLK_FREQ_450_432;
+ pcu_ack = 1;
+ break;
+ case 540000:
+ freq_select = CDCLK_FREQ_540;
+ pcu_ack = 2;
+ break;
+ case 308570:
+ case 337500:
+ default:
+ freq_select = CDCLK_FREQ_337_308;
+ pcu_ack = 0;
+ break;
+ case 617140:
+ case 675000:
+ freq_select = CDCLK_FREQ_675_617;
+ pcu_ack = 3;
+ break;
+ }
+
+ I915_WRITE(CDCLK_CTL, freq_select | skl_cdclk_decimal(freq));
+ POSTING_READ(CDCLK_CTL);
+
+ /* inform PCU of the change */
+ mutex_lock(&dev_priv->rps.hw_lock);
+ sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, pcu_ack);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
+{
+ /* disable DBUF power */
+ I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) & ~DBUF_POWER_REQUEST);
+ POSTING_READ(DBUF_CTL);
+
+ udelay(10);
+
+ if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE)
+ DRM_ERROR("DBuf power disable timeout\n");
+
+ /* disable DPLL0 */
+ I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
+ if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
+ DRM_ERROR("Couldn't disable DPLL0\n");
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+}
+
+void skl_init_cdclk(struct drm_i915_private *dev_priv)
+{
+ u32 val;
+ unsigned int required_vco;
+
+ /* enable PCH reset handshake */
+ val = I915_READ(HSW_NDE_RSTWRN_OPT);
+ I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE);
+
+ /* enable PG1 and Misc I/O */
+ intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
+
+ /* DPLL0 already enabed !? */
+ if (I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE) {
+ DRM_DEBUG_DRIVER("DPLL0 already running\n");
+ return;
+ }
+
+ /* enable DPLL0 */
+ required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk);
+ skl_dpll0_enable(dev_priv, required_vco);
+
+ /* set CDCLK to the frequency the BIOS chose */
+ skl_set_cdclk(dev_priv, dev_priv->skl_boot_cdclk);
+
+ /* enable DBUF power */
+ I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST);
+ POSTING_READ(DBUF_CTL);
+
+ udelay(10);
+
+ if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE))
+ DRM_ERROR("DBuf power enable timeout\n");
+}
+
/* returns HPLL frequency in kHz */
static int valleyview_get_vco(struct drm_i915_private *dev_priv)
{
int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
/* Obtain SKU information */
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) &
CCK_FUSE_HPLL_FREQ_MASK;
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
return vco_freq[hpll_freq] * 1000;
}
}
mutex_unlock(&dev_priv->rps.hw_lock);
+ mutex_lock(&dev_priv->sb_lock);
+
if (cdclk == 400000) {
u32 divider;
divider = DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, cdclk) - 1;
- mutex_lock(&dev_priv->dpio_lock);
/* adjust cdclk divider */
val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
val &= ~DISPLAY_FREQUENCY_VALUES;
DISPLAY_FREQUENCY_STATUS) == (divider << DISPLAY_FREQUENCY_STATUS_SHIFT),
50))
DRM_ERROR("timed out waiting for CDclk change\n");
- mutex_unlock(&dev_priv->dpio_lock);
}
- mutex_lock(&dev_priv->dpio_lock);
/* adjust self-refresh exit latency value */
val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC);
val &= ~0x7f;
else
val |= 3000 / 250; /* 3.0 usec */
vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val);
- mutex_unlock(&dev_priv->dpio_lock);
+
+ mutex_unlock(&dev_priv->sb_lock);
vlv_update_cdclk(dev);
}
return 144000;
}
-/* compute the max pixel clock for new configuration */
-static int intel_mode_max_pixclk(struct drm_atomic_state *state)
+/* Compute the max pixel clock for new configuration. Uses atomic state if
+ * that's non-NULL, look at current state otherwise. */
+static int intel_mode_max_pixclk(struct drm_device *dev,
+ struct drm_atomic_state *state)
{
- struct drm_device *dev = state->dev;
struct intel_crtc *intel_crtc;
struct intel_crtc_state *crtc_state;
int max_pixclk = 0;
for_each_intel_crtc(dev, intel_crtc) {
- crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
+ if (state)
+ crtc_state =
+ intel_atomic_get_crtc_state(state, intel_crtc);
+ else
+ crtc_state = intel_crtc->config;
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
return max_pixclk;
}
-static int valleyview_modeset_global_pipes(struct drm_atomic_state *state,
- unsigned *prepare_pipes)
+static int valleyview_modeset_global_pipes(struct drm_atomic_state *state)
{
struct drm_i915_private *dev_priv = to_i915(state->dev);
- struct intel_crtc *intel_crtc;
- int max_pixclk = intel_mode_max_pixclk(state);
- int cdclk;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int max_pixclk = intel_mode_max_pixclk(state->dev, state);
+ int cdclk, i;
if (max_pixclk < 0)
return max_pixclk;
if (cdclk == dev_priv->cdclk_freq)
return 0;
+ /* add all active pipes to the state */
+ for_each_crtc(state->dev, crtc) {
+ if (!crtc->state->enable)
+ continue;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+ }
+
/* disable/enable all currently active pipes while we change cdclk */
- for_each_intel_crtc(state->dev, intel_crtc)
- if (intel_crtc->base.state->enable)
- *prepare_pipes |= (1 << intel_crtc->pipe);
+ for_each_crtc_in_state(state, crtc, crtc_state, i)
+ if (crtc_state->enable)
+ crtc_state->mode_changed = true;
return 0;
}
WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND);
}
-static void valleyview_modeset_global_resources(struct drm_atomic_state *state)
+static void valleyview_modeset_global_resources(struct drm_atomic_state *old_state)
{
- struct drm_device *dev = state->dev;
+ struct drm_device *dev = old_state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int max_pixclk = intel_mode_max_pixclk(state);
+ int max_pixclk = intel_mode_max_pixclk(dev, NULL);
int req_cdclk;
- /* The only reason this can fail is if we fail to add the crtc_state
- * to the atomic state. But that can't happen since the call to
- * intel_mode_max_pixclk() in valleyview_modeset_global_pipes() (which
- * can't have failed otherwise the mode set would be aborted) added all
- * the states already. */
+ /* The path in intel_mode_max_pixclk() with a NULL atomic state should
+ * never fail. */
if (WARN_ON(max_pixclk < 0))
return;
enable |= intel_encoder->connectors_active;
intel_crtc_control(crtc, enable);
+
+ crtc->state->active = enable;
}
static void intel_crtc_disable(struct drm_crtc *crtc)
if (dev_priv->hpll_freq == 0)
dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
divider = val & DISPLAY_FREQUENCY_VALUES;
u32 bestn, bestm1, bestm2, bestp1, bestp2;
u32 coreclk, reg_val;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
bestn = pipe_config->dpll.n;
bestm1 = pipe_config->dpll.m1;
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000);
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
}
static void chv_update_pll(struct intel_crtc *crtc,
I915_WRITE(dpll_reg,
pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
/* p1 and p2 divider */
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port),
vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) |
DPIO_AFC_RECAL);
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
}
/**
struct drm_connector_state *connector_state;
int i;
+ memset(&crtc_state->dpll_hw_state, 0,
+ sizeof(crtc_state->dpll_hw_state));
+
for_each_connector_in_state(state, connector, connector_state, i) {
if (connector_state->crtc != &crtc->base)
continue;
if (!(pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE))
return;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7;
clock.m2 = mdiv & DPIO_M2DIV_MASK;
u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2;
int refclk = 100000;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port));
pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port));
pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port));
pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port));
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0;
clock.m2 = ((pll_dw0 & 0xff) << 22) | (pll_dw2 & 0x3fffff);
with_fdi, "LP PCH doesn't have FDI\n"))
with_fdi = false;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
tmp &= ~SBI_SSCCTL_DISABLE;
tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
}
/* Sequence to disable CLKOUT_DP */
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t reg, tmp;
- mutex_lock(&dev_priv->dpio_lock);
+ mutex_lock(&dev_priv->sb_lock);
reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
SBI_GEN0 : SBI_DBUFF0;
intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
}
- mutex_unlock(&dev_priv->dpio_lock);
+ mutex_unlock(&dev_priv->sb_lock);
}
static void lpt_init_pch_refclk(struct drm_device *dev)
bool is_lvds = false;
struct intel_shared_dpll *pll;
+ memset(&crtc_state->dpll_hw_state, 0,
+ sizeof(crtc_state->dpll_hw_state));
+
is_lvds = intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS);
WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
intel_prepare_ddi(dev);
}
-static void broxton_modeset_global_resources(struct drm_atomic_state *state)
+static void broxton_modeset_global_resources(struct drm_atomic_state *old_state)
{
- struct drm_device *dev = state->dev;
+ struct drm_device *dev = old_state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int max_pixclk = intel_mode_max_pixclk(state);
+ int max_pixclk = intel_mode_max_pixclk(dev, NULL);
int req_cdclk;
/* see the comment in valleyview_modeset_global_resources */
}
pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
+
+ if (INTEL_INFO(dev)->gen >= 9) {
+ pipe_config->scaler_state.scaler_id = -1;
+ pipe_config->scaler_state.scaler_users &= ~(1 << SKL_CRTC_INDEX);
+ }
+
if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
if (INTEL_INFO(dev)->gen == 9)
skylake_get_pfit_config(crtc, pipe_config);
ironlake_get_pfit_config(crtc, pipe_config);
else
MISSING_CASE(INTEL_INFO(dev)->gen);
-
- } else {
- pipe_config->scaler_state.scaler_id = -1;
- pipe_config->scaler_state.scaler_users &= ~(1 << SKL_CRTC_INDEX);
}
if (IS_HASWELL(dev))
#endif
}
+static int intel_modeset_setup_plane_state(struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_framebuffer *fb,
+ int x, int y)
+{
+ struct drm_plane_state *plane_state;
+ int hdisplay, vdisplay;
+ int ret;
+
+ plane_state = drm_atomic_get_plane_state(state, crtc->primary);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+
+ if (mode)
+ drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
+ else
+ hdisplay = vdisplay = 0;
+
+ ret = drm_atomic_set_crtc_for_plane(plane_state, fb ? crtc : NULL);
+ if (ret)
+ return ret;
+ drm_atomic_set_fb_for_plane(plane_state, fb);
+ plane_state->crtc_x = 0;
+ plane_state->crtc_y = 0;
+ plane_state->crtc_w = hdisplay;
+ plane_state->crtc_h = vdisplay;
+ plane_state->src_x = x << 16;
+ plane_state->src_y = y << 16;
+ plane_state->src_w = hdisplay << 16;
+ plane_state->src_h = vdisplay << 16;
+
+ return 0;
+}
+
bool intel_get_load_detect_pipe(struct drm_connector *connector,
struct drm_display_mode *mode,
struct intel_load_detect_pipe *old,
goto fail;
}
- crtc_state->base.enable = true;
+ crtc_state->base.active = crtc_state->base.enable = true;
if (!mode)
mode = &load_detect_mode;
goto fail;
}
- if (intel_set_mode(crtc, mode, 0, 0, fb, state)) {
+ ret = intel_modeset_setup_plane_state(state, crtc, mode, fb, 0, 0);
+ if (ret)
+ goto fail;
+
+ drm_mode_copy(&crtc_state->base.mode, mode);
+
+ if (intel_set_mode(crtc, state)) {
DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
if (old->release_fb)
old->release_fb->funcs->destroy(old->release_fb);
struct drm_atomic_state *state;
struct drm_connector_state *connector_state;
struct intel_crtc_state *crtc_state;
+ int ret;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
connector->base.id, connector->name,
connector_state->best_encoder = NULL;
connector_state->crtc = NULL;
- crtc_state->base.enable = false;
+ crtc_state->base.enable = crtc_state->base.active = false;
- intel_set_mode(crtc, NULL, 0, 0, NULL, state);
+ ret = intel_modeset_setup_plane_state(state, crtc, NULL, NULL,
+ 0, 0);
+ if (ret)
+ goto fail;
- drm_atomic_state_free(state);
+ ret = intel_set_mode(crtc, state);
+ if (ret)
+ goto fail;
if (old->release_fb) {
drm_framebuffer_unregister_private(old->release_fb);
intel_runtime_pm_put(dev_priv);
}
-static void intel_crtc_set_state(struct intel_crtc *crtc,
- struct intel_crtc_state *crtc_state)
-{
- kfree(crtc->config);
- crtc->config = crtc_state;
- crtc->base.state = &crtc_state->base;
-}
-
static void intel_crtc_destroy(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
kfree(work);
}
- intel_crtc_set_state(intel_crtc, NULL);
drm_crtc_cleanup(crtc);
kfree(intel_crtc);
else if (i915.enable_execlists)
return true;
else
- return ring != i915_gem_request_get_ring(obj->last_read_req);
+ return ring != i915_gem_request_get_ring(obj->last_write_req);
}
static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
static void intel_mmio_flip_work_func(struct work_struct *work)
{
- struct intel_crtc *crtc =
- container_of(work, struct intel_crtc, mmio_flip.work);
- struct intel_mmio_flip *mmio_flip;
+ struct intel_mmio_flip *mmio_flip =
+ container_of(work, struct intel_mmio_flip, work);
- mmio_flip = &crtc->mmio_flip;
if (mmio_flip->req)
WARN_ON(__i915_wait_request(mmio_flip->req,
- crtc->reset_counter,
- false, NULL, NULL) != 0);
+ mmio_flip->crtc->reset_counter,
+ false, NULL,
+ &mmio_flip->i915->rps.mmioflips));
- intel_do_mmio_flip(crtc);
- if (mmio_flip->req) {
- mutex_lock(&crtc->base.dev->struct_mutex);
- i915_gem_request_assign(&mmio_flip->req, NULL);
- mutex_unlock(&crtc->base.dev->struct_mutex);
- }
+ intel_do_mmio_flip(mmio_flip->crtc);
+
+ i915_gem_request_unreference__unlocked(mmio_flip->req);
+ kfree(mmio_flip);
}
static int intel_queue_mmio_flip(struct drm_device *dev,
struct intel_engine_cs *ring,
uint32_t flags)
{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_mmio_flip *mmio_flip;
+
+ mmio_flip = kmalloc(sizeof(*mmio_flip), GFP_KERNEL);
+ if (mmio_flip == NULL)
+ return -ENOMEM;
- i915_gem_request_assign(&intel_crtc->mmio_flip.req,
- obj->last_write_req);
+ mmio_flip->i915 = to_i915(dev);
+ mmio_flip->req = i915_gem_request_reference(obj->last_write_req);
+ mmio_flip->crtc = to_intel_crtc(crtc);
- schedule_work(&intel_crtc->mmio_flip.work);
+ INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func);
+ schedule_work(&mmio_flip->work);
return 0;
}
} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
ring = &dev_priv->ring[BCS];
} else if (INTEL_INFO(dev)->gen >= 7) {
- ring = i915_gem_request_get_ring(obj->last_read_req);
+ ring = i915_gem_request_get_ring(obj->last_write_req);
if (ring == NULL || ring->id != RCS)
ring = &dev_priv->ring[BCS];
} else {
*/
ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
crtc->primary->state,
- mmio_flip ? i915_gem_request_get_ring(obj->last_read_req) : ring);
+ mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring);
if (ret)
goto cleanup_pending;
i915_gem_request_assign(&work->flip_queued_req,
obj->last_write_req);
} else {
+ if (obj->last_write_req) {
+ ret = i915_gem_check_olr(obj->last_write_req);
+ if (ret)
+ goto cleanup_unpin;
+ }
+
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
page_flip_flags);
if (ret)
}
}
-/**
- * intel_modeset_commit_output_state
- *
- * This function copies the stage display pipe configuration to the real one.
+/* Fixup legacy state after an atomic state swap.
*/
-static void intel_modeset_commit_output_state(struct drm_device *dev)
+static void intel_modeset_fixup_state(struct drm_atomic_state *state)
{
struct intel_crtc *crtc;
struct intel_encoder *encoder;
struct intel_connector *connector;
- for_each_intel_connector(dev, connector) {
- connector->base.encoder = &connector->new_encoder->base;
+ for_each_intel_connector(state->dev, connector) {
+ connector->base.encoder = connector->base.state->best_encoder;
+ if (connector->base.encoder)
+ connector->base.encoder->crtc =
+ connector->base.state->crtc;
}
- for_each_intel_encoder(dev, encoder) {
- encoder->base.crtc = &encoder->new_crtc->base;
+ /* Update crtc of disabled encoders */
+ for_each_intel_encoder(state->dev, encoder) {
+ int num_connectors = 0;
+
+ for_each_intel_connector(state->dev, connector)
+ if (connector->base.encoder == &encoder->base)
+ num_connectors++;
+
+ if (num_connectors == 0)
+ encoder->base.crtc = NULL;
}
- for_each_intel_crtc(dev, crtc) {
- crtc->base.state->enable = crtc->new_enabled;
- crtc->base.enabled = crtc->new_enabled;
+ for_each_intel_crtc(state->dev, crtc) {
+ crtc->base.enabled = crtc->base.state->enable;
+ crtc->config = to_intel_crtc_state(crtc->base.state);
}
- intel_modeset_update_connector_atomic_state(dev);
+ /* Copy the new configuration to the staged state, to keep the few
+ * pieces of code that haven't been converted yet happy */
+ intel_modeset_update_staged_output_state(state->dev);
}
static void
DRM_DEBUG_KMS("port clock: %d\n", pipe_config->port_clock);
DRM_DEBUG_KMS("pipe src size: %dx%d\n",
pipe_config->pipe_src_w, pipe_config->pipe_src_h);
- DRM_DEBUG_KMS("num_scalers: %d\n", crtc->num_scalers);
- DRM_DEBUG_KMS("scaler_users: 0x%x\n", pipe_config->scaler_state.scaler_users);
- DRM_DEBUG_KMS("scaler id: %d\n", pipe_config->scaler_state.scaler_id);
+ DRM_DEBUG_KMS("num_scalers: %d, scaler_users: 0x%x, scaler_id: %d\n",
+ crtc->num_scalers,
+ pipe_config->scaler_state.scaler_users,
+ pipe_config->scaler_state.scaler_id);
DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
pipe_config->gmch_pfit.control,
pipe_config->gmch_pfit.pgm_ratios,
DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
+ if (IS_BROXTON(dev)) {
+ DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, "
+ "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, "
+ "pll6: 0x%x, pll8: 0x%x, pcsdw12: 0x%x\n",
+ pipe_config->ddi_pll_sel,
+ pipe_config->dpll_hw_state.ebb0,
+ pipe_config->dpll_hw_state.pll0,
+ pipe_config->dpll_hw_state.pll1,
+ pipe_config->dpll_hw_state.pll2,
+ pipe_config->dpll_hw_state.pll3,
+ pipe_config->dpll_hw_state.pll6,
+ pipe_config->dpll_hw_state.pll8,
+ pipe_config->dpll_hw_state.pcsdw12);
+ } else if (IS_SKYLAKE(dev)) {
+ DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: "
+ "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
+ pipe_config->ddi_pll_sel,
+ pipe_config->dpll_hw_state.ctrl1,
+ pipe_config->dpll_hw_state.cfgcr1,
+ pipe_config->dpll_hw_state.cfgcr2);
+ } else if (HAS_DDI(dev)) {
+ DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x\n",
+ pipe_config->ddi_pll_sel,
+ pipe_config->dpll_hw_state.wrpll);
+ } else {
+ DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
+ "fp0: 0x%x, fp1: 0x%x\n",
+ pipe_config->dpll_hw_state.dpll,
+ pipe_config->dpll_hw_state.dpll_md,
+ pipe_config->dpll_hw_state.fp0,
+ pipe_config->dpll_hw_state.fp1);
+ }
+
DRM_DEBUG_KMS("planes on this crtc\n");
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
intel_plane = to_intel_plane(plane);
{
struct drm_crtc_state tmp_state;
struct intel_crtc_scaler_state scaler_state;
+ struct intel_dpll_hw_state dpll_hw_state;
+ enum intel_dpll_id shared_dpll;
+ uint32_t ddi_pll_sel;
+
+ /* FIXME: before the switch to atomic started, a new pipe_config was
+ * kzalloc'd. Code that depends on any field being zero should be
+ * fixed, so that the crtc_state can be safely duplicated. For now,
+ * only fields that are know to not cause problems are preserved. */
- /* Clear only the intel specific part of the crtc state excluding scalers */
tmp_state = crtc_state->base;
scaler_state = crtc_state->scaler_state;
+ shared_dpll = crtc_state->shared_dpll;
+ dpll_hw_state = crtc_state->dpll_hw_state;
+ ddi_pll_sel = crtc_state->ddi_pll_sel;
+
memset(crtc_state, 0, sizeof *crtc_state);
+
crtc_state->base = tmp_state;
crtc_state->scaler_state = scaler_state;
+ crtc_state->shared_dpll = shared_dpll;
+ crtc_state->dpll_hw_state = dpll_hw_state;
+ crtc_state->ddi_pll_sel = ddi_pll_sel;
}
-static struct intel_crtc_state *
+static int
intel_modeset_pipe_config(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_atomic_state *state)
+ struct drm_atomic_state *state,
+ struct intel_crtc_state *pipe_config)
{
struct intel_encoder *encoder;
struct drm_connector *connector;
struct drm_connector_state *connector_state;
- struct intel_crtc_state *pipe_config;
int base_bpp, ret = -EINVAL;
int i;
bool retry = true;
if (!check_encoder_cloning(state, to_intel_crtc(crtc))) {
DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
if (!check_digital_port_conflicts(state)) {
DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
- pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));
- if (IS_ERR(pipe_config))
- return pipe_config;
-
clear_intel_crtc_state(pipe_config);
- pipe_config->base.crtc = crtc;
- drm_mode_copy(&pipe_config->base.adjusted_mode, mode);
- drm_mode_copy(&pipe_config->base.mode, mode);
-
pipe_config->cpu_transcoder =
(enum transcoder) to_intel_crtc(crtc)->pipe;
- pipe_config->shared_dpll = DPLL_ID_PRIVATE;
/*
* Sanitize sync polarity flags based on requested ones. If neither
DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
- return pipe_config;
+ return 0;
fail:
- return ERR_PTR(ret);
-}
-
-/* Computes which crtcs are affected and sets the relevant bits in the mask. For
- * simplicity we use the crtc's pipe number (because it's easier to obtain). */
-static void
-intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
- unsigned *prepare_pipes, unsigned *disable_pipes)
-{
- struct intel_crtc *intel_crtc;
- struct drm_device *dev = crtc->dev;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
- struct drm_crtc *tmp_crtc;
-
- *disable_pipes = *modeset_pipes = *prepare_pipes = 0;
-
- /* Check which crtcs have changed outputs connected to them, these need
- * to be part of the prepare_pipes mask. We don't (yet) support global
- * modeset across multiple crtcs, so modeset_pipes will only have one
- * bit set at most. */
- for_each_intel_connector(dev, connector) {
- if (connector->base.encoder == &connector->new_encoder->base)
- continue;
-
- if (connector->base.encoder) {
- tmp_crtc = connector->base.encoder->crtc;
-
- *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe;
- }
-
- if (connector->new_encoder)
- *prepare_pipes |=
- 1 << connector->new_encoder->new_crtc->pipe;
- }
-
- for_each_intel_encoder(dev, encoder) {
- if (encoder->base.crtc == &encoder->new_crtc->base)
- continue;
-
- if (encoder->base.crtc) {
- tmp_crtc = encoder->base.crtc;
-
- *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe;
- }
-
- if (encoder->new_crtc)
- *prepare_pipes |= 1 << encoder->new_crtc->pipe;
- }
-
- /* Check for pipes that will be enabled/disabled ... */
- for_each_intel_crtc(dev, intel_crtc) {
- if (intel_crtc->base.state->enable == intel_crtc->new_enabled)
- continue;
-
- if (!intel_crtc->new_enabled)
- *disable_pipes |= 1 << intel_crtc->pipe;
- else
- *prepare_pipes |= 1 << intel_crtc->pipe;
- }
-
-
- /* set_mode is also used to update properties on life display pipes. */
- intel_crtc = to_intel_crtc(crtc);
- if (intel_crtc->new_enabled)
- *prepare_pipes |= 1 << intel_crtc->pipe;
-
- /*
- * For simplicity do a full modeset on any pipe where the output routing
- * changed. We could be more clever, but that would require us to be
- * more careful with calling the relevant encoder->mode_set functions.
- */
- if (*prepare_pipes)
- *modeset_pipes = *prepare_pipes;
-
- /* ... and mask these out. */
- *modeset_pipes &= ~(*disable_pipes);
- *prepare_pipes &= ~(*disable_pipes);
-
- /*
- * HACK: We don't (yet) fully support global modesets. intel_set_config
- * obies this rule, but the modeset restore mode of
- * intel_modeset_setup_hw_state does not.
- */
- *modeset_pipes &= 1 << intel_crtc->pipe;
- *prepare_pipes &= 1 << intel_crtc->pipe;
-
- DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
- *modeset_pipes, *prepare_pipes, *disable_pipes);
+ return ret;
}
static bool intel_crtc_in_use(struct drm_crtc *crtc)
return false;
}
+static bool
+needs_modeset(struct drm_crtc_state *state)
+{
+ return state->mode_changed || state->active_changed;
+}
+
static void
-intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
+intel_modeset_update_state(struct drm_atomic_state *state)
{
+ struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
- struct intel_crtc *intel_crtc;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
+ int i;
intel_shared_dpll_commit(dev_priv);
if (!intel_encoder->base.crtc)
continue;
- intel_crtc = to_intel_crtc(intel_encoder->base.crtc);
+ for_each_crtc_in_state(state, crtc, crtc_state, i)
+ if (crtc == intel_encoder->base.crtc)
+ break;
+
+ if (crtc != intel_encoder->base.crtc)
+ continue;
- if (prepare_pipes & (1 << intel_crtc->pipe))
+ if (crtc_state->enable && needs_modeset(crtc_state))
intel_encoder->connectors_active = false;
}
- intel_modeset_commit_output_state(dev);
+ drm_atomic_helper_swap_state(state->dev, state);
+ intel_modeset_fixup_state(state);
/* Double check state. */
- for_each_intel_crtc(dev, intel_crtc) {
- WARN_ON(intel_crtc->base.state->enable != intel_crtc_in_use(&intel_crtc->base));
+ for_each_crtc(dev, crtc) {
+ WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc));
}
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (!connector->encoder || !connector->encoder->crtc)
continue;
- intel_crtc = to_intel_crtc(connector->encoder->crtc);
+ for_each_crtc_in_state(state, crtc, crtc_state, i)
+ if (crtc == connector->encoder->crtc)
+ break;
+
+ if (crtc != connector->encoder->crtc)
+ continue;
- if (prepare_pipes & (1 << intel_crtc->pipe)) {
+ if (crtc->state->enable && needs_modeset(crtc->state)) {
struct drm_property *dpms_property =
dev->mode_config.dpms_property;
static struct intel_crtc_state *
intel_modeset_compute_config(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_atomic_state *state,
- unsigned *modeset_pipes,
- unsigned *prepare_pipes,
- unsigned *disable_pipes)
+ struct drm_atomic_state *state)
{
- struct drm_device *dev = crtc->dev;
- struct intel_crtc_state *pipe_config = NULL;
- struct intel_crtc *intel_crtc;
+ struct intel_crtc_state *pipe_config;
int ret = 0;
ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret)
return ERR_PTR(ret);
- intel_modeset_affected_pipes(crtc, modeset_pipes,
- prepare_pipes, disable_pipes);
+ ret = drm_atomic_helper_check_modeset(state->dev, state);
+ if (ret)
+ return ERR_PTR(ret);
/*
* Note this needs changes when we start tracking multiple modes
* (i.e. one pipe_config for each crtc) rather than just the one
* for this crtc.
*/
- for_each_intel_crtc_masked(dev, *modeset_pipes, intel_crtc) {
- /* FIXME: For now we still expect modeset_pipes has at most
- * one bit set. */
- if (WARN_ON(&intel_crtc->base != crtc))
- continue;
+ pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));
+ if (IS_ERR(pipe_config))
+ return pipe_config;
- pipe_config = intel_modeset_pipe_config(crtc, mode, state);
- if (IS_ERR(pipe_config))
- return pipe_config;
+ if (!pipe_config->base.enable)
+ return pipe_config;
- intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
- "[modeset]");
- }
+ ret = intel_modeset_pipe_config(crtc, state, pipe_config);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Check things that can only be changed through modeset */
+ if (pipe_config->has_audio !=
+ to_intel_crtc(crtc)->config->has_audio)
+ pipe_config->base.mode_changed = true;
+
+ /*
+ * Note we have an issue here with infoframes: current code
+ * only updates them on the full mode set path per hw
+ * requirements. So here we should be checking for any
+ * required changes and forcing a mode set.
+ */
- return intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));;
+ intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,"[modeset]");
+
+ ret = drm_atomic_helper_check_planes(state->dev, state);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return pipe_config;
}
-static int __intel_set_mode_setup_plls(struct drm_atomic_state *state,
- unsigned modeset_pipes,
- unsigned disable_pipes)
+static int __intel_set_mode_setup_plls(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
- unsigned clear_pipes = modeset_pipes | disable_pipes;
+ unsigned clear_pipes = 0;
struct intel_crtc *intel_crtc;
+ struct intel_crtc_state *intel_crtc_state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
int ret = 0;
+ int i;
if (!dev_priv->display.crtc_compute_clock)
return 0;
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ intel_crtc = to_intel_crtc(crtc);
+ intel_crtc_state = to_intel_crtc_state(crtc_state);
+
+ if (needs_modeset(crtc_state)) {
+ clear_pipes |= 1 << intel_crtc->pipe;
+ intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE;
+ }
+ }
+
ret = intel_shared_dpll_start_config(dev_priv, clear_pipes);
if (ret)
goto done;
- for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
- struct intel_crtc_state *crtc_state =
- intel_atomic_get_crtc_state(state, intel_crtc);
-
- /* Modeset pipes should have a new state by now */
- if (WARN_ON(IS_ERR(crtc_state)))
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ if (!needs_modeset(crtc_state) || !crtc_state->enable)
continue;
+ intel_crtc = to_intel_crtc(crtc);
+ intel_crtc_state = to_intel_crtc_state(crtc_state);
+
ret = dev_priv->display.crtc_compute_clock(intel_crtc,
- crtc_state);
+ intel_crtc_state);
if (ret) {
intel_shared_dpll_abort_config(dev_priv);
goto done;
return ret;
}
-static int __intel_set_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb,
- struct intel_crtc_state *pipe_config,
- unsigned modeset_pipes,
- unsigned prepare_pipes,
- unsigned disable_pipes)
+/* Code that should eventually be part of atomic_check() */
+static int __intel_set_mode_checks(struct drm_atomic_state *state)
{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *saved_mode;
- struct drm_atomic_state *state = pipe_config->base.state;
- struct intel_crtc_state *crtc_state_copy = NULL;
- struct intel_crtc *intel_crtc;
- int ret = 0;
-
- saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL);
- if (!saved_mode)
- return -ENOMEM;
-
- crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL);
- if (!crtc_state_copy) {
- ret = -ENOMEM;
- goto done;
- }
-
- *saved_mode = crtc->mode;
+ struct drm_device *dev = state->dev;
+ int ret;
/*
* See if the config requires any additional preparation, e.g.
* adjusted_mode bits in the crtc directly.
*/
if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) {
- ret = valleyview_modeset_global_pipes(state, &prepare_pipes);
+ ret = valleyview_modeset_global_pipes(state);
if (ret)
- goto done;
-
- /* may have added more to prepare_pipes than we should */
- prepare_pipes &= ~disable_pipes;
+ return ret;
}
- ret = __intel_set_mode_setup_plls(state, modeset_pipes, disable_pipes);
+ ret = __intel_set_mode_setup_plls(state);
if (ret)
- goto done;
+ return ret;
- for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
- intel_crtc_disable(&intel_crtc->base);
+ return 0;
+}
- for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
- if (intel_crtc->base.state->enable) {
- intel_crtc_disable_planes(&intel_crtc->base);
- dev_priv->display.crtc_disable(&intel_crtc->base);
+static int __intel_set_mode(struct drm_crtc *modeset_crtc,
+ struct intel_crtc_state *pipe_config)
+{
+ struct drm_device *dev = modeset_crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_atomic_state *state = pipe_config->base.state;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int ret = 0;
+ int i;
+
+ ret = __intel_set_mode_checks(state);
+ if (ret < 0)
+ return ret;
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ if (!needs_modeset(crtc_state))
+ continue;
+
+ if (!crtc_state->enable) {
+ intel_crtc_disable(crtc);
+ } else if (crtc->state->enable) {
+ intel_crtc_disable_planes(crtc);
+ dev_priv->display.crtc_disable(crtc);
}
}
* pipes; here we assume a single modeset_pipe and only track the
* single crtc and mode.
*/
- if (modeset_pipes) {
- crtc->mode = *mode;
- /* mode_set/enable/disable functions rely on a correct pipe
- * config. */
- intel_crtc_set_state(to_intel_crtc(crtc), pipe_config);
+ if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) {
+ modeset_crtc->mode = pipe_config->base.mode;
/*
* Calculate and store various constants which
* are later needed by vblank and swap-completion
* timestamping. They are derived from true hwmode.
*/
- drm_calc_timestamping_constants(crtc,
+ drm_calc_timestamping_constants(modeset_crtc,
&pipe_config->base.adjusted_mode);
}
/* Only after disabling all output pipelines that will be changed can we
* update the the output configuration. */
- intel_modeset_update_state(dev, prepare_pipes);
+ intel_modeset_update_state(state);
+
+ /* The state has been swaped above, so state actually contains the
+ * old state now. */
modeset_update_crtc_power_domains(state);
- for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
- struct drm_plane *primary = intel_crtc->base.primary;
- int vdisplay, hdisplay;
-
- drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
- ret = drm_plane_helper_update(primary, &intel_crtc->base,
- fb, 0, 0,
- hdisplay, vdisplay,
- x << 16, y << 16,
- hdisplay << 16, vdisplay << 16);
- }
+ drm_atomic_helper_commit_planes(dev, state);
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
- for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) {
- update_scanline_offset(intel_crtc);
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ if (!needs_modeset(crtc->state) || !crtc->state->enable)
+ continue;
- dev_priv->display.crtc_enable(&intel_crtc->base);
- intel_crtc_enable_planes(&intel_crtc->base);
+ update_scanline_offset(to_intel_crtc(crtc));
+
+ dev_priv->display.crtc_enable(crtc);
+ intel_crtc_enable_planes(crtc);
}
/* FIXME: add subpixel order */
-done:
- if (ret && crtc->state->enable)
- crtc->mode = *saved_mode;
- if (ret == 0 && pipe_config) {
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ drm_atomic_helper_cleanup_planes(dev, state);
- /* The pipe_config will be freed with the atomic state, so
- * make a copy. */
- memcpy(crtc_state_copy, intel_crtc->config,
- sizeof *crtc_state_copy);
- intel_crtc->config = crtc_state_copy;
- intel_crtc->base.state = &crtc_state_copy->base;
- } else {
- kfree(crtc_state_copy);
- }
+ drm_atomic_state_free(state);
- kfree(saved_mode);
- return ret;
+ return 0;
}
-static int intel_set_mode_pipes(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb,
- struct intel_crtc_state *pipe_config,
- unsigned modeset_pipes,
- unsigned prepare_pipes,
- unsigned disable_pipes)
+static int intel_set_mode_with_config(struct drm_crtc *crtc,
+ struct intel_crtc_state *pipe_config)
{
int ret;
- ret = __intel_set_mode(crtc, mode, x, y, fb, pipe_config, modeset_pipes,
- prepare_pipes, disable_pipes);
+ ret = __intel_set_mode(crtc, pipe_config);
if (ret == 0)
intel_modeset_check_state(crtc->dev);
}
static int intel_set_mode(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- int x, int y, struct drm_framebuffer *fb,
struct drm_atomic_state *state)
{
struct intel_crtc_state *pipe_config;
- unsigned modeset_pipes, prepare_pipes, disable_pipes;
int ret = 0;
- pipe_config = intel_modeset_compute_config(crtc, mode, state,
- &modeset_pipes,
- &prepare_pipes,
- &disable_pipes);
-
+ pipe_config = intel_modeset_compute_config(crtc, state);
if (IS_ERR(pipe_config)) {
ret = PTR_ERR(pipe_config);
goto out;
}
- ret = intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config,
- modeset_pipes, prepare_pipes,
- disable_pipes);
+ ret = intel_set_mode_with_config(crtc, pipe_config);
if (ret)
goto out;
struct intel_connector *connector;
struct drm_connector_state *connector_state;
struct intel_crtc_state *crtc_state;
+ int ret;
state = drm_atomic_state_alloc(dev);
if (!state) {
continue;
}
- crtc_state->base.enable = intel_crtc->new_enabled;
- }
-
- intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb,
- state);
-
- drm_atomic_state_free(state);
-}
-
-#undef for_each_intel_crtc_masked
-
-static void intel_set_config_free(struct intel_set_config *config)
-{
- if (!config)
- return;
-
- kfree(config->save_connector_encoders);
- kfree(config->save_encoder_crtcs);
- kfree(config->save_crtc_enabled);
- kfree(config);
-}
-
-static int intel_set_config_save_state(struct drm_device *dev,
- struct intel_set_config *config)
-{
- struct drm_crtc *crtc;
- struct drm_encoder *encoder;
- struct drm_connector *connector;
- int count;
-
- config->save_crtc_enabled =
- kcalloc(dev->mode_config.num_crtc,
- sizeof(bool), GFP_KERNEL);
- if (!config->save_crtc_enabled)
- return -ENOMEM;
-
- config->save_encoder_crtcs =
- kcalloc(dev->mode_config.num_encoder,
- sizeof(struct drm_crtc *), GFP_KERNEL);
- if (!config->save_encoder_crtcs)
- return -ENOMEM;
-
- config->save_connector_encoders =
- kcalloc(dev->mode_config.num_connector,
- sizeof(struct drm_encoder *), GFP_KERNEL);
- if (!config->save_connector_encoders)
- return -ENOMEM;
-
- /* Copy data. Note that driver private data is not affected.
- * Should anything bad happen only the expected state is
- * restored, not the drivers personal bookkeeping.
- */
- count = 0;
- for_each_crtc(dev, crtc) {
- config->save_crtc_enabled[count++] = crtc->state->enable;
- }
+ crtc_state->base.active = crtc_state->base.enable =
+ intel_crtc->new_enabled;
- count = 0;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- config->save_encoder_crtcs[count++] = encoder->crtc;
+ if (&intel_crtc->base == crtc)
+ drm_mode_copy(&crtc_state->base.mode, &crtc->mode);
}
- count = 0;
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- config->save_connector_encoders[count++] = connector->encoder;
- }
+ intel_modeset_setup_plane_state(state, crtc, &crtc->mode,
+ crtc->primary->fb, crtc->x, crtc->y);
- return 0;
+ ret = intel_set_mode(crtc, state);
+ if (ret)
+ drm_atomic_state_free(state);
}
-static void intel_set_config_restore_state(struct drm_device *dev,
- struct intel_set_config *config)
-{
- struct intel_crtc *crtc;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
- int count;
-
- count = 0;
- for_each_intel_crtc(dev, crtc) {
- crtc->new_enabled = config->save_crtc_enabled[count++];
- }
-
- count = 0;
- for_each_intel_encoder(dev, encoder) {
- encoder->new_crtc =
- to_intel_crtc(config->save_encoder_crtcs[count++]);
- }
-
- count = 0;
- for_each_intel_connector(dev, connector) {
- connector->new_encoder =
- to_intel_encoder(config->save_connector_encoders[count++]);
- }
-}
+#undef for_each_intel_crtc_masked
-static bool
-is_crtc_connector_off(struct drm_mode_set *set)
+static bool intel_connector_in_mode_set(struct intel_connector *connector,
+ struct drm_mode_set *set)
{
- int i;
-
- if (set->num_connectors == 0)
- return false;
-
- if (WARN_ON(set->connectors == NULL))
- return false;
+ int ro;
- for (i = 0; i < set->num_connectors; i++)
- if (set->connectors[i]->encoder &&
- set->connectors[i]->encoder->crtc == set->crtc &&
- set->connectors[i]->dpms != DRM_MODE_DPMS_ON)
+ for (ro = 0; ro < set->num_connectors; ro++)
+ if (set->connectors[ro] == &connector->base)
return true;
return false;
}
-static void
-intel_set_config_compute_mode_changes(struct drm_mode_set *set,
- struct intel_set_config *config)
-{
- struct drm_device *dev = set->crtc->dev;
- struct intel_connector *connector;
- struct intel_encoder *encoder;
- struct intel_crtc *crtc;
-
- /* We should be able to check here if the fb has the same properties
- * and then just flip_or_move it */
- if (is_crtc_connector_off(set)) {
- config->mode_changed = true;
- } else if (set->crtc->primary->fb != set->fb) {
- /*
- * If we have no fb, we can only flip as long as the crtc is
- * active, otherwise we need a full mode set. The crtc may
- * be active if we've only disabled the primary plane, or
- * in fastboot situations.
- */
- if (set->crtc->primary->fb == NULL) {
- struct intel_crtc *intel_crtc =
- to_intel_crtc(set->crtc);
-
- if (intel_crtc->active) {
- DRM_DEBUG_KMS("crtc has no fb, will flip\n");
- config->fb_changed = true;
- } else {
- DRM_DEBUG_KMS("inactive crtc, full mode set\n");
- config->mode_changed = true;
- }
- } else if (set->fb == NULL) {
- config->mode_changed = true;
- } else if (set->fb->pixel_format !=
- set->crtc->primary->fb->pixel_format) {
- config->mode_changed = true;
- } else {
- config->fb_changed = true;
- }
- }
-
- if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y))
- config->fb_changed = true;
-
- if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
- DRM_DEBUG_KMS("modes are different, full mode set\n");
- drm_mode_debug_printmodeline(&set->crtc->mode);
- drm_mode_debug_printmodeline(set->mode);
- config->mode_changed = true;
- }
-
- for_each_intel_connector(dev, connector) {
- if (&connector->new_encoder->base == connector->base.encoder)
- continue;
-
- config->mode_changed = true;
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n",
- connector->base.base.id,
- connector->base.name);
- }
-
- for_each_intel_encoder(dev, encoder) {
- if (&encoder->new_crtc->base == encoder->base.crtc)
- continue;
-
- DRM_DEBUG_KMS("[ENCODER:%d:%s] crtc changed, full mode switch\n",
- encoder->base.base.id,
- encoder->base.name);
- config->mode_changed = true;
- }
-
- for_each_intel_crtc(dev, crtc) {
- if (crtc->new_enabled == crtc->base.state->enable)
- continue;
-
- DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n",
- crtc->base.base.id,
- crtc->new_enabled ? "en" : "dis");
- config->mode_changed = true;
- }
-
- DRM_DEBUG_KMS("computed changes for [CRTC:%d], mode_changed=%d, fb_changed=%d\n",
- set->crtc->base.id, config->mode_changed, config->fb_changed);
-}
-
static int
intel_modeset_stage_output_state(struct drm_device *dev,
struct drm_mode_set *set,
struct drm_atomic_state *state)
{
struct intel_connector *connector;
+ struct drm_connector *drm_connector;
struct drm_connector_state *connector_state;
- struct intel_encoder *encoder;
- struct intel_crtc *crtc;
- struct intel_crtc_state *crtc_state;
- int ro;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int i, ret;
/* The upper layers ensure that we either disable a crtc or have a list
* of connectors. For paranoia, double-check this. */
WARN_ON(set->fb && (set->num_connectors == 0));
for_each_intel_connector(dev, connector) {
- /* Otherwise traverse passed in connector list and get encoders
- * for them. */
- for (ro = 0; ro < set->num_connectors; ro++) {
- if (set->connectors[ro] == &connector->base) {
- connector->new_encoder = intel_find_encoder(connector, to_intel_crtc(set->crtc)->pipe);
- break;
- }
+ bool in_mode_set = intel_connector_in_mode_set(connector, set);
+
+ if (!in_mode_set && connector->base.state->crtc != set->crtc)
+ continue;
+
+ connector_state =
+ drm_atomic_get_connector_state(state, &connector->base);
+ if (IS_ERR(connector_state))
+ return PTR_ERR(connector_state);
+
+ if (in_mode_set) {
+ int pipe = to_intel_crtc(set->crtc)->pipe;
+ connector_state->best_encoder =
+ &intel_find_encoder(connector, pipe)->base;
}
+ if (connector->base.state->crtc != set->crtc)
+ continue;
+
/* If we disable the crtc, disable all its connectors. Also, if
* the connector is on the changing crtc but not on the new
* connector list, disable it. */
- if ((!set->fb || ro == set->num_connectors) &&
- connector->base.encoder &&
- connector->base.encoder->crtc == set->crtc) {
- connector->new_encoder = NULL;
+ if (!set->fb || !in_mode_set) {
+ connector_state->best_encoder = NULL;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",
connector->base.base.id,
}
/* connector->new_encoder is now updated for all connectors. */
- /* Update crtc of enabled connectors. */
- for_each_intel_connector(dev, connector) {
- struct drm_crtc *new_crtc;
+ for_each_connector_in_state(state, drm_connector, connector_state, i) {
+ connector = to_intel_connector(drm_connector);
+
+ if (!connector_state->best_encoder) {
+ ret = drm_atomic_set_crtc_for_connector(connector_state,
+ NULL);
+ if (ret)
+ return ret;
- if (!connector->new_encoder)
continue;
+ }
- new_crtc = connector->new_encoder->base.crtc;
+ if (intel_connector_in_mode_set(connector, set)) {
+ struct drm_crtc *crtc = connector->base.state->crtc;
- for (ro = 0; ro < set->num_connectors; ro++) {
- if (set->connectors[ro] == &connector->base)
- new_crtc = set->crtc;
+ /* If this connector was in a previous crtc, add it
+ * to the state. We might need to disable it. */
+ if (crtc) {
+ crtc_state =
+ drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+ }
+
+ ret = drm_atomic_set_crtc_for_connector(connector_state,
+ set->crtc);
+ if (ret)
+ return ret;
}
/* Make sure the new CRTC will work with the encoder */
- if (!drm_encoder_crtc_ok(&connector->new_encoder->base,
- new_crtc)) {
+ if (!drm_encoder_crtc_ok(connector_state->best_encoder,
+ connector_state->crtc)) {
return -EINVAL;
}
- connector->new_encoder->new_crtc = to_intel_crtc(new_crtc);
-
- connector_state =
- drm_atomic_get_connector_state(state, &connector->base);
- if (IS_ERR(connector_state))
- return PTR_ERR(connector_state);
-
- connector_state->crtc = new_crtc;
- connector_state->best_encoder = &connector->new_encoder->base;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",
connector->base.base.id,
connector->base.name,
- new_crtc->base.id);
+ connector_state->crtc->base.id);
+
+ if (connector_state->best_encoder != &connector->encoder->base)
+ connector->encoder =
+ to_intel_encoder(connector_state->best_encoder);
}
- /* Check for any encoders that needs to be disabled. */
- for_each_intel_encoder(dev, encoder) {
- int num_connectors = 0;
- for_each_intel_connector(dev, connector) {
- if (connector->new_encoder == encoder) {
- WARN_ON(!connector->new_encoder->new_crtc);
- num_connectors++;
- }
- }
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ bool has_connectors;
- if (num_connectors == 0)
- encoder->new_crtc = NULL;
- else if (num_connectors > 1)
- return -EINVAL;
- }
- /* Now we've also updated encoder->new_crtc for all encoders. */
- for_each_intel_connector(dev, connector) {
- connector_state =
- drm_atomic_get_connector_state(state, &connector->base);
- if (IS_ERR(connector_state))
- return PTR_ERR(connector_state);
+ ret = drm_atomic_add_affected_connectors(state, crtc);
+ if (ret)
+ return ret;
- if (connector->new_encoder) {
- if (connector->new_encoder != connector->encoder)
- connector->encoder = connector->new_encoder;
- } else {
- connector_state->crtc = NULL;
- connector_state->best_encoder = NULL;
- }
+ has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc);
+ if (has_connectors != crtc_state->enable)
+ crtc_state->enable =
+ crtc_state->active = has_connectors;
}
- for_each_intel_crtc(dev, crtc) {
- crtc->new_enabled = false;
- for_each_intel_encoder(dev, encoder) {
- if (encoder->new_crtc == crtc) {
- crtc->new_enabled = true;
- break;
- }
- }
+ ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode,
+ set->fb, set->x, set->y);
+ if (ret)
+ return ret;
- if (crtc->new_enabled != crtc->base.state->enable) {
- crtc_state = intel_atomic_get_crtc_state(state, crtc);
- if (IS_ERR(crtc_state))
- return PTR_ERR(crtc_state);
+ crtc_state = drm_atomic_get_crtc_state(state, set->crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
- crtc_state->base.enable = crtc->new_enabled;
- }
- }
+ if (set->mode)
+ drm_mode_copy(&crtc_state->mode, set->mode);
+
+ if (set->num_connectors)
+ crtc_state->active = true;
return 0;
}
-static void disable_crtc_nofb(struct intel_crtc *crtc)
+static bool primary_plane_visible(struct drm_crtc *crtc)
{
- struct drm_device *dev = crtc->base.dev;
- struct intel_encoder *encoder;
- struct intel_connector *connector;
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(crtc->primary->state);
- DRM_DEBUG_KMS("Trying to restore without FB -> disabling pipe %c\n",
- pipe_name(crtc->pipe));
-
- for_each_intel_connector(dev, connector) {
- if (connector->new_encoder &&
- connector->new_encoder->new_crtc == crtc)
- connector->new_encoder = NULL;
- }
-
- for_each_intel_encoder(dev, encoder) {
- if (encoder->new_crtc == crtc)
- encoder->new_crtc = NULL;
- }
-
- crtc->new_enabled = false;
+ return plane_state->visible;
}
static int intel_crtc_set_config(struct drm_mode_set *set)
{
struct drm_device *dev;
- struct drm_mode_set save_set;
struct drm_atomic_state *state = NULL;
- struct intel_set_config *config;
struct intel_crtc_state *pipe_config;
- unsigned modeset_pipes, prepare_pipes, disable_pipes;
+ bool primary_plane_was_visible;
int ret;
BUG_ON(!set);
dev = set->crtc->dev;
- ret = -ENOMEM;
- config = kzalloc(sizeof(*config), GFP_KERNEL);
- if (!config)
- goto out_config;
-
- ret = intel_set_config_save_state(dev, config);
- if (ret)
- goto out_config;
-
- save_set.crtc = set->crtc;
- save_set.mode = &set->crtc->mode;
- save_set.x = set->crtc->x;
- save_set.y = set->crtc->y;
- save_set.fb = set->crtc->primary->fb;
-
state = drm_atomic_state_alloc(dev);
- if (!state) {
- ret = -ENOMEM;
- goto out_config;
- }
+ if (!state)
+ return -ENOMEM;
state->acquire_ctx = dev->mode_config.acquire_ctx;
ret = intel_modeset_stage_output_state(dev, set, state);
if (ret)
- goto fail;
+ goto out;
- /* Compute whether we need a full modeset, only an fb base update or no
- * change at all. In the future we might also check whether only the
- * mode changed, e.g. for LVDS where we only change the panel fitter in
- * such cases. */
- intel_set_config_compute_mode_changes(set, config);
-
- pipe_config = intel_modeset_compute_config(set->crtc, set->mode,
- state,
- &modeset_pipes,
- &prepare_pipes,
- &disable_pipes);
+ pipe_config = intel_modeset_compute_config(set->crtc, state);
if (IS_ERR(pipe_config)) {
ret = PTR_ERR(pipe_config);
- goto fail;
- } else if (pipe_config) {
- if (pipe_config->has_audio !=
- to_intel_crtc(set->crtc)->config->has_audio)
- config->mode_changed = true;
-
- /*
- * Note we have an issue here with infoframes: current code
- * only updates them on the full mode set path per hw
- * requirements. So here we should be checking for any
- * required changes and forcing a mode set.
- */
+ goto out;
}
intel_update_pipe_size(to_intel_crtc(set->crtc));
- if (config->mode_changed) {
- ret = intel_set_mode_pipes(set->crtc, set->mode,
- set->x, set->y, set->fb, pipe_config,
- modeset_pipes, prepare_pipes,
- disable_pipes);
- } else if (config->fb_changed) {
+ primary_plane_was_visible = primary_plane_visible(set->crtc);
+
+ ret = intel_set_mode_with_config(set->crtc, pipe_config);
+
+ if (ret == 0 &&
+ pipe_config->base.enable &&
+ pipe_config->base.planes_changed &&
+ !needs_modeset(&pipe_config->base)) {
struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
- struct drm_plane *primary = set->crtc->primary;
- struct intel_plane_state *plane_state =
- to_intel_plane_state(primary->state);
- bool was_visible = plane_state->visible;
- int vdisplay, hdisplay;
-
- drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
- ret = drm_plane_helper_update(primary, set->crtc, set->fb,
- 0, 0, hdisplay, vdisplay,
- set->x << 16, set->y << 16,
- hdisplay << 16, vdisplay << 16);
/*
* We need to make sure the primary plane is re-enabled if it
* has previously been turned off.
*/
- plane_state = to_intel_plane_state(primary->state);
- if (ret == 0 && !was_visible && plane_state->visible) {
+ if (ret == 0 && !primary_plane_was_visible &&
+ primary_plane_visible(set->crtc)) {
WARN_ON(!intel_crtc->active);
intel_post_enable_primary(set->crtc);
}
if (ret) {
DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
set->crtc->base.id, ret);
-fail:
- intel_set_config_restore_state(dev, config);
-
- drm_atomic_state_clear(state);
-
- /*
- * HACK: if the pipe was on, but we didn't have a framebuffer,
- * force the pipe off to avoid oopsing in the modeset code
- * due to fb==NULL. This should only happen during boot since
- * we don't yet reconstruct the FB from the hardware state.
- */
- if (to_intel_crtc(save_set.crtc)->new_enabled && !save_set.fb)
- disable_crtc_nofb(to_intel_crtc(save_set.crtc));
-
- /* Try to restore the config */
- if (config->mode_changed &&
- intel_set_mode(save_set.crtc, save_set.mode,
- save_set.x, save_set.y, save_set.fb,
- state))
- DRM_ERROR("failed to restore config after modeset failure\n");
}
-out_config:
- drm_atomic_state_free(state);
-
- intel_set_config_free(config);
+out:
+ if (ret)
+ drm_atomic_state_free(state);
return ret;
}
intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL;
if (INTEL_INFO(dev)->gen >= 9) {
- min_scale = 1;
- max_scale = skl_max_scale(intel_crtc, crtc_state);
+ /* use scaler when colorkey is not required */
+ if (to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) {
+ min_scale = 1;
+ max_scale = skl_max_scale(intel_crtc, crtc_state);
+ }
can_position = true;
}
primary->max_downscale = 1;
if (INTEL_INFO(dev)->gen >= 9) {
primary->can_scale = true;
+ state->scaler_id = -1;
}
- state->scaler_id = -1;
primary->pipe = pipe;
primary->plane = pipe;
primary->check_plane = intel_check_primary_plane;
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
primary->plane = !pipe;
- if (INTEL_INFO(dev)->gen <= 3) {
- intel_primary_formats = intel_primary_formats_gen2;
- num_formats = ARRAY_SIZE(intel_primary_formats_gen2);
+ if (INTEL_INFO(dev)->gen >= 9) {
+ intel_primary_formats = skl_primary_formats;
+ num_formats = ARRAY_SIZE(skl_primary_formats);
+ } else if (INTEL_INFO(dev)->gen >= 4) {
+ intel_primary_formats = i965_primary_formats;
+ num_formats = ARRAY_SIZE(i965_primary_formats);
} else {
- intel_primary_formats = intel_primary_formats_gen4;
- num_formats = ARRAY_SIZE(intel_primary_formats_gen4);
+ intel_primary_formats = i8xx_primary_formats;
+ num_formats = ARRAY_SIZE(i8xx_primary_formats);
}
drm_universal_plane_init(dev, &primary->base, 0,
cursor->max_downscale = 1;
cursor->pipe = pipe;
cursor->plane = pipe;
- state->scaler_id = -1;
cursor->check_plane = intel_check_cursor_plane;
cursor->commit_plane = intel_commit_cursor_plane;
cursor->disable_plane = intel_disable_cursor_plane;
state->base.rotation);
}
+ if (INTEL_INFO(dev)->gen >=9)
+ state->scaler_id = -1;
+
drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
return &cursor->base;
crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
if (!crtc_state)
goto fail;
- intel_crtc_set_state(intel_crtc, crtc_state);
+ intel_crtc->config = crtc_state;
+ intel_crtc->base.state = &crtc_state->base;
crtc_state->base.crtc = &intel_crtc->base;
/* initialize shared scalers */
dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
- INIT_WORK(&intel_crtc->mmio_flip.work, intel_mmio_flip_work_func);
-
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
WARN_ON(drm_crtc_index(&intel_crtc->base) != intel_crtc->pipe);
case DRM_FORMAT_ARGB8888:
break;
case DRM_FORMAT_XRGB1555:
- case DRM_FORMAT_ARGB1555:
if (INTEL_INFO(dev)->gen > 3) {
DRM_DEBUG("unsupported pixel format: %s\n",
drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
}
break;
- case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
+ if (!IS_VALLEYVIEW(dev) && INTEL_INFO(dev)->gen < 9) {
+ DRM_DEBUG("unsupported pixel format: %s\n",
+ drm_get_format_name(mode_cmd->pixel_format));
+ return -EINVAL;
+ }
+ break;
+ case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010:
if (INTEL_INFO(dev)->gen < 4) {
DRM_DEBUG("unsupported pixel format: %s\n",
drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
}
break;
+ case DRM_FORMAT_ABGR2101010:
+ if (!IS_VALLEYVIEW(dev)) {
+ DRM_DEBUG("unsupported pixel format: %s\n",
+ drm_get_format_name(mode_cmd->pixel_format));
+ return -EINVAL;
+ }
+ break;
case DRM_FORMAT_YUYV:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_YVYU:
};
static struct intel_quirk intel_quirks[] = {
- /* HP Mini needs pipe A force quirk (LP: #322104) */
- { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
-
/* Toshiba Protege R-205, S-209 needs pipe A force quirk */
{ 0x2592, 0x1179, 0x0001, quirk_pipea_force },
WARN_ON(crtc->active);
crtc->base.state->enable = false;
+ crtc->base.state->active = false;
crtc->base.enabled = false;
}
crtc->active ? "enabled" : "disabled");
crtc->base.state->enable = crtc->active;
+ crtc->base.state->active = crtc->active;
crtc->base.enabled = crtc->active;
/* Because we only establish the connector -> encoder ->
crtc->config);
crtc->base.state->enable = crtc->active;
+ crtc->base.state->active = crtc->active;
crtc->base.enabled = crtc->active;
plane_state = to_intel_plane_state(primary->state);