|
@@ -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) {
|