aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1295
1 files changed, 1027 insertions, 268 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d547d9c8dda2..3094b0807b40 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -103,6 +103,10 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config);
static void intel_begin_crtc_commit(struct drm_crtc *crtc);
static void intel_finish_crtc_commit(struct drm_crtc *crtc);
+static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *crtc_state);
+static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
+ int num_connectors);
static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
{
@@ -400,6 +404,18 @@ static const intel_limit_t intel_limits_chv = {
.p2 = { .p2_slow = 1, .p2_fast = 14 },
};
+static const intel_limit_t intel_limits_bxt = {
+ /* FIXME: find real dot limits */
+ .dot = { .min = 0, .max = INT_MAX },
+ .vco = { .min = 4800000, .max = 6480000 },
+ .n = { .min = 1, .max = 1 },
+ .m1 = { .min = 2, .max = 2 },
+ /* FIXME: find real m2 limits */
+ .m2 = { .min = 2 << 22, .max = 255 << 22 },
+ .p1 = { .min = 2, .max = 4 },
+ .p2 = { .p2_slow = 1, .p2_fast = 20 },
+};
+
static void vlv_clock(int refclk, intel_clock_t *clock)
{
clock->m = clock->m1 * clock->m2;
@@ -511,7 +527,9 @@ intel_limit(struct intel_crtc_state *crtc_state, int refclk)
struct drm_device *dev = crtc_state->base.crtc->dev;
const intel_limit_t *limit;
- if (HAS_PCH_SPLIT(dev))
+ if (IS_BROXTON(dev))
+ limit = &intel_limits_bxt;
+ else if (HAS_PCH_SPLIT(dev))
limit = intel_ironlake_limit(crtc_state, refclk);
else if (IS_G4X(dev)) {
limit = intel_g4x_limit(crtc_state);
@@ -596,11 +614,11 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
INTELPllInvalid("m1 out of range\n");
- if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev))
+ if (!IS_PINEVIEW(dev) && !IS_VALLEYVIEW(dev) && !IS_BROXTON(dev))
if (clock->m1 <= clock->m2)
INTELPllInvalid("m1 <= m2\n");
- if (!IS_VALLEYVIEW(dev)) {
+ if (!IS_VALLEYVIEW(dev) && !IS_BROXTON(dev)) {
if (clock->p < limit->p.min || limit->p.max < clock->p)
INTELPllInvalid("p out of range\n");
if (clock->m < limit->m.min || limit->m.max < clock->m)
@@ -953,6 +971,15 @@ chv_find_best_dpll(const intel_limit_t *limit,
return found;
}
+bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock,
+ intel_clock_t *best_clock)
+{
+ int refclk = i9xx_get_refclk(crtc_state, 0);
+
+ return chv_find_best_dpll(intel_limit(crtc_state, refclk), crtc_state,
+ target_clock, refclk, NULL, best_clock);
+}
+
bool intel_crtc_active(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -2104,7 +2131,7 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
* a plane. On ILK+ the pipe PLLs are integrated, so we don't
* need the check.
*/
- if (!HAS_PCH_SPLIT(dev_priv->dev))
+ if (HAS_GMCH_DISPLAY(dev_priv->dev))
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DSI))
assert_dsi_pll_enabled(dev_priv);
else
@@ -2338,13 +2365,6 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
info->pitch = fb->pitches[0];
info->fb_modifier = fb->modifier[0];
- if (!(info->fb_modifier == I915_FORMAT_MOD_Y_TILED ||
- info->fb_modifier == I915_FORMAT_MOD_Yf_TILED)) {
- DRM_DEBUG_KMS(
- "Y or Yf tiling is needed for 90/270 rotation!\n");
- return -EINVAL;
- }
-
return 0;
}
@@ -2936,6 +2956,35 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
return i915_gem_obj_ggtt_offset_view(obj, view);
}
+/*
+ * This function detaches (aka. unbinds) unused scalers in hardware
+ */
+void skl_detach_scalers(struct intel_crtc *intel_crtc)
+{
+ struct drm_device *dev;
+ struct drm_i915_private *dev_priv;
+ struct intel_crtc_scaler_state *scaler_state;
+ int i;
+
+ if (!intel_crtc || !intel_crtc->config)
+ return;
+
+ dev = intel_crtc->base.dev;
+ dev_priv = dev->dev_private;
+ scaler_state = &intel_crtc->config->scaler_state;
+
+ /* loop through and disable scalers that aren't in use */
+ for (i = 0; i < intel_crtc->num_scalers; i++) {
+ if (!scaler_state->scalers[i].in_use) {
+ I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, i), 0);
+ I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, i), 0);
+ I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, i), 0);
+ DRM_DEBUG_KMS("CRTC:%d Disabled scaler id %u.%u\n",
+ intel_crtc->base.base.id, intel_crtc->pipe, i);
+ }
+ }
+}
+
static void skylake_update_primary_plane(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
int x, int y)
@@ -2945,8 +2994,12 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_i915_gem_object *obj;
int pipe = intel_crtc->pipe;
- u32 plane_ctl, stride_div;
+ u32 plane_ctl, stride_div, stride;
+ u32 tile_height, plane_offset, plane_size;
+ unsigned int rotation;
+ int x_offset, y_offset;
unsigned long surf_addr;
+ struct drm_plane *plane;
if (!intel_crtc->primary_enabled) {
I915_WRITE(PLANE_CTL(pipe, 0), 0);
@@ -3007,21 +3060,51 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
}
plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
- if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180))
+
+ plane = crtc->primary;
+ rotation = plane->state->rotation;
+ switch (rotation) {
+ case BIT(DRM_ROTATE_90):
+ plane_ctl |= PLANE_CTL_ROTATE_90;
+ break;
+
+ case BIT(DRM_ROTATE_180):
plane_ctl |= PLANE_CTL_ROTATE_180;
+ break;
+
+ case BIT(DRM_ROTATE_270):
+ plane_ctl |= PLANE_CTL_ROTATE_270;
+ break;
+ }
obj = intel_fb_obj(fb);
stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
fb->pixel_format);
- surf_addr = intel_plane_obj_offset(to_intel_plane(crtc->primary), obj);
+ surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj);
+
+ if (intel_rotation_90_or_270(rotation)) {
+ /* stride = Surface height in tiles */
+ tile_height = intel_tile_height(dev, fb->bits_per_pixel,
+ fb->modifier[0]);
+ stride = DIV_ROUND_UP(fb->height, tile_height);
+ x_offset = stride * tile_height - y - (plane->state->src_h >> 16);
+ y_offset = x;
+ plane_size = ((plane->state->src_w >> 16) - 1) << 16 |
+ ((plane->state->src_h >> 16) - 1);
+ } else {
+ stride = fb->pitches[0] / stride_div;
+ x_offset = x;
+ y_offset = y;
+ plane_size = ((plane->state->src_h >> 16) - 1) << 16 |
+ ((plane->state->src_w >> 16) - 1);
+ }
+ plane_offset = y_offset << 16 | x_offset;
I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
I915_WRITE(PLANE_POS(pipe, 0), 0);
- I915_WRITE(PLANE_OFFSET(pipe, 0), (y << 16) | x);
- I915_WRITE(PLANE_SIZE(pipe, 0),
- (intel_crtc->config->pipe_src_h - 1) << 16 |
- (intel_crtc->config->pipe_src_w - 1));
- I915_WRITE(PLANE_STRIDE(pipe, 0), fb->pitches[0] / stride_div);
+ I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
+ I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
+ I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
I915_WRITE(PLANE_SURF(pipe, 0), surf_addr);
POSTING_READ(PLANE_SURF(pipe, 0));
@@ -4126,6 +4209,26 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
goto found;
}
+ if (IS_BROXTON(dev_priv->dev)) {
+ /* PLL is attached to port in bxt */
+ struct intel_encoder *encoder;
+ struct intel_digital_port *intel_dig_port;
+
+ encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
+ if (WARN_ON(!encoder))
+ return NULL;
+
+ intel_dig_port = enc_to_dig_port(&encoder->base);
+ /* 1:1 mapping between ports and PLLs */
+ i = (enum intel_dpll_id)intel_dig_port->port;
+ pll = &dev_priv->shared_dplls[i];
+ DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
+ crtc->base.base.id, pll->name);
+ WARN_ON(pll->new_config->crtc_mask);
+
+ goto found;
+ }
+
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
pll = &dev_priv->shared_dplls[i];
@@ -4251,16 +4354,175 @@ static void cpt_verify_modeset(struct drm_device *dev, int pipe)
}
}
-static void skylake_pfit_enable(struct intel_crtc *crtc)
+/**
+ * skl_update_scaler_users - Stages update to crtc's scaler state
+ * @intel_crtc: crtc
+ * @crtc_state: crtc_state
+ * @plane: plane (NULL indicates crtc is requesting update)
+ * @plane_state: plane's state
+ * @force_detach: request unconditional detachment of scaler
+ *
+ * This function updates scaler state for requested plane or crtc.
+ * To request scaler usage update for a plane, caller shall pass plane pointer.
+ * To request scaler usage update for crtc, caller shall pass plane pointer
+ * as NULL.
+ *
+ * Return
+ * 0 - scaler_usage updated successfully
+ * error - requested scaling cannot be supported or other error condition
+ */
+int
+skl_update_scaler_users(
+ struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state,
+ struct intel_plane *intel_plane, struct intel_plane_state *plane_state,
+ int force_detach)
+{
+ int need_scaling;
+ int idx;
+ int src_w, src_h, dst_w, dst_h;
+ int *scaler_id;
+ struct drm_framebuffer *fb;
+ struct intel_crtc_scaler_state *scaler_state;
+
+ if (!intel_crtc || !crtc_state)
+ return 0;
+
+ scaler_state = &crtc_state->scaler_state;
+
+ idx = intel_plane ? drm_plane_index(&intel_plane->base) : SKL_CRTC_INDEX;
+ fb = intel_plane ? plane_state->base.fb : NULL;
+
+ if (intel_plane) {
+ src_w = drm_rect_width(&plane_state->src) >> 16;
+ src_h = drm_rect_height(&plane_state->src) >> 16;
+ dst_w = drm_rect_width(&plane_state->dst);
+ dst_h = drm_rect_height(&plane_state->dst);
+ scaler_id = &plane_state->scaler_id;
+ } else {
+ struct drm_display_mode *adjusted_mode =
+ &crtc_state->base.adjusted_mode;
+ src_w = crtc_state->pipe_src_w;
+ src_h = crtc_state->pipe_src_h;
+ dst_w = adjusted_mode->hdisplay;
+ dst_h = adjusted_mode->vdisplay;
+ scaler_id = &scaler_state->scaler_id;
+ }
+ need_scaling = (src_w != dst_w || src_h != dst_h);
+
+ /*
+ * if plane is being disabled or scaler is no more required or force detach
+ * - free scaler binded to this plane/crtc
+ * - in order to do this, update crtc->scaler_usage
+ *
+ * Here scaler state in crtc_state is set free so that
+ * scaler can be assigned to other user. Actual register
+ * update to free the scaler is done in plane/panel-fit programming.
+ * For this purpose crtc/plane_state->scaler_id isn't reset here.
+ */
+ if (force_detach || !need_scaling || (intel_plane &&
+ (!fb || !plane_state->visible))) {
+ if (*scaler_id >= 0) {
+ scaler_state->scaler_users &= ~(1 << idx);
+ scaler_state->scalers[*scaler_id].in_use = 0;
+
+ DRM_DEBUG_KMS("Staged freeing scaler id %d.%d from %s:%d "
+ "crtc_state = %p scaler_users = 0x%x\n",
+ intel_crtc->pipe, *scaler_id, intel_plane ? "PLANE" : "CRTC",
+ intel_plane ? intel_plane->base.base.id :
+ intel_crtc->base.base.id, crtc_state,
+ scaler_state->scaler_users);
+ *scaler_id = -1;
+ }
+ return 0;
+ }
+
+ /* range checks */
+ if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
+ dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
+
+ src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
+ dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H) {
+ DRM_DEBUG_KMS("%s:%d scaler_user index %u.%u: src %ux%u dst %ux%u "
+ "size is out of scaler range\n",
+ intel_plane ? "PLANE" : "CRTC",
+ intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id,
+ intel_crtc->pipe, idx, src_w, src_h, dst_w, dst_h);
+ return -EINVAL;
+ }
+
+ /* 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);
+ return -EINVAL;
+ }
+
+ /* Check src format */
+ if (intel_plane) {
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_XRGB8888:
+ 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:
+ case DRM_FORMAT_VYUY:
+ break;
+ default:
+ DRM_DEBUG_KMS("PLANE:%d FB:%d unsupported scaling format 0x%x\n",
+ intel_plane->base.base.id, fb->base.id, fb->pixel_format);
+ return -EINVAL;
+ }
+ }
+
+ /* mark this plane as a scaler user in crtc_state */
+ scaler_state->scaler_users |= (1 << idx);
+ DRM_DEBUG_KMS("%s:%d staged scaling request for %ux%u->%ux%u "
+ "crtc_state = %p scaler_users = 0x%x\n",
+ intel_plane ? "PLANE" : "CRTC",
+ intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id,
+ src_w, src_h, dst_w, dst_h, crtc_state, scaler_state->scaler_users);
+ return 0;
+}
+
+static void skylake_pfit_update(struct intel_crtc *crtc, int enable)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = crtc->pipe;
+ struct intel_crtc_scaler_state *scaler_state =
+ &crtc->config->scaler_state;
+
+ DRM_DEBUG_KMS("for crtc_state = %p\n", crtc->config);
+
+ /* To update pfit, first update scaler state */
+ skl_update_scaler_users(crtc, crtc->config, NULL, NULL, !enable);
+ intel_atomic_setup_scalers(crtc->base.dev, crtc, crtc->config);
+ skl_detach_scalers(crtc);
+ if (!enable)
+ return;
if (crtc->config->pch_pfit.enabled) {
- I915_WRITE(PS_CTL(pipe), PS_ENABLE);
- I915_WRITE(PS_WIN_POS(pipe), crtc->config->pch_pfit.pos);
- I915_WRITE(PS_WIN_SZ(pipe), crtc->config->pch_pfit.size);
+ int id;
+
+ if (WARN_ON(crtc->config->scaler_state.scaler_id < 0)) {
+ DRM_ERROR("Requesting pfit without getting a scaler first\n");
+ return;
+ }
+
+ id = scaler_state->scaler_id;
+ I915_WRITE(SKL_PS_CTRL(pipe, id), PS_SCALER_EN |
+ PS_FILTER_MEDIUM | scaler_state->scalers[id].mode);
+ I915_WRITE(SKL_PS_WIN_POS(pipe, id), crtc->config->pch_pfit.pos);
+ I915_WRITE(SKL_PS_WIN_SZ(pipe, id), crtc->config->pch_pfit.size);
+
+ DRM_DEBUG_KMS("for crtc_state = %p scaler_id = %d\n", crtc->config, id);
}
}
@@ -4404,7 +4666,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
if (!crtc->state->enable || !intel_crtc->active)
return;
- if (!HAS_PCH_SPLIT(dev_priv->dev)) {
+ if (HAS_GMCH_DISPLAY(dev_priv->dev)) {
if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI))
assert_dsi_pll_enabled(dev_priv);
else
@@ -4664,10 +4926,12 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_ddi_enable_pipe_clock(intel_crtc);
- if (IS_SKYLAKE(dev))
- skylake_pfit_enable(intel_crtc);
- else
+ if (INTEL_INFO(dev)->gen == 9)
+ skylake_pfit_update(intel_crtc, 1);
+ else if (INTEL_INFO(dev)->gen < 9)
ironlake_pfit_enable(intel_crtc);
+ else
+ MISSING_CASE(INTEL_INFO(dev)->gen);
/*
* On ILK+ LUT must be loaded before the pipe is running but with
@@ -4701,21 +4965,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc_enable_planes(crtc);
}
-static void skylake_pfit_disable(struct intel_crtc *crtc)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe = crtc->pipe;
-
- /* To avoid upsetting the power well on haswell only disable the pfit if
- * it's in use. The hw state code will make sure we get this right. */
- if (crtc->config->pch_pfit.enabled) {
- I915_WRITE(PS_CTL(pipe), 0);
- I915_WRITE(PS_WIN_POS(pipe), 0);
- I915_WRITE(PS_WIN_SZ(pipe), 0);
- }
-}
-
static void ironlake_pfit_disable(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
@@ -4827,10 +5076,12 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
- if (IS_SKYLAKE(dev))
- skylake_pfit_disable(intel_crtc);
- else
+ if (INTEL_INFO(dev)->gen == 9)
+ skylake_pfit_update(intel_crtc, 0);
+ else if (INTEL_INFO(dev)->gen < 9)
ironlake_pfit_disable(intel_crtc);
+ else
+ MISSING_CASE(INTEL_INFO(dev)->gen);
intel_ddi_disable_pipe_clock(intel_crtc);
@@ -4994,6 +5245,181 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
intel_display_set_init_power(dev_priv, false);
}
+void broxton_set_cdclk(struct drm_device *dev, int frequency)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t divider;
+ uint32_t ratio;
+ uint32_t current_freq;
+ int ret;
+
+ /* frequency = 19.2MHz * ratio / 2 / div{1,1.5,2,4} */
+ switch (frequency) {
+ case 144000:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_4;
+ ratio = BXT_DE_PLL_RATIO(60);
+ break;
+ case 288000:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_2;
+ ratio = BXT_DE_PLL_RATIO(60);
+ break;
+ case 384000:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_1_5;
+ ratio = BXT_DE_PLL_RATIO(60);
+ break;
+ case 576000:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_1;
+ ratio = BXT_DE_PLL_RATIO(60);
+ break;
+ case 624000:
+ divider = BXT_CDCLK_CD2X_DIV_SEL_1;
+ ratio = BXT_DE_PLL_RATIO(65);
+ break;
+ case 19200:
+ /*
+ * Bypass frequency with DE PLL disabled. Init ratio, divider
+ * to suppress GCC warning.
+ */
+ ratio = 0;
+ divider = 0;
+ break;
+ default:
+ DRM_ERROR("unsupported CDCLK freq %d", frequency);
+
+ return;
+ }
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ /* Inform power controller of upcoming frequency change */
+ ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ 0x80000000);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ if (ret) {
+ DRM_ERROR("PCode CDCLK freq change notify failed (err %d, freq %d)\n",
+ ret, frequency);
+ return;
+ }
+
+ current_freq = I915_READ(CDCLK_CTL) & CDCLK_FREQ_DECIMAL_MASK;
+ /* convert from .1 fixpoint MHz with -1MHz offset to kHz */
+ current_freq = current_freq * 500 + 1000;
+
+ /*
+ * DE PLL has to be disabled when
+ * - setting to 19.2MHz (bypass, PLL isn't used)
+ * - before setting to 624MHz (PLL needs toggling)
+ * - before setting to any frequency from 624MHz (PLL needs toggling)
+ */
+ if (frequency == 19200 || frequency == 624000 ||
+ current_freq == 624000) {
+ I915_WRITE(BXT_DE_PLL_ENABLE, ~BXT_DE_PLL_PLL_ENABLE);
+ /* Timeout 200us */
+ if (wait_for(!(I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK),
+ 1))
+ DRM_ERROR("timout waiting for DE PLL unlock\n");
+ }
+
+ if (frequency != 19200) {
+ uint32_t val;
+
+ val = I915_READ(BXT_DE_PLL_CTL);
+ val &= ~BXT_DE_PLL_RATIO_MASK;
+ val |= ratio;
+ I915_WRITE(BXT_DE_PLL_CTL, val);
+
+ I915_WRITE(BXT_DE_PLL_ENABLE, BXT_DE_PLL_PLL_ENABLE);
+ /* Timeout 200us */
+ if (wait_for(I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK, 1))
+ DRM_ERROR("timeout waiting for DE PLL lock\n");
+
+ val = I915_READ(CDCLK_CTL);
+ val &= ~BXT_CDCLK_CD2X_DIV_SEL_MASK;
+ val |= divider;
+ /*
+ * Disable SSA Precharge when CD clock frequency < 500 MHz,
+ * enable otherwise.
+ */
+ val &= ~BXT_CDCLK_SSA_PRECHARGE_ENABLE;
+ if (frequency >= 500000)
+ val |= BXT_CDCLK_SSA_PRECHARGE_ENABLE;
+
+ val &= ~CDCLK_FREQ_DECIMAL_MASK;
+ /* convert from kHz to .1 fixpoint MHz with -1MHz offset */
+ val |= (frequency - 1000) / 500;
+ I915_WRITE(CDCLK_CTL, val);
+ }
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ,
+ DIV_ROUND_UP(frequency, 25000));
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ if (ret) {
+ DRM_ERROR("PCode CDCLK freq set failed, (err %d, freq %d)\n",
+ ret, frequency);
+ return;
+ }
+
+ dev_priv->cdclk_freq = frequency;
+}
+
+void broxton_init_cdclk(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t val;
+
+ /*
+ * NDE_RSTWRN_OPT RST PCH Handshake En must always be 0b on BXT
+ * or else the reset will hang because there is no PCH to respond.
+ * Move the handshake programming to initialization sequence.
+ * Previously was left up to BIOS.
+ */
+ val = I915_READ(HSW_NDE_RSTWRN_OPT);
+ val &= ~RESET_PCH_HANDSHAKE_ENABLE;
+ I915_WRITE(HSW_NDE_RSTWRN_OPT, val);
+
+ /* Enable PG1 for cdclk */
+ intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
+
+ /* check if cd clock is enabled */
+ if (I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_PLL_ENABLE) {
+ DRM_DEBUG_KMS("Display already initialized\n");
+ return;
+ }
+
+ /*
+ * FIXME:
+ * - The initial CDCLK needs to be read from VBT.
+ * Need to make this change after VBT has changes for BXT.
+ * - check if setting the max (or any) cdclk freq is really necessary
+ * here, it belongs to modeset time
+ */
+ broxton_set_cdclk(dev, 624000);
+
+ I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST);
+ udelay(10);
+
+ if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE))
+ DRM_ERROR("DBuf power enable timeout!\n");
+}
+
+void broxton_uninit_cdclk(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) & ~DBUF_POWER_REQUEST);
+ udelay(10);
+
+ if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE)
+ DRM_ERROR("DBuf power disable timeout!\n");
+
+ /* Set minimum (bypass) frequency, in effect turning off the DE PLL */
+ broxton_set_cdclk(dev, 19200);
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+}
+
/* returns HPLL frequency in kHz */
static int valleyview_get_vco(struct drm_i915_private *dev_priv)
{
@@ -5012,16 +5438,16 @@ static void vlv_update_cdclk(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- dev_priv->vlv_cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
+ dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n",
- dev_priv->vlv_cdclk_freq);
+ dev_priv->cdclk_freq);
/*
* Program the gmbus_freq based on the cdclk frequency.
* BSpec erroneously claims we should aim for 4MHz, but
* in fact 1MHz is the correct frequency.
*/
- I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->vlv_cdclk_freq, 1000));
+ I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000));
}
/* Adjust CDclk dividers to allow high res or save power if possible */
@@ -5030,7 +5456,8 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 val, cmd;
- WARN_ON(dev_priv->display.get_display_clock_speed(dev) != dev_priv->vlv_cdclk_freq);
+ WARN_ON(dev_priv->display.get_display_clock_speed(dev)
+ != dev_priv->cdclk_freq);
if (cdclk >= 320000) /* jump to highest voltage for 400MHz too */
cmd = 2;
@@ -5094,7 +5521,8 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 val, cmd;
- WARN_ON(dev_priv->display.get_display_clock_speed(dev) != dev_priv->vlv_cdclk_freq);
+ WARN_ON(dev_priv->display.get_display_clock_speed(dev)
+ != dev_priv->cdclk_freq);
switch (cdclk) {
case 333333:
@@ -5159,37 +5587,74 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
return 200000;
}
+static int broxton_calc_cdclk(struct drm_i915_private *dev_priv,
+ int max_pixclk)
+{
+ /*
+ * FIXME:
+ * - remove the guardband, it's not needed on BXT
+ * - set 19.2MHz bypass frequency if there are no active pipes
+ */
+ if (max_pixclk > 576000*9/10)
+ return 624000;
+ else if (max_pixclk > 384000*9/10)
+ return 576000;
+ else if (max_pixclk > 288000*9/10)
+ return 384000;
+ else if (max_pixclk > 144000*9/10)
+ return 288000;
+ else
+ return 144000;
+}
+
/* compute the max pixel clock for new configuration */
-static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv)
+static int intel_mode_max_pixclk(struct drm_atomic_state *state)
{
- struct drm_device *dev = dev_priv->dev;
+ 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) {
- if (intel_crtc->new_enabled)
- max_pixclk = max(max_pixclk,
- intel_crtc->new_config->base.adjusted_mode.crtc_clock);
+ crtc_state = intel_atomic_get_crtc_state(state, intel_crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ if (!crtc_state->base.enable)
+ continue;
+
+ max_pixclk = max(max_pixclk,
+ crtc_state->base.adjusted_mode.crtc_clock);
}
return max_pixclk;
}
-static void valleyview_modeset_global_pipes(struct drm_device *dev,
+static int valleyview_modeset_global_pipes(struct drm_atomic_state *state,
unsigned *prepare_pipes)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
struct intel_crtc *intel_crtc;
- int max_pixclk = intel_mode_max_pixclk(dev_priv);
+ int max_pixclk = intel_mode_max_pixclk(state);
+ int cdclk;
- if (valleyview_calc_cdclk(dev_priv, max_pixclk) ==
- dev_priv->vlv_cdclk_freq)
- return;
+ if (max_pixclk < 0)
+ return max_pixclk;
+
+ if (IS_VALLEYVIEW(dev_priv))
+ cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
+ else
+ cdclk = broxton_calc_cdclk(dev_priv, max_pixclk);
+
+ if (cdclk == dev_priv->cdclk_freq)
+ return 0;
/* disable/enable all currently active pipes while we change cdclk */
- for_each_intel_crtc(dev, intel_crtc)
+ for_each_intel_crtc(state->dev, intel_crtc)
if (intel_crtc->base.state->enable)
*prepare_pipes |= (1 << intel_crtc->pipe);
+
+ return 0;
}
static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
@@ -5201,7 +5666,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
else
default_credits = PFI_CREDIT(8);
- if (DIV_ROUND_CLOSEST(dev_priv->vlv_cdclk_freq, 1000) >= dev_priv->rps.cz_freq) {
+ if (DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 1000) >= dev_priv->rps.cz_freq) {
/* CHV suggested value is 31 or 63 */
if (IS_CHERRYVIEW(dev_priv))
credits = PFI_CREDIT_31;
@@ -5232,10 +5697,20 @@ static void valleyview_modeset_global_resources(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int max_pixclk = intel_mode_max_pixclk(dev_priv);
- int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
+ int max_pixclk = intel_mode_max_pixclk(state);
+ int req_cdclk;
- if (req_cdclk != dev_priv->vlv_cdclk_freq) {
+ /* 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. */
+ if (WARN_ON(max_pixclk < 0))
+ return;
+
+ req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
+
+ if (req_cdclk != dev_priv->cdclk_freq) {
/*
* FIXME: We can end up here with all power domains off, yet
* with a CDCLK frequency other than the minimum. To account
@@ -5554,7 +6029,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
dev_priv->display.crtc_disable(crtc);
dev_priv->display.off(crtc);
- crtc->primary->funcs->disable_plane(crtc->primary);
+ drm_plane_helper_disable(crtc->primary);
/* Update computed state. */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -5695,65 +6170,80 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
return encoder->get_hw_state(encoder, &pipe);
}
-static int pipe_required_fdi_lanes(struct drm_device *dev, enum pipe pipe)
+static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
{
- struct intel_crtc *crtc =
- to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
-
- if (crtc->base.state->enable &&
- crtc->config->has_pch_encoder)
- return crtc->config->fdi_lanes;
+ if (crtc_state->base.enable && crtc_state->has_pch_encoder)
+ return crtc_state->fdi_lanes;
return 0;
}
-static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
+static int ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
struct intel_crtc_state *pipe_config)
{
+ struct drm_atomic_state *state = pipe_config->base.state;
+ struct intel_crtc *other_crtc;
+ struct intel_crtc_state *other_crtc_state;
+
DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n",
pipe_name(pipe), pipe_config->fdi_lanes);
if (pipe_config->fdi_lanes > 4) {
DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n",
pipe_name(pipe), pipe_config->fdi_lanes);
- return false;
+ return -EINVAL;
}
if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
if (pipe_config->fdi_lanes > 2) {
DRM_DEBUG_KMS("only 2 lanes on haswell, required: %i lanes\n",
pipe_config->fdi_lanes);
- return false;
+ return -EINVAL;
} else {
- return true;
+ return 0;
}
}
if (INTEL_INFO(dev)->num_pipes == 2)
- return true;
+ return 0;
/* Ivybridge 3 pipe is really complicated */
switch (pipe) {
case PIPE_A:
- return true;
+ return 0;
case PIPE_B:
- if (pipe_config->fdi_lanes > 2 &&
- pipe_required_fdi_lanes(dev, PIPE_C) > 0) {
+ if (pipe_config->fdi_lanes <= 2)
+ return 0;
+
+ other_crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, PIPE_C));
+ other_crtc_state =
+ intel_atomic_get_crtc_state(state, other_crtc);
+ if (IS_ERR(other_crtc_state))
+ return PTR_ERR(other_crtc_state);
+
+ if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
pipe_name(pipe), pipe_config->fdi_lanes);
- return false;
+ return -EINVAL;
}
- return true;
+ return 0;
case PIPE_C:
if (pipe_config->fdi_lanes > 2) {
DRM_DEBUG_KMS("only 2 lanes on pipe %c: required %i lanes\n",
pipe_name(pipe), pipe_config->fdi_lanes);
- return false;
+ return -EINVAL;
}
- if (pipe_required_fdi_lanes(dev, PIPE_B) > 2) {
+
+ other_crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, PIPE_B));
+ other_crtc_state =
+ intel_atomic_get_crtc_state(state, other_crtc);
+ if (IS_ERR(other_crtc_state))
+ return PTR_ERR(other_crtc_state);
+
+ if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n");
- return false;
+ return -EINVAL;
}
- return true;
+ return 0;
default:
BUG();
}
@@ -5765,8 +6255,8 @@ static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc,
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
- int lane, link_bw, fdi_dotclock;
- bool setup_ok, needs_recompute = false;
+ int lane, link_bw, fdi_dotclock, ret;
+ bool needs_recompute = false;
retry:
/* FDI is a binary signal running at ~2.7GHz, encoding
@@ -5788,9 +6278,9 @@ retry:
intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
link_bw, &pipe_config->fdi_m_n);
- setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev,
- intel_crtc->pipe, pipe_config);
- if (!setup_ok && pipe_config->pipe_bpp > 6*3) {
+ ret = ironlake_check_fdi_lanes(intel_crtc->base.dev,
+ intel_crtc->pipe, pipe_config);
+ if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
pipe_config->pipe_bpp -= 2*3;
DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n",
pipe_config->pipe_bpp);
@@ -5803,7 +6293,7 @@ retry:
if (needs_recompute)
return RETRY;
- return setup_ok ? 0 : -EINVAL;
+ return ret;
}
static void hsw_compute_ips_config(struct intel_crtc *crtc,
@@ -5820,6 +6310,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ int ret;
/* FIXME should check pixel clock limits on all platforms */
if (INTEL_INFO(dev)->gen < 4) {
@@ -5860,21 +6351,107 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
adjusted_mode->hsync_start == adjusted_mode->hdisplay)
return -EINVAL;
- if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) {
- pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */
- } else if (INTEL_INFO(dev)->gen <= 4 && pipe_config->pipe_bpp > 8*3) {
- /* only a 8bpc pipe, with 6bpc dither through the panel fitter
- * for lvds. */
- pipe_config->pipe_bpp = 8*3;
- }
-
if (HAS_IPS(dev))
hsw_compute_ips_config(crtc, pipe_config);
if (pipe_config->has_pch_encoder)
return ironlake_fdi_compute_config(crtc, pipe_config);
- return 0;
+ /* FIXME: remove below call once atomic mode set is place and all crtc
+ * related checks called from atomic_crtc_check function */
+ ret = 0;
+ DRM_DEBUG_KMS("intel_crtc = %p drm_state (pipe_config->base.state) = %p\n",
+ crtc, pipe_config->base.state);
+ ret = intel_atomic_setup_scalers(dev, crtc, pipe_config);
+
+ return ret;
+}
+
+static int skylake_get_display_clock_speed(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ uint32_t lcpll1 = I915_READ(LCPLL1_CTL);
+ uint32_t cdctl = I915_READ(CDCLK_CTL);
+ uint32_t linkrate;
+
+ if (!(lcpll1 & LCPLL_PLL_ENABLE)) {
+ WARN(1, "LCPLL1 not enabled\n");
+ return 24000; /* 24MHz is the cd freq with NSSC ref */
+ }
+
+ if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540)
+ return 540000;
+
+ linkrate = (I915_READ(DPLL_CTRL1) &
+ DPLL_CRTL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1;
+
+ if (linkrate == DPLL_CRTL1_LINK_RATE_2160 ||
+ linkrate == DPLL_CRTL1_LINK_RATE_1080) {
+ /* vco 8640 */
+ switch (cdctl & CDCLK_FREQ_SEL_MASK) {
+ case CDCLK_FREQ_450_432:
+ return 432000;
+ case CDCLK_FREQ_337_308:
+ return 308570;
+ case CDCLK_FREQ_675_617:
+ return 617140;
+ default:
+ WARN(1, "Unknown cd freq selection\n");
+ }
+ } else {
+ /* vco 8100 */
+ switch (cdctl & CDCLK_FREQ_SEL_MASK) {
+ case CDCLK_FREQ_450_432:
+ return 450000;
+ case CDCLK_FREQ_337_308:
+ return 337500;
+ case CDCLK_FREQ_675_617:
+ return 675000;
+ default:
+ WARN(1, "Unknown cd freq selection\n");
+ }
+ }
+
+ /* error case, do as if DPLL0 isn't enabled */
+ return 24000;
+}
+
+static int broadwell_get_display_clock_speed(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t lcpll = I915_READ(LCPLL_CTL);
+ uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
+
+ if (lcpll & LCPLL_CD_SOURCE_FCLK)
+ return 800000;
+ else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
+ return 450000;
+ else if (freq == LCPLL_CLK_FREQ_450)
+ return 450000;
+ else if (freq == LCPLL_CLK_FREQ_54O_BDW)
+ return 540000;
+ else if (freq == LCPLL_CLK_FREQ_337_5_BDW)
+ return 337500;
+ else
+ return 675000;
+}
+
+static int haswell_get_display_clock_speed(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t lcpll = I915_READ(LCPLL_CTL);
+ uint32_t freq = lcpll & LCPLL_CLK_FREQ_MASK;
+
+ if (lcpll & LCPLL_CD_SOURCE_FCLK)
+ return 800000;
+ else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT)
+ return 450000;
+ else if (freq == LCPLL_CLK_FREQ_450)
+ return 450000;
+ else if (IS_HSW_ULT(dev))
+ return 337500;
+ else
+ return 540000;
}
static int valleyview_get_display_clock_speed(struct drm_device *dev)
@@ -5899,6 +6476,11 @@ static int valleyview_get_display_clock_speed(struct drm_device *dev)
return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1);
}
+static int ilk_get_display_clock_speed(struct drm_device *dev)
+{
+ return 450000;
+}
+
static int i945_get_display_clock_speed(struct drm_device *dev)
{
return 400000;
@@ -5906,7 +6488,7 @@ static int i945_get_display_clock_speed(struct drm_device *dev)
static int i915_get_display_clock_speed(struct drm_device *dev)
{
- return 333000;
+ return 333333;
}
static int i9xx_misc_get_display_clock_speed(struct drm_device *dev)
@@ -5922,19 +6504,19 @@ static int pnv_get_display_clock_speed(struct drm_device *dev)
switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
case GC_DISPLAY_CLOCK_267_MHZ_PNV:
- return 267000;
+ return 266667;
case GC_DISPLAY_CLOCK_333_MHZ_PNV:
- return 333000;
+ return 333333;
case GC_DISPLAY_CLOCK_444_MHZ_PNV:
- return 444000;
+ return 444444;
case GC_DISPLAY_CLOCK_200_MHZ_PNV:
return 200000;
default:
DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc);
case GC_DISPLAY_CLOCK_133_MHZ_PNV:
- return 133000;
+ return 133333;
case GC_DISPLAY_CLOCK_167_MHZ_PNV:
- return 167000;
+ return 166667;
}
}
@@ -5945,11 +6527,11 @@ static int i915gm_get_display_clock_speed(struct drm_device *dev)
pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
if (gcfgc & GC_LOW_FREQUENCY_ENABLE)
- return 133000;
+ return 133333;
else {
switch (gcfgc & GC_DISPLAY_CLOCK_MASK) {
case GC_DISPLAY_CLOCK_333_MHZ:
- return 333000;
+ return 333333;
default:
case GC_DISPLAY_CLOCK_190_200_MHZ:
return 190000;
@@ -5959,7 +6541,7 @@ static int i915gm_get_display_clock_speed(struct drm_device *dev)
static int i865_get_display_clock_speed(struct drm_device *dev)
{
- return 266000;
+ return 266667;
}
static int i855_get_display_clock_speed(struct drm_device *dev)
@@ -5975,7 +6557,7 @@ static int i855_get_display_clock_speed(struct drm_device *dev)
case GC_CLOCK_166_250:
return 250000;
case GC_CLOCK_100_133:
- return 133000;
+ return 133333;
}
/* Shouldn't happen */
@@ -5984,7 +6566,7 @@ static int i855_get_display_clock_speed(struct drm_device *dev)
static int i830_get_display_clock_speed(struct drm_device *dev)
{
- return 133000;
+ return 133333;
}
static void
@@ -6037,7 +6619,7 @@ static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
WARN_ON(!crtc_state->base.state);
- if (IS_VALLEYVIEW(dev)) {
+ if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) {
refclk = 100000;
} else if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
@@ -7980,14 +8562,28 @@ static void skylake_get_pfit_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t tmp;
+ struct intel_crtc_scaler_state *scaler_state = &pipe_config->scaler_state;
+ uint32_t ps_ctrl = 0;
+ int id = -1;
+ int i;
- tmp = I915_READ(PS_CTL(crtc->pipe));
+ /* find scaler attached to this pipe */
+ for (i = 0; i < crtc->num_scalers; i++) {
+ ps_ctrl = I915_READ(SKL_PS_CTRL(crtc->pipe, i));
+ if (ps_ctrl & PS_SCALER_EN && !(ps_ctrl & PS_PLANE_SEL_MASK)) {
+ id = i;
+ pipe_config->pch_pfit.enabled = true;
+ pipe_config->pch_pfit.pos = I915_READ(SKL_PS_WIN_POS(crtc->pipe, i));
+ pipe_config->pch_pfit.size = I915_READ(SKL_PS_WIN_SZ(crtc->pipe, i));
+ break;
+ }
+ }
- if (tmp & PS_ENABLE) {
- pipe_config->pch_pfit.enabled = true;
- pipe_config->pch_pfit.pos = I915_READ(PS_WIN_POS(crtc->pipe));
- pipe_config->pch_pfit.size = I915_READ(PS_WIN_SZ(crtc->pipe));
+ scaler_state->scaler_id = id;
+ if (id >= 0) {
+ scaler_state->scaler_users |= (1 << SKL_CRTC_INDEX);
+ } else {
+ scaler_state->scaler_users &= ~(1 << SKL_CRTC_INDEX);
}
}
@@ -8472,6 +9068,23 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
intel_prepare_ddi(dev);
}
+static void broxton_modeset_global_resources(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int max_pixclk = intel_mode_max_pixclk(state);
+ int req_cdclk;
+
+ /* see the comment in valleyview_modeset_global_resources */
+ if (WARN_ON(max_pixclk < 0))
+ return;
+
+ req_cdclk = broxton_calc_cdclk(dev_priv, max_pixclk);
+
+ if (req_cdclk != dev_priv->cdclk_freq)
+ broxton_set_cdclk(dev, req_cdclk);
+}
+
static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state)
{
@@ -8483,6 +9096,28 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
return 0;
}
+static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
+ enum port port,
+ struct intel_crtc_state *pipe_config)
+{
+ switch (port) {
+ case PORT_A:
+ pipe_config->ddi_pll_sel = SKL_DPLL0;
+ pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+ break;
+ case PORT_B:
+ pipe_config->ddi_pll_sel = SKL_DPLL1;
+ pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+ break;
+ case PORT_C:
+ pipe_config->ddi_pll_sel = SKL_DPLL2;
+ pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+ break;
+ default:
+ DRM_ERROR("Incorrect port type\n");
+ }
+}
+
static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_state *pipe_config)
@@ -8545,6 +9180,8 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
if (IS_SKYLAKE(dev))
skylake_get_ddi_pll(dev_priv, port, pipe_config);
+ else if (IS_BROXTON(dev))
+ bxt_get_ddi_pll(dev_priv, port, pipe_config);
else
haswell_get_ddi_pll(dev_priv, port, pipe_config);
@@ -8621,12 +9258,22 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
intel_get_pipe_timings(crtc, pipe_config);
+ if (INTEL_INFO(dev)->gen >= 9) {
+ skl_init_scalers(dev, crtc, pipe_config);
+ }
+
pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
- if (IS_SKYLAKE(dev))
+ if (INTEL_INFO(dev)->gen == 9)
skylake_get_pfit_config(crtc, pipe_config);
- else
+ else if (INTEL_INFO(dev)->gen < 9)
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))
@@ -9070,7 +9717,6 @@ retry:
intel_crtc = to_intel_crtc(crtc);
intel_crtc->new_enabled = true;
- intel_crtc->new_config = intel_crtc->config;
old->dpms_mode = connector->dpms;
old->load_detect_temp = true;
old->release_fb = NULL;
@@ -9126,10 +9772,6 @@ retry:
fail:
intel_crtc->new_enabled = crtc->state->enable;
- if (intel_crtc->new_enabled)
- intel_crtc->new_config = intel_crtc->config;
- else
- intel_crtc->new_config = NULL;
fail_unlock:
if (state) {
drm_atomic_state_free(state);
@@ -9175,7 +9817,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
to_intel_connector(connector)->new_encoder = NULL;
intel_encoder->new_crtc = NULL;
intel_crtc->new_enabled = false;
- intel_crtc->new_config = NULL;
connector_state->best_encoder = NULL;
connector_state->crtc = NULL;
@@ -9915,23 +10556,34 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
- struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj = intel_fb->obj;
const enum pipe pipe = intel_crtc->pipe;
u32 ctl, stride;
ctl = I915_READ(PLANE_CTL(pipe, 0));
ctl &= ~PLANE_CTL_TILED_MASK;
- if (obj->tiling_mode == I915_TILING_X)
+ switch (fb->modifier[0]) {
+ case DRM_FORMAT_MOD_NONE:
+ break;
+ case I915_FORMAT_MOD_X_TILED:
ctl |= PLANE_CTL_TILED_X;
+ break;
+ case I915_FORMAT_MOD_Y_TILED:
+ ctl |= PLANE_CTL_TILED_Y;
+ break;
+ case I915_FORMAT_MOD_Yf_TILED:
+ ctl |= PLANE_CTL_TILED_YF;
+ break;
+ default:
+ MISSING_CASE(fb->modifier[0]);
+ }
/*
* The stride is either expressed as a multiple of 64 bytes chunks for
* linear buffers or in number of tiles for tiled buffers.
*/
- stride = fb->pitches[0] >> 6;
- if (obj->tiling_mode == I915_TILING_X)
- stride = fb->pitches[0] >> 9; /* X tiles are 512 bytes wide */
+ stride = fb->pitches[0] /
+ intel_fb_stride_alignment(dev, fb->modifier[0],
+ fb->pixel_format);
/*
* Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
@@ -10085,6 +10737,7 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_unpin_work *work;
WARN_ON(!in_interrupt());
@@ -10092,12 +10745,16 @@ void intel_check_page_flip(struct drm_device *dev, int pipe)
return;
spin_lock(&dev->event_lock);
- if (intel_crtc->unpin_work && __intel_pageflip_stall_check(dev, crtc)) {
+ work = intel_crtc->unpin_work;
+ if (work != NULL && __intel_pageflip_stall_check(dev, crtc)) {
WARN_ONCE(1, "Kicking stuck page flip: queued at %d, now %d\n",
- intel_crtc->unpin_work->flip_queued_vblank,
- drm_vblank_count(dev, pipe));
+ work->flip_queued_vblank, drm_vblank_count(dev, pipe));
page_flip_completed(intel_crtc);
+ work = NULL;
}
+ if (work != NULL &&
+ drm_vblank_count(dev, pipe) - work->flip_queued_vblank > 1)
+ intel_queue_rps_boost_for_request(dev, work->flip_queued_req);
spin_unlock(&dev->event_lock);
}
@@ -10115,6 +10772,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
enum pipe pipe = intel_crtc->pipe;
struct intel_unpin_work *work;
struct intel_engine_cs *ring;
+ bool mmio_flip;
int ret;
/*
@@ -10212,15 +10870,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
ring = &dev_priv->ring[RCS];
}
+ mmio_flip = use_mmio_flip(ring, obj);
+
+ /* When using CS flips, we want to emit semaphores between rings.
+ * However, when using mmio flips we will create a task to do the
+ * synchronisation, so all we want here is to pin the framebuffer
+ * into the display plane and skip any waits.
+ */
ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
- crtc->primary->state, ring);
+ crtc->primary->state,
+ mmio_flip ? i915_gem_request_get_ring(obj->last_read_req) : ring);
if (ret)
goto cleanup_pending;
work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), obj)
+ intel_crtc->dspaddr_offset;
- if (use_mmio_flip(ring, obj)) {
+ if (mmio_flip) {
ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
page_flip_flags);
if (ret)
@@ -10315,11 +10981,6 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
for_each_intel_crtc(dev, crtc) {
crtc->new_enabled = crtc->base.state->enable;
-
- if (crtc->new_enabled)
- crtc->new_config = crtc->config;
- else
- crtc->new_config = NULL;
}
}
@@ -10399,7 +11060,6 @@ connected_sink_compute_bpp(struct intel_connector *connector,
static int
compute_baseline_pipe_bpp(struct intel_crtc *crtc,
- struct drm_framebuffer *fb,
struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
@@ -10407,41 +11067,13 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc,
struct intel_connector *connector;
int bpp, i;
- switch (fb->pixel_format) {
- case DRM_FORMAT_C8:
- bpp = 8*3; /* since we go through a colormap */
- break;
- case DRM_FORMAT_XRGB1555:
- case DRM_FORMAT_ARGB1555:
- /* checked in intel_framebuffer_init already */
- if (WARN_ON(INTEL_INFO(dev)->gen > 3))
- return -EINVAL;
- case DRM_FORMAT_RGB565:
- bpp = 6*3; /* min is 18bpp */
- break;
- case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_ABGR8888:
- /* checked in intel_framebuffer_init already */
- if (WARN_ON(INTEL_INFO(dev)->gen < 4))
- return -EINVAL;
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_ARGB8888:
- bpp = 8*3;
- break;
- case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010:
- case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010:
- /* checked in intel_framebuffer_init already */
- if (WARN_ON(INTEL_INFO(dev)->gen < 4))
- return -EINVAL;
+ if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)))
bpp = 10*3;
- break;
- /* TODO: gen4+ supports 16 bpc floating point, too. */
- default:
- DRM_DEBUG_KMS("unsupported depth\n");
- return -EINVAL;
- }
+ else if (INTEL_INFO(dev)->gen >= 5)
+ bpp = 12*3;
+ else
+ bpp = 8*3;
+
pipe_config->pipe_bpp = bpp;
@@ -10477,8 +11109,14 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config,
const char *context)
{
- DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id,
- context, pipe_name(crtc->pipe));
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_plane *plane;
+ struct intel_plane *intel_plane;
+ struct intel_plane_state *state;
+ struct drm_framebuffer *fb;
+
+ DRM_DEBUG_KMS("[CRTC:%d]%s config %p for pipe %c\n", crtc->base.base.id,
+ context, pipe_config, pipe_name(crtc->pipe));
DRM_DEBUG_KMS("cpu_transcoder: %c\n", transcoder_name(pipe_config->cpu_transcoder));
DRM_DEBUG_KMS("pipe bpp: %i, dithering: %i\n",
@@ -10515,6 +11153,9 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
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("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
pipe_config->gmch_pfit.control,
pipe_config->gmch_pfit.pgm_ratios,
@@ -10525,6 +11166,40 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->pch_pfit.enabled ? "enabled" : "disabled");
DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
+
+ 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);
+ if (intel_plane->pipe != crtc->pipe)
+ continue;
+
+ state = to_intel_plane_state(plane->state);
+ fb = state->base.fb;
+ if (!fb) {
+ DRM_DEBUG_KMS("%s PLANE:%d plane: %u.%u idx: %d "
+ "disabled, scaler_id = %d\n",
+ plane->type == DRM_PLANE_TYPE_CURSOR ? "CURSOR" : "STANDARD",
+ plane->base.id, intel_plane->pipe,
+ (crtc->base.primary == plane) ? 0 : intel_plane->plane + 1,
+ drm_plane_index(plane), state->scaler_id);
+ continue;
+ }
+
+ DRM_DEBUG_KMS("%s PLANE:%d plane: %u.%u idx: %d enabled",
+ plane->type == DRM_PLANE_TYPE_CURSOR ? "CURSOR" : "STANDARD",
+ plane->base.id, intel_plane->pipe,
+ crtc->base.primary == plane ? 0 : intel_plane->plane + 1,
+ drm_plane_index(plane));
+ DRM_DEBUG_KMS("\tFB:%d, fb = %ux%u format = 0x%x",
+ fb->base.id, fb->width, fb->height, fb->pixel_format);
+ DRM_DEBUG_KMS("\tscaler:%d src (%u, %u) %ux%u dst (%u, %u) %ux%u\n",
+ state->scaler_id,
+ state->src.x1 >> 16, state->src.y1 >> 16,
+ drm_rect_width(&state->src) >> 16,
+ drm_rect_height(&state->src) >> 16,
+ state->dst.x1, state->dst.y1,
+ drm_rect_width(&state->dst), drm_rect_height(&state->dst));
+ }
}
static bool encoders_cloneable(const struct intel_encoder *a,
@@ -10535,16 +11210,24 @@ static bool encoders_cloneable(const struct intel_encoder *a,
b->cloneable & (1 << a->type));
}
-static bool check_single_encoder_cloning(struct intel_crtc *crtc,
+static bool check_single_encoder_cloning(struct drm_atomic_state *state,
+ struct intel_crtc *crtc,
struct intel_encoder *encoder)
{
- struct drm_device *dev = crtc->base.dev;
struct intel_encoder *source_encoder;
+ struct drm_connector_state *connector_state;
+ int i;
- for_each_intel_encoder(dev, source_encoder) {
- if (source_encoder->new_crtc != crtc)
+ for (i = 0; i < state->num_connector; i++) {
+ if (!state->connectors[i])
+ continue;
+
+ connector_state = state->connector_states[i];
+ if (connector_state->crtc != &crtc->base)
continue;
+ source_encoder =
+ to_intel_encoder(connector_state->best_encoder);
if (!encoders_cloneable(encoder, source_encoder))
return false;
}
@@ -10552,39 +11235,53 @@ static bool check_single_encoder_cloning(struct intel_crtc *crtc,
return true;
}
-static bool check_encoder_cloning(struct intel_crtc *crtc)
+static bool check_encoder_cloning(struct drm_atomic_state *state,
+ struct intel_crtc *crtc)
{
- struct drm_device *dev = crtc->base.dev;
struct intel_encoder *encoder;
+ struct drm_connector_state *connector_state;
+ int i;
- for_each_intel_encoder(dev, encoder) {
- if (encoder->new_crtc != crtc)
+ for (i = 0; i < state->num_connector; i++) {
+ if (!state->connectors[i])
continue;
- if (!check_single_encoder_cloning(crtc, encoder))
+ connector_state = state->connector_states[i];
+ if (connector_state->crtc != &crtc->base)
+ continue;
+
+ encoder = to_intel_encoder(connector_state->best_encoder);
+ if (!check_single_encoder_cloning(state, crtc, encoder))
return false;
}
return true;
}
-static bool check_digital_port_conflicts(struct drm_device *dev)
+static bool check_digital_port_conflicts(struct drm_atomic_state *state)
{
- struct intel_connector *connector;
+ struct drm_device *dev = state->dev;
+ struct intel_encoder *encoder;
+ struct drm_connector_state *connector_state;
unsigned int used_ports = 0;
+ int i;
/*
* Walk the connector list instead of the encoder
* list to detect the problem on ddi platforms
* where there's just one encoder per digital port.
*/
- for_each_intel_connector(dev, connector) {
- struct intel_encoder *encoder = connector->new_encoder;
+ for (i = 0; i < state->num_connector; i++) {
+ if (!state->connectors[i])
+ continue;
- if (!encoder)
+ connector_state = state->connector_states[i];
+ if (!connector_state->best_encoder)
continue;
- WARN_ON(!encoder->new_crtc);
+ encoder = to_intel_encoder(connector_state->best_encoder);
+
+ WARN_ON(!connector_state->crtc);
switch (encoder->type) {
unsigned int port_mask;
@@ -10613,34 +11310,35 @@ static void
clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
{
struct drm_crtc_state tmp_state;
+ struct intel_crtc_scaler_state scaler_state;
- /* Clear only the intel specific part of the crtc state */
+ /* Clear only the intel specific part of the crtc state excluding scalers */
tmp_state = crtc_state->base;
+ scaler_state = crtc_state->scaler_state;
memset(crtc_state, 0, sizeof *crtc_state);
crtc_state->base = tmp_state;
+ crtc_state->scaler_state = scaler_state;
}
static struct intel_crtc_state *
intel_modeset_pipe_config(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
struct drm_display_mode *mode,
struct drm_atomic_state *state)
{
- struct drm_device *dev = crtc->dev;
struct intel_encoder *encoder;
struct intel_connector *connector;
struct drm_connector_state *connector_state;
struct intel_crtc_state *pipe_config;
- int plane_bpp, ret = -EINVAL;
+ int base_bpp, ret = -EINVAL;
int i;
bool retry = true;
- if (!check_encoder_cloning(to_intel_crtc(crtc))) {
+ if (!check_encoder_cloning(state, to_intel_crtc(crtc))) {
DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
return ERR_PTR(-EINVAL);
}
- if (!check_digital_port_conflicts(dev)) {
+ if (!check_digital_port_conflicts(state)) {
DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n");
return ERR_PTR(-EINVAL);
}
@@ -10676,9 +11374,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
* plane pixel format and any sink constraints into account. Returns the
* source plane bpp so that dithering can be selected on mismatches
* after encoders and crtc also have had their say. */
- plane_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
- fb, pipe_config);
- if (plane_bpp < 0)
+ base_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
+ pipe_config);
+ if (base_bpp < 0)
goto fail;
/*
@@ -10746,9 +11444,9 @@ encoder_retry:
goto encoder_retry;
}
- pipe_config->dither = pipe_config->pipe_bpp != plane_bpp;
+ pipe_config->dither = pipe_config->pipe_bpp != base_bpp;
DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
- plane_bpp, pipe_config->pipe_bpp, pipe_config->dither);
+ base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
return pipe_config;
fail:
@@ -10880,9 +11578,6 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
/* Double check state. */
for_each_intel_crtc(dev, intel_crtc) {
WARN_ON(intel_crtc->base.state->enable != intel_crtc_in_use(&intel_crtc->base));
- WARN_ON(intel_crtc->new_config &&
- intel_crtc->new_config != intel_crtc->config);
- WARN_ON(intel_crtc->base.state->enable != !!intel_crtc->new_config);
}
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -11087,6 +11782,8 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_I(pch_pfit.size);
}
+ PIPE_CONF_CHECK_I(scaler_state.scaler_id);
+
/* BDW+ don't expose a synchronous way to read the state */
if (IS_HASWELL(dev))
PIPE_CONF_CHECK_I(ips_enabled);
@@ -11429,7 +12126,6 @@ static void update_scanline_offset(struct intel_crtc *crtc)
static struct intel_crtc_state *
intel_modeset_compute_config(struct drm_crtc *crtc,
struct drm_display_mode *mode,
- struct drm_framebuffer *fb,
struct drm_atomic_state *state,
unsigned *modeset_pipes,
unsigned *prepare_pipes,
@@ -11467,10 +12163,12 @@ intel_modeset_compute_config(struct drm_crtc *crtc,
if (WARN_ON(&intel_crtc->base != crtc))
continue;
- pipe_config = intel_modeset_pipe_config(crtc, fb, mode, state);
+ pipe_config = intel_modeset_pipe_config(crtc, mode, state);
if (IS_ERR(pipe_config))
return pipe_config;
+ pipe_config->base.enable = true;
+
intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
"[modeset]");
}
@@ -11478,10 +12176,11 @@ intel_modeset_compute_config(struct drm_crtc *crtc,
return intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));;
}
-static int __intel_set_mode_setup_plls(struct drm_device *dev,
+static int __intel_set_mode_setup_plls(struct drm_atomic_state *state,
unsigned modeset_pipes,
unsigned disable_pipes)
{
+ struct drm_device *dev = state->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
unsigned clear_pipes = modeset_pipes | disable_pipes;
struct intel_crtc *intel_crtc;
@@ -11495,9 +12194,15 @@ static int __intel_set_mode_setup_plls(struct drm_device *dev,
goto done;
for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
- struct intel_crtc_state *state = intel_crtc->new_config;
+ 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)))
+ continue;
+
ret = dev_priv->display.crtc_compute_clock(intel_crtc,
- state);
+ crtc_state);
if (ret) {
intel_shared_dpll_abort_config(dev_priv);
goto done;
@@ -11519,6 +12224,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
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;
@@ -11535,9 +12241,6 @@ static int __intel_set_mode(struct drm_crtc *crtc,
*saved_mode = crtc->mode;
- if (modeset_pipes)
- to_intel_crtc(crtc)->new_config = pipe_config;
-
/*
* See if the config requires any additional preparation, e.g.
* to adjust global state with pipes off. We need to do this
@@ -11545,14 +12248,16 @@ static int __intel_set_mode(struct drm_crtc *crtc,
* mode set on this crtc. For other crtcs we need to use the
* adjusted_mode bits in the crtc directly.
*/
- if (IS_VALLEYVIEW(dev)) {
- valleyview_modeset_global_pipes(dev, &prepare_pipes);
+ if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) {
+ ret = valleyview_modeset_global_pipes(state, &prepare_pipes);
+ if (ret)
+ goto done;
/* may have added more to prepare_pipes than we should */
prepare_pipes &= ~disable_pipes;
}
- ret = __intel_set_mode_setup_plls(dev, modeset_pipes, disable_pipes);
+ ret = __intel_set_mode_setup_plls(state, modeset_pipes, disable_pipes);
if (ret)
goto done;
@@ -11590,21 +12295,18 @@ static int __intel_set_mode(struct drm_crtc *crtc,
* update the the output configuration. */
intel_modeset_update_state(dev, prepare_pipes);
- modeset_update_crtc_power_domains(pipe_config->base.state);
+ modeset_update_crtc_power_domains(state);
- /* Set up the DPLL and any encoders state that needs to adjust or depend
- * on the DPLL.
- */
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 = primary->funcs->update_plane(primary, &intel_crtc->base,
- fb, 0, 0,
- hdisplay, vdisplay,
- x << 16, y << 16,
- hdisplay << 16, vdisplay << 16);
+ ret = drm_plane_helper_update(primary, &intel_crtc->base,
+ fb, 0, 0,
+ hdisplay, vdisplay,
+ x << 16, y << 16,
+ hdisplay << 16, vdisplay << 16);
}
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
@@ -11628,9 +12330,6 @@ done:
sizeof *crtc_state_copy);
intel_crtc->config = crtc_state_copy;
intel_crtc->base.state = &crtc_state_copy->base;
-
- if (modeset_pipes)
- intel_crtc->new_config = intel_crtc->config;
} else {
kfree(crtc_state_copy);
}
@@ -11667,7 +12366,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
unsigned modeset_pipes, prepare_pipes, disable_pipes;
int ret = 0;
- pipe_config = intel_modeset_compute_config(crtc, mode, fb, state,
+ pipe_config = intel_modeset_compute_config(crtc, mode, state,
&modeset_pipes,
&prepare_pipes,
&disable_pipes);
@@ -11809,11 +12508,6 @@ static void intel_set_config_restore_state(struct drm_device *dev,
count = 0;
for_each_intel_crtc(dev, crtc) {
crtc->new_enabled = config->save_crtc_enabled[count++];
-
- if (crtc->new_enabled)
- crtc->new_config = crtc->config;
- else
- crtc->new_config = NULL;
}
count = 0;
@@ -12021,6 +12715,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
connector->encoder = connector->new_encoder;
} else {
connector_state->crtc = NULL;
+ connector_state->best_encoder = NULL;
}
}
for_each_intel_crtc(dev, crtc) {
@@ -12039,11 +12734,6 @@ intel_modeset_stage_output_state(struct drm_device *dev,
crtc->new_enabled ? "en" : "dis");
config->mode_changed = true;
}
-
- if (crtc->new_enabled)
- crtc->new_config = crtc->config;
- else
- crtc->new_config = NULL;
}
return 0;
@@ -12070,7 +12760,6 @@ static void disable_crtc_nofb(struct intel_crtc *crtc)
}
crtc->new_enabled = false;
- crtc->new_config = NULL;
}
static int intel_crtc_set_config(struct drm_mode_set *set)
@@ -12135,7 +12824,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
goto fail;
pipe_config = intel_modeset_compute_config(set->crtc, set->mode,
- set->fb, state,
+ state,
&modeset_pipes,
&prepare_pipes,
&disable_pipes);
@@ -12168,10 +12857,10 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
int vdisplay, hdisplay;
drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
- ret = primary->funcs->update_plane(primary, set->crtc, set->fb,
- 0, 0, hdisplay, vdisplay,
- set->x << 16, set->y << 16,
- hdisplay << 16, vdisplay << 16);
+ 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
@@ -12456,16 +13145,21 @@ intel_check_primary_plane(struct drm_plane *plane,
struct drm_rect *dest = &state->dst;
struct drm_rect *src = &state->src;
const struct drm_rect *clip = &state->clip;
+ bool can_position = false;
int ret;
crtc = crtc ? crtc : plane->crtc;
intel_crtc = to_intel_crtc(crtc);
+ if (INTEL_INFO(dev)->gen >= 9)
+ can_position = true;
+
ret = drm_plane_helper_check_update(plane, crtc, fb,
src, dest, clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
- false, true, &state->visible);
+ can_position, true,
+ &state->visible);
if (ret)
return ret;
@@ -12655,8 +13349,8 @@ void intel_plane_destroy(struct drm_plane *plane)
}
const struct drm_plane_funcs intel_plane_funcs = {
- .update_plane = drm_plane_helper_update,
- .disable_plane = drm_plane_helper_disable,
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
.destroy = intel_plane_destroy,
.set_property = drm_atomic_helper_plane_set_property,
.atomic_get_property = intel_plane_atomic_get_property,
@@ -12687,10 +13381,12 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
primary->can_scale = false;
primary->max_downscale = 1;
+ state->scaler_id = -1;
primary->pipe = pipe;
primary->plane = pipe;
primary->check_plane = intel_check_primary_plane;
primary->commit_plane = intel_commit_primary_plane;
+ primary->ckey.flags = I915_SET_COLORKEY_NONE;
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
primary->plane = !pipe;
@@ -12707,23 +13403,32 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
intel_primary_formats, num_formats,
DRM_PLANE_TYPE_PRIMARY);
- if (INTEL_INFO(dev)->gen >= 4) {
- if (!dev->mode_config.rotation_property)
- dev->mode_config.rotation_property =
- drm_mode_create_rotation_property(dev,
- BIT(DRM_ROTATE_0) |
- BIT(DRM_ROTATE_180));
- if (dev->mode_config.rotation_property)
- drm_object_attach_property(&primary->base.base,
- dev->mode_config.rotation_property,
- state->base.rotation);
- }
+ if (INTEL_INFO(dev)->gen >= 4)
+ intel_create_rotation_property(dev, primary);
drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
return &primary->base;
}
+void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane)
+{
+ if (!dev->mode_config.rotation_property) {
+ unsigned long flags = BIT(DRM_ROTATE_0) |
+ BIT(DRM_ROTATE_180);
+
+ if (INTEL_INFO(dev)->gen >= 9)
+ flags |= BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270);
+
+ dev->mode_config.rotation_property =
+ drm_mode_create_rotation_property(dev, flags);
+ }
+ if (dev->mode_config.rotation_property)
+ drm_object_attach_property(&plane->base.base,
+ dev->mode_config.rotation_property,
+ plane->base.state->rotation);
+}
+
static int
intel_check_cursor_plane(struct drm_plane *plane,
struct intel_plane_state *state)
@@ -12841,6 +13546,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
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;
@@ -12867,6 +13573,24 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
return &cursor->base;
}
+static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *crtc_state)
+{
+ int i;
+ struct intel_scaler *intel_scaler;
+ struct intel_crtc_scaler_state *scaler_state = &crtc_state->scaler_state;
+
+ for (i = 0; i < intel_crtc->num_scalers; i++) {
+ intel_scaler = &scaler_state->scalers[i];
+ intel_scaler->in_use = 0;
+ intel_scaler->id = i;
+
+ intel_scaler->mode = PS_SCALER_MODE_DYN;
+ }
+
+ scaler_state->scaler_id = -1;
+}
+
static void intel_crtc_init(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -12886,6 +13610,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc_set_state(intel_crtc, crtc_state);
crtc_state->base.crtc = &intel_crtc->base;
+ /* initialize shared scalers */
+ if (INTEL_INFO(dev)->gen >= 9) {
+ if (pipe == PIPE_C)
+ intel_crtc->num_scalers = 1;
+ else
+ intel_crtc->num_scalers = SKL_NUM_SCALERS;
+
+ skl_init_scalers(dev, intel_crtc, crtc_state);
+ }
+
primary = intel_primary_plane_create(dev, pipe);
if (!primary)
goto fail;
@@ -13038,7 +13772,16 @@ static void intel_setup_outputs(struct drm_device *dev)
if (intel_crt_present(dev))
intel_crt_init(dev);
- if (HAS_DDI(dev)) {
+ if (IS_BROXTON(dev)) {
+ /*
+ * FIXME: Broxton doesn't support port detection via the
+ * DDI_BUF_CTL_A or SFUSE_STRAP registers, find another way to
+ * detect the ports.
+ */
+ intel_ddi_init(dev, PORT_A);
+ intel_ddi_init(dev, PORT_B);
+ intel_ddi_init(dev, PORT_C);
+ } else if (HAS_DDI(dev)) {
int found;
/*
@@ -13474,10 +14217,23 @@ static void intel_init_display(struct drm_device *dev)
}
/* Returns the core display clock speed */
- if (IS_VALLEYVIEW(dev))
+ if (IS_SKYLAKE(dev))
+ dev_priv->display.get_display_clock_speed =
+ skylake_get_display_clock_speed;
+ else if (IS_BROADWELL(dev))
+ dev_priv->display.get_display_clock_speed =
+ broadwell_get_display_clock_speed;
+ else if (IS_HASWELL(dev))
+ dev_priv->display.get_display_clock_speed =
+ haswell_get_display_clock_speed;
+ else if (IS_VALLEYVIEW(dev))
dev_priv->display.get_display_clock_speed =
valleyview_get_display_clock_speed;
- else if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
+ else if (IS_GEN5(dev))
+ dev_priv->display.get_display_clock_speed =
+ ilk_get_display_clock_speed;
+ else if (IS_I945G(dev) || IS_BROADWATER(dev) ||
+ IS_GEN6(dev) || IS_IVYBRIDGE(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
dev_priv->display.get_display_clock_speed =
i945_get_display_clock_speed;
else if (IS_I915G(dev))
@@ -13514,6 +14270,9 @@ static void intel_init_display(struct drm_device *dev)
} else if (IS_VALLEYVIEW(dev)) {
dev_priv->display.modeset_global_resources =
valleyview_modeset_global_resources;
+ } else if (IS_BROXTON(dev)) {
+ dev_priv->display.modeset_global_resources =
+ broxton_modeset_global_resources;
}
switch (INTEL_INFO(dev)->gen) {