From 6156a45602f990cdb140025a3ced96e6695980cf Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Mon, 27 Apr 2015 13:48:39 -0700 Subject: drm/i915: skylake primary plane scaling using shared scalers This patch enables skylake primary plane scaling using shared scalers atomic desgin. v2: -use single copy of scaler limits (Matt) v3: -move detach_scalers to crtc commit path (Matt) -use values in plane_state->src as regular integers (me) v4: -changes to align with updated scaler structures (Matt, me) -keep plane src rect in 16.16 format (Matt, Daniel) v5: -Rebased on top of 90/270 rotation changes (me) -Fixed an issue introduced by 90/270 changes where plane programming is using drm_plane->state rect instead of intel_plane->state rect. This change also required for scaling to work properly. (me) -With 90/270, updated limits to cover both portrait and landscape usages (me) -Refactored skylake_update_primary_plane to reduce its size (Daniel) Added helper functions for refactoring are comprehended enough to be used for skylake_update_plane (for sprite) too. One stop towards having single function for all planes. v6: -Added fixme note when checking plane_state->src width in update_plane (Daniel) -Release lock when failing to colorkey request with active scaler (Daniel) Signed-off-by: Chandra Konduru Reviewed-by: matthew.d.roper@intel.com Reviewed-by: sonika.jindal@intel.com (v5) Testcase: igt/kms_plane_scaling Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 5 +- drivers/gpu/drm/i915/intel_display.c | 266 ++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_sprite.c | 10 ++ 4 files changed, 219 insertions(+), 70 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 3c4b7cdeab77..cb6d5f2d9b60 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -169,7 +169,7 @@ int intel_atomic_commit(struct drm_device *dev, plane->state->state = NULL; } - /* swap crtc_state */ + /* swap crtc_scaler_state */ for (i = 0; i < dev->mode_config.num_crtc; i++) { struct drm_crtc *crtc = state->crtcs[i]; if (!crtc) { @@ -178,6 +178,9 @@ int intel_atomic_commit(struct drm_device *dev, to_intel_crtc(crtc)->config->scaler_state = to_intel_crtc_state(state->crtc_states[i])->scaler_state; + + if (INTEL_INFO(dev)->gen >= 9) + skl_detach_scalers(to_intel_crtc(crtc)); } drm_atomic_helper_commit_planes(dev, state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3094b0807b40..14709547659f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2985,126 +2985,204 @@ void skl_detach_scalers(struct intel_crtc *intel_crtc) } } -static void skylake_update_primary_plane(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - int x, int y) +u32 skl_plane_ctl_format(uint32_t pixel_format) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - 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, 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); - I915_WRITE(PLANE_SURF(pipe, 0), 0); - POSTING_READ(PLANE_CTL(pipe, 0)); - return; - } - - plane_ctl = PLANE_CTL_ENABLE | - PLANE_CTL_PIPE_GAMMA_ENABLE | - PLANE_CTL_PIPE_CSC_ENABLE; - - switch (fb->pixel_format) { + u32 plane_ctl_format = 0; + switch (pixel_format) { case DRM_FORMAT_RGB565: - plane_ctl |= PLANE_CTL_FORMAT_RGB_565; - break; - case DRM_FORMAT_XRGB8888: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; - break; - case DRM_FORMAT_ARGB8888: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; - plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY; + plane_ctl_format = PLANE_CTL_FORMAT_RGB_565; break; case DRM_FORMAT_XBGR8888: - plane_ctl |= PLANE_CTL_ORDER_RGBX; - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; + plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; break; + case DRM_FORMAT_XRGB8888: + plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888; + break; + /* + * XXX: For ARBG/ABGR formats we default to expecting scanout buffers + * to be already pre-multiplied. We need to add a knob (or a different + * DRM_FORMAT) for user-space to configure that. + */ case DRM_FORMAT_ABGR8888: - plane_ctl |= PLANE_CTL_ORDER_RGBX; - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; - plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY; + plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX | + PLANE_CTL_ALPHA_SW_PREMULTIPLY; + break; + case DRM_FORMAT_ARGB8888: + plane_ctl_format = PLANE_CTL_FORMAT_XRGB_8888 | + PLANE_CTL_ALPHA_SW_PREMULTIPLY; break; case DRM_FORMAT_XRGB2101010: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_2101010; + plane_ctl_format = PLANE_CTL_FORMAT_XRGB_2101010; break; case DRM_FORMAT_XBGR2101010: - plane_ctl |= PLANE_CTL_ORDER_RGBX; - plane_ctl |= PLANE_CTL_FORMAT_XRGB_2101010; + plane_ctl_format = PLANE_CTL_ORDER_RGBX | PLANE_CTL_FORMAT_XRGB_2101010; + break; + case DRM_FORMAT_YUYV: + plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; + break; + case DRM_FORMAT_YVYU: + plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; + break; + case DRM_FORMAT_UYVY: + plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; + break; + case DRM_FORMAT_VYUY: + plane_ctl_format = PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; break; default: BUG(); } + return plane_ctl_format; +} - switch (fb->modifier[0]) { +u32 skl_plane_ctl_tiling(uint64_t fb_modifier) +{ + u32 plane_ctl_tiling = 0; + switch (fb_modifier) { case DRM_FORMAT_MOD_NONE: break; case I915_FORMAT_MOD_X_TILED: - plane_ctl |= PLANE_CTL_TILED_X; + plane_ctl_tiling = PLANE_CTL_TILED_X; break; case I915_FORMAT_MOD_Y_TILED: - plane_ctl |= PLANE_CTL_TILED_Y; + plane_ctl_tiling = PLANE_CTL_TILED_Y; break; case I915_FORMAT_MOD_Yf_TILED: - plane_ctl |= PLANE_CTL_TILED_YF; + plane_ctl_tiling = PLANE_CTL_TILED_YF; break; default: - MISSING_CASE(fb->modifier[0]); + MISSING_CASE(fb_modifier); } + return plane_ctl_tiling; +} - plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; - - plane = crtc->primary; - rotation = plane->state->rotation; +u32 skl_plane_ctl_rotation(unsigned int rotation) +{ + u32 plane_ctl_rotation = 0; switch (rotation) { + case BIT(DRM_ROTATE_0): + break; case BIT(DRM_ROTATE_90): - plane_ctl |= PLANE_CTL_ROTATE_90; + plane_ctl_rotation = PLANE_CTL_ROTATE_90; break; - case BIT(DRM_ROTATE_180): - plane_ctl |= PLANE_CTL_ROTATE_180; + plane_ctl_rotation = PLANE_CTL_ROTATE_180; break; - case BIT(DRM_ROTATE_270): - plane_ctl |= PLANE_CTL_ROTATE_270; + plane_ctl_rotation = PLANE_CTL_ROTATE_270; break; + default: + MISSING_CASE(rotation); + } + + return plane_ctl_rotation; +} + +static void skylake_update_primary_plane(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + 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, stride; + u32 tile_height, plane_offset, plane_size; + unsigned int rotation; + int x_offset, y_offset; + unsigned long surf_addr; + struct drm_plane *plane; + struct intel_crtc_state *crtc_state = intel_crtc->config; + struct intel_plane_state *plane_state; + int src_x = 0, src_y = 0, src_w = 0, src_h = 0; + int dst_x = 0, dst_y = 0, dst_w = 0, dst_h = 0; + int scaler_id = -1; + + plane = crtc->primary; + plane_state = to_intel_plane_state(plane->state); + + if (!intel_crtc->primary_enabled) { + I915_WRITE(PLANE_CTL(pipe, 0), 0); + I915_WRITE(PLANE_SURF(pipe, 0), 0); + POSTING_READ(PLANE_CTL(pipe, 0)); + return; } + plane_ctl = PLANE_CTL_ENABLE | + PLANE_CTL_PIPE_GAMMA_ENABLE | + PLANE_CTL_PIPE_CSC_ENABLE; + + plane_ctl |= skl_plane_ctl_format(fb->pixel_format); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); + plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE; + + rotation = plane->state->rotation; + plane_ctl |= skl_plane_ctl_rotation(rotation); + 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(plane), obj); + /* + * FIXME: intel_plane_state->src, dst aren't set when transitional + * update_plane helpers are called from legacy paths. + * Once full atomic crtc is available, below check can be avoided. + */ + if (drm_rect_width(&plane_state->src)) { + scaler_id = plane_state->scaler_id; + src_x = plane_state->src.x1 >> 16; + src_y = plane_state->src.y1 >> 16; + src_w = drm_rect_width(&plane_state->src) >> 16; + src_h = drm_rect_height(&plane_state->src) >> 16; + dst_x = plane_state->dst.x1; + dst_y = plane_state->dst.y1; + dst_w = drm_rect_width(&plane_state->dst); + dst_h = drm_rect_height(&plane_state->dst); + + WARN_ON(x != src_x || y != src_y); + } else { + src_w = intel_crtc->config->pipe_src_w; + src_h = intel_crtc->config->pipe_src_h; + } + 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); + x_offset = stride * tile_height - y - src_h; y_offset = x; - plane_size = ((plane->state->src_w >> 16) - 1) << 16 | - ((plane->state->src_h >> 16) - 1); + plane_size = (src_w - 1) << 16 | (src_h - 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_size = (src_h - 1) << 16 | (src_w - 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), plane_offset); I915_WRITE(PLANE_SIZE(pipe, 0), plane_size); I915_WRITE(PLANE_STRIDE(pipe, 0), stride); + + if (scaler_id >= 0) { + uint32_t ps_ctrl = 0; + + WARN_ON(!dst_w || !dst_h); + ps_ctrl = PS_SCALER_EN | PS_PLANE_SEL(0) | + crtc_state->scaler_state.scalers[scaler_id].mode; + I915_WRITE(SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); + I915_WRITE(SKL_PS_PWR_GATE(pipe, scaler_id), 0); + I915_WRITE(SKL_PS_WIN_POS(pipe, scaler_id), (dst_x << 16) | dst_y); + I915_WRITE(SKL_PS_WIN_SZ(pipe, scaler_id), (dst_w << 16) | dst_h); + I915_WRITE(PLANE_POS(pipe, 0), 0); + } else { + I915_WRITE(PLANE_POS(pipe, 0), (dst_y << 16) | dst_x); + } + I915_WRITE(PLANE_SURF(pipe, 0), surf_addr); POSTING_READ(PLANE_SURF(pipe, 0)); @@ -4383,6 +4461,7 @@ skl_update_scaler_users( int *scaler_id; struct drm_framebuffer *fb; struct intel_crtc_scaler_state *scaler_state; + unsigned int rotation; if (!intel_crtc || !crtc_state) return 0; @@ -4398,6 +4477,7 @@ skl_update_scaler_users( dst_w = drm_rect_width(&plane_state->dst); dst_h = drm_rect_height(&plane_state->dst); scaler_id = &plane_state->scaler_id; + rotation = plane_state->base.rotation; } else { struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode; @@ -4406,8 +4486,12 @@ skl_update_scaler_users( dst_w = adjusted_mode->hdisplay; dst_h = adjusted_mode->vdisplay; scaler_id = &scaler_state->scaler_id; + rotation = DRM_ROTATE_0; } - need_scaling = (src_w != dst_w || src_h != dst_h); + + need_scaling = intel_rotation_90_or_270(rotation) ? + (src_h != dst_w || src_w != dst_h): + (src_w != dst_w || src_h != dst_h); /* * if plane is being disabled or scaler is no more required or force detach @@ -13133,6 +13217,36 @@ intel_cleanup_plane_fb(struct drm_plane *plane, } } +int +skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state) +{ + int max_scale; + struct drm_device *dev; + struct drm_i915_private *dev_priv; + int crtc_clock, cdclk; + + if (!intel_crtc || !crtc_state) + return DRM_PLANE_HELPER_NO_SCALING; + + dev = intel_crtc->base.dev; + dev_priv = dev->dev_private; + crtc_clock = crtc_state->base.adjusted_mode.crtc_clock; + cdclk = dev_priv->display.get_display_clock_speed(dev); + + if (!crtc_clock || !cdclk) + return DRM_PLANE_HELPER_NO_SCALING; + + /* + * skl max scale is lower of: + * close to 3 but not 3, -1 is for that purpose + * or + * cdclk/crtc_clock + */ + max_scale = min((1 << 16) * 3 - 1, (1 << 8) * ((cdclk << 8) / crtc_clock)); + + return max_scale; +} + static int intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -13141,23 +13255,31 @@ intel_check_primary_plane(struct drm_plane *plane, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc; + struct intel_crtc_state *crtc_state; struct drm_framebuffer *fb = state->base.fb; struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; bool can_position = false; + int max_scale = DRM_PLANE_HELPER_NO_SCALING; + int min_scale = DRM_PLANE_HELPER_NO_SCALING; int ret; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); + crtc_state = state->base.state ? + intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; - if (INTEL_INFO(dev)->gen >= 9) + if (INTEL_INFO(dev)->gen >= 9) { + min_scale = 1; + max_scale = skl_max_scale(intel_crtc, crtc_state); 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, + min_scale, + max_scale, can_position, true, &state->visible); if (ret) @@ -13202,6 +13324,13 @@ intel_check_primary_plane(struct drm_plane *plane, intel_crtc->atomic.update_wm = true; } + if (INTEL_INFO(dev)->gen >= 9) { + ret = skl_update_scaler_users(intel_crtc, crtc_state, + to_intel_plane(plane), state, 0); + if (ret) + return ret; + } + return 0; } @@ -13381,6 +13510,9 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->can_scale = false; primary->max_downscale = 1; + if (INTEL_INFO(dev)->gen >= 9) { + primary->can_scale = true; + } state->scaler_id = -1; primary->pipe = pipe; primary->plane = pipe; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 43fe003ba3da..fb8797f1eb8e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -285,11 +285,11 @@ struct intel_initial_plane_config { #define SKL_MIN_SRC_W 8 #define SKL_MAX_SRC_W 4096 #define SKL_MIN_SRC_H 8 -#define SKL_MAX_SRC_H 2304 +#define SKL_MAX_SRC_H 4096 #define SKL_MIN_DST_W 8 #define SKL_MAX_DST_W 4096 #define SKL_MIN_DST_H 8 -#define SKL_MAX_DST_H 2304 +#define SKL_MAX_DST_H 4096 struct intel_scaler { int id; @@ -1145,9 +1145,13 @@ void skl_detach_scalers(struct intel_crtc *intel_crtc); 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 skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, struct drm_i915_gem_object *obj); +u32 skl_plane_ctl_format(uint32_t pixel_format); +u32 skl_plane_ctl_tiling(uint64_t fb_modifier); +u32 skl_plane_ctl_rotation(unsigned int rotation); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e3d41c096dc6..b3c5911a6239 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1150,6 +1150,16 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, } intel_plane = to_intel_plane(plane); + + if (INTEL_INFO(dev)->gen >= 9) { + /* plane scaling and colorkey are mutually exclusive */ + if (to_intel_plane_state(plane->state)->scaler_id >= 0) { + DRM_ERROR("colorkey not allowed with scaler\n"); + ret = -EINVAL; + goto out_unlock; + } + } + intel_plane->ckey = *set; /* -- cgit v1.2.3 From c331879ce8ea4508260c5e9da5ea4b1a7d20e381 Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Wed, 15 Apr 2015 15:15:02 -0700 Subject: drm/i915: skylake sprite plane scaling using shared scalers This patch enables skylake sprite plane display scaling using shared scalers atomic desgin. v2: -use single copy of scaler limits (Matt) v3: -detaching scalers moved to crtc commit path (Matt) v4: -changes to align with updated scaler structures (Matt, me) -keep sprite src rect in 16.16 format (Matt, Daniel) v5: -rebased on top of 90/270 rotation changes (me) -Refactored skl_update_plane to reduce its size (Daniel) It is a step towards having a single function covering all planes. Signed-off-by: Chandra Konduru Reviewed-by: Matt Roper Testcase: igt/kms_plane_scaling Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sprite.c | 125 ++++++++++++++---------------------- 1 file changed, 48 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b3c5911a6239..856395bbcc4e 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "intel_drv.h" #include @@ -197,80 +198,17 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, u32 tile_height, plane_offset, plane_size; unsigned int rotation; int x_offset, y_offset; + struct intel_crtc_state *crtc_state = to_intel_crtc(crtc)->config; + int scaler_id; plane_ctl = PLANE_CTL_ENABLE | PLANE_CTL_PIPE_CSC_ENABLE; - switch (fb->pixel_format) { - case DRM_FORMAT_RGB565: - plane_ctl |= PLANE_CTL_FORMAT_RGB_565; - break; - case DRM_FORMAT_XBGR8888: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX; - break; - case DRM_FORMAT_XRGB8888: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888; - break; - /* - * XXX: For ARBG/ABGR formats we default to expecting scanout buffers - * to be already pre-multiplied. We need to add a knob (or a different - * DRM_FORMAT) for user-space to configure that. - */ - case DRM_FORMAT_ABGR8888: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | - PLANE_CTL_ORDER_RGBX | - PLANE_CTL_ALPHA_SW_PREMULTIPLY; - break; - case DRM_FORMAT_ARGB8888: - plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | - PLANE_CTL_ALPHA_SW_PREMULTIPLY; - break; - case DRM_FORMAT_YUYV: - plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV; - break; - case DRM_FORMAT_YVYU: - plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU; - break; - case DRM_FORMAT_UYVY: - plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY; - break; - case DRM_FORMAT_VYUY: - plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY; - break; - default: - BUG(); - } - - switch (fb->modifier[0]) { - case DRM_FORMAT_MOD_NONE: - break; - case I915_FORMAT_MOD_X_TILED: - plane_ctl |= PLANE_CTL_TILED_X; - break; - case I915_FORMAT_MOD_Y_TILED: - plane_ctl |= PLANE_CTL_TILED_Y; - break; - case I915_FORMAT_MOD_Yf_TILED: - plane_ctl |= PLANE_CTL_TILED_YF; - break; - default: - MISSING_CASE(fb->modifier[0]); - } + plane_ctl |= skl_plane_ctl_format(fb->pixel_format); + plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]); rotation = drm_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; - } + plane_ctl |= skl_plane_ctl_rotation(rotation); intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h, pixel_size, true, @@ -279,6 +217,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], fb->pixel_format); + scaler_id = to_intel_plane_state(drm_plane->state)->scaler_id; + /* Sizes are 0 based */ src_w--; src_h--; @@ -316,8 +256,27 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, I915_WRITE(PLANE_OFFSET(pipe, plane), plane_offset); I915_WRITE(PLANE_STRIDE(pipe, plane), stride); - I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); I915_WRITE(PLANE_SIZE(pipe, plane), plane_size); + + /* program plane scaler */ + if (scaler_id >= 0) { + uint32_t ps_ctrl = 0; + + DRM_DEBUG_KMS("plane = %d PS_PLANE_SEL(plane) = 0x%x\n", plane, + PS_PLANE_SEL(plane)); + ps_ctrl = PS_SCALER_EN | PS_PLANE_SEL(plane) | + crtc_state->scaler_state.scalers[scaler_id].mode; + I915_WRITE(SKL_PS_CTRL(pipe, scaler_id), ps_ctrl); + I915_WRITE(SKL_PS_PWR_GATE(pipe, scaler_id), 0); + I915_WRITE(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y); + I915_WRITE(SKL_PS_WIN_SZ(pipe, scaler_id), + ((crtc_w + 1) << 16)|(crtc_h + 1)); + + I915_WRITE(PLANE_POS(pipe, plane), 0); + } else { + I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x); + } + I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); I915_WRITE(PLANE_SURF(pipe, plane), surf_addr); POSTING_READ(PLANE_SURF(pipe, plane)); @@ -894,7 +853,9 @@ static int intel_check_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { + struct drm_device *dev = plane->dev; struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + struct intel_crtc_state *crtc_state; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; int crtc_x, crtc_y; @@ -906,8 +867,11 @@ intel_check_sprite_plane(struct drm_plane *plane, int hscale, vscale; int max_scale, min_scale; int pixel_size; + int ret; intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); + crtc_state = state->base.state ? + intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; if (!fb) { state->visible = false; @@ -934,6 +898,11 @@ intel_check_sprite_plane(struct drm_plane *plane, max_scale = intel_plane->max_downscale << 16; min_scale = intel_plane->can_scale ? 1 : (1 << 16); + if (INTEL_INFO(dev)->gen >= 9) { + min_scale = 1; + max_scale = skl_max_scale(intel_crtc, crtc_state); + } + drm_rect_rotate(src, fb->width << 16, fb->height << 16, state->base.rotation); @@ -1029,8 +998,8 @@ intel_check_sprite_plane(struct drm_plane *plane, width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size; - if (src_w > 2048 || src_h > 2048 || - width_bytes > 4096 || fb->pitches[0] > 4096) { + if (INTEL_INFO(dev)->gen < 9 && (src_w > 2048 || src_h > 2048 || + width_bytes > 4096 || fb->pitches[0] > 4096)) { DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n"); return -EINVAL; } @@ -1084,6 +1053,13 @@ finish: } } + if (INTEL_INFO(dev)->gen >= 9) { + ret = skl_update_scaler_users(intel_crtc, crtc_state, intel_plane, + state, 0); + if (ret) + return ret; + } + return 0; } @@ -1296,12 +1272,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) } break; case 9: - /* - * FIXME: Skylake planes can be scaled (with some restrictions), - * but this is for another time. - */ - intel_plane->can_scale = false; - intel_plane->max_downscale = 1; + intel_plane->can_scale = true; intel_plane->update_plane = skl_update_plane; intel_plane->disable_plane = skl_disable_plane; state->scaler_id = -1; -- cgit v1.2.3 From dfb601e6d2c72a7d2d9eddec1d1f65f2ccf66bda Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Fri, 10 Apr 2015 13:12:24 +0100 Subject: drm/i915/bxt: Add WaDisableThreadStallDopClockGating Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index de8c0747aaef..98424e29917c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1041,8 +1041,15 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) static int bxt_init_workarounds(struct intel_engine_cs *ring) { + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + gen9_init_workarounds(ring); + /* WaDisableThreadStallDopClockGating:bxt */ + WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, + STALL_DOP_GATING_DISABLE); + return 0; } -- cgit v1.2.3 From c6b8a4bc1ece2469ceef55f3c9423afdcb3b95c8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 4 May 2015 14:58:33 +0200 Subject: drm/i915: Simplify cmd-parser DISPATCH_SECURE check i915_needs_cmd_parser already checks that for us. Suggested-by: Mika Kuoppala Cc: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d2e21c549756..7ab63d9d7dc5 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1559,8 +1559,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * don't want that set when the command parser is * enabled. */ - if (USES_PPGTT(dev)) - dispatch_flags |= I915_DISPATCH_SECURE; + dispatch_flags |= I915_DISPATCH_SECURE; exec_start = 0; } -- cgit v1.2.3 From eb805623d8b161342ed9c9caf366f0a295041a6d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 4 May 2015 14:58:44 +0200 Subject: drm/i915/skl: Add support to load SKL CSR firmware. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display Context Save and Restore support is needed for various SKL Display C states like DC5, DC6. This implementation is added based on first version of DMC CSR program that we received from h/w team. Here we are using request_firmware based design. Finally this firmware should end up in linux-firmware tree. For SKL platform its mandatory to ensure that we load this csr program before enabling DC states like DC5/DC6. As CSR program gets reset on various conditions, we should ensure to load it during boot and in future change to be added to load this system resume sequence too. v1: Initial relese as RFC patch v2: Design change as per Daniel, Damien and Shobit's review comments request firmware method followed. v3: Some optimization and functional changes. Pulled register defines into drivers/gpu/drm/i915/i915_reg.h Used kmemdup to allocate and duplicate firmware content. Ensured to free allocated buffer. v4: Modified as per review comments from Satheesh and Daniel Removed temporary buffer. Optimized number of writes by replacing I915_WRITE with I915_WRITE64. v5: Modified as per review comemnts from Damien. - Changed name for functions and firmware. - Introduced HAS_CSR. - Reverted back previous change and used csr_buf with u8 size. - Using cpu_to_be64 for endianness change. Modified as per review comments from Imre. - Modified registers and macro names to be a bit closer to bspec terminology and the existing register naming in the driver. - Early return for non SKL platforms in intel_load_csr_program function. - Added locking around CSR program load function as it may be called concurrently during system/runtime resume. - Releasing the fw before loading the program for consistency - Handled error path during f/w load. v6: Modified as per review comments from Imre. - Corrected out_freecsr sequence. v7: Modified as per review comments from Imre. Fail loading fw if fw->size%8!=0. v8: Rebase to latest. v9: Rebase on top of -nightly (Damien) v10: Enabled support for dmc firmware ver 1.0. According to ver 1.0 in a single binary package all the firmware's that are required for different stepping's of the product will be stored. The package contains the css header, followed by the package header and the actual dmc firmwares. Package header contains the firmware/stepping mapping table and the corresponding firmware offsets to the individual binaries, within the package. Each individual program binary contains the header and the payload sections whose size is specified in the header section. This changes are done to extract the specific firmaware from the package. (Animesh) v11: Modified as per review comemnts from Imre. - Added code comment from bpec for header structure elements. - Added __packed to avoid structure padding. - Added helper functions for stepping and substepping info. - Added code comment for CSR_MAX_FW_SIZE. - Disabled BXT firmware loading, will be enabled with dmc 1.0 support. - Changed skl_stepping_info based on bspec, earlier used from config DB. - Removed duplicate call of cpu_to_be* from intel_csr_load_program function. - Used cpu_to_be32 instead of cpu_to_be64 as firmware binary in dword aligned. - Added sanity check for header length. - Added sanity check for mmio address got from firmware binary. - kmalloc done separately for dmc header and dmc firmware. (Animesh) v12: Modified as per review comemnts from Imre. - Corrected the typo error in skl stepping info structure. - Added out-of-bound access for skl_stepping_info. - Sanity check for mmio address modified. - Sanity check added for stepping and substeppig. - Modified the intel_dmc_info structure, cache only the required header info. (Animesh) v13: clarify firmware load error message. The reason for a firmware loading failure can be obscure if the driver is built-in. Provide an explanation to the user about the likely reason for the failure and how to resolve it. (Imre) v14: Suggested by Jani. - fix s/I915/CONFIG_DRM_I915/ typo - add fw_path to the firmware object instead of using a static ptr (Jani) v15: 1) Changed the firmware name as dmc_gen9.bin, everytime for a new firmware version a symbolic link with same name will help not to build kernel again. 2) Changes done as per review comments from Imre. - Error check removed for intel_csr_ucode_init. - Moved csr-specific data structure to intel_csr.h and optimization done on structure definition. - fw->data used directly for parsing the header info & memory allocation only done separately for payload. (Animesh) v16: - No need for out_regs label in i915_driver_load(), so removed it. - Changed the firmware name as skl_dmc_ver1.bin, followed naming convention _dmc_.bin (Animesh) Issue: VIZ-2569 Signed-off-by: A.Sunil Kamath Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Signed-off-by: Imre Deak Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/i915_dma.c | 11 +- drivers/gpu/drm/i915/i915_drv.c | 20 +++ drivers/gpu/drm/i915/i915_drv.h | 17 ++ drivers/gpu/drm/i915/intel_csr.c | 367 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 5 + 6 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_csr.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index a69002e2257d..5238deb64505 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -12,7 +12,8 @@ i915-y := i915_drv.o \ i915_suspend.o \ i915_sysfs.o \ intel_pm.o \ - intel_runtime_pm.o + intel_runtime_pm.o \ + intel_csr.o i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e44116f0ad0a..a238889630d8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -816,6 +816,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->mmio_flip_lock); mutex_init(&dev_priv->dpio_lock); mutex_init(&dev_priv->modeset_restore_lock); + mutex_init(&dev_priv->csr_lock); intel_pm_setup(dev); @@ -861,9 +862,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_uncore_init(dev); + /* Load CSR Firmware for SKL */ + intel_csr_ucode_init(dev); + ret = i915_gem_gtt_init(dev); if (ret) - goto out_regs; + goto out_freecsr; /* WARNING: Apparently we must kick fbdev drivers before vgacon, * otherwise the vga fbdev driver falls over. */ @@ -1033,7 +1037,8 @@ out_mtrrfree: io_mapping_free(dev_priv->gtt.mappable); out_gtt: i915_global_gtt_cleanup(dev); -out_regs: +out_freecsr: + intel_csr_ucode_fini(dev); intel_uncore_fini(dev); pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: @@ -1113,6 +1118,8 @@ int i915_driver_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_stolen(dev); + intel_csr_ucode_fini(dev); + intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 6e9ab2fb1647..b743bb17e288 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -556,6 +556,26 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); } +void i915_firmware_load_error_print(const char *fw_path, int err) +{ + DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err); + + /* + * If the reason is not known assume -ENOENT since that's the most + * usual failure mode. + */ + if (!err) + err = -ENOENT; + + if (!(IS_BUILTIN(CONFIG_DRM_I915) && err == -ENOENT)) + return; + + DRM_ERROR( + "The driver is built-in, so to load the firmware you need to\n" + "include it either in the kernel (see CONFIG_EXTRA_FIRMWARE) or\n" + "in your initrd/initramfs image.\n"); +} + static void intel_suspend_encoders(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e8e8145df869..df46e2735991 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -669,6 +669,15 @@ struct intel_uncore { #define for_each_fw_domain(domain__, dev_priv__, i__) \ for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__) +struct intel_csr { + const char *fw_path; + __be32 *dmc_payload; + uint32_t dmc_fw_size; + uint32_t mmio_count; + uint32_t mmioaddr[8]; + uint32_t mmiodata[8]; +}; + #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ func(is_mobile) sep \ func(is_i85x) sep \ @@ -1574,6 +1583,11 @@ struct drm_i915_private { struct i915_virtual_gpu vgpu; + struct intel_csr csr; + + /* Display CSR-related protection */ + struct mutex csr_lock; + struct intel_gmbus gmbus[GMBUS_NUM_PINS]; /** gmbus_mutex protects against concurrent usage of the single hw gmbus @@ -2426,6 +2440,8 @@ struct drm_i915_cmd_table { #define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_RC6p(dev) (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev)) +#define HAS_CSR(dev) (IS_SKYLAKE(dev)) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 @@ -2516,6 +2532,7 @@ extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); +void i915_firmware_load_error_print(const char *fw_path, int err); /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c new file mode 100644 index 000000000000..b3d6fbefa5c6 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -0,0 +1,367 @@ +/* + * Copyright © 2014 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ +#include +#include "i915_drv.h" +#include "i915_reg.h" + +#define I915_CSR_SKL "i915/skl_dmc_ver4.bin" + +MODULE_FIRMWARE(I915_CSR_SKL); + +/* +* SKL CSR registers for DC5 and DC6 +*/ +#define CSR_PROGRAM_BASE 0x80000 +#define CSR_SSP_BASE_ADDR_GEN9 0x00002FC0 +#define CSR_HTP_ADDR_SKL 0x00500034 +#define CSR_SSP_BASE 0x8F074 +#define CSR_HTP_SKL 0x8F004 +#define CSR_LAST_WRITE 0x8F034 +#define CSR_LAST_WRITE_VALUE 0xc003b400 +/* MMIO address range for CSR program (0x80000 - 0x82FFF) */ +#define CSR_MAX_FW_SIZE 0x2FFF +#define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF +#define CSR_MMIO_START_RANGE 0x80000 +#define CSR_MMIO_END_RANGE 0x8FFFF + +struct intel_css_header { + /* 0x09 for DMC */ + uint32_t module_type; + + /* Includes the DMC specific header in dwords */ + uint32_t header_len; + + /* always value would be 0x10000 */ + uint32_t header_ver; + + /* Not used */ + uint32_t module_id; + + /* Not used */ + uint32_t module_vendor; + + /* in YYYYMMDD format */ + uint32_t date; + + /* Size in dwords (CSS_Headerlen + PackageHeaderLen + dmc FWsLen)/4 */ + uint32_t size; + + /* Not used */ + uint32_t key_size; + + /* Not used */ + uint32_t modulus_size; + + /* Not used */ + uint32_t exponent_size; + + /* Not used */ + uint32_t reserved1[12]; + + /* Major Minor */ + uint32_t version; + + /* Not used */ + uint32_t reserved2[8]; + + /* Not used */ + uint32_t kernel_header_info; +} __packed; + +struct intel_fw_info { + uint16_t reserved1; + + /* Stepping (A, B, C, ..., *). * is a wildcard */ + char stepping; + + /* Sub-stepping (0, 1, ..., *). * is a wildcard */ + char substepping; + + uint32_t offset; + uint32_t reserved2; +} __packed; + +struct intel_package_header { + /* DMC container header length in dwords */ + unsigned char header_len; + + /* always value would be 0x01 */ + unsigned char header_ver; + + unsigned char reserved[10]; + + /* Number of valid entries in the FWInfo array below */ + uint32_t num_entries; + + struct intel_fw_info fw_info[20]; +} __packed; + +struct intel_dmc_header { + /* always value would be 0x40403E3E */ + uint32_t signature; + + /* DMC binary header length */ + unsigned char header_len; + + /* 0x01 */ + unsigned char header_ver; + + /* Reserved */ + uint16_t dmcc_ver; + + /* Major, Minor */ + uint32_t project; + + /* Firmware program size (excluding header) in dwords */ + uint32_t fw_size; + + /* Major Minor version */ + uint32_t fw_version; + + /* Number of valid MMIO cycles present. */ + uint32_t mmio_count; + + /* MMIO address */ + uint32_t mmioaddr[8]; + + /* MMIO data */ + uint32_t mmiodata[8]; + + /* FW filename */ + unsigned char dfile[32]; + + uint32_t reserved1[2]; +} __packed; + +struct stepping_info { + char stepping; + char substepping; +}; + +static const struct stepping_info skl_stepping_info[] = { + {'A', '0'}, {'B', '0'}, {'C', '0'}, + {'D', '0'}, {'E', '0'}, {'F', '0'}, + {'G', '0'}, {'H', '0'}, {'I', '0'} +}; + +static char intel_get_stepping(struct drm_device *dev) +{ + if (IS_SKYLAKE(dev) && (dev->pdev->revision < + ARRAY_SIZE(skl_stepping_info))) + return skl_stepping_info[dev->pdev->revision].stepping; + else + return -ENODATA; +} + +static char intel_get_substepping(struct drm_device *dev) +{ + if (IS_SKYLAKE(dev) && (dev->pdev->revision < + ARRAY_SIZE(skl_stepping_info))) + return skl_stepping_info[dev->pdev->revision].substepping; + else + return -ENODATA; +} + +void intel_csr_load_program(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + __be32 *payload = dev_priv->csr.dmc_payload; + uint32_t i, fw_size; + + if (!IS_GEN9(dev)) { + DRM_ERROR("No CSR support available for this platform\n"); + return; + } + + mutex_lock(&dev_priv->csr_lock); + fw_size = dev_priv->csr.dmc_fw_size; + for (i = 0; i < fw_size; i++) + I915_WRITE(CSR_PROGRAM_BASE + i * 4, + (u32 __force)payload[i]); + + for (i = 0; i < dev_priv->csr.mmio_count; i++) { + I915_WRITE(dev_priv->csr.mmioaddr[i], + dev_priv->csr.mmiodata[i]); + } + mutex_unlock(&dev_priv->csr_lock); +} + +static void finish_csr_load(const struct firmware *fw, void *context) +{ + struct drm_i915_private *dev_priv = context; + struct drm_device *dev = dev_priv->dev; + struct intel_css_header *css_header; + struct intel_package_header *package_header; + struct intel_dmc_header *dmc_header; + struct intel_csr *csr = &dev_priv->csr; + char stepping = intel_get_stepping(dev); + char substepping = intel_get_substepping(dev); + uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; + uint32_t i; + __be32 *dmc_payload; + + if (!fw) { + i915_firmware_load_error_print(csr->fw_path, 0); + goto out; + } + + if ((stepping == -ENODATA) || (substepping == -ENODATA)) { + DRM_ERROR("Unknown stepping info, firmware loading failed\n"); + goto out; + } + + /* Extract CSS Header information*/ + css_header = (struct intel_css_header *)fw->data; + if (sizeof(struct intel_css_header) != + (css_header->header_len * 4)) { + DRM_ERROR("Firmware has wrong CSS header length %u bytes\n", + (css_header->header_len * 4)); + goto out; + } + readcount += sizeof(struct intel_css_header); + + /* Extract Package Header information*/ + package_header = (struct intel_package_header *) + &fw->data[readcount]; + if (sizeof(struct intel_package_header) != + (package_header->header_len * 4)) { + DRM_ERROR("Firmware has wrong package header length %u bytes\n", + (package_header->header_len * 4)); + goto out; + } + readcount += sizeof(struct intel_package_header); + + /* Search for dmc_offset to find firware binary. */ + for (i = 0; i < package_header->num_entries; i++) { + if (package_header->fw_info[i].substepping == '*' && + stepping == package_header->fw_info[i].stepping) { + dmc_offset = package_header->fw_info[i].offset; + break; + } else if (stepping == package_header->fw_info[i].stepping && + substepping == package_header->fw_info[i].substepping) { + dmc_offset = package_header->fw_info[i].offset; + break; + } else if (package_header->fw_info[i].stepping == '*' && + package_header->fw_info[i].substepping == '*') + dmc_offset = package_header->fw_info[i].offset; + } + if (dmc_offset == CSR_DEFAULT_FW_OFFSET) { + DRM_ERROR("Firmware not supported for %c stepping\n", stepping); + goto out; + } + readcount += dmc_offset; + + /* Extract dmc_header information. */ + dmc_header = (struct intel_dmc_header *)&fw->data[readcount]; + if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) { + DRM_ERROR("Firmware has wrong dmc header length %u bytes\n", + (dmc_header->header_len)); + goto out; + } + readcount += sizeof(struct intel_dmc_header); + + /* Cache the dmc header info. */ + if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { + DRM_ERROR("Firmware has wrong mmio count %u\n", + dmc_header->mmio_count); + goto out; + } + csr->mmio_count = dmc_header->mmio_count; + for (i = 0; i < dmc_header->mmio_count; i++) { + if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE && + dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { + DRM_ERROR(" Firmware has wrong mmio address 0x%x\n", + dmc_header->mmioaddr[i]); + goto out; + } + csr->mmioaddr[i] = dmc_header->mmioaddr[i]; + csr->mmiodata[i] = dmc_header->mmiodata[i]; + } + + /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ + nbytes = dmc_header->fw_size * 4; + if (nbytes > CSR_MAX_FW_SIZE) { + DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes); + goto out; + } + csr->dmc_fw_size = dmc_header->fw_size; + + csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); + if (!csr->dmc_payload) { + DRM_ERROR("Memory allocation failed for dmc payload\n"); + goto out; + } + + dmc_payload = csr->dmc_payload; + for (i = 0; i < dmc_header->fw_size; i++) { + uint32_t *tmp = (u32 *)&fw->data[readcount + i * 4]; + /* + * The firmware payload is an array of 32 bit words stored in + * little-endian format in the firmware image and programmed + * as 32 bit big-endian format to memory. + */ + dmc_payload[i] = cpu_to_be32(*tmp); + } + + /* load csr program during system boot, as needed for DC states */ + intel_csr_load_program(dev); +out: + release_firmware(fw); +} + +void intel_csr_ucode_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_csr *csr = &dev_priv->csr; + int ret; + + if (!HAS_CSR(dev)) + return; + + if (IS_SKYLAKE(dev)) + csr->fw_path = I915_CSR_SKL; + else { + DRM_ERROR("Unexpected: no known CSR firmware for platform\n"); + return; + } + + /* CSR supported for platform, load firmware */ + ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path, + &dev_priv->dev->pdev->dev, + GFP_KERNEL, dev_priv, + finish_csr_load); + if (ret) + i915_firmware_load_error_print(csr->fw_path, ret); + +} + +void intel_csr_ucode_fini(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!HAS_CSR(dev)) + return; + + kfree(dev_priv->csr.dmc_payload); +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index fb8797f1eb8e..8bdb29e3ecb2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1153,6 +1153,11 @@ u32 skl_plane_ctl_format(uint32_t pixel_format); u32 skl_plane_ctl_tiling(uint64_t fb_modifier); u32 skl_plane_ctl_rotation(unsigned int rotation); +/* intel_csr.c */ +void intel_csr_ucode_init(struct drm_device *dev); +void intel_csr_load_program(struct drm_device *dev); +void intel_csr_ucode_fini(struct drm_device *dev); + /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, -- cgit v1.2.3 From dc17430054056049e8b279ffe3f18d0ff13ae3e2 Mon Sep 17 00:00:00 2001 From: Suketu Shah Date: Fri, 17 Apr 2015 19:46:16 +0530 Subject: drm/i915/skl: Add DC5 Trigger Sequence Add triggers as per expectations mentioned in gen9_enable_dc5 and gen9_disable_dc5 patch. Also call POSTING_READ for every write to a register to ensure that its written immediately. v1: Remove POSTING_READ calls as they've already been added in previous patches. v2: Rebase to move all runtime pm specific changes to intel_runtime_pm.c file. Modified as per review comments from Imre: 1] Change variable name 'dc5_allowed' to 'dc5_enabled' to correspond to relevant functions. 2] Move the check dc5_enabled in skl_set_power_well() to disable DC5 into gen9_disable_DC5 which is a more appropriate place. 3] Convert checks for 'pm.dc5_enabled' and 'pm.suspended' in skl_set_power_well() to warnings. However, removing them for now as they'll be included in a future patch asserting DC-state entry/exit criteria. 4] Enable DC5, only when CSR firmware is verified to be loaded. Create new structure to track 'enabled' and 'deferred' status of DC5. 5] Ensure runtime PM reference is obtained, if CSR is not loaded, to avoid entering runtime-suspend and release it when it's loaded. 6] Protect necessary CSR-related code with locks. 7] Move CSR-loading call to runtime PM initialization, as power domains needed to be accessed during deferred DC5-enabling, are not initialized earlier. v3: Rebase to latest. Modified as per review comments from Imre: 1] Use blocking wait for CSR-loading to finish to enable DC5 for simplicity, instead of deferring enabling DC5 until CSR is loaded. 2] Obtain runtime PM reference during CSR-loading initialization itself as deferred DC5- enabling is removed and release it at the end of CSR-loading functionality. 3] Revert calling CSR-loading functionality to the beginning of i915 driver-load functionality to avoid any delay in loading. 4] Define another variable to track whether CSR-loading failed and use it to avoid enabling DC5 if it's true. 5] Define CSR-load-status accessor functions for use later. v4: 1] Disable DC5 before enabling PG2 instead of after it. 2] DC5 was being mistaken enabled even when CSR-loading timed-out. Fix that. 3] Enable DC5-related functionality using a macro. 4] Remove dc5_enabled tracking variable and its use as it's not needed now. v5: 1] Mark CSR failed to load where necessary in finish_csr_load function. 2] Use mutex-protected accessor function to check if CSR loaded instead of directly accessing the variable. 3] Prefix csr_load_status_get/set function names with intel_. v6: rebase to latest. v7: Rebase on top of nightly (Damien) v8: Squashed the patch from Imre - added csr helper pointers to simplify the code. (Imre) v9: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh) v10: Added a enum for different csr states, suggested by Imre. (Animesh) v11: Based on review comments from Imre, Damien and Daniel following changes done - enum name chnaged to csr_state (singular form). - FW_UNINITIALIZED used as zeroth element in enum csr_state. - Prototype changed for helper function(set/get csr status), using enum csr_state instead of bool. v12: Based on review comment from Imre, introduced bool fw_loaded local to finish_csr_load() which helps calling once to set the csr status. The same flag used to fail RPM if find any issue during firmware loading. Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Imre Deak Signed-off-by: Animesh Manna Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 ++++++ drivers/gpu/drm/i915/intel_csr.c | 42 +++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 3 +++ drivers/gpu/drm/i915/intel_runtime_pm.c | 33 ++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index df46e2735991..a49986f8b7f0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -669,6 +669,12 @@ struct intel_uncore { #define for_each_fw_domain(domain__, dev_priv__, i__) \ for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__) +enum csr_state { + FW_UNINITIALIZED = 0, + FW_LOADED, + FW_FAILED +}; + struct intel_csr { const char *fw_path; __be32 *dmc_payload; @@ -676,6 +682,7 @@ struct intel_csr { uint32_t mmio_count; uint32_t mmioaddr[8]; uint32_t mmiodata[8]; + enum csr_state state; }; #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index b3d6fbefa5c6..0cae0cd90c21 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -183,6 +183,25 @@ static char intel_get_substepping(struct drm_device *dev) return -ENODATA; } +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv) +{ + enum csr_state state; + + mutex_lock(&dev_priv->csr_lock); + state = dev_priv->csr.state; + mutex_unlock(&dev_priv->csr_lock); + + return state; +} + +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, + enum csr_state state) +{ + mutex_lock(&dev_priv->csr_lock); + dev_priv->csr.state = state; + mutex_unlock(&dev_priv->csr_lock); +} + void intel_csr_load_program(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -204,6 +223,8 @@ void intel_csr_load_program(struct drm_device *dev) I915_WRITE(dev_priv->csr.mmioaddr[i], dev_priv->csr.mmiodata[i]); } + + dev_priv->csr.state = FW_LOADED; mutex_unlock(&dev_priv->csr_lock); } @@ -220,6 +241,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; uint32_t i; __be32 *dmc_payload; + bool fw_loaded = false; if (!fw) { i915_firmware_load_error_print(csr->fw_path, 0); @@ -326,7 +348,14 @@ static void finish_csr_load(const struct firmware *fw, void *context) /* load csr program during system boot, as needed for DC states */ intel_csr_load_program(dev); + fw_loaded = true; + out: + if (fw_loaded) + intel_runtime_pm_put(dev_priv); + else + intel_csr_load_status_set(dev_priv, FW_FAILED); + release_firmware(fw); } @@ -343,17 +372,25 @@ void intel_csr_ucode_init(struct drm_device *dev) csr->fw_path = I915_CSR_SKL; else { DRM_ERROR("Unexpected: no known CSR firmware for platform\n"); + intel_csr_load_status_set(dev_priv, FW_FAILED); return; } + /* + * Obtain a runtime pm reference, until CSR is loaded, + * to avoid entering runtime-suspend. + */ + intel_runtime_pm_get(dev_priv); + /* CSR supported for platform, load firmware */ ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path, &dev_priv->dev->pdev->dev, GFP_KERNEL, dev_priv, finish_csr_load); - if (ret) + if (ret) { i915_firmware_load_error_print(csr->fw_path, ret); - + intel_csr_load_status_set(dev_priv, FW_FAILED); + } } void intel_csr_ucode_fini(struct drm_device *dev) @@ -363,5 +400,6 @@ void intel_csr_ucode_fini(struct drm_device *dev) if (!HAS_CSR(dev)) return; + intel_csr_load_status_set(dev_priv, FW_FAILED); kfree(dev_priv->csr.dmc_payload); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8bdb29e3ecb2..980b3aff9bf4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1155,6 +1155,9 @@ u32 skl_plane_ctl_rotation(unsigned int rotation); /* intel_csr.c */ void intel_csr_ucode_init(struct drm_device *dev); +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv); +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, + enum csr_state state); void intel_csr_load_program(struct drm_device *dev); void intel_csr_ucode_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8fe2fdeab652..ffbf9779c26d 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -49,6 +49,8 @@ * present for a given platform. */ +#define GEN9_ENABLE_DC5(dev) (IS_SKYLAKE(dev)) + #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ i < (power_domains)->power_well_count && \ @@ -417,9 +419,20 @@ void bxt_disable_dc9(struct drm_i915_private *dev_priv) POSTING_READ(DC_STATE_EN); } +static void gen9_enable_dc5(struct drm_i915_private *dev_priv) +{ + /* TODO: Implementation to be done. */ +} + +static void gen9_disable_dc5(struct drm_i915_private *dev_priv) +{ + /* TODO: Implementation to be done. */ +} + static void skl_set_power_well(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, bool enable) { + struct drm_device *dev = dev_priv->dev; uint32_t tmp, fuse_status; uint32_t req_mask, state_mask; bool is_enabled, enable_requested, check_fuse_status = false; @@ -459,6 +472,13 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, if (enable) { if (!enable_requested) { + WARN((tmp & state_mask) && + !I915_READ(HSW_PWR_WELL_BIOS), + "Invalid for power well status to be enabled, unless done by the BIOS, \ + when request is to disable!\n"); + if (GEN9_ENABLE_DC5(dev) && + power_well->data == SKL_DISP_PW_2) + gen9_disable_dc5(dev_priv); I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask); } @@ -475,6 +495,19 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask); POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Disabling %s\n", power_well->name); + + if (GEN9_ENABLE_DC5(dev) && + power_well->data == SKL_DISP_PW_2) { + enum csr_state state; + + wait_for((state = intel_csr_load_status_get(dev_priv)) != + FW_UNINITIALIZED, 1000); + if (state != FW_LOADED) + DRM_ERROR("CSR firmware not ready (%d)\n", + state); + else + gen9_enable_dc5(dev_priv); + } } } -- cgit v1.2.3 From 6b457d31ea0465fcadcf6d5044f5f71398954727 Mon Sep 17 00:00:00 2001 From: "A.Sunil Kamath" Date: Thu, 16 Apr 2015 14:22:09 +0530 Subject: drm/i915/skl: Implement enable/disable for Display C5 state. This patch just implements the basic enable and disable functions of DC5 state which is needed for both SKL and BXT. Its important to load respective CSR program before calling enable, which anyways will happen as CSR program is executed during boot. DC5 is a power saving state where hardware dynamically disables power well 1 and the CDCLK PLL and saves the associated registers. DC5 can be entered when software allows it, power well 2 is disabled, and hardware detects that all pipes are disabled or pipe A is enabled with PSR active. Its better to configure display engine to have power well 2 disabled before getting into DC5 enable function. Hence rpm framework will have to ensure to check status of power well 2 before calling gen9_enable_dc5. Rather dc5 entry criteria should be decided based on power well 2 status. If disabled, then call gen9_enable_dc5. v2: Replace HAS_ with IS_ check as per Daniel's review comments v3: Cleared the bits dc5/dc6 enable of DC_STATE_EN register before setting them as per Satheesh's review comments. v4: call POSTING_READ for every write to a register to ensure that its written immediately. v5: Modified as per review comments from Imre. - Squashed register definitions into this patch. - Finetuned comments and functions. v6: Avoid redundant writes in gen9_set_dc_state_debugmask_memory_up function. v7: - Rebase to latest. - Move all runtime PM functions defined in intel_display.c to intel_runtime_pm.c. v8: Rebased to drm-intel-nightly. (Animesh) Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 +++++++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 41 +++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e35d7f29d7c2..1b31238fa531 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7204,6 +7204,17 @@ enum skl_disp_power_wells { #define DC_STATE_EN_UPTO_DC5 (1<<0) #define DC_STATE_EN_DC9 (1<<3) +/* +* SKL DC +*/ +#define DC_STATE_EN 0x45504 +#define DC_STATE_EN_UPTO_DC5 (1<<0) +#define DC_STATE_EN_UPTO_DC6 (2<<0) +#define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3 + +#define DC_STATE_DEBUG 0x45520 +#define DC_STATE_DEBUG_MASK_MEMORY_UP (1<<1) + /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, * since on HSW we can't write to it using I915_WRITE. */ #define D_COMP_HSW (MCHBAR_MIRROR_BASE_SNB + 0x5F0C) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index ffbf9779c26d..839010a57a2b 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -419,14 +419,51 @@ void bxt_disable_dc9(struct drm_i915_private *dev_priv) POSTING_READ(DC_STATE_EN); } +static void gen9_set_dc_state_debugmask_memory_up( + struct drm_i915_private *dev_priv) +{ + uint32_t val; + + /* The below bit doesn't need to be cleared ever afterwards */ + val = I915_READ(DC_STATE_DEBUG); + if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) { + val |= DC_STATE_DEBUG_MASK_MEMORY_UP; + I915_WRITE(DC_STATE_DEBUG, val); + POSTING_READ(DC_STATE_DEBUG); + } +} + static void gen9_enable_dc5(struct drm_i915_private *dev_priv) { - /* TODO: Implementation to be done. */ + struct drm_device *dev = dev_priv->dev; + uint32_t val; + + WARN_ON(!IS_GEN9(dev)); + + DRM_DEBUG_KMS("Enabling DC5\n"); + + gen9_set_dc_state_debugmask_memory_up(dev_priv); + + val = I915_READ(DC_STATE_EN); + val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK; + val |= DC_STATE_EN_UPTO_DC5; + I915_WRITE(DC_STATE_EN, val); + POSTING_READ(DC_STATE_EN); } static void gen9_disable_dc5(struct drm_i915_private *dev_priv) { - /* TODO: Implementation to be done. */ + struct drm_device *dev = dev_priv->dev; + uint32_t val; + + WARN_ON(!IS_GEN9(dev)); + + DRM_DEBUG_KMS("Disabling DC5\n"); + + val = I915_READ(DC_STATE_EN); + val &= ~DC_STATE_EN_UPTO_DC5; + I915_WRITE(DC_STATE_EN, val); + POSTING_READ(DC_STATE_EN); } static void skl_set_power_well(struct drm_i915_private *dev_priv, -- cgit v1.2.3 From 5aefb2398afad6998d51f90294e02b37b3f19a40 Mon Sep 17 00:00:00 2001 From: Suketu Shah Date: Thu, 16 Apr 2015 14:22:10 +0530 Subject: drm/i915/skl: Assert the requirements to enter or exit DC5. Warn if the conditions to enter or exit DC5 are not satisfied such as support for runtime PM, state of power well, CSR loading etc. v2: Removed camelcase in functions and variables. v3: Do some minimal check to assert if CSR program is not loaded. v4: 1] Used an appropriate function lookup_power_well() to identify power well, instead of using a magic number which can change in future. 2] Split the conditions further in assert_can_enable_DC5() and added more checks. 3] Removed all WARNs from assert_can_disable_DC5 as they were unnecessary and added two new ones. 4] Changed variable names as updated in earlier patches. v5: 1] Change lookup_power_well function to take an int power well id. 2] Define a new intel_display_power_well_is_enabled helper function to check whether a particular power well is enabled. 3] Use CSR-related mutex in assert_csr_loaded function. v6: Remove use of dc5_enabled variable as it's no longer needed. v7: 1] Rebase to latest. 2] Move all DC5-related functions from intel_display.c to intel_runtime_pm.c. v8: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh) v9: Modified below changes based on review comments from Imre. - Moved intel_display_power_well_is_enabled() to intel_runtime_pm.c. - Removed mutex lock from assert_csr_loaded(). (Animesh) Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 9 ++++++ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_runtime_pm.c | 51 +++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 0cae0cd90c21..9311cddb86e6 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -403,3 +403,12 @@ void intel_csr_ucode_fini(struct drm_device *dev) intel_csr_load_status_set(dev_priv, FW_FAILED); kfree(dev_priv->csr.dmc_payload); } + +void assert_csr_loaded(struct drm_i915_private *dev_priv) +{ + WARN((intel_csr_load_status_get(dev_priv) != FW_LOADED), "CSR is not loaded.\n"); + WARN(!I915_READ(CSR_PROGRAM_BASE), + "CSR program storage start is NULL\n"); + WARN(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); + WARN(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n"); +} diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 980b3aff9bf4..ddf3fefd96b2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1160,6 +1160,7 @@ void intel_csr_load_status_set(struct drm_i915_private *dev_priv, enum csr_state state); void intel_csr_load_program(struct drm_device *dev); void intel_csr_ucode_fini(struct drm_device *dev); +void assert_csr_loaded(struct drm_i915_private *dev_priv); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 839010a57a2b..2f7f0ab363fb 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -64,6 +64,9 @@ i--) \ if ((power_well)->domains & (domain_mask)) +bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, + int power_well_id); + /* * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to @@ -433,12 +436,39 @@ static void gen9_set_dc_state_debugmask_memory_up( } } -static void gen9_enable_dc5(struct drm_i915_private *dev_priv) +static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; + bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, + SKL_DISP_PW_2); + + WARN(!IS_SKYLAKE(dev), "Platform doesn't support DC5.\n"); + WARN(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); + WARN(pg2_enabled, "PG2 not disabled to enable DC5.\n"); + + WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5), + "DC5 already programmed to be enabled.\n"); + WARN(dev_priv->pm.suspended, + "DC5 cannot be enabled, if platform is runtime-suspended.\n"); + + assert_csr_loaded(dev_priv); +} + +static void assert_can_disable_dc5(struct drm_i915_private *dev_priv) +{ + bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, + SKL_DISP_PW_2); + + WARN(!pg2_enabled, "PG2 not enabled to disable DC5.\n"); + WARN(dev_priv->pm.suspended, + "Disabling of DC5 while platform is runtime-suspended should never happen.\n"); +} + +static void gen9_enable_dc5(struct drm_i915_private *dev_priv) +{ uint32_t val; - WARN_ON(!IS_GEN9(dev)); + assert_can_enable_dc5(dev_priv); DRM_DEBUG_KMS("Enabling DC5\n"); @@ -453,10 +483,9 @@ static void gen9_enable_dc5(struct drm_i915_private *dev_priv) static void gen9_disable_dc5(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; uint32_t val; - WARN_ON(!IS_GEN9(dev)); + assert_can_disable_dc5(dev_priv); DRM_DEBUG_KMS("Disabling DC5\n"); @@ -1416,7 +1445,7 @@ static struct i915_power_well chv_power_wells[] = { }; static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv, - enum punit_power_well power_well_id) + int power_well_id) { struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *power_well; @@ -1430,6 +1459,18 @@ static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_pr return NULL; } +bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, + int power_well_id) +{ + struct i915_power_well *power_well; + bool ret; + + power_well = lookup_power_well(dev_priv, power_well_id); + ret = power_well->ops->is_enabled(dev_priv, power_well); + + return ret; +} + static struct i915_power_well skl_power_wells[] = { { .name = "always-on", -- cgit v1.2.3 From f75a1985137f272dff1a361b763a76fb8f68c3b9 Mon Sep 17 00:00:00 2001 From: Suketu Shah Date: Thu, 16 Apr 2015 14:22:11 +0530 Subject: drm/i915/skl: Add DC6 Trigger sequence. Add triggers for DC6 as per details provided in skl_enable_dc6 and skl_disable_dc6 implementations. Also Call POSTING_READ for every write to a register to ensure it is written to immediately v1: Remove POSTING_READ and intel_prepare_ddi calls as they've been added in previous patches. v2: 1] Remove check for backlight disabled as it should be the case by that time. 2] Mark DC5 as disabled when enabling DC6. 3] Return from DC5-disabling function early if DC5 is already be disabled which can happen due to DC6-enabling earlier. 3] Ensure CSR firmware is loaded after resume from DC6 as corresponding memory contents won't be retained after runtime-suspend. 4] Ensure that CSR isn't identified as loaded before CSR-loading program is called during runtime-resume. v3: Rebase to latest Modified as per review comments from Imre and after discussion with Art: 1] DC6 should be preferably enabled when PG2 is disabled by SW as the check for PG1 being disabled is taken of by HW to enter DC6, and disabled when PG2 is enabled respectively. This helps save more power, especially in the case when display is disabled but GT is enabled. Accordingly, replacing DC5 trigger sequence with DC6 for SKL. 2] DC6 could be enabled from intel_runtime_suspend() function, if DC5 is already enabled. 3] Move CSR-load-status setting code from intel_runtime_suspend function to a new function. v4: 1] Enable/disable DC6 only when toggling the power-well using a newly defined macro ENABLE_DC6. v5: 1] Load CSR on system resume too as firmware may be lost on system suspend preventing enabling DC5, DC6. 2] DDI buffers shouldn't be programmed during driver-load/resume as it's already done during modeset initialization then and also that the encoder list is still uninitialized by then. Therefore, call intel_prepare_ddi function right after disabling DC6 but outside skl_disable_dc6 function and not during driver-load/resume. v6: 1] Rebase to latest. 2] Move SKL_ENABLE_DC6 macro definition from intel_display.c to intel_runtime_pm.c. v7: 1) Refactored the code for removing the warning got from checkpatch. 2) After adding dmc ver 1.0 support rebased on top of nightly. (Animesh) v8: - Reverted the changes done in v7. - Removed the condition check in skl_prepare_resune(). (Animesh) Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 30 +++++++++++++++++++++++ drivers/gpu/drm/i915/intel_runtime_pm.c | 43 +++++++++++++++++++++++++++------ 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b743bb17e288..334bcc1badaa 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -594,6 +594,8 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv) static int intel_suspend_complete(struct drm_i915_private *dev_priv); static int vlv_resume_prepare(struct drm_i915_private *dev_priv, bool rpm_resume); +static int skl_resume_prepare(struct drm_i915_private *dev_priv); + static int i915_drm_suspend(struct drm_device *dev) { @@ -808,6 +810,8 @@ static int i915_drm_resume_early(struct drm_device *dev) if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_disable_pc8(dev_priv); + else if (IS_SKYLAKE(dev_priv)) + ret = skl_resume_prepare(dev_priv); intel_uncore_sanitize(dev); intel_power_domains_init_hw(dev_priv); @@ -1022,6 +1026,19 @@ static int i915_pm_resume(struct device *dev) return i915_drm_resume(drm_dev); } +static int skl_suspend_complete(struct drm_i915_private *dev_priv) +{ + /* Enabling DC6 is not a hard requirement to enter runtime D3 */ + + /* + * This is to ensure that CSR isn't identified as loaded before + * CSR-loading program is called during runtime-resume. + */ + intel_csr_load_status_set(dev_priv, FW_UNINITIALIZED); + + return 0; +} + static int hsw_suspend_complete(struct drm_i915_private *dev_priv) { hsw_enable_pc8(dev_priv); @@ -1061,6 +1078,15 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv) return 0; } +static int skl_resume_prepare(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + + intel_csr_load_program(dev); + + return 0; +} + /* * Save all Gunit registers that may be lost after a D3 and a subsequent * S0i[R123] transition. The list of registers needing a save/restore is @@ -1536,6 +1562,8 @@ static int intel_runtime_resume(struct device *device) if (IS_BROXTON(dev)) ret = bxt_resume_prepare(dev_priv); + else if (IS_SKYLAKE(dev)) + ret = skl_resume_prepare(dev_priv); else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_disable_pc8(dev_priv); else if (IS_VALLEYVIEW(dev_priv)) @@ -1570,6 +1598,8 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv) if (IS_BROXTON(dev)) ret = bxt_suspend_complete(dev_priv); + else if (IS_SKYLAKE(dev)) + ret = skl_suspend_complete(dev_priv); else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) ret = hsw_suspend_complete(dev_priv); else if (IS_VALLEYVIEW(dev)) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 2f7f0ab363fb..5bd7f083aa34 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -49,7 +49,8 @@ * present for a given platform. */ -#define GEN9_ENABLE_DC5(dev) (IS_SKYLAKE(dev)) +#define GEN9_ENABLE_DC5(dev) 0 +#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev) #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ @@ -495,6 +496,16 @@ static void gen9_disable_dc5(struct drm_i915_private *dev_priv) POSTING_READ(DC_STATE_EN); } +static void skl_enable_dc6(struct drm_i915_private *dev_priv) +{ + /* TODO: Implementation to be done. */ +} + +static void skl_disable_dc6(struct drm_i915_private *dev_priv) +{ + /* TODO: Implementation to be done. */ +} + static void skl_set_power_well(struct drm_i915_private *dev_priv, struct i915_power_well *power_well, bool enable) { @@ -542,9 +553,21 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, !I915_READ(HSW_PWR_WELL_BIOS), "Invalid for power well status to be enabled, unless done by the BIOS, \ when request is to disable!\n"); - if (GEN9_ENABLE_DC5(dev) && - power_well->data == SKL_DISP_PW_2) - gen9_disable_dc5(dev_priv); + if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) && + power_well->data == SKL_DISP_PW_2) { + if (SKL_ENABLE_DC6(dev)) { + skl_disable_dc6(dev_priv); + /* + * DDI buffer programming unnecessary during driver-load/resume + * as it's already done during modeset initialization then. + * It's also invalid here as encoder list is still uninitialized. + */ + if (!dev_priv->power_domains.initializing) + intel_prepare_ddi(dev); + } else { + gen9_disable_dc5(dev_priv); + } + } I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask); } @@ -562,17 +585,23 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Disabling %s\n", power_well->name); - if (GEN9_ENABLE_DC5(dev) && + if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) && power_well->data == SKL_DISP_PW_2) { enum csr_state state; - + /* TODO: wait for a completion event or + * similar here instead of busy + * waiting using wait_for function. + */ wait_for((state = intel_csr_load_status_get(dev_priv)) != FW_UNINITIALIZED, 1000); if (state != FW_LOADED) DRM_ERROR("CSR firmware not ready (%d)\n", state); else - gen9_enable_dc5(dev_priv); + if (SKL_ENABLE_DC6(dev)) + skl_enable_dc6(dev_priv); + else + gen9_enable_dc5(dev_priv); } } } -- cgit v1.2.3 From 74b4f371f56fc7ca4058041080b30d5b0a7271af Mon Sep 17 00:00:00 2001 From: "A.Sunil Kamath" Date: Thu, 16 Apr 2015 14:22:12 +0530 Subject: Implement enable/disable for Display C6 state This patch just implements the basic enable and disable functions of DC6 state which is needed for SKL platform. Its important to load SKL CSR program before calling enable. DC6 is a deeper power saving state where hardware dynamically disables power well 0 and saves the associated registers. DC6 can be entered when software allows it, the conditions for DC5 are met, and the PCU allows DC6. DC6 cannot be used if the backlight is being driven from the display utility pin. Its better to configure display engine to have power well 2 disabled before getting into DC6 enable function. Hence rpm framework will ensure to check status of power well 2 and DC5 before calling skl_enable_dc6. v2: Replace HAS_ with IS_ check as per Daniel's review comments v3: Cleared the bits dc5/dc6 enable of DC_STATE_EN register before setting them as per Satheesh's review comments. v4: No need to call gen9_disable_dc5 inside enable sequence of DC6, as its already take care above. v5: call POSTING_READ for every write to a register to ensure that its written immediately. Call intel_prepare_ddi during DC6 exit as it's required on low-power exit. v6: Protect DC6-enabling-disabling functionality with locks to synchronize with CSR-loading code. v7: Remove grabbing CSR-related mutex in skl_enable/disable_dc6 functions as deferred DC5-enabling functionality is now removed. v8: Remove 'Disabling DC5' from the debug comment during DC6 enabling as when DC6 is allowed, DC5 is not programmed at all. v9: - Rebase to latest. - Move all DC6-related functions from intel_display.c to intel_runtime_pm.c. v10: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh) Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 5bd7f083aa34..39810844a9c9 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -498,12 +498,35 @@ static void gen9_disable_dc5(struct drm_i915_private *dev_priv) static void skl_enable_dc6(struct drm_i915_private *dev_priv) { - /* TODO: Implementation to be done. */ + struct drm_device *dev = dev_priv->dev; + uint32_t val; + + WARN_ON(!IS_SKYLAKE(dev)); + + DRM_DEBUG_KMS("Enabling DC6\n"); + + gen9_set_dc_state_debugmask_memory_up(dev_priv); + + val = I915_READ(DC_STATE_EN); + val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK; + val |= DC_STATE_EN_UPTO_DC6; + I915_WRITE(DC_STATE_EN, val); + POSTING_READ(DC_STATE_EN); } static void skl_disable_dc6(struct drm_i915_private *dev_priv) { - /* TODO: Implementation to be done. */ + struct drm_device *dev = dev_priv->dev; + uint32_t val; + + WARN_ON(!IS_SKYLAKE(dev)); + + DRM_DEBUG_KMS("Disabling DC6\n"); + + val = I915_READ(DC_STATE_EN); + val &= ~DC_STATE_EN_UPTO_DC6; + I915_WRITE(DC_STATE_EN, val); + POSTING_READ(DC_STATE_EN); } static void skl_set_power_well(struct drm_i915_private *dev_priv, -- cgit v1.2.3 From 93c7cb6c3a2f8c7204fc8bcf7769059875a54027 Mon Sep 17 00:00:00 2001 From: Suketu Shah Date: Thu, 16 Apr 2015 14:22:13 +0530 Subject: drm/i915/skl: Assert the requirements to enter or exit DC6. Warn if the conditions to enter or exit DC6 are not satisfied such as support for runtime PM, state of power well, CSR loading etc. v2: Removed camelcase in functions and variables. v3: Do some minimal check to assert if CSR program is not loaded. v4: 1] Correct the check for backlight-disabling in assert_can_enable_dc6(). 2] Check csr.loaded = false before disabling DC6 and simplify other checks. v5: 1] Remove checks for DC5 state from assert_can_enable_dc6 function as DC5 is no longer enabled before enabling DC6. 2] Correct the check for CSR-loading in assert_can_disable_dc6 function as CSR must be loaded for context restore to happen on DC6 disabling. v6: 1] It's okay to explicitly disable DC6 during driver-load/resume even though it might already be disabled and so don't warn about it. v7: Rebase to latest. v8: Sqashed the patch from Imre - [PATCH] drm/i915/skl: avoid false CSR fw not loaded WARN during driver load/resume v9: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh) v10: During initialization added a early return before disabling DC5. (Animesh) Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 40 +++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 39810844a9c9..b393db78e5cb 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -459,6 +459,12 @@ static void assert_can_disable_dc5(struct drm_i915_private *dev_priv) { bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, SKL_DISP_PW_2); + /* + * During initialization, the firmware may not be loaded yet. + * We still want to make sure that the DC enabling flag is cleared. + */ + if (dev_priv->power_domains.initializing) + return; WARN(!pg2_enabled, "PG2 not enabled to disable DC5.\n"); WARN(dev_priv->pm.suspended, @@ -496,12 +502,39 @@ static void gen9_disable_dc5(struct drm_i915_private *dev_priv) POSTING_READ(DC_STATE_EN); } -static void skl_enable_dc6(struct drm_i915_private *dev_priv) +static void assert_can_enable_dc6(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; + + WARN(!IS_SKYLAKE(dev), "Platform doesn't support DC6.\n"); + WARN(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n"); + WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE, + "Backlight is not disabled.\n"); + WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), + "DC6 already programmed to be enabled.\n"); + + assert_csr_loaded(dev_priv); +} + +static void assert_can_disable_dc6(struct drm_i915_private *dev_priv) +{ + /* + * During initialization, the firmware may not be loaded yet. + * We still want to make sure that the DC enabling flag is cleared. + */ + if (dev_priv->power_domains.initializing) + return; + + assert_csr_loaded(dev_priv); + WARN(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), + "DC6 already programmed to be disabled.\n"); +} + +static void skl_enable_dc6(struct drm_i915_private *dev_priv) +{ uint32_t val; - WARN_ON(!IS_SKYLAKE(dev)); + assert_can_enable_dc6(dev_priv); DRM_DEBUG_KMS("Enabling DC6\n"); @@ -516,10 +549,9 @@ static void skl_enable_dc6(struct drm_i915_private *dev_priv) static void skl_disable_dc6(struct drm_i915_private *dev_priv) { - struct drm_device *dev = dev_priv->dev; uint32_t val; - WARN_ON(!IS_SKYLAKE(dev)); + assert_can_disable_dc6(dev_priv); DRM_DEBUG_KMS("Disabling DC6\n"); -- cgit v1.2.3 From 00776511da7134b25dd3ea45e2bf38ea08738a64 Mon Sep 17 00:00:00 2001 From: Suketu Shah Date: Thu, 16 Apr 2015 14:22:14 +0530 Subject: drm/i915/skl: Enable runtime PM Enable runtime PM for Skylake platform v2: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh) Issue: VIZ-2819 Signed-off-by: A.Sunil Kamath Signed-off-by: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Animesh Manna Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a49986f8b7f0..136d42a2ef44 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2443,7 +2443,8 @@ struct drm_i915_cmd_table { IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \ IS_SKYLAKE(dev)) #define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \ - IS_BROADWELL(dev) || IS_VALLEYVIEW(dev)) + IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \ + IS_SKYLAKE(dev)) #define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_RC6p(dev) (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev)) -- cgit v1.2.3 From 09b1eb130e43264d6a4e8c99ed75d07f40a2d4b3 Mon Sep 17 00:00:00 2001 From: Todd Previte Date: Mon, 20 Apr 2015 15:27:34 -0700 Subject: drm/i915: Move Displayport test request and sink IRQ logic to intel_dp_detect() Due to changes in the driver and to support Displayport compliance testing, the test request and sink IRQ logic has been relocated from intel_dp_check_link_status to intel_dp_detect. This is because the bulk of the compliance tests that set the TEST_REQUEST bit in the DEVICE_IRQ field of the DPCD issue a long pulse / hot plug event to signify the start of the test. Currently, for a long pulse, intel_dp_check_link_status is not called for a long HPD pulse, so if test requests come in, they cannot be detected by the driver. Once located in the intel_dp_detect, in the regular hot plug event path, proper detection of Displayport compliance test requests occurs which then invokes the test handler to support them. Additionally, this places compliance testing in the normal operational paths, eliminating as much special case code as possible. The only change in intel_dp_check_link_status with this patch is that when the IRQ is the result of a test request from the sink, the test handler is not invoked during the short pulse path. Short pulse test requests are for a particular variety of tests (mainly link training) that will be implemented in the future. Once those tests are available, the test request handler will be called from here as well. V2: - Rewored the commit message to be more clear about the content and intent of this patch - Restore IRQ detection logic to intel_dp_check_link_status(). Continue to detect and clear sink IRQs in the short pulse case. Ignore test requests in the short pulses for now since they are for future test implementations. Signed-off-by: Todd Previte Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 937ba31d8dde..bacdec5d8f3f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4220,7 +4220,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) sink_irq_vector); if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) - intel_dp_handle_test_request(intel_dp); + DRM_DEBUG_DRIVER("Test request in short pulse not handled\n"); if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ)) DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); } @@ -4450,6 +4450,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) enum drm_connector_status status; enum intel_display_power_domain power_domain; bool ret; + u8 sink_irq_vector; DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -4492,6 +4493,20 @@ intel_dp_detect(struct drm_connector *connector, bool force) intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; status = connector_status_connected; + /* Try to read the source of the interrupt */ + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && + intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) { + /* Clear interrupt source */ + drm_dp_dpcd_writeb(&intel_dp->aux, + DP_DEVICE_SERVICE_IRQ_VECTOR, + sink_irq_vector); + + if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) + intel_dp_handle_test_request(intel_dp); + if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ)) + DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); + } + out: intel_dp_power_put(intel_dp, power_domain); return status; -- cgit v1.2.3 From 06615ee5c54740a970754b6d8d7d5e7106dec186 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Fri, 24 Apr 2015 15:09:03 +0300 Subject: drm/i915: Do not clear mappings beyond VMA size Do not to clear mappings outside the allocated VMA under any circumstances. Only clear the smaller of VMA or object page count. This is required to allow creating partial object VMAs which in turn are needed for partial GGTT views. Signed-off-by: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 9d3852c521c7..fc562c68bf48 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1945,19 +1945,23 @@ static void ggtt_unbind_vma(struct i915_vma *vma) struct drm_device *dev = vma->vm->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj = vma->obj; + const uint64_t size = min_t(uint64_t, + obj->base.size, + vma->node.size); if (vma->bound & GLOBAL_BIND) { vma->vm->clear_range(vma->vm, vma->node.start, - obj->base.size, + size, true); } if (dev_priv->mm.aliasing_ppgtt && vma->bound & LOCAL_BIND) { struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt; + appgtt->base.clear_range(&appgtt->base, vma->node.start, - obj->base.size, + size, true); } } -- cgit v1.2.3 From 0b6cc18810cfa958985602ab1849b647250deb0f Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 25 Apr 2015 11:34:29 +0200 Subject: drm/i915: use ERR_CAST instead of ERR_PTR/PTR_ERR Inspired by scripts/coccinelle/api/err_cast.cocci Signed-off-by: Fabian Frederick Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ddf3fefd96b2..ea20edb58528 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1419,7 +1419,7 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state, struct drm_crtc_state *crtc_state; crtc_state = drm_atomic_get_crtc_state(state, &crtc->base); if (IS_ERR(crtc_state)) - return ERR_PTR(PTR_ERR(crtc_state)); + return ERR_CAST(crtc_state); return to_intel_crtc_state(crtc_state); } -- cgit v1.2.3 From d86ed34a4eeefffcc9030e903465a902f6aea9f3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 27 Apr 2015 13:41:19 +0100 Subject: drm/i915: Add RPS thresholds to debugfs/i915_frequency_info Expose some more of our internal RPS bookkeeping for debugging. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9c2b9e450799..9e5a56cff2f3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1211,12 +1211,17 @@ static int i915_frequency_info(struct seq_file *m, void *unused) GEN6_CURBSYTAVG_MASK); seq_printf(m, "RP PREV UP: %dus\n", rpprevup & GEN6_CURBSYTAVG_MASK); + seq_printf(m, "Up threshold: %d%%\n", + dev_priv->rps.up_threshold); + seq_printf(m, "RP CUR DOWN EI: %dus\n", rpdownei & GEN6_CURIAVG_MASK); seq_printf(m, "RP CUR DOWN: %dus\n", rpcurdown & GEN6_CURBSYTAVG_MASK); seq_printf(m, "RP PREV DOWN: %dus\n", rpprevdown & GEN6_CURBSYTAVG_MASK); + seq_printf(m, "Down threshold: %d%%\n", + dev_priv->rps.down_threshold); max_freq = (rp_state_cap & 0xff0000) >> 16; max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); @@ -1232,12 +1237,21 @@ static int i915_frequency_info(struct seq_file *m, void *unused) max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); - seq_printf(m, "Max overclocked frequency: %dMHz\n", intel_gpu_freq(dev_priv, dev_priv->rps.max_freq)); + seq_printf(m, "Current freq: %d MHz\n", + intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq)); + seq_printf(m, "Actual freq: %d MHz\n", cagf); seq_printf(m, "Idle freq: %d MHz\n", intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq)); + seq_printf(m, "Min freq: %d MHz\n", + intel_gpu_freq(dev_priv, dev_priv->rps.min_freq)); + seq_printf(m, "Max freq: %d MHz\n", + intel_gpu_freq(dev_priv, dev_priv->rps.max_freq)); + seq_printf(m, + "efficient (RPe) frequency: %d MHz\n", + intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq)); } else if (IS_VALLEYVIEW(dev)) { u32 freq_sts; @@ -1246,6 +1260,12 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts); seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq); + seq_printf(m, "actual GPU freq: %d MHz\n", + intel_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff)); + + seq_printf(m, "current GPU freq: %d MHz\n", + intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq)); + seq_printf(m, "max GPU freq: %d MHz\n", intel_gpu_freq(dev_priv, dev_priv->rps.max_freq)); @@ -1258,9 +1278,6 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "efficient (RPe) frequency: %d MHz\n", intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq)); - - seq_printf(m, "current GPU freq: %d MHz\n", - intel_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff)); mutex_unlock(&dev_priv->rps.hw_lock); } else { seq_puts(m, "no P-state info available\n"); -- cgit v1.2.3 From d4dc5e92c00d41044a86bd98243b322000514d41 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 28 Apr 2015 08:48:03 +0100 Subject: drm/i915: Remove incorrect restriction on 32bit offsets in ppGTT backend This is the wrong layer to apply an arbitrary restriction and the wrong error code (object too large!). If we do want to prevent large offsets being return to the user on 32bit systems (to hide bugs in userspace), you want to restrict the drm_mm range manager instead. This first tells userspace about the correct size of the GTT they can use (so they don't try and overallocate object or batches), and fixes the eviction logic to avoid the eventual and *guaranteed* error. Fixes regression in commit d7b2633dba04ef0fd7385f02a7b552abc5f1062f Author: Michel Thierry Date: Wed Apr 8 12:13:34 2015 +0100 drm/i915/gen8: Dynamic page table allocations Signed-off-by: Chris Wilson Cc: Michel Thierry Cc: Mika Kuoppala Cc: Daniel Vetter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index fc562c68bf48..ce91314f2c0c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -844,15 +844,6 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, uint32_t pdpe; int ret; -#ifndef CONFIG_64BIT - /* Disallow 64b address on 32b platforms. Nothing is wrong with doing - * this in hardware, but a lot of the drm code is not prepared to handle - * 64b offset on 32b platforms. - * This will be addressed when 48b PPGTT is added */ - if (start + length > 0x100000000ULL) - return -E2BIG; -#endif - /* Wrap is never okay since we can only represent 48b, and we don't * actually use the other side of the canonical address space. */ -- cgit v1.2.3 From 3126a660f352b3fe48125a8a0b4fdbf85935d8bf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Apr 2015 17:30:50 +0300 Subject: drm/i915: checking IS_ERR() instead of NULL We switched from calling i915_gem_alloc_context_obj() to calling i915_gem_alloc_object() so the error handling needs to be updated to check for NULL instead of IS_ERR(). Fixes: 149c86e74fe4 ('drm/i915: Allocate context objects from stolen') Signed-off-by: Dan Carpenter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 732fd633e73a..0fa9209ff556 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1895,10 +1895,9 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, context_size = round_up(get_lr_context_size(ring), 4096); ctx_obj = i915_gem_alloc_object(dev, context_size); - if (IS_ERR(ctx_obj)) { - ret = PTR_ERR(ctx_obj); - DRM_DEBUG_DRIVER("Alloc LRC backing obj failed: %d\n", ret); - return ret; + if (!ctx_obj) { + DRM_DEBUG_DRIVER("Alloc LRC backing obj failed.\n"); + return -ENOMEM; } if (is_global_default_ctx) { -- cgit v1.2.3 From 3ef62342bd854fff5d792d67fc6a8e66f26c862b Mon Sep 17 00:00:00 2001 From: Deepak S Date: Wed, 29 Apr 2015 08:36:24 +0530 Subject: drm/i915: Setup static bias for GPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the spec, Setting up static BIAS for GPU to improve the rps performace. v2: rename reg defn to match spec. (Ville) v3: Updated bias setting for chv (Deepak) Signed-off-by: Deepak S Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 ++++++ drivers/gpu/drm/i915/intel_pm.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1b31238fa531..1d4871b8fdab 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -670,6 +670,12 @@ enum skl_disp_power_wells { #define FB_FMAX_VMIN_FREQ_LO_SHIFT 27 #define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000 +#define VLV_TURBO_SOC_OVERRIDE 0x04 +#define VLV_OVERRIDE_EN 1 +#define VLV_SOC_TDP_EN (1 << 1) +#define VLV_BIAS_CPU_125_SOC_875 (6 << 2) +#define CHV_BIAS_CPU_50_SOC_50 (3 << 2) + #define VLV_CZ_CLOCK_TO_MILLI_SEC 100000 /* vlv2 north clock has */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a7516ed24eee..8812fffeac5e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5082,6 +5082,12 @@ static void cherryview_enable_rps(struct drm_device *dev) GEN6_RP_UP_BUSY_AVG | GEN6_RP_DOWN_IDLE_AVG); + /* Setting Fixed Bias */ + val = VLV_OVERRIDE_EN | + VLV_SOC_TDP_EN | + CHV_BIAS_CPU_50_SOC_50; + vlv_punit_write(dev_priv, VLV_TURBO_SOC_OVERRIDE, val); + val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); /* RPS code assumes GPLL is used */ @@ -5166,6 +5172,12 @@ static void valleyview_enable_rps(struct drm_device *dev) I915_WRITE(GEN6_RC_CONTROL, rc6_mode); + /* Setting Fixed Bias */ + val = VLV_OVERRIDE_EN | + VLV_SOC_TDP_EN | + VLV_BIAS_CPU_125_SOC_875; + vlv_punit_write(dev_priv, VLV_TURBO_SOC_OVERRIDE, val); + val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS); /* RPS code assumes GPLL is used */ -- cgit v1.2.3 From 4e96c97742f4201edf1b0f8e1b1b6b2ac6ff33e7 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Wed, 29 Apr 2015 09:17:39 +0300 Subject: drm/i915: eDP link training optimization This is a first of series patches that optimize DP link training. The first patch is for eDP only where we reuse the previously trained link training values from cache i.e. voltage swing and pre-emphasis levels. In case we are not able to train the link by reusing the known values, the link training parameters are set to zero and training is restarted. V2: - flag that indicates if DP link is trained and valid renamed from 'link_trained' to 'train_set_valid' - removed routine 'intel_dp_reuse_link_train' V3: - rebased against the latest drm-intel-nightly V4: - removed HPD long pulse handling for eDP case to clear the flag that indicates to reuse the current link training parameters. (based on Sivakumar's comment) Signed-off-by: Mika Kahola Reviewed-by: Sivakumar Thulasimani [danvet: s/DP/eDP/ in subject to make scope clear.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 27 ++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index bacdec5d8f3f..1af97adadde8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3547,7 +3547,8 @@ static bool intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP, uint8_t dp_train_pat) { - memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set)); + if (!intel_dp->train_set_valid) + memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set)); intel_dp_set_signal_levels(intel_dp, DP); return intel_dp_set_link_train(intel_dp, DP, dp_train_pat); } @@ -3660,6 +3661,23 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) break; } + /* + * if we used previously trained voltage and pre-emphasis values + * and we don't get clock recovery, reset link training values + */ + if (intel_dp->train_set_valid) { + DRM_DEBUG_KMS("clock recovery not ok, reset"); + /* clear the flag as we are not reusing train set */ + intel_dp->train_set_valid = false; + if (!intel_dp_reset_link_train(intel_dp, &DP, + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE)) { + DRM_ERROR("failed to enable link training\n"); + return; + } + continue; + } + /* Check to see if we've tried the max voltage */ for (i = 0; i < intel_dp->lane_count; i++) if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) @@ -3737,6 +3755,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* Make sure clock is still ok */ if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { + intel_dp->train_set_valid = false; intel_dp_start_link_train(intel_dp); intel_dp_set_link_train(intel_dp, &DP, training_pattern | @@ -3752,6 +3771,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* Try 5 times, then try clock recovery if that fails */ if (tries > 5) { + intel_dp->train_set_valid = false; intel_dp_start_link_train(intel_dp); intel_dp_set_link_train(intel_dp, &DP, training_pattern | @@ -3773,9 +3793,10 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) intel_dp->DP = DP; - if (channel_eq) + if (channel_eq) { + intel_dp->train_set_valid = is_edp(intel_dp); DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n"); - + } } void intel_dp_stop_link_train(struct intel_dp *intel_dp) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ea20edb58528..cf701ed26478 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -736,6 +736,7 @@ struct intel_dp { bool has_aux_irq, int send_bytes, uint32_t aux_clock_divider); + bool train_set_valid; /* Displayport compliance testing */ unsigned long compliance_test_type; -- cgit v1.2.3 From 5fa836a9d85975c5f0f1219669523c1f0ac64349 Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Wed, 29 Apr 2015 09:17:40 +0300 Subject: drm/i915: DP link training optimization This patch adds DP link training optimization by reusing the previously trained values. v2: - rebase V3: - rebase V4: - when HPD long pulse is received, the flag is cleared that indicates if DP link training is required or not (based on Sivakumar's comment) Signed-off-by: Mika Kahola Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 1af97adadde8..7c3dbd465c78 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3794,7 +3794,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) intel_dp->DP = DP; if (channel_eq) { - intel_dp->train_set_valid = is_edp(intel_dp); + intel_dp->train_set_valid = true; DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n"); } } @@ -4858,6 +4858,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) intel_display_power_get(dev_priv, power_domain); if (long_hpd) { + /* indicate that we need to restart link training */ + intel_dp->train_set_valid = false; if (HAS_PCH_SPLIT(dev)) { if (!ibx_digital_port_connected(dev_priv, intel_dig_port)) -- cgit v1.2.3 From 65b38e0d87a491e25848bea3274825b594cbdb22 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Apr 2015 11:26:56 +0300 Subject: drm/i915: make drm_crtc_helper_funcs const data Because they can be. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 14709547659f..abbca0e76ccf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11034,7 +11034,7 @@ out_hang: return ret; } -static struct drm_crtc_helper_funcs intel_helper_funcs = { +static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, .atomic_begin = intel_begin_crtc_commit, -- cgit v1.2.3 From 5e562f1dddfa3242cede5ec49888260a856a9da2 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 30 Apr 2015 11:02:31 +0300 Subject: drm/i915: Clear vma->bound on unbinding Unbinding doesn't always lead to unconditional destruction of vma. This destruction avoidance happens if vma is part of execbuffer relocation list or if vma is being considered for eviction in i915_gem_evict_something(). For those other users, mark the vma unbound so that the correct state of this vma is preserved. Reported-by: Chris Wilson Cc: Chris Wilson Cc: Daniel Vetter Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e8f6f4c0a2c6..c378f0421145 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3069,6 +3069,7 @@ int i915_vma_unbind(struct i915_vma *vma) trace_i915_vma_unbind(vma); vma->vm->unbind_vma(vma); + vma->bound = 0; list_del_init(&vma->mm_list); if (i915_is_ggtt(vma->vm)) { -- cgit v1.2.3 From 4dd738e9cd791ebac2a009f09f1761e85e7f0805 Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Thu, 30 Apr 2015 16:06:51 +0100 Subject: drm/i915: Fix 32b overflow check in gen8_ppgtt_alloc_page_directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch 69876bed7e008f5fe01538a2d47c09f2862129d0: "drm/i915/gen8: page directories rework allocation" added an overflow warning, but the mask had an extra 0. Use less typo-prone option suggested by Dave instead, to check for (start + length) >= 0x100000000ULL. This check will be unnecessary after gen8_alloc_va_range handles more than 4 PDPs (48b addressing). v2: Really check for 32b overflow (Ville) Reported-by: Dan Carpenter Cc: Dave Gordon Cc: Ville Syrjälä Signed-off-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ce91314f2c0c..8fee6789fae2 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -756,8 +756,8 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, WARN_ON(!bitmap_empty(new_pds, GEN8_LEGACY_PDPES)); - /* FIXME: PPGTT container_of won't work for 64b */ - WARN_ON((start + length) > 0x800000000ULL); + /* FIXME: upper bound must not overflow 32 bits */ + WARN_ON((start + length) >= (1ULL << 32)); gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) { if (pd) -- cgit v1.2.3 From aeaa2122af4e53f3bfd28e8f294557bb95af43fc Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Apr 2015 16:39:16 +0100 Subject: drm/i915/skl: Add the INIT power domain to the MISC I/O power well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index b393db78e5cb..64968d4ec62c 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -314,7 +314,8 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_MISC_IO_POWER_DOMAINS ( \ - SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS) + SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ + BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \ (POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ -- cgit v1.2.3 From 71cd8423cd874d18d9a454a39e2c4d9c9fb3fc69 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Apr 2015 16:39:17 +0100 Subject: drm/i915/skl: Fix the CTRL typo in the DPLL_CRTL1 defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_reg.h | 18 +++++++++--------- drivers/gpu/drm/i915/intel_ddi.c | 26 +++++++++++++------------- drivers/gpu/drm/i915/intel_display.c | 6 +++--- drivers/gpu/drm/i915/intel_dp.c | 12 ++++++------ 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 136d42a2ef44..51baca1e085b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -295,7 +295,7 @@ struct intel_dpll_hw_state { /* skl */ /* * DPLL_CTRL1 has 6 bits for each each this DPLL. We store those in - * lower part of crtl1 and they get shifted into position when writing + * lower part of ctrl1 and they get shifted into position when writing * the register. This allows us to easily compare the state to share * the DPLL. */ diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1d4871b8fdab..8924f4b68893 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7141,16 +7141,16 @@ enum skl_disp_power_wells { #define DPLL_CTRL1 0x6C058 #define DPLL_CTRL1_HDMI_MODE(id) (1<<((id)*6+5)) #define DPLL_CTRL1_SSC(id) (1<<((id)*6+4)) -#define DPLL_CRTL1_LINK_RATE_MASK(id) (7<<((id)*6+1)) -#define DPLL_CRTL1_LINK_RATE_SHIFT(id) ((id)*6+1) -#define DPLL_CRTL1_LINK_RATE(linkrate, id) ((linkrate)<<((id)*6+1)) +#define DPLL_CTRL1_LINK_RATE_MASK(id) (7<<((id)*6+1)) +#define DPLL_CTRL1_LINK_RATE_SHIFT(id) ((id)*6+1) +#define DPLL_CTRL1_LINK_RATE(linkrate, id) ((linkrate)<<((id)*6+1)) #define DPLL_CTRL1_OVERRIDE(id) (1<<((id)*6)) -#define DPLL_CRTL1_LINK_RATE_2700 0 -#define DPLL_CRTL1_LINK_RATE_1350 1 -#define DPLL_CRTL1_LINK_RATE_810 2 -#define DPLL_CRTL1_LINK_RATE_1620 3 -#define DPLL_CRTL1_LINK_RATE_1080 4 -#define DPLL_CRTL1_LINK_RATE_2160 5 +#define DPLL_CTRL1_LINK_RATE_2700 0 +#define DPLL_CTRL1_LINK_RATE_1350 1 +#define DPLL_CTRL1_LINK_RATE_810 2 +#define DPLL_CTRL1_LINK_RATE_1620 3 +#define DPLL_CTRL1_LINK_RATE_1080 4 +#define DPLL_CTRL1_LINK_RATE_2160 5 /* DPLL control2 */ #define DPLL_CTRL2 0x6C05C diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 9c1e74a3a277..d5bee8b8c15f 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -870,26 +870,26 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder, if (dpll_ctl1 & DPLL_CTRL1_HDMI_MODE(dpll)) { link_clock = skl_calc_wrpll_link(dev_priv, dpll); } else { - link_clock = dpll_ctl1 & DPLL_CRTL1_LINK_RATE_MASK(dpll); - link_clock >>= DPLL_CRTL1_LINK_RATE_SHIFT(dpll); + link_clock = dpll_ctl1 & DPLL_CTRL1_LINK_RATE_MASK(dpll); + link_clock >>= DPLL_CTRL1_LINK_RATE_SHIFT(dpll); switch (link_clock) { - case DPLL_CRTL1_LINK_RATE_810: + case DPLL_CTRL1_LINK_RATE_810: link_clock = 81000; break; - case DPLL_CRTL1_LINK_RATE_1080: + case DPLL_CTRL1_LINK_RATE_1080: link_clock = 108000; break; - case DPLL_CRTL1_LINK_RATE_1350: + case DPLL_CTRL1_LINK_RATE_1350: link_clock = 135000; break; - case DPLL_CRTL1_LINK_RATE_1620: + case DPLL_CTRL1_LINK_RATE_1620: link_clock = 162000; break; - case DPLL_CRTL1_LINK_RATE_2160: + case DPLL_CTRL1_LINK_RATE_2160: link_clock = 216000; break; - case DPLL_CRTL1_LINK_RATE_2700: + case DPLL_CTRL1_LINK_RATE_2700: link_clock = 270000; break; default: @@ -1294,13 +1294,13 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, switch (intel_dp->link_bw) { case DP_LINK_BW_1_62: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, 0); + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); break; case DP_LINK_BW_2_7: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, 0); + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); break; case DP_LINK_BW_5_4: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, 0); + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); break; } @@ -1854,7 +1854,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | - DPLL_CRTL1_LINK_RATE_MASK(dpll)); + DPLL_CTRL1_LINK_RATE_MASK(dpll)); val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6); I915_WRITE(DPLL_CTRL1, val); @@ -2100,7 +2100,7 @@ static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, val = I915_READ(DPLL_CTRL1); val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | - DPLL_CRTL1_LINK_RATE_MASK(dpll)); + DPLL_CTRL1_LINK_RATE_MASK(dpll)); val |= pll->config.hw_state.ctrl1 << (dpll * 6); I915_WRITE(DPLL_CTRL1, val); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index abbca0e76ccf..8e21e2358c0a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6467,10 +6467,10 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) return 540000; linkrate = (I915_READ(DPLL_CTRL1) & - DPLL_CRTL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1; + DPLL_CTRL1_LINK_RATE_MASK(SKL_DPLL0)) >> 1; - if (linkrate == DPLL_CRTL1_LINK_RATE_2160 || - linkrate == DPLL_CRTL1_LINK_RATE_1080) { + if (linkrate == DPLL_CTRL1_LINK_RATE_2160 || + linkrate == DPLL_CTRL1_LINK_RATE_1080) { /* vco 8640 */ switch (cdctl & CDCLK_FREQ_SEL_MASK) { case CDCLK_FREQ_450_432: diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7c3dbd465c78..5e978d69004c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1098,30 +1098,30 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0); switch (link_clock / 2) { case 81000: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_810, + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0); break; case 135000: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1350, + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, SKL_DPLL0); break; case 270000: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2700, + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, SKL_DPLL0); break; case 162000: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1620, + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, SKL_DPLL0); break; /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which results in CDCLK change. Need to handle the change of CDCLK by disabling pipes and re-enabling them */ case 108000: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_1080, + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, SKL_DPLL0); break; case 216000: - ctrl1 |= DPLL_CRTL1_LINK_RATE(DPLL_CRTL1_LINK_RATE_2160, + ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, SKL_DPLL0); break; -- cgit v1.2.3 From 9043ae020506808b3d2552eace047d3083688512 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Apr 2015 16:39:18 +0100 Subject: drm/i915: Re-order the PCU opcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's keep that list sorted! Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8924f4b68893..20ed82fa8fb6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6644,15 +6644,15 @@ enum skl_disp_power_wells { #define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_READY (1<<31) -#define GEN6_READ_OC_PARAMS 0xc -#define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 -#define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 #define GEN6_PCODE_WRITE_RC6VIDS 0x4 #define GEN6_PCODE_READ_RC6VIDS 0x5 +#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) +#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) +#define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 +#define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 +#define GEN6_READ_OC_PARAMS 0xc #define GEN6_PCODE_READ_D_COMP 0x10 #define GEN6_PCODE_WRITE_D_COMP 0x11 -#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) -#define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) #define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17 #define DISPLAY_IPS_CONTROL 0x19 #define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A -- cgit v1.2.3 From 57520bc55cf56b77e7a67cb0877fafdb65181f6a Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Apr 2015 16:39:19 +0100 Subject: drm/i915: Merge the GEN9 memory latency PCU opcode with its friends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 20ed82fa8fb6..ea5ca44766d0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6648,6 +6648,11 @@ enum skl_disp_power_wells { #define GEN6_PCODE_READ_RC6VIDS 0x5 #define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) #define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) +#define GEN9_PCODE_READ_MEM_LATENCY 0x6 +#define GEN9_MEM_LATENCY_LEVEL_MASK 0xFF +#define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8 +#define GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT 16 +#define GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT 24 #define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 #define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 #define GEN6_READ_OC_PARAMS 0xc @@ -6661,12 +6666,6 @@ enum skl_disp_power_wells { #define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 #define GEN6_PCODE_DATA1 0x13812C -#define GEN9_PCODE_READ_MEM_LATENCY 0x6 -#define GEN9_MEM_LATENCY_LEVEL_MASK 0xFF -#define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8 -#define GEN9_MEM_LATENCY_LEVEL_2_6_SHIFT 16 -#define GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT 24 - #define GEN6_GT_CORE_STATUS 0x138060 #define GEN6_CORE_CPD_STATE_MASK (7<<4) #define GEN6_RCn_MASK 7 -- cgit v1.2.3 From 6222709d60734dd1e11f8d24520d9f23b4eb953e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Apr 2015 16:39:20 +0100 Subject: drm/i915/skl: Make the Misc I/O power well part of the PLLS domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The specs tell us to ungate PG1 and Misc I/O at display init. We'll use the PLLS power domain to ensure those two power wells are up. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 64968d4ec62c..bd7ad1d2d5f5 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -315,6 +315,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_MISC_IO_POWER_DOMAINS ( \ SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ + BIT(POWER_DOMAIN_PLLS) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \ (POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ -- cgit v1.2.3 From d3902c3eba3666f001fa82fa16109aa4ab0074dc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 4 May 2015 17:20:49 +0300 Subject: drm/i915/audio: do not mess with audio registers if port is invalid We should no longer enter the codec enable/disable functions in question with port A anyway, but to err on the safe side, keep the warnings. Just bail out early without messing with the registers. Signed-off-by: Jani Nikula Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index f72e93a45e11..c4312177b0ee 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -269,6 +269,9 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); + if (WARN_ON(port == PORT_A)) + return; + if (HAS_PCH_IBX(dev_priv->dev)) { aud_config = IBX_AUD_CFG(pipe); aud_cntrl_st2 = IBX_AUD_CNTL_ST2; @@ -290,12 +293,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder) tmp |= AUD_CONFIG_N_VALUE_INDEX; I915_WRITE(aud_config, tmp); - if (WARN_ON(!port)) { - eldv = IBX_ELD_VALID(PORT_B) | IBX_ELD_VALID(PORT_C) | - IBX_ELD_VALID(PORT_D); - } else { - eldv = IBX_ELD_VALID(port); - } + eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ tmp = I915_READ(aud_cntrl_st2); @@ -325,6 +323,9 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, DRM_DEBUG_KMS("Enable audio codec on port %c, pipe %c, %u bytes ELD\n", port_name(port), pipe_name(pipe), drm_eld_size(eld)); + if (WARN_ON(port == PORT_A)) + return; + /* * FIXME: We're supposed to wait for vblank here, but we have vblanks * disabled during the mode set. The proper fix would be to push the @@ -349,12 +350,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, aud_cntrl_st2 = CPT_AUD_CNTRL_ST2; } - if (WARN_ON(!port)) { - eldv = IBX_ELD_VALID(PORT_B) | IBX_ELD_VALID(PORT_C) | - IBX_ELD_VALID(PORT_D); - } else { - eldv = IBX_ELD_VALID(port); - } + eldv = IBX_ELD_VALID(port); /* Invalidate ELD */ tmp = I915_READ(aud_cntrl_st2); -- cgit v1.2.3 From b3da4a627eb710254e09c6b8dbe94a4aa35382d2 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 4 May 2015 17:44:11 +0300 Subject: drm/i915: Free wa_batchbuffer when freeing error state wa_batchbuffer is part of some error states. Make sure it is freed. Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gpu_error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index ac22614dbb0e..a3e330d2a1d8 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -554,6 +554,7 @@ static void i915_error_state_free(struct kref *error_ref) for (i = 0; i < ARRAY_SIZE(error->ring); i++) { i915_error_object_free(error->ring[i].batchbuffer); + i915_error_object_free(error->ring[i].wa_batchbuffer); i915_error_object_free(error->ring[i].ringbuffer); i915_error_object_free(error->ring[i].hws_page); i915_error_object_free(error->ring[i].ctx); -- cgit v1.2.3 From 0fb890c01349c52b55b7adb4a18b362d141303d1 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Tue, 5 May 2015 14:51:56 +0530 Subject: drm/i915/bxt: BLC implementation Enabling BLC on BXT. Includes register definition, and new functions for BXT. In BXT, there are 2 sets of registers for BLC. Until there is clarity about which set would be effective, set 1 is being used. This would have to be re-visited if there is any change or when 2 LFPs are enabled on BXT. This patch enables brightness change which would be effected by use of hot-keys or sysfs entry. TODO:- BLC implementation will have to re-visited when 1. there is clarity about which set of registers has to be used and when. 2. CDCLK frequency is changed v2: Jani's review comments - Modified comment in i915_reg.h - Renamed register defintions - Removed definition of duty cycle max. Not required now and its not 64-bit. v3: - Rebase on top of VLV/CHV backlight changes, in particuliar bxt_set_backlight() now has a different prototype (Damien) Reviewed-by: Jani Nikula Signed-off-by: Vandana Kannan Signed-off-by: Damien Lespiau Cc: Jani Nikula Cc: Shankar, Uma Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 12 ++++++ drivers/gpu/drm/i915/intel_panel.c | 87 +++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ea5ca44766d0..9447b27703f4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3486,6 +3486,18 @@ enum skl_disp_power_wells { #define UTIL_PIN_CTL 0x48400 #define UTIL_PIN_ENABLE (1 << 31) +/* BXT backlight register definition. */ +#define BXT_BLC_PWM_CTL1 0xC8250 +#define BXT_BLC_PWM_ENABLE (1 << 31) +#define BXT_BLC_PWM_POLARITY (1 << 29) +#define BXT_BLC_PWM_FREQ1 0xC8254 +#define BXT_BLC_PWM_DUTY1 0xC8258 + +#define BXT_BLC_PWM_CTL2 0xC8350 +#define BXT_BLC_PWM_FREQ2 0xC8354 +#define BXT_BLC_PWM_DUTY2 0xC8358 + + #define PCH_GTC_CTL 0xe7000 #define PCH_GTC_ENABLE (1 << 31) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 08532d4ffe0a..7d83527f95f7 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -536,6 +536,14 @@ static u32 vlv_get_backlight(struct intel_connector *connector) return _vlv_get_backlight(dev, pipe); } +static u32 bxt_get_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(BXT_BLC_PWM_DUTY1); +} + static u32 intel_panel_get_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -616,6 +624,14 @@ static void vlv_set_backlight(struct intel_connector *connector, u32 level) I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level); } +static void bxt_set_backlight(struct intel_connector *connector, u32 level) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(BXT_BLC_PWM_DUTY1, level); +} + static void intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) { @@ -741,6 +757,18 @@ static void vlv_disable_backlight(struct intel_connector *connector) I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE); } +static void bxt_disable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 tmp; + + intel_panel_actually_set_backlight(connector, 0); + + tmp = I915_READ(BXT_BLC_PWM_CTL1); + I915_WRITE(BXT_BLC_PWM_CTL1, tmp & ~BXT_BLC_PWM_ENABLE); +} + void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -947,6 +975,33 @@ static void vlv_enable_backlight(struct intel_connector *connector) I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE); } +static void bxt_enable_backlight(struct intel_connector *connector) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 pwm_ctl; + + pwm_ctl = I915_READ(BXT_BLC_PWM_CTL1); + if (pwm_ctl & BXT_BLC_PWM_ENABLE) { + DRM_DEBUG_KMS("backlight already enabled\n"); + pwm_ctl &= ~BXT_BLC_PWM_ENABLE; + I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl); + } + + I915_WRITE(BXT_BLC_PWM_FREQ1, panel->backlight.max); + + intel_panel_actually_set_backlight(connector, panel->backlight.level); + + pwm_ctl = 0; + if (panel->backlight.active_low_pwm) + pwm_ctl |= BXT_BLC_PWM_POLARITY; + + I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl); + POSTING_READ(BXT_BLC_PWM_CTL1); + I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl | BXT_BLC_PWM_ENABLE); +} + void intel_panel_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1299,6 +1354,30 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe return 0; } +static int +bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) +{ + struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_panel *panel = &connector->panel; + u32 pwm_ctl, val; + + pwm_ctl = I915_READ(BXT_BLC_PWM_CTL1); + panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY; + + panel->backlight.max = I915_READ(BXT_BLC_PWM_FREQ1); + if (!panel->backlight.max) + return -ENODEV; + + val = bxt_get_backlight(connector); + panel->backlight.level = intel_panel_compute_brightness(connector, val); + + panel->backlight.enabled = (pwm_ctl & BXT_BLC_PWM_ENABLE) && + panel->backlight.level != 0; + + return 0; +} + int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) { struct drm_device *dev = connector->dev; @@ -1350,7 +1429,13 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_BROADWELL(dev) || (INTEL_INFO(dev)->gen >= 9)) { + if (IS_BROXTON(dev)) { + dev_priv->display.setup_backlight = bxt_setup_backlight; + dev_priv->display.enable_backlight = bxt_enable_backlight; + dev_priv->display.disable_backlight = bxt_disable_backlight; + dev_priv->display.set_backlight = bxt_set_backlight; + dev_priv->display.get_backlight = bxt_get_backlight; + } else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev)) { dev_priv->display.setup_backlight = bdw_setup_backlight; dev_priv->display.enable_backlight = bdw_enable_backlight; dev_priv->display.disable_backlight = pch_disable_backlight; -- cgit v1.2.3 From abab6311a5784a94a35beda54d4b25312cfc77f3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:17:32 +0300 Subject: drm/i915: Use POSTING_READ() in intel_sdvo_write_sdvox() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use POSTING_READ() in intel_sdvo_write_sdvox() as appropriate. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_sdvo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 10cd33252838..0a0625761f42 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -242,7 +242,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) if (intel_sdvo->sdvo_reg == PCH_SDVOB) { I915_WRITE(intel_sdvo->sdvo_reg, val); - I915_READ(intel_sdvo->sdvo_reg); + POSTING_READ(intel_sdvo->sdvo_reg); return; } @@ -259,9 +259,9 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) for (i = 0; i < 2; i++) { I915_WRITE(GEN3_SDVOB, bval); - I915_READ(GEN3_SDVOB); + POSTING_READ(GEN3_SDVOB); I915_WRITE(GEN3_SDVOC, cval); - I915_READ(GEN3_SDVOC); + POSTING_READ(GEN3_SDVOC); } } -- cgit v1.2.3 From 983b4b9def913991ef829ca635f1b3e7dd391c1b Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Fri, 10 Apr 2015 13:12:25 +0100 Subject: drm/i915/bxt: Add WaDisableSbeCacheDispatchPortSharing Note that we also need this for skl. Signed-off-by: Nick Hoath Reviewed-by: Imre Deak [danvet: Note that we also need this for skl, requested by Imre.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9447b27703f4..558d3dd5a039 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6738,6 +6738,7 @@ enum skl_disp_power_wells { #define GEN7_HALF_SLICE_CHICKEN1_GT2 0xf100 #define GEN7_MAX_PS_THREAD_DEP (8<<12) #define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1<<10) +#define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1<<4) #define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3) #define GEN9_HALF_SLICE_CHICKEN5 0xe188 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 98424e29917c..b0bd9bb6676e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1050,6 +1050,13 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE); + /* WaDisableSbeCacheDispatchPortSharing:bxt */ + if (INTEL_REVID(dev) <= BXT_REVID_B0) { + WA_SET_BIT_MASKED( + GEN7_HALF_SLICE_CHICKEN1, + GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); + } + return 0; } -- cgit v1.2.3 From 9e45803465417acfaaefc331d59dd7e6cf06110b Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Wed, 6 May 2015 17:35:48 +0530 Subject: drm/i915/skl: Add module parameter to select edp vswing table This provides an option to override the value set by VBT for selecting edp Vswing Pre-emph setting table. v2: Adding comment about this being a temporary workaround and making the parameter read-only (Jani) v3: Changing mode to 0400 instead of 0 (Jani) https://bugs.freedesktop.org/show_bug.cgi?id=89554 Signed-off-by: Sonika Jindal Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 +++- drivers/gpu/drm/i915/i915_params.c | 8 ++++++++ drivers/gpu/drm/i915/intel_bios.c | 9 +++++++-- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 51baca1e085b..8136005d2c6e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1364,7 +1364,6 @@ struct intel_vbt_data { bool edp_initialized; bool edp_support; int edp_bpp; - bool edp_low_vswing; struct edp_power_seq edp_pps; struct { @@ -1846,6 +1845,8 @@ struct drm_i915_private { void (*stop_ring)(struct intel_engine_cs *ring); } gt; + bool edp_low_vswing; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -2515,6 +2516,7 @@ struct i915_params { int mmio_debug; bool verbose_state_checks; bool nuclear_pageflip; + int edp_vswing; }; extern struct i915_params i915 __read_mostly; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index bb64415a1c3e..8ac5a1b29ac0 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -53,6 +53,7 @@ struct i915_params i915 __read_mostly = { .mmio_debug = 0, .verbose_state_checks = 1, .nuclear_pageflip = 0, + .edp_vswing = 0, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -184,3 +185,10 @@ MODULE_PARM_DESC(verbose_state_checks, module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600); MODULE_PARM_DESC(nuclear_pageflip, "Force atomic modeset functionality; only planes work for now (default: false)."); + +/* WA to get away with the default setting in VBT for early platforms.Will be removed */ +module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400); +MODULE_PARM_DESC(edp_vswing, + "Ignore/Override vswing pre-emph table selection from VBT " + "(0=use value from vbt [default], 1=low power swing(200mV)," + "2=default swing(400mV))"); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index c08368c03dad..cee596d0a6a2 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -672,8 +672,13 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) if (bdb->version >= 173) { uint8_t vswing; - vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; - dev_priv->vbt.edp_low_vswing = vswing == 0; + /* Don't read from VBT if module parameter has valid value*/ + if (i915.edp_vswing) { + dev_priv->edp_low_vswing = i915.edp_vswing == 1; + } else { + vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; + dev_priv->edp_low_vswing = vswing == 0; + } } } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index d5bee8b8c15f..b8eabc65dc27 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -282,7 +282,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, ddi_translations_fdi = NULL; ddi_translations_dp = skl_ddi_translations_dp; n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp); - if (dev_priv->vbt.edp_low_vswing) { + if (dev_priv->edp_low_vswing) { ddi_translations_edp = skl_ddi_translations_edp; n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp); } else { diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5e978d69004c..91c8bf3cf62b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2894,7 +2894,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp) if (IS_BROXTON(dev)) return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; else if (INTEL_INFO(dev)->gen >= 9) { - if (dev_priv->vbt.edp_low_vswing && port == PORT_A) + if (dev_priv->edp_low_vswing && port == PORT_A) return DP_TRAIN_VOLTAGE_SWING_LEVEL_3; return DP_TRAIN_VOLTAGE_SWING_LEVEL_2; } else if (IS_VALLEYVIEW(dev)) -- cgit v1.2.3 From 813b5e6971cbf1ae7dd0298fe44e39f7f2629f8d Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 25 Mar 2015 19:27:16 +0200 Subject: drm/i915: s/9/intel_freq_opcode(450)/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the hardcoded 9 with a call to intel_freq_opcode(450). Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8812fffeac5e..9e3bfff2d845 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4295,8 +4295,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) if (dev_priv->rps.min_freq_softlimit == 0) { if (IS_HASWELL(dev) || IS_BROADWELL(dev)) dev_priv->rps.min_freq_softlimit = - /* max(RPe, 450 MHz) */ - max(dev_priv->rps.efficient_freq, (u8) 9); + max_t(int, dev_priv->rps.efficient_freq, + intel_freq_opcode(dev_priv, 450)); else dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq; -- cgit v1.2.3 From 22e02c0b4bc87c94895b1f4cb25ee705d5687cb1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 6 May 2015 14:28:57 +0300 Subject: drm/i915: Add missing POSTING_READ()s to BXT dbuf enable sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do a POSTING_READ() between the DBUF_CTL register write and the udelay() to make sure we really wait after the register write has happened. Spotted while reviewing Damien's SKL cdclk patch which had the POSTING_READ()s. Cc: Imre Deak Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8e21e2358c0a..5c2047b6127b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5482,6 +5482,8 @@ void broxton_init_cdclk(struct drm_device *dev) broxton_set_cdclk(dev, 624000); I915_WRITE(DBUF_CTL, I915_READ(DBUF_CTL) | DBUF_POWER_REQUEST); + POSTING_READ(DBUF_CTL); + udelay(10); if (!(I915_READ(DBUF_CTL) & DBUF_POWER_STATE)) @@ -5493,6 +5495,8 @@ 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); + POSTING_READ(DBUF_CTL); + udelay(10); if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) -- cgit v1.2.3 From f1d3d34d1740e13f01411d85f53945596488d4c1 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Wed, 6 May 2015 14:36:27 +0100 Subject: drm/i915/skl: Fix WaDisableChickenBitTSGBarrierAckForFFSliceCS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Robert noticed that the FF_SLICE_CS_CHICKEN2 offset was wrong. Ooops. Ville noticed that the write was wrong since FF_SLICE_CS_CHICKEN2 is a masked register. Re-oops. A wonder if went through 2 people while having roughly a bug per line... The problem was introduced in the original patch: commit 2caa3b260aa6a3d015352c07d1bce1461825fa6c Author: Damien Lespiau Date: Mon Feb 9 19:33:20 2015 +0000 drm/i915/skl: Implement WaDisableChickenBitTSGBarrierAckForFFSliceCS v2: Also fix the register write (Ville) Reported-by: Robert Beckett Reported-by: Ville Syrjälä Cc: Robert Beckett Cc: Ville Syrjälä Cc: Nick Hoath Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 558d3dd5a039..60ef5406fe57 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5718,7 +5718,7 @@ enum skl_disp_power_wells { #define HSW_NDE_RSTWRN_OPT 0x46408 #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) -#define FF_SLICE_CS_CHICKEN2 0x02e4 +#define FF_SLICE_CS_CHICKEN2 0x20e4 #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) /* GEN7 chicken */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9e3bfff2d845..7006f94b94c1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -88,8 +88,7 @@ static void skl_init_clock_gating(struct drm_device *dev) /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */ I915_WRITE(FF_SLICE_CS_CHICKEN2, - I915_READ(FF_SLICE_CS_CHICKEN2) | - GEN9_TSG_BARRIER_ACK_DISABLE); + _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE)); } if (INTEL_REVID(dev) <= SKL_REVID_E0) -- cgit v1.2.3 From 83a24979c40ebbf0fa0cd14df16f74142f373cd3 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Fri, 10 Apr 2015 13:12:26 +0100 Subject: drm/i915/bxt: Add WaForceContextSaveRestoreNonCoherent Note that we also need this for skl. Signed-off-by: Nick Hoath Reviewed-by: Imre Deak [danvet: Note that we also need this for skl, requested by Imre.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b0bd9bb6676e..7ef9a29405cd 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1057,6 +1057,10 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring) GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); } + /* WaForceContextSaveRestoreNonCoherent:bxt */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT); + return 0; } -- cgit v1.2.3 From 6ba2bd3da7d3f9af3db83f704ca055943fd9ee40 Mon Sep 17 00:00:00 2001 From: Todd Previte Date: Tue, 21 Apr 2015 11:09:41 -0700 Subject: drm: Add edid_corrupt flag for Displayport Link CTS 4.2.2.6 Displayport compliance test 4.2.2.6 requires that a source device be capable of detecting a corrupt EDID. The test specification states that the sink device sets up the EDID with an invalid checksum. To do this, the sink sets up an invalid EDID header, expecting the source device to generate the checksum and compare it to the value stored in the last byte of the block data. Unfortunately, the DRM EDID reading and parsing functions are actually too good in this case; the header is fixed before the checksum is computed and thus the test never sees the invalid checksum. This results in a failure to pass the compliance test. To correct this issue, when the EDID code detects that the header is invalid, a flag is set to indicate that the EDID is corrupted. In this case, it sets edid_corrupt flag and continues with its fix-up code. This flag is also set in the case of a more seriously damaged header (fixup score less than the threshold). For consistency, the edid_corrupt flag is also set when the checksum is invalid as well. V2: - Removed the static bool global - Added a bool to the drm_connector struct to reaplce the static one for holding the status of raw edid header corruption detection - Modified the function signature of the is_valid function to take an additional parameter to store the corruption detected value - Fixed the other callers of the above is_valid function V3: - Updated the commit message to be more clear about what and why this patch does what it does. - Added comment in code to clarify the operations there - Removed compliance variable and check_link_status update; those have been moved to a later patch - Removed variable assignment from the bottom of the test handler V4: - Removed i915 tag from subject line as the patch is not i915-specific V5: - Moved code causing a compilation error to this patch where the variable is actually declared - Maintained blank lines / spacing so as to not contaminate the patch V6: - Removed extra debug messages - Added documentation to for the added parameter on drm_edid_block_valid - Fixed more whitespace issues in check_link_status - Added a clear of the header_corrupt flag to the end of the test handler in intel_dp.c - Changed the usage of the new function prototype in several places to use NULL where it is not needed by compliance testing V7: - Updated to account for long_pulse flag propagation V8: - Removed clearing of header_corrupt flag from the test handler in intel_dp.c - Added clearing of header_corrupt flag in the drm_edid_block_valid function V9: - Renamed header_corrupt flag to edid_corrupt to more accurately reflect its value and purpose - Updated commit message V10: - Updated for versioning and patch swizzle - Revised the title to more accurately reflect the nature and contents of the patch - Fixed formatting/whitespace problems - Added set flag when computed checksum is invalid Signed-off-by: Todd Previte Cc: dri-devel@lists.freedesktop.org Acked-by: Dave Airlie Reviewed-by: Alex Deucher Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 32 ++++++++++++++++++++++++++------ drivers/gpu/drm/drm_edid_load.c | 7 +++++-- include/drm/drm_crtc.h | 8 +++++++- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 53bc7a628909..be6713c2fc9d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1041,13 +1041,15 @@ static bool drm_edid_is_zero(const u8 *in_edid, int length) * @raw_edid: pointer to raw EDID block * @block: type of block to validate (0 for base, extension otherwise) * @print_bad_edid: if true, dump bad EDID blocks to the console + * @edid_corrupt: if true, the header or checksum is invalid * * Validate a base or extension EDID block and optionally dump bad blocks to * the console. * * Return: True if the block is valid, false otherwise. */ -bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) +bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, + bool *edid_corrupt) { u8 csum; struct edid *edid = (struct edid *)raw_edid; @@ -1060,11 +1062,22 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) if (block == 0) { int score = drm_edid_header_is_valid(raw_edid); - if (score == 8) ; - else if (score >= edid_fixup) { + if (score == 8) { + if (edid_corrupt) + *edid_corrupt = 0; + } else if (score >= edid_fixup) { + /* Displayport Link CTS Core 1.2 rev1.1 test 4.2.2.6 + * The corrupt flag needs to be set here otherwise, the + * fix-up code here will correct the problem, the + * checksum is correct and the test fails + */ + if (edid_corrupt) + *edid_corrupt = 1; DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); memcpy(raw_edid, edid_header, sizeof(edid_header)); } else { + if (edid_corrupt) + *edid_corrupt = 1; goto bad; } } @@ -1075,6 +1088,9 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid) DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); } + if (edid_corrupt) + *edid_corrupt = 1; + /* allow CEA to slide through, switches mangle this */ if (raw_edid[0] != 0x02) goto bad; @@ -1129,7 +1145,7 @@ bool drm_edid_is_valid(struct edid *edid) return false; for (i = 0; i <= edid->extensions; i++) - if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true)) + if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true, NULL)) return false; return true; @@ -1232,7 +1248,8 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, for (i = 0; i < 4; i++) { if (get_edid_block(data, block, 0, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block, 0, print_bad_edid)) + if (drm_edid_block_valid(block, 0, print_bad_edid, + &connector->edid_corrupt)) break; if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) { connector->null_edid_counter++; @@ -1257,7 +1274,10 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; - if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) { + if (drm_edid_block_valid(block + (valid_extensions + 1) + * EDID_LENGTH, j, + print_bad_edid, + NULL)) { valid_extensions++; break; } diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 4c0aa97aaf03..c5605fe4907e 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -216,7 +216,8 @@ static void *edid_load(struct drm_connector *connector, const char *name, goto out; } - if (!drm_edid_block_valid(edid, 0, print_bad_edid)) { + if (!drm_edid_block_valid(edid, 0, print_bad_edid, + &connector->edid_corrupt)) { connector->bad_edid_counter++; DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ", name); @@ -229,7 +230,9 @@ static void *edid_load(struct drm_connector *connector, const char *name, if (i != valid_extensions + 1) memcpy(edid + (valid_extensions + 1) * EDID_LENGTH, edid + i * EDID_LENGTH, EDID_LENGTH); - if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid)) + if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, + print_bad_edid, + NULL)) valid_extensions++; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index db9a30f10bc4..b9fcdc824997 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -719,6 +719,11 @@ struct drm_connector { int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ unsigned bad_edid_counter; + /* Flag for raw EDID header corruption - used in Displayport + * compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6 + */ + bool edid_corrupt; + struct dentry *debugfs_entry; struct drm_connector_state *state; @@ -1443,7 +1448,8 @@ extern void drm_set_preferred_mode(struct drm_connector *connector, int hpref, int vpref); extern int drm_edid_header_is_valid(const u8 *raw_edid); -extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); +extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, + bool *edid_corrupt); extern bool drm_edid_is_valid(struct edid *edid); extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev, -- cgit v1.2.3 From 559be30cb74d6a9f3345f78a0cf3a02a564d8eef Mon Sep 17 00:00:00 2001 From: Todd Previte Date: Mon, 4 May 2015 07:48:20 -0700 Subject: drm/i915: Implement the intel_dp_autotest_edid function for DP EDID complaince tests Updates the EDID compliance test function to perform the analyze and react to the EDID data read as a result of a hot plug event. The results of this analysis are handed off to userspace so that the userspace app can set the display mode appropriately for the test result/response. The compliance_test_active flag now appears at the end of the individual test handling functions. This is so that the kernel-side operations can be completed without the risk of interruption from the userspace app that is polling on that flag. V2: - Addressed mailing list feedback - Removed excess debug messages - Removed extraneous comments - Fixed formatting issues (line length > 80) - Updated the debug message in compute_edid_checksum to output hex values instead of decimal V3: - Addressed more list feedback - Added the test_active flag to the autotest function - Removed test_active flag from handler - Added failsafe check on the compliance test active flag at the end of the test handler - Fixed checkpatch.pl issues V4: - Removed the checksum computation function and its use as it has been rendered superfluous by changes to the core DRM EDID functions - Updated to use the raw header corruption detection mechanism - Moved the declaration of the test_data variable here V5: - Update test active flag variable name to match the change in the first patch of the series. - Relocated the test active flag declaration and initialization to this patch V6: - Updated to use the new flag for raw EDID header corruption - Removed the extra EDID read from the autotest function - Added the edid_checksum variable to struct intel_dp so that the autotest function can write it to the sink device - Moved the update to the hpd_pulse function to another patch - Removed extraneous constants V7: - Fixed erroneous placement of the checksum assignment. In some cases such as when the EDID read fails and is NULL, this causes a NULL ptr dereference in the kernel. Bad news. Fixed now. V8: - Updated to support the kfree() on the EDID data added previously V9: - Updated for the long_hpd flag propagation V10: - Updated to use actual checksum from the EDID read that occurs during normal hot plug path execution - Removed variables from intel_dp struct that are no longer needed - Updated the patch subject to more closely match the nature and contents of the patch - Fixed formatting problem (long line) V11: - Removed extra debug messages - Updated comments to be more informative - Removed extra variable V12: - Removed the 4 bit offset of the resolution setting in compliance data - Changed to DRM_DEBUG_KMS instead of DRM_DEBUG_DRIVER Signed-off-by: Todd Previte Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 42 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ 2 files changed, 44 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 91c8bf3cf62b..d0a88602efab 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -41,6 +41,12 @@ #define DP_LINK_CHECK_TIMEOUT (10 * 1000) +/* Compliance test status bits */ +#define INTEL_DP_RESOLUTION_SHIFT_MASK 0 +#define INTEL_DP_RESOLUTION_PREFERRED (1 << INTEL_DP_RESOLUTION_SHIFT_MASK) +#define INTEL_DP_RESOLUTION_STANDARD (2 << INTEL_DP_RESOLUTION_SHIFT_MASK) +#define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK) + struct dp_link_dpll { int link_bw; struct dpll dpll; @@ -4079,6 +4085,39 @@ static uint8_t intel_dp_autotest_video_pattern(struct intel_dp *intel_dp) static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp) { uint8_t test_result = DP_TEST_NAK; + struct intel_connector *intel_connector = intel_dp->attached_connector; + struct drm_connector *connector = &intel_connector->base; + + if (intel_connector->detect_edid == NULL || + connector->edid_corrupt == 1 || + intel_dp->aux.i2c_defer_count > 6) { + /* Check EDID read for NACKs, DEFERs and corruption + * (DP CTS 1.2 Core r1.1) + * 4.2.2.4 : Failed EDID read, I2C_NAK + * 4.2.2.5 : Failed EDID read, I2C_DEFER + * 4.2.2.6 : EDID corruption detected + * Use failsafe mode for all cases + */ + if (intel_dp->aux.i2c_nack_count > 0 || + intel_dp->aux.i2c_defer_count > 0) + DRM_DEBUG_KMS("EDID read had %d NACKs, %d DEFERs\n", + intel_dp->aux.i2c_nack_count, + intel_dp->aux.i2c_defer_count); + intel_dp->compliance_test_data = INTEL_DP_RESOLUTION_FAILSAFE; + } else { + if (!drm_dp_dpcd_write(&intel_dp->aux, + DP_TEST_EDID_CHECKSUM, + &intel_connector->detect_edid->checksum, + 1)); + DRM_DEBUG_KMS("Failed to write EDID checksum\n"); + + test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE; + intel_dp->compliance_test_data = INTEL_DP_RESOLUTION_STANDARD; + } + + /* Set test active flag here so userspace doesn't interrupt things */ + intel_dp->compliance_test_active = 1; + return test_result; } @@ -4094,7 +4133,10 @@ static void intel_dp_handle_test_request(struct intel_dp *intel_dp) uint8_t rxdata = 0; int status = 0; + intel_dp->compliance_test_active = 0; intel_dp->compliance_test_type = 0; + intel_dp->compliance_test_data = 0; + intel_dp->aux.i2c_nack_count = 0; intel_dp->aux.i2c_defer_count = 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cf701ed26478..da553af78a65 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -740,6 +740,8 @@ struct intel_dp { /* Displayport compliance testing */ unsigned long compliance_test_type; + unsigned long compliance_test_data; + bool compliance_test_active; }; struct intel_digital_port { -- cgit v1.2.3 From eb3394faeb97d981fae1fab50fd0b49997643d10 Mon Sep 17 00:00:00 2001 From: Todd Previte Date: Sat, 18 Apr 2015 00:04:19 -0700 Subject: drm/i915: Add debugfs test control files for Displayport compliance testing This patch adds 3 debugfs files for handling Displayport compliance testing and supercedes the previous patches that implemented debugfs support for compliance testing. Those patches were: - [PATCH 04/17] drm/i915: Add debugfs functions for Displayport compliance testing - [PATCH 08/17] drm/i915: Add new debugfs file for Displayport compliance test control - [PATCH 09/17] drm/i915: Add debugfs write and test param parsing functions for DP test control This new patch simplifies the debugfs implementation by places a single test control value into an individual file. Each file is readable by the usersapce application and the test_active file is writable to indicate to the kernel when userspace has completed its portion of the test sequence. Replacing the previous files simplifies operation and speeds response time for the user app, as it is required to poll on the test_active file in order to determine when it needs to begin its operations. V2: - Updated the test active variable name to match the change in the initial patch of the series V3: - Added a fix in the test_active_write function to prevent a NULL pointer dereference if the encoder on the connector is invalid Signed-off-by: Todd Previte Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 209 ++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 9e5a56cff2f3..1afbce2c591e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3951,6 +3951,212 @@ static const struct file_operations i915_display_crc_ctl_fops = { .write = display_crc_ctl_write }; +static ssize_t i915_displayport_test_active_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + char *input_buffer; + int status = 0; + struct seq_file *m; + struct drm_device *dev; + struct drm_connector *connector; + struct list_head *connector_list; + struct intel_dp *intel_dp; + int val = 0; + + m = file->private_data; + if (!m) { + status = -ENODEV; + return status; + } + dev = m->private; + + if (!dev) { + status = -ENODEV; + return status; + } + connector_list = &dev->mode_config.connector_list; + + if (len == 0) + return 0; + + input_buffer = kmalloc(len + 1, GFP_KERNEL); + if (!input_buffer) + return -ENOMEM; + + if (copy_from_user(input_buffer, ubuf, len)) { + status = -EFAULT; + goto out; + } + + input_buffer[len] = '\0'; + DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len); + + list_for_each_entry(connector, connector_list, head) { + + if (connector->connector_type != + DRM_MODE_CONNECTOR_DisplayPort) + continue; + + if (connector->connector_type == + DRM_MODE_CONNECTOR_DisplayPort && + connector->status == connector_status_connected && + connector->encoder != NULL) { + intel_dp = enc_to_intel_dp(connector->encoder); + status = kstrtoint(input_buffer, 10, &val); + if (status < 0) + goto out; + DRM_DEBUG_DRIVER("Got %d for test active\n", val); + /* To prevent erroneous activation of the compliance + * testing code, only accept an actual value of 1 here + */ + if (val == 1) + intel_dp->compliance_test_active = 1; + else + intel_dp->compliance_test_active = 0; + } + } +out: + kfree(input_buffer); + if (status < 0) + return status; + + *offp += len; + return len; +} + +static int i915_displayport_test_active_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + struct drm_connector *connector; + struct list_head *connector_list = &dev->mode_config.connector_list; + struct intel_dp *intel_dp; + + if (!dev) + return -ENODEV; + + list_for_each_entry(connector, connector_list, head) { + + if (connector->connector_type != + DRM_MODE_CONNECTOR_DisplayPort) + continue; + + if (connector->status == connector_status_connected && + connector->encoder != NULL) { + intel_dp = enc_to_intel_dp(connector->encoder); + if (intel_dp->compliance_test_active) + seq_puts(m, "1"); + else + seq_puts(m, "0"); + } else + seq_puts(m, "0"); + } + + return 0; +} + +static int i915_displayport_test_active_open(struct inode *inode, + struct file *file) +{ + struct drm_device *dev = inode->i_private; + + return single_open(file, i915_displayport_test_active_show, dev); +} + +static const struct file_operations i915_displayport_test_active_fops = { + .owner = THIS_MODULE, + .open = i915_displayport_test_active_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = i915_displayport_test_active_write +}; + +static int i915_displayport_test_data_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + struct drm_connector *connector; + struct list_head *connector_list = &dev->mode_config.connector_list; + struct intel_dp *intel_dp; + + if (!dev) + return -ENODEV; + + list_for_each_entry(connector, connector_list, head) { + + if (connector->connector_type != + DRM_MODE_CONNECTOR_DisplayPort) + continue; + + if (connector->status == connector_status_connected && + connector->encoder != NULL) { + intel_dp = enc_to_intel_dp(connector->encoder); + seq_printf(m, "%lx", intel_dp->compliance_test_data); + } else + seq_puts(m, "0"); + } + + return 0; +} +static int i915_displayport_test_data_open(struct inode *inode, + struct file *file) +{ + struct drm_device *dev = inode->i_private; + + return single_open(file, i915_displayport_test_data_show, dev); +} + +static const struct file_operations i915_displayport_test_data_fops = { + .owner = THIS_MODULE, + .open = i915_displayport_test_data_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +static int i915_displayport_test_type_show(struct seq_file *m, void *data) +{ + struct drm_device *dev = m->private; + struct drm_connector *connector; + struct list_head *connector_list = &dev->mode_config.connector_list; + struct intel_dp *intel_dp; + + if (!dev) + return -ENODEV; + + list_for_each_entry(connector, connector_list, head) { + + if (connector->connector_type != + DRM_MODE_CONNECTOR_DisplayPort) + continue; + + if (connector->status == connector_status_connected && + connector->encoder != NULL) { + intel_dp = enc_to_intel_dp(connector->encoder); + seq_printf(m, "%02lx", intel_dp->compliance_test_type); + } else + seq_puts(m, "0"); + } + + return 0; +} + +static int i915_displayport_test_type_open(struct inode *inode, + struct file *file) +{ + struct drm_device *dev = inode->i_private; + + return single_open(file, i915_displayport_test_type_show, dev); +} + +static const struct file_operations i915_displayport_test_type_fops = { + .owner = THIS_MODULE, + .open = i915_displayport_test_type_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) { struct drm_device *dev = m->private; @@ -4846,6 +5052,9 @@ static const struct i915_debugfs_files { {"i915_spr_wm_latency", &i915_spr_wm_latency_fops}, {"i915_cur_wm_latency", &i915_cur_wm_latency_fops}, {"i915_fbc_false_color", &i915_fbc_fc_fops}, + {"i915_dp_test_data", &i915_displayport_test_data_fops}, + {"i915_dp_test_type", &i915_displayport_test_type_fops}, + {"i915_dp_test_active", &i915_displayport_test_active_fops} }; void intel_display_crc_init(struct drm_device *dev) -- cgit v1.2.3 From ecce87ea3ab55ad0dc64460e6422c357d158a55e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:50 +0300 Subject: drm/i915: Remove implicitly disabling primary plane for now Some of the flags that were used are still useful when transitioning to atomic, so keep those around for now. This removes some of the complications of crtc->primary_enabled, making it easier to remove. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 6 ----- drivers/gpu/drm/i915/intel_sprite.c | 45 +------------------------------------ 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index da553af78a65..ade8384a52b4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -248,12 +248,6 @@ struct intel_plane_state { struct drm_rect clip; bool visible; - /* - * used only for sprite planes to determine when to implicitly - * enable/disable the primary plane - */ - bool hides_primary; - /* * scaler_id * = -1 : not using a scaler diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 856395bbcc4e..be5527245bfc 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -166,17 +166,6 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) pipe_name(pipe), start_vbl_count, end_vbl_count); } -static void intel_update_primary_plane(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - int reg = DSPCNTR(crtc->plane); - - if (crtc->primary_enabled) - I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE); - else - I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE); -} - static void skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, @@ -438,8 +427,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } - intel_update_primary_plane(intel_crtc); - if (key->flags) { I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value); I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value); @@ -480,8 +467,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) int pipe = intel_plane->pipe; int plane = intel_plane->plane; - intel_update_primary_plane(intel_crtc); - I915_WRITE(SPCNTR(pipe, plane), 0); /* Activate double buffered register update */ @@ -585,8 +570,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } } - intel_update_primary_plane(intel_crtc); - if (key->flags) { I915_WRITE(SPRKEYVAL(pipe), key->min_value); I915_WRITE(SPRKEYMAX(pipe), key->max_value); @@ -629,8 +612,6 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; - intel_update_primary_plane(intel_crtc); - I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ if (intel_plane->can_scale) @@ -725,8 +706,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset += src_h * fb->pitches[0] + src_w * pixel_size; } - intel_update_primary_plane(intel_crtc); - if (key->flags) { I915_WRITE(DVSKEYVAL(pipe), key->min_value); I915_WRITE(DVSKEYMAX(pipe), key->max_value); @@ -764,8 +743,6 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_plane->pipe; - intel_update_primary_plane(intel_crtc); - I915_WRITE(DVSCNTR(pipe), 0); /* Disable the scaler */ I915_WRITE(DVSSCALE(pipe), 0); @@ -818,7 +795,7 @@ intel_post_enable_primary(struct drm_crtc *crtc) * @crtc: the CRTC whose primary plane is to be disabled * * Performs potentially sleeping operations that must be done before the - * primary plane is enabled, such as updating FBC and IPS. Note that this may + * primary plane is disabled, such as updating FBC and IPS. Note that this may * be called due to an explicit primary plane update, or due to an implicit * disable that is caused when a sprite plane completely hides the primary * plane. @@ -844,11 +821,6 @@ intel_pre_disable_primary(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); } -static bool colorkey_enabled(struct intel_plane *intel_plane) -{ - return intel_plane->ckey.flags != I915_SET_COLORKEY_NONE; -} - static int intel_check_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -1022,23 +994,10 @@ finish: * If the sprite is completely covering the primary plane, * we can disable the primary and save power. */ - state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) && - !colorkey_enabled(intel_plane); - WARN_ON(state->hides_primary && !state->visible && intel_crtc->active); - if (intel_crtc->active) { - if (intel_crtc->primary_enabled == state->hides_primary) - intel_crtc->atomic.wait_for_flips = true; - - if (intel_crtc->primary_enabled && state->hides_primary) - intel_crtc->atomic.pre_disable_primary = true; - intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - if (!intel_crtc->primary_enabled && !state->hides_primary) - intel_crtc->atomic.post_enable_primary = true; - if (intel_wm_need_update(plane, &state->base)) intel_crtc->atomic.update_wm = true; @@ -1081,8 +1040,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, plane->fb = fb; if (intel_crtc->active) { - intel_crtc->primary_enabled = !state->hides_primary; - if (state->visible) { crtc_x = state->dst.x1; crtc_y = state->dst.y1; -- cgit v1.2.3 From a8ad0d8e179945a7c714fce834207e39d2957d9f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:51 +0300 Subject: drm/i915: Add a way to disable planes without updating state This is used by the next commit to disable all planes on a crtc without caring what type it is. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 38 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 16 +++++++-------- 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5c2047b6127b..7c0beef7f3ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2694,7 +2694,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, u32 reg = DSPCNTR(plane); int pixel_size; - if (!intel_crtc->primary_enabled) { + if (!intel_crtc->primary_enabled || !fb) { I915_WRITE(reg, 0); if (INTEL_INFO(dev)->gen >= 4) I915_WRITE(DSPSURF(plane), 0); @@ -2823,7 +2823,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, u32 reg = DSPCNTR(plane); int pixel_size; - if (!intel_crtc->primary_enabled) { + if (!intel_crtc->primary_enabled || !fb) { I915_WRITE(reg, 0); I915_WRITE(DSPSURF(plane), 0); POSTING_READ(reg); @@ -3102,7 +3102,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, plane = crtc->primary; plane_state = to_intel_plane_state(plane->state); - if (!intel_crtc->primary_enabled) { + if (!intel_crtc->primary_enabled || !fb) { I915_WRITE(PLANE_CTL(pipe, 0), 0); I915_WRITE(PLANE_SURF(pipe, 0), 0); POSTING_READ(PLANE_CTL(pipe, 0)); @@ -13378,6 +13378,20 @@ intel_commit_primary_plane(struct drm_plane *plane, } } +static void +intel_disable_primary_plane(struct drm_plane *plane, + struct drm_crtc *crtc, + bool force) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!force) + to_intel_crtc(crtc)->primary_enabled = false; + + dev_priv->display.update_primary_plane(crtc, NULL, 0, 0); +} + static void intel_begin_crtc_commit(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -13522,6 +13536,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->plane = pipe; primary->check_plane = intel_check_primary_plane; primary->commit_plane = intel_commit_primary_plane; + primary->disable_plane = intel_disable_primary_plane; primary->ckey.flags = I915_SET_COLORKEY_NONE; if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) primary->plane = !pipe; @@ -13626,6 +13641,22 @@ finish: return ret; } +static void +intel_disable_cursor_plane(struct drm_plane *plane, + struct drm_crtc *crtc, + bool force) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + if (!force) { + plane->fb = NULL; + intel_crtc->cursor_bo = NULL; + intel_crtc->cursor_addr = 0; + } + + intel_crtc_update_cursor(crtc, false); +} + static void intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) @@ -13685,6 +13716,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, state->scaler_id = -1; cursor->check_plane = intel_check_cursor_plane; cursor->commit_plane = intel_commit_cursor_plane; + cursor->disable_plane = intel_disable_cursor_plane; drm_universal_plane_init(dev, &cursor->base, 0, &intel_plane_funcs, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ade8384a52b4..9d69d7cfd17a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -594,7 +594,7 @@ struct intel_plane { uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h); void (*disable_plane)(struct drm_plane *plane, - struct drm_crtc *crtc); + struct drm_crtc *crtc, bool force); int (*check_plane)(struct drm_plane *plane, struct intel_plane_state *state); void (*commit_plane)(struct drm_plane *plane, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index be5527245bfc..95602da15984 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -272,11 +272,11 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, } static void -skl_disable_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc) +skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc, bool force) { - struct drm_device *dev = drm_plane->dev; + struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_plane *intel_plane = to_intel_plane(drm_plane); + struct intel_plane *intel_plane = to_intel_plane(dplane); const int pipe = intel_plane->pipe; const int plane = intel_plane->plane + 1; @@ -286,7 +286,7 @@ skl_disable_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc) I915_WRITE(PLANE_SURF(pipe, plane), 0); POSTING_READ(PLANE_SURF(pipe, plane)); - intel_update_sprite_watermarks(drm_plane, crtc, 0, 0, 0, false, false); + intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } static void @@ -458,7 +458,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, } static void -vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) +vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc, bool force) { struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -604,7 +604,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static void -ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) +ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -735,7 +735,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static void -ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) +ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1053,7 +1053,7 @@ intel_commit_sprite_plane(struct drm_plane *plane, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h); } else { - intel_plane->disable_plane(plane, crtc); + intel_plane->disable_plane(plane, crtc, false); } } } -- cgit v1.2.3 From 27321ae88c70104df1ade701e079932b54360885 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:52 +0300 Subject: drm/i915: Use the disable callback for disabling planes. This allows disabling all planes affecting a crtc without caring what type it is. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 ++ drivers/gpu/drm/i915/intel_display.c | 91 ++++++------------------------------ 2 files changed, 20 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8136005d2c6e..87fe4f7d5ce5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -238,6 +238,11 @@ enum hpd_pin { #define for_each_crtc(dev, crtc) \ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) +#define for_each_intel_plane(dev, intel_plane) \ + list_for_each_entry(intel_plane, \ + &dev->mode_config.plane_list, \ + base.head) + #define for_each_intel_crtc(dev, intel_crtc) \ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7c0beef7f3ef..a08cb14f076c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2254,32 +2254,6 @@ static void intel_enable_primary_hw_plane(struct drm_plane *plane, intel_wait_for_vblank(dev, intel_crtc->pipe); } -/** - * intel_disable_primary_hw_plane - disable the primary hardware plane - * @plane: plane to be disabled - * @crtc: crtc for the plane - * - * Disable @plane on @crtc, making sure that the pipe is running first. - */ -static void intel_disable_primary_hw_plane(struct drm_plane *plane, - struct drm_crtc *crtc) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - if (WARN_ON(!intel_crtc->active)) - return; - - if (!intel_crtc->primary_enabled) - return; - - intel_crtc->primary_enabled = false; - - dev_priv->display.update_primary_plane(crtc, plane->fb, - crtc->x, crtc->y); -} - static bool need_vtd_wa(struct drm_device *dev) { #ifdef CONFIG_INTEL_IOMMU @@ -4645,38 +4619,6 @@ static void intel_enable_sprite_planes(struct drm_crtc *crtc) } } -/* - * Disable a plane internally without actually modifying the plane's state. - * This will allow us to easily restore the plane later by just reprogramming - * its state. - */ -static void disable_plane_internal(struct drm_plane *plane) -{ - struct intel_plane *intel_plane = to_intel_plane(plane); - struct drm_plane_state *state = - plane->funcs->atomic_duplicate_state(plane); - struct intel_plane_state *intel_state = to_intel_plane_state(state); - - intel_state->visible = false; - intel_plane->commit_plane(plane, intel_state); - - intel_plane_destroy_state(plane, state); -} - -static void intel_disable_sprite_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - enum pipe pipe = to_intel_crtc(crtc)->pipe; - struct drm_plane *plane; - struct intel_plane *intel_plane; - - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { - intel_plane = to_intel_plane(plane); - if (plane->fb && intel_plane->pipe == pipe) - disable_plane_internal(plane); - } -} - void hsw_enable_ips(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -4830,6 +4772,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane; int pipe = intel_crtc->pipe; intel_crtc_wait_for_pending_flips(crtc); @@ -4840,9 +4783,15 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); intel_crtc_dpms_overlay(intel_crtc, false); - intel_crtc_update_cursor(crtc, false); - intel_disable_sprite_planes(crtc); - intel_disable_primary_hw_plane(crtc->primary, crtc); + intel_crtc->primary_enabled = false; + for_each_intel_plane(dev, intel_plane) { + if (intel_plane->pipe == pipe) { + struct drm_crtc *from = intel_plane->base.crtc; + + intel_plane->disable_plane(&intel_plane->base, + from ?: crtc, true); + } + } /* * FIXME: Once we grow proper nuclear flip support out of this we need @@ -13357,24 +13306,14 @@ intel_commit_primary_plane(struct drm_plane *plane, crtc->y = src->y1 >> 16; if (intel_crtc->active) { - if (state->visible) { + intel_crtc->primary_enabled = state->visible; + + if (state->visible) /* FIXME: kill this fastboot hack */ intel_update_pipe_size(intel_crtc); - intel_crtc->primary_enabled = true; - - dev_priv->display.update_primary_plane(crtc, plane->fb, - crtc->x, crtc->y); - } else { - /* - * If clipping results in a non-visible primary plane, - * we'll disable the primary plane. Note that this is - * a bit different than what happens if userspace - * explicitly disables the plane by passing fb=0 - * because plane->fb still gets set and pinned. - */ - intel_disable_primary_hw_plane(plane, crtc); - } + dev_priv->display.update_primary_plane(crtc, plane->fb, + crtc->x, crtc->y); } } -- cgit v1.2.3 From b70709a6f0e9176c2bc7ecf44acf015c7362ddc6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:53 +0300 Subject: drm/i915: get rid of primary_enabled and use atomic state This was an optimization from way back before we had primary plane support to be able to disable the primary plane. But with primary plane support userspace can tell the kernel this directly, so there's no big need for this any more. And it's getting in the way of the atomic conversion. If need be we can resurrect this later on properly again. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira [danvet: Explain why removing this is ok.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 50 ++++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_fbc.c | 2 +- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a08cb14f076c..a912934e65a2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2236,11 +2236,7 @@ static void intel_enable_primary_hw_plane(struct drm_plane *plane, /* If the pipe isn't enabled, we can't pump pixels and may hang */ assert_pipe_enabled(dev_priv, intel_crtc->pipe); - - if (intel_crtc->primary_enabled) - return; - - intel_crtc->primary_enabled = true; + to_intel_plane_state(plane->state)->visible = true; dev_priv->display.update_primary_plane(crtc, plane->fb, crtc->x, crtc->y); @@ -2661,6 +2657,8 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *primary = crtc->primary; + bool visible = to_intel_plane_state(primary->state)->visible; struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned long linear_offset; @@ -2668,7 +2666,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, u32 reg = DSPCNTR(plane); int pixel_size; - if (!intel_crtc->primary_enabled || !fb) { + if (!visible || !fb) { I915_WRITE(reg, 0); if (INTEL_INFO(dev)->gen >= 4) I915_WRITE(DSPSURF(plane), 0); @@ -2790,6 +2788,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *primary = crtc->primary; + bool visible = to_intel_plane_state(primary->state)->visible; struct drm_i915_gem_object *obj; int plane = intel_crtc->plane; unsigned long linear_offset; @@ -2797,7 +2797,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, u32 reg = DSPCNTR(plane); int pixel_size; - if (!intel_crtc->primary_enabled || !fb) { + if (!visible || !fb) { I915_WRITE(reg, 0); I915_WRITE(DSPSURF(plane), 0); POSTING_READ(reg); @@ -3059,6 +3059,8 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *plane = crtc->primary; + bool visible = to_intel_plane_state(plane->state)->visible; struct drm_i915_gem_object *obj; int pipe = intel_crtc->pipe; u32 plane_ctl, stride_div, stride; @@ -3066,17 +3068,15 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, unsigned int rotation; int x_offset, y_offset; unsigned long surf_addr; - struct drm_plane *plane; struct intel_crtc_state *crtc_state = intel_crtc->config; struct intel_plane_state *plane_state; int src_x = 0, src_y = 0, src_w = 0, src_h = 0; int dst_x = 0, dst_y = 0, dst_w = 0, dst_h = 0; int scaler_id = -1; - plane = crtc->primary; plane_state = to_intel_plane_state(plane->state); - if (!intel_crtc->primary_enabled || !fb) { + if (!visible || !fb) { I915_WRITE(PLANE_CTL(pipe, 0), 0); I915_WRITE(PLANE_SURF(pipe, 0), 0); POSTING_READ(PLANE_CTL(pipe, 0)); @@ -4783,7 +4783,6 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); intel_crtc_dpms_overlay(intel_crtc, false); - intel_crtc->primary_enabled = false; for_each_intel_plane(dev, intel_plane) { if (intel_plane->pipe == pipe) { struct drm_crtc *from = intel_plane->base.crtc; @@ -12891,6 +12890,9 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } else if (config->fb_changed) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); struct drm_plane *primary = set->crtc->primary; + struct intel_plane_state *plane_state = + to_intel_plane_state(primary->state); + bool was_visible = plane_state->visible; int vdisplay, hdisplay; drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay); @@ -12903,7 +12905,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) * We need to make sure the primary plane is re-enabled if it * has previously been turned off. */ - if (!intel_crtc->primary_enabled && ret == 0) { + plane_state = to_intel_plane_state(primary->state); + if (ret == 0 && !was_visible && plane_state->visible) { WARN_ON(!intel_crtc->active); intel_enable_primary_hw_plane(set->crtc->primary, set->crtc); } @@ -13239,6 +13242,9 @@ intel_check_primary_plane(struct drm_plane *plane, return ret; if (intel_crtc->active) { + struct intel_plane_state *old_state = + to_intel_plane_state(plane->state); + intel_crtc->atomic.wait_for_flips = true; /* @@ -13251,20 +13257,20 @@ intel_check_primary_plane(struct drm_plane *plane, * one is done too late. We eventually need to unify * this. */ - if (intel_crtc->primary_enabled && + if (state->visible && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && dev_priv->fbc.crtc == intel_crtc && state->base.rotation != BIT(DRM_ROTATE_0)) { intel_crtc->atomic.disable_fbc = true; } - if (state->visible) { + if (state->visible && !old_state->visible) { /* * BDW signals flip done immediately if the plane * is disabled, even if the plane enable is already * armed to occur at the next vblank :( */ - if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled) + if (IS_BROADWELL(dev)) intel_crtc->atomic.wait_vblank = true; } @@ -13306,8 +13312,6 @@ intel_commit_primary_plane(struct drm_plane *plane, crtc->y = src->y1 >> 16; if (intel_crtc->active) { - intel_crtc->primary_enabled = state->visible; - if (state->visible) /* FIXME: kill this fastboot hack */ intel_update_pipe_size(intel_crtc); @@ -13325,9 +13329,6 @@ intel_disable_primary_plane(struct drm_plane *plane, struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!force) - to_intel_crtc(crtc)->primary_enabled = false; - dev_priv->display.update_primary_plane(crtc, NULL, 0, 0); } @@ -14791,8 +14792,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * Temporarily change the plane mapping and disable everything * ... */ plane = crtc->plane; + to_intel_plane_state(crtc->base.primary->state)->visible = true; crtc->plane = !plane; - crtc->primary_enabled = true; dev_priv->display.crtc_disable(&crtc->base); crtc->plane = plane; @@ -14969,6 +14970,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) int i; for_each_intel_crtc(dev, crtc) { + struct drm_plane *primary = crtc->base.primary; + struct intel_plane_state *plane_state; + memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; @@ -14978,7 +14982,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.state->enable = crtc->active; crtc->base.enabled = crtc->active; - crtc->primary_enabled = primary_get_hw_state(crtc); + + plane_state = to_intel_plane_state(primary->state); + plane_state->visible = primary_get_hw_state(crtc); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9d69d7cfd17a..52673c74855b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -507,7 +507,6 @@ struct intel_crtc { */ bool active; unsigned long enabled_power_domains; - bool primary_enabled; /* is the primary plane (partially) visible? */ bool lowfreq_avail; struct intel_overlay *overlay; struct intel_unpin_work *unpin_work; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 4165ce0644f7..6abb83432d4d 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -457,7 +457,7 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe]; if (intel_crtc_active(tmp_crtc) && - to_intel_crtc(tmp_crtc)->primary_enabled) { + to_intel_plane_state(tmp_crtc->primary->state)->visible) { if (one_pipe_only && crtc) { if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES)) DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); -- cgit v1.2.3 From 87d4300a7dbc19634018e147b4753f3c9bb5f471 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:54 +0300 Subject: drm/i915: Move intel_(pre_disable/post_enable)_primary to intel_display.c, and use it there. They're the same code, so why not? Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 158 ++++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 2 - drivers/gpu/drm/i915/intel_sprite.c | 68 --------------- 3 files changed, 102 insertions(+), 126 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a912934e65a2..cb0c025427b7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2240,14 +2240,6 @@ static void intel_enable_primary_hw_plane(struct drm_plane *plane, dev_priv->display.update_primary_plane(crtc, plane->fb, crtc->x, crtc->y); - - /* - * BDW signals flip done immediately if the plane - * is disabled, even if the plane enable is already - * armed to occur at the next vblank :( - */ - if (IS_BROADWELL(dev)) - intel_wait_for_vblank(dev, intel_crtc->pipe); } static bool need_vtd_wa(struct drm_device *dev) @@ -4742,17 +4734,38 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) */ } -static void intel_crtc_enable_planes(struct drm_crtc *crtc) +/** + * intel_post_enable_primary - Perform operations after enabling primary plane + * @crtc: the CRTC whose primary plane was just enabled + * + * Performs potentially sleeping operations that must be done after the primary + * plane is enabled, such as updating FBC and IPS. Note that this may be + * called due to an explicit primary plane update, or due to an implicit + * re-enable that is caused when a sprite plane is updated to no longer + * completely hide the primary plane. + */ +static void +intel_post_enable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - intel_enable_primary_hw_plane(crtc->primary, crtc); - intel_enable_sprite_planes(crtc); - intel_crtc_update_cursor(crtc, true); - intel_crtc_dpms_overlay(intel_crtc, true); + /* + * BDW signals flip done immediately if the plane + * is disabled, even if the plane enable is already + * armed to occur at the next vblank :( + */ + if (IS_BROADWELL(dev)) + intel_wait_for_vblank(dev, pipe); + /* + * FIXME IPS should be fine as long as one plane is + * enabled, but in practice it seems to have problems + * when going from primary only to sprite only and vice + * versa. + */ hsw_enable_ips(intel_crtc); mutex_lock(&dev->struct_mutex); @@ -4760,27 +4773,95 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); /* - * FIXME: Once we grow proper nuclear flip support out of this we need - * to compute the mask of flip planes precisely. For the time being - * consider this a flip from a NULL plane. + * Gen2 reports pipe underruns whenever all planes are disabled. + * So don't enable underrun reporting before at least some planes + * are enabled. + * FIXME: Need to fix the logic to work when we turn off all planes + * but leave the pipe running. */ - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); + if (IS_GEN2(dev)) + intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); + + /* Underruns don't raise interrupts, so check manually. */ + if (HAS_GMCH_DISPLAY(dev)) + i9xx_check_fifo_underruns(dev_priv); } -static void intel_crtc_disable_planes(struct drm_crtc *crtc) +/** + * intel_pre_disable_primary - Perform operations before disabling primary plane + * @crtc: the CRTC whose primary plane is to be disabled + * + * Performs potentially sleeping operations that must be done before the + * primary plane is disabled, such as updating FBC and IPS. Note that this may + * be called due to an explicit primary plane update, or due to an implicit + * disable that is caused when a sprite plane completely hides the primary + * plane. + */ +static void +intel_pre_disable_primary(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane *intel_plane; int pipe = intel_crtc->pipe; - intel_crtc_wait_for_pending_flips(crtc); + /* + * Gen2 reports pipe underruns whenever all planes are disabled. + * So diasble underrun reporting before all the planes get disabled. + * FIXME: Need to fix the logic to work when we turn off all planes + * but leave the pipe running. + */ + if (IS_GEN2(dev)) + intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); + + /* + * Vblank time updates from the shadow to live plane control register + * are blocked if the memory self-refresh mode is active at that + * moment. So to make sure the plane gets truly disabled, disable + * first the self-refresh mode. The self-refresh enable bit in turn + * will be checked/applied by the HW only at the next frame start + * event which is after the vblank start event, so we need to have a + * wait-for-vblank between disabling the plane and the pipe. + */ + if (HAS_GMCH_DISPLAY(dev)) + intel_set_memory_cxsr(dev_priv, false); + mutex_lock(&dev->struct_mutex); if (dev_priv->fbc.crtc == intel_crtc) intel_fbc_disable(dev); + mutex_unlock(&dev->struct_mutex); + /* + * FIXME IPS should be fine as long as one plane is + * enabled, but in practice it seems to have problems + * when going from primary only to sprite only and vice + * versa. + */ hsw_disable_ips(intel_crtc); +} + +static void intel_crtc_enable_planes(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + intel_enable_primary_hw_plane(crtc->primary, crtc); + intel_enable_sprite_planes(crtc); + intel_crtc_update_cursor(crtc, true); + intel_crtc_dpms_overlay(intel_crtc, true); + + intel_post_enable_primary(crtc); +} + +static void intel_crtc_disable_planes(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane; + int pipe = intel_crtc->pipe; + + intel_crtc_wait_for_pending_flips(crtc); + + intel_pre_disable_primary(crtc); intel_crtc_dpms_overlay(intel_crtc, false); for_each_intel_plane(dev, intel_plane) { @@ -5839,9 +5920,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) encoder->enable(encoder); intel_crtc_enable_planes(crtc); - - /* Underruns don't raise interrupts, so check manually. */ - i9xx_check_fifo_underruns(dev_priv); } static void i9xx_set_pll_dividers(struct intel_crtc *crtc) @@ -5900,19 +5978,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) encoder->enable(encoder); intel_crtc_enable_planes(crtc); - - /* - * Gen2 reports pipe underruns whenever all planes are disabled. - * So don't enable underrun reporting before at least some planes - * are enabled. - * FIXME: Need to fix the logic to work when we turn off all planes - * but leave the pipe running. - */ - if (IS_GEN2(dev)) - intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); - - /* Underruns don't raise interrupts, so check manually. */ - i9xx_check_fifo_underruns(dev_priv); } static void i9xx_pfit_disable(struct intel_crtc *crtc) @@ -5941,25 +6006,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!intel_crtc->active) return; - /* - * Gen2 reports pipe underruns whenever all planes are disabled. - * So diasble underrun reporting before all the planes get disabled. - * FIXME: Need to fix the logic to work when we turn off all planes - * but leave the pipe running. - */ - if (IS_GEN2(dev)) - intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - - /* - * Vblank time updates from the shadow to live plane control register - * are blocked if the memory self-refresh mode is active at that - * moment. So to make sure the plane gets truly disabled, disable - * first the self-refresh mode. The self-refresh enable bit in turn - * will be checked/applied by the HW only at the next frame start - * event which is after the vblank start event, so we need to have a - * wait-for-vblank between disabling the plane and the pipe. - */ - intel_set_memory_cxsr(dev_priv, false); intel_crtc_disable_planes(crtc); /* @@ -12908,7 +12954,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) plane_state = to_intel_plane_state(primary->state); if (ret == 0 && !was_visible && plane_state->visible) { WARN_ON(!intel_crtc->active); - intel_enable_primary_hw_plane(set->crtc->primary, set->crtc); + intel_post_enable_primary(set->crtc); } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 52673c74855b..af697520a5cf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1389,8 +1389,6 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count); void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count); -void intel_post_enable_primary(struct drm_crtc *crtc); -void intel_pre_disable_primary(struct drm_crtc *crtc); /* intel_tv.c */ void intel_tv_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 95602da15984..f215e223aa4a 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -753,74 +753,6 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) intel_flush_primary_plane(dev_priv, intel_crtc->plane); } -/** - * intel_post_enable_primary - Perform operations after enabling primary plane - * @crtc: the CRTC whose primary plane was just enabled - * - * Performs potentially sleeping operations that must be done after the primary - * plane is enabled, such as updating FBC and IPS. Note that this may be - * called due to an explicit primary plane update, or due to an implicit - * re-enable that is caused when a sprite plane is updated to no longer - * completely hide the primary plane. - */ -void -intel_post_enable_primary(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* - * BDW signals flip done immediately if the plane - * is disabled, even if the plane enable is already - * armed to occur at the next vblank :( - */ - if (IS_BROADWELL(dev)) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - /* - * FIXME IPS should be fine as long as one plane is - * enabled, but in practice it seems to have problems - * when going from primary only to sprite only and vice - * versa. - */ - hsw_enable_ips(intel_crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); -} - -/** - * intel_pre_disable_primary - Perform operations before disabling primary plane - * @crtc: the CRTC whose primary plane is to be disabled - * - * Performs potentially sleeping operations that must be done before the - * primary plane is disabled, such as updating FBC and IPS. Note that this may - * be called due to an explicit primary plane update, or due to an implicit - * disable that is caused when a sprite plane completely hides the primary - * plane. - */ -void -intel_pre_disable_primary(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - mutex_lock(&dev->struct_mutex); - if (dev_priv->fbc.crtc == intel_crtc) - intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); - - /* - * FIXME IPS should be fine as long as one plane is - * enabled, but in practice it seems to have problems - * when going from primary only to sprite only and vice - * versa. - */ - hsw_disable_ips(intel_crtc); -} - static int intel_check_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) -- cgit v1.2.3 From 7cac945fbebceb99b68f357cde10622441b5510f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:55 +0300 Subject: drm/i915: Rename intel_crtc_dpms_overlay. To make it clear that it isn't called during crtc enable. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cb0c025427b7..63db21a39d81 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4716,9 +4716,9 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) hsw_enable_ips(intel_crtc); } -static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) +static void intel_crtc_dpms_overlay_disable(struct intel_crtc *intel_crtc) { - if (!enable && intel_crtc->overlay) { + if (intel_crtc->overlay) { struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4847,7 +4847,6 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) intel_enable_primary_hw_plane(crtc->primary, crtc); intel_enable_sprite_planes(crtc); intel_crtc_update_cursor(crtc, true); - intel_crtc_dpms_overlay(intel_crtc, true); intel_post_enable_primary(crtc); } @@ -4863,7 +4862,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_pre_disable_primary(crtc); - intel_crtc_dpms_overlay(intel_crtc, false); + intel_crtc_dpms_overlay_disable(intel_crtc); for_each_intel_plane(dev, intel_plane) { if (intel_plane->pipe == pipe) { struct drm_crtc *from = intel_plane->base.crtc; -- cgit v1.2.3 From ce22dba92de22e951dee2ff89937a39754d2dd91 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Apr 2015 17:12:56 +0300 Subject: drm/i915: Move toggling planes out of crtc enable/disable. This makes disabling planes more explicit. Signed-off-by: Maarten Lankhorst [anderco: fixed warning due to using drm_crtc instead of intel_crtc] Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 6 ++--- drivers/gpu/drm/i915/intel_display.c | 46 ++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 1afbce2c591e..adbbddab42c6 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3611,8 +3611,7 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev) intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); - dev_priv->display.crtc_disable(&crtc->base); - dev_priv->display.crtc_enable(&crtc->base); + intel_crtc_reset(crtc); } drm_modeset_unlock_all(dev); } @@ -3633,8 +3632,7 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) if (crtc->config->pch_pfit.force_thru) { crtc->config->pch_pfit.force_thru = false; - dev_priv->display.crtc_disable(&crtc->base); - dev_priv->display.crtc_enable(&crtc->base); + intel_crtc_reset(crtc); intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 63db21a39d81..d5d648030af0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -107,6 +107,8 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); +static void intel_crtc_enable_planes(struct drm_crtc *crtc); +static void intel_crtc_disable_planes(struct drm_crtc *crtc); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -3206,6 +3208,19 @@ static void intel_update_primary_planes(struct drm_device *dev) } } +void intel_crtc_reset(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + if (!crtc->active) + return; + + intel_crtc_disable_planes(&crtc->base); + dev_priv->display.crtc_disable(&crtc->base); + dev_priv->display.crtc_enable(&crtc->base); + intel_crtc_enable_planes(&crtc->base); +} + void intel_prepare_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -3226,8 +3241,11 @@ void intel_prepare_reset(struct drm_device *dev) * g33 docs say we should at least disable all the planes. */ for_each_intel_crtc(dev, crtc) { - if (crtc->active) - dev_priv->display.crtc_disable(&crtc->base); + if (!crtc->active) + continue; + + intel_crtc_disable_planes(&crtc->base); + dev_priv->display.crtc_disable(&crtc->base); } } @@ -4842,8 +4860,6 @@ intel_pre_disable_primary(struct drm_crtc *crtc) static void intel_crtc_enable_planes(struct drm_crtc *crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_enable_primary_hw_plane(crtc->primary, crtc); intel_enable_sprite_planes(crtc); intel_crtc_update_cursor(crtc, true); @@ -4949,8 +4965,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (HAS_PCH_CPT(dev)) cpt_verify_modeset(dev, intel_crtc->pipe); - - intel_crtc_enable_planes(crtc); } /* IPS only exists on ULT machines and is tied to pipe A. */ @@ -5074,7 +5088,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ haswell_mode_set_planes_workaround(intel_crtc); - intel_crtc_enable_planes(crtc); } static void ironlake_pfit_disable(struct intel_crtc *crtc) @@ -5104,8 +5117,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) if (!intel_crtc->active) return; - intel_crtc_disable_planes(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); @@ -5168,8 +5179,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (!intel_crtc->active) return; - intel_crtc_disable_planes(crtc); - for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); encoder->disable(encoder); @@ -5917,8 +5926,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); - - intel_crtc_enable_planes(crtc); } static void i9xx_set_pll_dividers(struct intel_crtc *crtc) @@ -5975,8 +5982,6 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) encoder->enable(encoder); - - intel_crtc_enable_planes(crtc); } static void i9xx_pfit_disable(struct intel_crtc *crtc) @@ -6005,8 +6010,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!intel_crtc->active) return; - intel_crtc_disable_planes(crtc); - /* * On gen2 planes are double buffered but the pipe isn't, so we must * wait for planes to fully turn off before disabling the pipe. @@ -6070,9 +6073,11 @@ void intel_crtc_control(struct drm_crtc *crtc, bool enable) intel_crtc->enabled_power_domains = domains; dev_priv->display.crtc_enable(crtc); + intel_crtc_enable_planes(crtc); } } else { if (intel_crtc->active) { + intel_crtc_disable_planes(crtc); dev_priv->display.crtc_disable(crtc); domains = intel_crtc->enabled_power_domains; @@ -6107,6 +6112,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc) /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->state->enable); + intel_crtc_disable_planes(crtc); dev_priv->display.crtc_disable(crtc); dev_priv->display.off(crtc); @@ -12346,8 +12352,10 @@ static int __intel_set_mode(struct drm_crtc *crtc, intel_crtc_disable(&intel_crtc->base); for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { - if (intel_crtc->base.state->enable) + if (intel_crtc->base.state->enable) { + intel_crtc_disable_planes(&intel_crtc->base); dev_priv->display.crtc_disable(&intel_crtc->base); + } } /* crtc->mode is already used by the ->mode_set callbacks, hence we need @@ -12395,6 +12403,7 @@ static int __intel_set_mode(struct drm_crtc *crtc, update_scanline_offset(intel_crtc); dev_priv->display.crtc_enable(&intel_crtc->base); + intel_crtc_enable_planes(&intel_crtc->base); } /* FIXME: add subpixel order */ @@ -14839,6 +14848,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; crtc->plane = !plane; + intel_crtc_disable_planes(&crtc->base); dev_priv->display.crtc_disable(&crtc->base); crtc->plane = plane; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index af697520a5cf..6fe36ddbb42f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -994,6 +994,7 @@ void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); void intel_crtc_control(struct drm_crtc *crtc, bool enable); +void intel_crtc_reset(struct intel_crtc *crtc); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); -- cgit v1.2.3 From e5d958ef42ff99ab2cf7980f4b7317d3bbd8793f Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:12:57 +0300 Subject: drm/i915: Don't check for NULL before freeing state This is not necessary after the below commit. commit a0211bb482c346820506c546a6a58b8357999a99 Author: Ander Conselvan de Oliveira Date: Mon Mar 30 14:05:43 2015 +0300 drm/atomic: Don't try to free a NULL state Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d5d648030af0..1375f53cdc95 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9860,10 +9860,8 @@ retry: fail: intel_crtc->new_enabled = crtc->state->enable; fail_unlock: - if (state) { - drm_atomic_state_free(state); - state = NULL; - } + drm_atomic_state_free(state); + state = NULL; if (ret == -EDEADLK) { drm_modeset_backoff(ctx); @@ -13003,8 +13001,7 @@ fail: } out_config: - if (state) - drm_atomic_state_free(state); + drm_atomic_state_free(state); intel_set_config_free(config); return ret; -- cgit v1.2.3 From f0c60574eb1216b0904c0d696c64d5096d6e4913 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:12:58 +0300 Subject: drm/i915: Call drm helpers when duplicating crtc and plane states Use the helpers introduced by the commit below to properly initialize the duplicated states. commit f5e7840b0c4368f8cdbb055188c2a0eef50c3052 Author: Thierry Reding Date: Wed Jan 28 14:54:32 2015 +0100 drm/atomic: Add helpers for state-subclassing drivers Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 8 ++++++-- drivers/gpu/drm/i915/intel_atomic_plane.c | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index cb6d5f2d9b60..7ed8033aae60 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -250,8 +250,12 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) crtc_state = kmemdup(intel_crtc->config, sizeof(*intel_crtc->config), GFP_KERNEL); - if (crtc_state) - crtc_state->base.crtc = crtc; + if (!crtc_state) + return NULL; + + __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); + + crtc_state->base.crtc = crtc; return &crtc_state->base; } diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index dc8e1360fb20..77462e1360bc 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -85,8 +85,8 @@ intel_plane_duplicate_state(struct drm_plane *plane) return NULL; state = &intel_state->base; - if (state->fb) - drm_framebuffer_reference(state->fb); + + __drm_atomic_helper_plane_duplicate_state(plane, state); return state; } -- cgit v1.2.3 From da3ced29869a1e11720b71bf9354f7a548596338 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:12:59 +0300 Subject: drm/i915: Use for_each_connector_in_state helper macro Simplifies looping over connector states a bit. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 9 +++-- drivers/gpu/drm/i915/intel_display.c | 72 +++++++++++------------------------- drivers/gpu/drm/i915/intel_dp_mst.c | 13 ++++--- drivers/gpu/drm/i915/intel_hdmi.c | 7 +--- 4 files changed, 36 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b8eabc65dc27..ec5d2eaef43c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -584,17 +584,18 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct intel_encoder *ret = NULL; struct drm_atomic_state *state; + struct drm_connector *connector; + struct drm_connector_state *connector_state; int num_encoders = 0; int i; state = crtc_state->base.state; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i] || - state->connector_states[i]->crtc != crtc_state->base.crtc) + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != crtc_state->base.crtc) continue; - ret = to_intel_encoder(state->connector_states[i]->best_encoder); + ret = to_intel_encoder(connector_state->best_encoder); num_encoders++; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1375f53cdc95..b1f5038221d5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -453,15 +453,12 @@ static bool intel_pipe_will_have_type(const struct intel_crtc_state *crtc_state, int type) { struct drm_atomic_state *state = crtc_state->base.state; + struct drm_connector *connector; struct drm_connector_state *connector_state; struct intel_encoder *encoder; int i, num_connectors = 0; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != crtc_state->base.crtc) continue; @@ -7461,14 +7458,11 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, struct intel_encoder *encoder; const intel_limit_t *limit; struct drm_atomic_state *state = crtc_state->base.state; + struct drm_connector *connector; struct drm_connector_state *connector_state; int i; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != &crtc->base) continue; @@ -8152,16 +8146,13 @@ static int ironlake_get_refclk(struct intel_crtc_state *crtc_state) struct drm_device *dev = crtc_state->base.crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_atomic_state *state = crtc_state->base.state; + struct drm_connector *connector; struct drm_connector_state *connector_state; struct intel_encoder *encoder; int num_connectors = 0, i; bool is_lvds = false; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != crtc_state->base.crtc) continue; @@ -8415,17 +8406,14 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_atomic_state *state = crtc_state->base.state; + struct drm_connector *connector; struct drm_connector_state *connector_state; struct intel_encoder *encoder; uint32_t dpll; int factor, num_connectors = 0, i; bool is_lvds = false, is_sdvo = false; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != crtc_state->base.crtc) continue; @@ -11149,7 +11137,8 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_atomic_state *state; - struct intel_connector *connector; + struct drm_connector *connector; + struct drm_connector_state *connector_state; int bpp, i; if ((IS_G4X(dev) || IS_VALLEYVIEW(dev))) @@ -11165,15 +11154,12 @@ compute_baseline_pipe_bpp(struct intel_crtc *crtc, state = pipe_config->base.state; /* Clamp display bpp to EDID value */ - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector = to_intel_connector(state->connectors[i]); - if (state->connector_states[i]->crtc != &crtc->base) + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != &crtc->base) continue; - connected_sink_compute_bpp(connector, pipe_config); + connected_sink_compute_bpp(to_intel_connector(connector), + pipe_config); } return bpp; @@ -11300,14 +11286,11 @@ static bool check_single_encoder_cloning(struct drm_atomic_state *state, struct intel_encoder *encoder) { struct intel_encoder *source_encoder; + struct drm_connector *connector; struct drm_connector_state *connector_state; int i; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != &crtc->base) continue; @@ -11324,14 +11307,11 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, struct intel_crtc *crtc) { struct intel_encoder *encoder; + struct drm_connector *connector; struct drm_connector_state *connector_state; int i; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != &crtc->base) continue; @@ -11347,6 +11327,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct intel_encoder *encoder; + struct drm_connector *connector; struct drm_connector_state *connector_state; unsigned int used_ports = 0; int i; @@ -11356,11 +11337,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state) * list to detect the problem on ddi platforms * where there's just one encoder per digital port. */ - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (!connector_state->best_encoder) continue; @@ -11411,7 +11388,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct intel_encoder *encoder; - struct intel_connector *connector; + struct drm_connector *connector; struct drm_connector_state *connector_state; struct intel_crtc_state *pipe_config; int base_bpp, ret = -EINVAL; @@ -11489,12 +11466,7 @@ encoder_retry: * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - for (i = 0; i < state->num_connector; i++) { - connector = to_intel_connector(state->connectors[i]); - if (!connector) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 3945057c5bbe..6e4cc5334f47 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -40,7 +40,9 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, int bpp, i; int lane_count, slots, rate; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - struct intel_connector *found = NULL; + struct drm_connector *drm_connector; + struct intel_connector *connector, *found = NULL; + struct drm_connector_state *connector_state; int mst_pbn; pipe_config->dp_encoder_is_mst = true; @@ -70,12 +72,11 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, state = pipe_config->base.state; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; + for_each_connector_in_state(state, drm_connector, connector_state, i) { + connector = to_intel_connector(drm_connector); - if (state->connector_states[i]->best_encoder == &encoder->base) { - found = to_intel_connector(state->connectors[i]); + if (connector_state->best_encoder == &encoder->base) { + found = connector; break; } } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 65bc3867dda2..590d46b124e0 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -964,6 +964,7 @@ static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state) struct drm_device *dev = crtc_state->base.crtc->dev; struct drm_atomic_state *state; struct intel_encoder *encoder; + struct drm_connector *connector; struct drm_connector_state *connector_state; int count = 0, count_hdmi = 0; int i; @@ -973,11 +974,7 @@ static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state) state = crtc_state->base.state; - for (i = 0; i < state->num_connector; i++) { - if (!state->connectors[i]) - continue; - - connector_state = state->connector_states[i]; + for_each_connector_in_state(state, connector, connector_state, i) { if (connector_state->crtc != crtc_state->base.crtc) continue; -- cgit v1.2.3 From 462a425aa541703a320b15f7f7f5b64de7e0eb47 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:00 +0300 Subject: drm/i915: Extract mode_changed computation out of stage_output_config() This should make the conversion to atomic easier, by splitting the initialization of the atomic state from the logic that decides if a modeset is needed. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 73 ++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b1f5038221d5..3207b0c1546f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12607,6 +12607,10 @@ static void intel_set_config_compute_mode_changes(struct drm_mode_set *set, struct intel_set_config *config) { + struct drm_device *dev = set->crtc->dev; + struct intel_connector *connector; + struct intel_encoder *encoder; + struct intel_crtc *crtc; /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ @@ -12650,6 +12654,36 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, config->mode_changed = true; } + for_each_intel_connector(dev, connector) { + if (&connector->new_encoder->base == connector->base.encoder) + continue; + + config->mode_changed = true; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n", + connector->base.base.id, + connector->base.name); + } + + for_each_intel_encoder(dev, encoder) { + if (&encoder->new_crtc->base == encoder->base.crtc) + continue; + + DRM_DEBUG_KMS("[ENCODER:%d:%s] crtc changed, full mode switch\n", + encoder->base.base.id, + encoder->base.name); + config->mode_changed = true; + } + + for_each_intel_crtc(dev, crtc) { + if (crtc->new_enabled == crtc->base.state->enable) + continue; + + DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n", + crtc->base.base.id, + crtc->new_enabled ? "en" : "dis"); + config->mode_changed = true; + } + DRM_DEBUG_KMS("computed changes for [CRTC:%d], mode_changed=%d, fb_changed=%d\n", set->crtc->base.id, config->mode_changed, config->fb_changed); } @@ -12657,7 +12691,6 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, static int intel_modeset_stage_output_state(struct drm_device *dev, struct drm_mode_set *set, - struct intel_set_config *config, struct drm_atomic_state *state) { struct intel_connector *connector; @@ -12693,14 +12726,6 @@ intel_modeset_stage_output_state(struct drm_device *dev, connector->base.base.id, connector->base.name); } - - - if (&connector->new_encoder->base != connector->base.encoder) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n", - connector->base.base.id, - connector->base.name); - config->mode_changed = true; - } } /* connector->new_encoder is now updated for all connectors. */ @@ -12753,15 +12778,6 @@ intel_modeset_stage_output_state(struct drm_device *dev, encoder->new_crtc = NULL; else if (num_connectors > 1) return -EINVAL; - - /* Only now check for crtc changes so we don't miss encoders - * that will be disabled. */ - if (&encoder->new_crtc->base != encoder->base.crtc) { - DRM_DEBUG_KMS("[ENCODER:%d:%s] crtc changed, full mode switch\n", - encoder->base.base.id, - encoder->base.name); - config->mode_changed = true; - } } /* Now we've also updated encoder->new_crtc for all encoders. */ for_each_intel_connector(dev, connector) { @@ -12787,13 +12803,6 @@ intel_modeset_stage_output_state(struct drm_device *dev, break; } } - - if (crtc->new_enabled != crtc->base.state->enable) { - DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n", - crtc->base.base.id, - crtc->new_enabled ? "en" : "dis"); - config->mode_changed = true; - } } return 0; @@ -12865,12 +12874,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) save_set.y = set->crtc->y; save_set.fb = set->crtc->primary->fb; - /* Compute whether we need a full modeset, only an fb base update or no - * change at all. In the future we might also check whether only the - * mode changed, e.g. for LVDS where we only change the panel fitter in - * such cases. */ - intel_set_config_compute_mode_changes(set, config); - state = drm_atomic_state_alloc(dev); if (!state) { ret = -ENOMEM; @@ -12879,10 +12882,16 @@ static int intel_crtc_set_config(struct drm_mode_set *set) state->acquire_ctx = dev->mode_config.acquire_ctx; - ret = intel_modeset_stage_output_state(dev, set, config, state); + ret = intel_modeset_stage_output_state(dev, set, state); if (ret) goto fail; + /* Compute whether we need a full modeset, only an fb base update or no + * change at all. In the future we might also check whether only the + * mode changed, e.g. for LVDS where we only change the panel fitter in + * such cases. */ + intel_set_config_compute_mode_changes(set, config); + pipe_config = intel_modeset_compute_config(set->crtc, set->mode, state, &modeset_pipes, -- cgit v1.2.3 From 4be0731786de10d0e9ae1d159504c83c6b052647 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:01 +0300 Subject: drm/i915: Add crtc states before calling compute_config() The function intel_modeset_compute_config() needs to eventually become part of atomic_check(). At that point, all the affected crtcs need to be in the atomic state with the new values. So move the logic of adding crtc states out of that function. v2: Set crtc_state->enable in all cases. (Ander) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 52 +++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3207b0c1546f..afdc065e0af1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9716,6 +9716,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_mode_config *config = &dev->mode_config; struct drm_atomic_state *state = NULL; struct drm_connector_state *connector_state; + struct intel_crtc_state *crtc_state; int ret, i = -1; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", @@ -9811,6 +9812,14 @@ retry: connector_state->crtc = crtc; connector_state->best_encoder = &intel_encoder->base; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + + crtc_state->base.enable = true; + if (!mode) mode = &load_detect_mode; @@ -9871,6 +9880,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_atomic_state *state; struct drm_connector_state *connector_state; + struct intel_crtc_state *crtc_state; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, connector->name, @@ -9887,6 +9897,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(connector_state)) goto fail; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(crtc_state)) + goto fail; + to_intel_connector(connector)->new_encoder = NULL; intel_encoder->new_crtc = NULL; intel_crtc->new_enabled = false; @@ -9894,6 +9908,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, connector_state->best_encoder = NULL; connector_state->crtc = NULL; + crtc_state->base.enable = false; + intel_set_mode(crtc, NULL, 0, 0, NULL, state); drm_atomic_state_free(state); @@ -12200,14 +12216,6 @@ intel_modeset_compute_config(struct drm_crtc *crtc, intel_modeset_affected_pipes(crtc, modeset_pipes, prepare_pipes, disable_pipes); - for_each_intel_crtc_masked(dev, *disable_pipes, intel_crtc) { - pipe_config = intel_atomic_get_crtc_state(state, intel_crtc); - if (IS_ERR(pipe_config)) - return pipe_config; - - pipe_config->base.enable = false; - } - /* * Note this needs changes when we start tracking multiple modes * and crtcs. At that point we'll need to compute the whole config @@ -12224,8 +12232,6 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (IS_ERR(pipe_config)) return pipe_config; - pipe_config->base.enable = true; - intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, "[modeset]"); } @@ -12450,9 +12456,11 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_atomic_state *state; + struct intel_crtc *intel_crtc; struct intel_encoder *encoder; struct intel_connector *connector; struct drm_connector_state *connector_state; + struct intel_crtc_state *crtc_state; state = drm_atomic_state_alloc(dev); if (!state) { @@ -12490,6 +12498,21 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } } + for_each_intel_crtc(dev, intel_crtc) { + if (intel_crtc->new_enabled == intel_crtc->base.enabled) + continue; + + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(crtc_state)) { + DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", + intel_crtc->base.base.id, + PTR_ERR(crtc_state)); + continue; + } + + crtc_state->base.enable = intel_crtc->new_enabled; + } + intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb, state); @@ -12697,6 +12720,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct drm_connector_state *connector_state; struct intel_encoder *encoder; struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; int ro; /* The upper layers ensure that we either disable a crtc or have a list @@ -12803,6 +12827,14 @@ intel_modeset_stage_output_state(struct drm_device *dev, break; } } + + if (crtc->new_enabled != crtc->base.state->enable) { + crtc_state = intel_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->base.enable = crtc->new_enabled; + } } return 0; -- cgit v1.2.3 From 548ee15b38ff5f6d7561f9e633efa20e7d7383b6 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:02 +0300 Subject: drm/i915: Don't pretend we can calculate multiple pipe_configs The code in intel_modeset_pipe_config() still needs changes before it can calculate more than just one pipe_config, and pretending it can will only make those changes more difficult. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 45 +++++++++++++++--------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index afdc065e0af1..0d18a436e34c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11398,33 +11398,29 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) crtc_state->scaler_state = scaler_state; } -static struct intel_crtc_state * +static int intel_modeset_pipe_config(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_atomic_state *state) + struct drm_atomic_state *state, + struct intel_crtc_state *pipe_config) { struct intel_encoder *encoder; struct drm_connector *connector; struct drm_connector_state *connector_state; - struct intel_crtc_state *pipe_config; int base_bpp, ret = -EINVAL; int i; bool retry = true; if (!check_encoder_cloning(state, to_intel_crtc(crtc))) { DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } if (!check_digital_port_conflicts(state)) { DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } - pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); - if (IS_ERR(pipe_config)) - return pipe_config; - clear_intel_crtc_state(pipe_config); pipe_config->base.crtc = crtc; @@ -11521,9 +11517,9 @@ encoder_retry: DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", base_bpp, pipe_config->pipe_bpp, pipe_config->dither); - return pipe_config; + return 0; fail: - return ERR_PTR(ret); + return ret; } /* Computes which crtcs are affected and sets the relevant bits in the mask. For @@ -12204,9 +12200,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc, unsigned *prepare_pipes, unsigned *disable_pipes) { - struct drm_device *dev = crtc->dev; - struct intel_crtc_state *pipe_config = NULL; - struct intel_crtc *intel_crtc; + struct intel_crtc_state *pipe_config; int ret = 0; ret = drm_atomic_add_affected_connectors(state, crtc); @@ -12222,21 +12216,20 @@ intel_modeset_compute_config(struct drm_crtc *crtc, * (i.e. one pipe_config for each crtc) rather than just the one * for this crtc. */ - for_each_intel_crtc_masked(dev, *modeset_pipes, intel_crtc) { - /* FIXME: For now we still expect modeset_pipes has at most - * one bit set. */ - if (WARN_ON(&intel_crtc->base != crtc)) - continue; + pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); + if (IS_ERR(pipe_config)) + return pipe_config; - pipe_config = intel_modeset_pipe_config(crtc, mode, state); - if (IS_ERR(pipe_config)) - return pipe_config; + if (!(*modeset_pipes & (1 << to_intel_crtc(crtc)->pipe))) + return pipe_config; - intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, - "[modeset]"); - } + ret = intel_modeset_pipe_config(crtc, mode, state, pipe_config); + if (ret) + return ERR_PTR(ret); + + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,"[modeset]"); - return intel_atomic_get_crtc_state(state, to_intel_crtc(crtc));; + return pipe_config; } static int __intel_set_mode_setup_plls(struct drm_atomic_state *state, -- cgit v1.2.3 From 4fed33f6485be65b1e8155c843987030a2ae74fa Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:03 +0300 Subject: drm/i915: Calculate a new pipe_config based on new enabled state With the current implementation of intel_modeset_affected_pipes(), if a pipe will be enabled then it is in modeset_pipes. We'll remove that mask in a follow up patch, but want to preserve this behavior, so just make that explicit. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0d18a436e34c..aa445386b21f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12220,7 +12220,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (IS_ERR(pipe_config)) return pipe_config; - if (!(*modeset_pipes & (1 << to_intel_crtc(crtc)->pipe))) + if (!pipe_config->base.enable) return pipe_config; ret = intel_modeset_pipe_config(crtc, mode, state, pipe_config); -- cgit v1.2.3 From 0a9ab303b87a94115e361a7f3a15d9f481bc453b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:04 +0300 Subject: drm/i915: Remove all *_pipes flags from modeset Set the mode_changed field on the crtc_states and use that instead. Note that even though this patch doesn't completely replace the logic in intel_modeset_affected_pipes(), that logic was never fully used to its full extent. Since the commit mentioned below, modeset_pipes and prepare_pipes would only contain at most the pipe for which the set_crtc ioctl was called. We can grow back that logic when the time comes. commit b6c5164d7bf624f3e1b750787ddb983150c5117c Author: Daniel Vetter Date: Fri Apr 12 18:48:43 2013 +0200 drm/i915: Fixup Oops in the pipe config computation v2: Don't set mode_changed unconditionally for modeset_crtc. (Ander) Check for needs_modeset() before trying to allocate a PLL. (Ander) Only call .crtc_enable() for pipes that were disabled. (Maarten) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 311 +++++++++++++++-------------------- 1 file changed, 132 insertions(+), 179 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aa445386b21f..62163d4e9b5f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5752,13 +5752,13 @@ static int intel_mode_max_pixclk(struct drm_atomic_state *state) return max_pixclk; } -static int valleyview_modeset_global_pipes(struct drm_atomic_state *state, - unsigned *prepare_pipes) +static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; int max_pixclk = intel_mode_max_pixclk(state); - int cdclk; + int cdclk, i; if (max_pixclk < 0) return max_pixclk; @@ -5771,10 +5771,20 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state, if (cdclk == dev_priv->cdclk_freq) return 0; + /* add all active pipes to the state */ + for_each_crtc(state->dev, crtc) { + if (!crtc->state->enable) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + /* disable/enable all currently active pipes while we change cdclk */ - for_each_intel_crtc(state->dev, intel_crtc) - if (intel_crtc->base.state->enable) - *prepare_pipes |= (1 << intel_crtc->pipe); + for_each_crtc_in_state(state, crtc, crtc_state, i) + if (crtc_state->enable) + crtc_state->mode_changed = true; return 0; } @@ -11522,94 +11532,6 @@ fail: return ret; } -/* Computes which crtcs are affected and sets the relevant bits in the mask. For - * simplicity we use the crtc's pipe number (because it's easier to obtain). */ -static void -intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes, - unsigned *prepare_pipes, unsigned *disable_pipes) -{ - struct intel_crtc *intel_crtc; - struct drm_device *dev = crtc->dev; - struct intel_encoder *encoder; - struct intel_connector *connector; - struct drm_crtc *tmp_crtc; - - *disable_pipes = *modeset_pipes = *prepare_pipes = 0; - - /* Check which crtcs have changed outputs connected to them, these need - * to be part of the prepare_pipes mask. We don't (yet) support global - * modeset across multiple crtcs, so modeset_pipes will only have one - * bit set at most. */ - for_each_intel_connector(dev, connector) { - if (connector->base.encoder == &connector->new_encoder->base) - continue; - - if (connector->base.encoder) { - tmp_crtc = connector->base.encoder->crtc; - - *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe; - } - - if (connector->new_encoder) - *prepare_pipes |= - 1 << connector->new_encoder->new_crtc->pipe; - } - - for_each_intel_encoder(dev, encoder) { - if (encoder->base.crtc == &encoder->new_crtc->base) - continue; - - if (encoder->base.crtc) { - tmp_crtc = encoder->base.crtc; - - *prepare_pipes |= 1 << to_intel_crtc(tmp_crtc)->pipe; - } - - if (encoder->new_crtc) - *prepare_pipes |= 1 << encoder->new_crtc->pipe; - } - - /* Check for pipes that will be enabled/disabled ... */ - for_each_intel_crtc(dev, intel_crtc) { - if (intel_crtc->base.state->enable == intel_crtc->new_enabled) - continue; - - if (!intel_crtc->new_enabled) - *disable_pipes |= 1 << intel_crtc->pipe; - else - *prepare_pipes |= 1 << intel_crtc->pipe; - } - - - /* set_mode is also used to update properties on life display pipes. */ - intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->new_enabled) - *prepare_pipes |= 1 << intel_crtc->pipe; - - /* - * For simplicity do a full modeset on any pipe where the output routing - * changed. We could be more clever, but that would require us to be - * more careful with calling the relevant encoder->mode_set functions. - */ - if (*prepare_pipes) - *modeset_pipes = *prepare_pipes; - - /* ... and mask these out. */ - *modeset_pipes &= ~(*disable_pipes); - *prepare_pipes &= ~(*disable_pipes); - - /* - * HACK: We don't (yet) fully support global modesets. intel_set_config - * obies this rule, but the modeset restore mode of - * intel_modeset_setup_hw_state does not. - */ - *modeset_pipes &= 1 << intel_crtc->pipe; - *prepare_pipes &= 1 << intel_crtc->pipe; - - DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n", - *modeset_pipes, *prepare_pipes, *disable_pipes); -} - static bool intel_crtc_in_use(struct drm_crtc *crtc) { struct drm_encoder *encoder; @@ -11622,13 +11544,22 @@ static bool intel_crtc_in_use(struct drm_crtc *crtc) return false; } +static bool +needs_modeset(struct drm_crtc_state *state) +{ + return state->mode_changed || state->active_changed; +} + static void -intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) +intel_modeset_update_state(struct drm_atomic_state *state) { + struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; - struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; struct drm_connector *connector; + int i; intel_shared_dpll_commit(dev_priv); @@ -11636,26 +11567,36 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes) if (!intel_encoder->base.crtc) continue; - intel_crtc = to_intel_crtc(intel_encoder->base.crtc); + for_each_crtc_in_state(state, crtc, crtc_state, i) + if (crtc == intel_encoder->base.crtc) + break; - if (prepare_pipes & (1 << intel_crtc->pipe)) + if (crtc != intel_encoder->base.crtc) + continue; + + if (crtc_state->enable && needs_modeset(crtc_state)) intel_encoder->connectors_active = false; } intel_modeset_commit_output_state(dev); /* Double check state. */ - for_each_intel_crtc(dev, intel_crtc) { - WARN_ON(intel_crtc->base.state->enable != intel_crtc_in_use(&intel_crtc->base)); + for_each_crtc(dev, crtc) { + WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder || !connector->encoder->crtc) continue; - intel_crtc = to_intel_crtc(connector->encoder->crtc); + for_each_crtc_in_state(state, crtc, crtc_state, i) + if (crtc == connector->encoder->crtc) + break; + + if (crtc != connector->encoder->crtc) + continue; - if (prepare_pipes & (1 << intel_crtc->pipe)) { + if (crtc_state->enable && needs_modeset(crtc_state)) { struct drm_property *dpms_property = dev->mode_config.dpms_property; @@ -12192,13 +12133,28 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } +static void +intel_atomic_modeset_compute_changed_flags(struct drm_atomic_state *state, + struct drm_crtc *modeset_crtc) +{ + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc_state->enable != crtc->state->enable) + crtc_state->mode_changed = true; + + /* FIXME: Do we need to always set mode_changed for + * modeset_crtc if it is enabled? modeset_affect_pipes() + * did that. */ + } +} + static struct intel_crtc_state * intel_modeset_compute_config(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_atomic_state *state, - unsigned *modeset_pipes, - unsigned *prepare_pipes, - unsigned *disable_pipes) + struct drm_atomic_state *state) { struct intel_crtc_state *pipe_config; int ret = 0; @@ -12207,8 +12163,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (ret) return ERR_PTR(ret); - intel_modeset_affected_pipes(crtc, modeset_pipes, - prepare_pipes, disable_pipes); + intel_atomic_modeset_compute_changed_flags(state, crtc); /* * Note this needs changes when we start tracking multiple modes @@ -12232,33 +12187,41 @@ intel_modeset_compute_config(struct drm_crtc *crtc, return pipe_config; } -static int __intel_set_mode_setup_plls(struct drm_atomic_state *state, - unsigned modeset_pipes, - unsigned disable_pipes) +static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = to_i915(dev); - unsigned clear_pipes = modeset_pipes | disable_pipes; + unsigned clear_pipes = 0; struct intel_crtc *intel_crtc; + struct intel_crtc_state *intel_crtc_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; int ret = 0; + int i; if (!dev_priv->display.crtc_compute_clock) return 0; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + intel_crtc = to_intel_crtc(crtc); + + if (needs_modeset(crtc_state)) + clear_pipes |= 1 << intel_crtc->pipe; + } + ret = intel_shared_dpll_start_config(dev_priv, clear_pipes); if (ret) goto done; - for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { - struct intel_crtc_state *crtc_state = - intel_atomic_get_crtc_state(state, intel_crtc); - - /* Modeset pipes should have a new state by now */ - if (WARN_ON(IS_ERR(crtc_state))) + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!needs_modeset(crtc_state) || !crtc_state->enable) continue; + intel_crtc = to_intel_crtc(crtc); + intel_crtc_state = to_intel_crtc_state(crtc_state); + ret = dev_priv->display.crtc_compute_clock(intel_crtc, - crtc_state); + intel_crtc_state); if (ret) { intel_shared_dpll_abort_config(dev_priv); goto done; @@ -12269,21 +12232,21 @@ done: return ret; } -static int __intel_set_mode(struct drm_crtc *crtc, +static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb, - struct intel_crtc_state *pipe_config, - unsigned modeset_pipes, - unsigned prepare_pipes, - unsigned disable_pipes) + struct intel_crtc_state *pipe_config) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = modeset_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; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; int ret = 0; + int i; saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL); if (!saved_mode) @@ -12295,7 +12258,7 @@ static int __intel_set_mode(struct drm_crtc *crtc, goto done; } - *saved_mode = crtc->mode; + *saved_mode = modeset_crtc->mode; /* * See if the config requires any additional preparation, e.g. @@ -12305,25 +12268,24 @@ static int __intel_set_mode(struct drm_crtc *crtc, * adjusted_mode bits in the crtc directly. */ if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) { - ret = valleyview_modeset_global_pipes(state, &prepare_pipes); + ret = valleyview_modeset_global_pipes(state); if (ret) goto done; - - /* may have added more to prepare_pipes than we should */ - prepare_pipes &= ~disable_pipes; } - ret = __intel_set_mode_setup_plls(state, modeset_pipes, disable_pipes); + ret = __intel_set_mode_setup_plls(state); if (ret) goto done; - for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) - intel_crtc_disable(&intel_crtc->base); + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!needs_modeset(crtc_state)) + continue; - for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { - if (intel_crtc->base.state->enable) { - intel_crtc_disable_planes(&intel_crtc->base); - dev_priv->display.crtc_disable(&intel_crtc->base); + if (!crtc_state->enable) { + intel_crtc_disable(crtc); + } else if (crtc->state->enable) { + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); } } @@ -12334,32 +12296,36 @@ static int __intel_set_mode(struct drm_crtc *crtc, * pipes; here we assume a single modeset_pipe and only track the * single crtc and mode. */ - if (modeset_pipes) { - crtc->mode = *mode; + if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { + modeset_crtc->mode = *mode; /* mode_set/enable/disable functions rely on a correct pipe * config. */ - intel_crtc_set_state(to_intel_crtc(crtc), pipe_config); + intel_crtc_set_state(to_intel_crtc(modeset_crtc), pipe_config); /* * Calculate and store various constants which * are later needed by vblank and swap-completion * timestamping. They are derived from true hwmode. */ - drm_calc_timestamping_constants(crtc, + drm_calc_timestamping_constants(modeset_crtc, &pipe_config->base.adjusted_mode); } /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ - intel_modeset_update_state(dev, prepare_pipes); + intel_modeset_update_state(state); modeset_update_crtc_power_domains(state); - for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { - struct drm_plane *primary = intel_crtc->base.primary; + if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { + struct drm_plane *primary; int vdisplay, hdisplay; + intel_crtc = to_intel_crtc(modeset_crtc); + primary = intel_crtc->base.primary; + drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); + ret = drm_plane_helper_update(primary, &intel_crtc->base, fb, 0, 0, hdisplay, vdisplay, @@ -12368,20 +12334,23 @@ static int __intel_set_mode(struct drm_crtc *crtc, } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ - for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { - update_scanline_offset(intel_crtc); + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!needs_modeset(crtc_state) || !crtc_state->enable) + continue; + + update_scanline_offset(to_intel_crtc(crtc)); - dev_priv->display.crtc_enable(&intel_crtc->base); - intel_crtc_enable_planes(&intel_crtc->base); + dev_priv->display.crtc_enable(crtc); + intel_crtc_enable_planes(crtc); } /* FIXME: add subpixel order */ done: - if (ret && crtc->state->enable) - crtc->mode = *saved_mode; + if (ret && modeset_crtc->state->enable) + modeset_crtc->mode = *saved_mode; if (ret == 0 && pipe_config) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc *intel_crtc = to_intel_crtc(modeset_crtc); /* The pipe_config will be freed with the atomic state, so * make a copy. */ @@ -12397,18 +12366,14 @@ done: return ret; } -static int intel_set_mode_pipes(struct drm_crtc *crtc, - struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb, - struct intel_crtc_state *pipe_config, - unsigned modeset_pipes, - unsigned prepare_pipes, - unsigned disable_pipes) +static int intel_set_mode_with_config(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb, + struct intel_crtc_state *pipe_config) { int ret; - ret = __intel_set_mode(crtc, mode, x, y, fb, pipe_config, modeset_pipes, - prepare_pipes, disable_pipes); + ret = __intel_set_mode(crtc, mode, x, y, fb, pipe_config); if (ret == 0) intel_modeset_check_state(crtc->dev); @@ -12422,22 +12387,15 @@ static int intel_set_mode(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct intel_crtc_state *pipe_config; - unsigned modeset_pipes, prepare_pipes, disable_pipes; int ret = 0; - pipe_config = intel_modeset_compute_config(crtc, mode, state, - &modeset_pipes, - &prepare_pipes, - &disable_pipes); - + pipe_config = intel_modeset_compute_config(crtc, mode, state); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); goto out; } - ret = intel_set_mode_pipes(crtc, mode, x, y, fb, pipe_config, - modeset_pipes, prepare_pipes, - disable_pipes); + ret = intel_set_mode_with_config(crtc, mode, x, y, fb, pipe_config); if (ret) goto out; @@ -12863,7 +12821,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) struct drm_atomic_state *state = NULL; struct intel_set_config *config; struct intel_crtc_state *pipe_config; - unsigned modeset_pipes, prepare_pipes, disable_pipes; int ret; BUG_ON(!set); @@ -12918,10 +12875,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_set_config_compute_mode_changes(set, config); pipe_config = intel_modeset_compute_config(set->crtc, set->mode, - state, - &modeset_pipes, - &prepare_pipes, - &disable_pipes); + state); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); goto fail; @@ -12941,10 +12895,9 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_update_pipe_size(to_intel_crtc(set->crtc)); if (config->mode_changed) { - ret = intel_set_mode_pipes(set->crtc, set->mode, - set->x, set->y, set->fb, pipe_config, - modeset_pipes, prepare_pipes, - disable_pipes); + ret = intel_set_mode_with_config(set->crtc, set->mode, + set->x, set->y, set->fb, + pipe_config); } else if (config->fb_changed) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); struct drm_plane *primary = set->crtc->primary; -- cgit v1.2.3 From e13be6651743b6cebdd29d4049dcd52b3ece4274 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:05 +0300 Subject: drm/i915: Remove saved_mode from __intel_set_mode() There's no way that function can fail after it sets crtc->mode anymore, so there's no need to save the old mode for the failure case. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 62163d4e9b5f..e47dddf4aacb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12239,7 +12239,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, { struct drm_device *dev = modeset_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; @@ -12248,18 +12247,12 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, int ret = 0; int i; - saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL); - if (!saved_mode) - return -ENOMEM; - crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL); if (!crtc_state_copy) { ret = -ENOMEM; goto done; } - *saved_mode = modeset_crtc->mode; - /* * See if the config requires any additional preparation, e.g. * to adjust global state with pipes off. We need to do this @@ -12346,9 +12339,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, /* FIXME: add subpixel order */ done: - if (ret && modeset_crtc->state->enable) - modeset_crtc->mode = *saved_mode; - if (ret == 0 && pipe_config) { struct intel_crtc *intel_crtc = to_intel_crtc(modeset_crtc); @@ -12362,7 +12352,6 @@ done: kfree(crtc_state_copy); } - kfree(saved_mode); return ret; } -- cgit v1.2.3 From 054518ddff87565022bf1eb1578fcb00e42cc847 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:06 +0300 Subject: drm/i915: Move compute part of __intel_set_mode() to separate function The first function calls done in that function can still cause changes to the atomic state and may fail. This should eventually be part of our atomic check function, while the rest of the code in __intel_set_mode() is the commit hook. So this makes the legacy mode set more atomic-y. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 47 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e47dddf4aacb..9655f1f1ae85 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12232,6 +12232,32 @@ done: return ret; } +/* Code that should eventually be part of atomic_check() */ +static int __intel_set_mode_checks(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + int ret; + + /* + * See if the config requires any additional preparation, e.g. + * to adjust global state with pipes off. We need to do this + * here so we can get the modeset_pipe updated config for the new + * mode set on this crtc. For other crtcs we need to use the + * adjusted_mode bits in the crtc directly. + */ + if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) { + ret = valleyview_modeset_global_pipes(state); + if (ret) + return ret; + } + + ret = __intel_set_mode_setup_plls(state); + if (ret) + return ret; + + return 0; +} + static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct drm_display_mode *mode, int x, int y, struct drm_framebuffer *fb, @@ -12247,29 +12273,16 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, int ret = 0; int i; + ret = __intel_set_mode_checks(state); + if (ret < 0) + return ret; + crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL); if (!crtc_state_copy) { ret = -ENOMEM; goto done; } - /* - * See if the config requires any additional preparation, e.g. - * to adjust global state with pipes off. We need to do this - * here so we can get the modeset_pipe updated config for the new - * mode set on this crtc. For other crtcs we need to use the - * adjusted_mode bits in the crtc directly. - */ - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) { - ret = valleyview_modeset_global_pipes(state); - if (ret) - goto done; - } - - ret = __intel_set_mode_setup_plls(state); - if (ret) - goto done; - for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!needs_modeset(crtc_state)) continue; -- cgit v1.2.3 From 9eb45f228f24a2d1d98cb526e149aa18ba1f5ef5 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:07 +0300 Subject: drm/i915: Simplify error handling in __intel_set_mode() The remaining parts of the failure path could only be reached if the allocation of crtc_state_copy would fail. In that case, there is nothing to undo, so just get rid of the label for error handling and return an error code immediately. We also always allocate a pipe_config, even if the pipe is being disabled, so the remaining part of what was the error/done case can be simplified a little too. v2: Ignore return value from drm_plane_helper_update(). (Ander) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9655f1f1ae85..9aa90abab4ba 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12278,10 +12278,8 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, return ret; crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL); - if (!crtc_state_copy) { - ret = -ENOMEM; - goto done; - } + if (!crtc_state_copy) + return -ENOMEM; for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!needs_modeset(crtc_state)) @@ -12337,6 +12335,7 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, hdisplay, vdisplay, x << 16, y << 16, hdisplay << 16, vdisplay << 16); + WARN_ON(ret != 0); } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ @@ -12351,21 +12350,16 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, } /* FIXME: add subpixel order */ -done: - if (ret == 0 && pipe_config) { - struct intel_crtc *intel_crtc = to_intel_crtc(modeset_crtc); - - /* The pipe_config will be freed with the atomic state, so - * make a copy. */ - memcpy(crtc_state_copy, intel_crtc->config, - sizeof *crtc_state_copy); - intel_crtc->config = crtc_state_copy; - intel_crtc->base.state = &crtc_state_copy->base; - } else { - kfree(crtc_state_copy); - } - return ret; + intel_crtc = to_intel_crtc(modeset_crtc); + + /* The pipe_config will be freed with the atomic state, so + * make a copy. */ + memcpy(crtc_state_copy, intel_crtc->config, sizeof *crtc_state_copy); + intel_crtc->config = crtc_state_copy; + intel_crtc->base.state = &crtc_state_copy->base; + + return 0; } static int intel_set_mode_with_config(struct drm_crtc *crtc, -- cgit v1.2.3 From 561c8bda8fd1c536231eac8032e3792715f7db87 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:08 +0300 Subject: drm/i915: Don't modeset with old mode when set_crtc fails The modeset code is now properly divided in two phases, so that it only changes hardware state if it succeeds, so there's no ill-effect that needs to be undone on failure anymore. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 48 ------------------------------------ 1 file changed, 48 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9aa90abab4ba..36775a30664a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12787,33 +12787,9 @@ intel_modeset_stage_output_state(struct drm_device *dev, return 0; } -static void disable_crtc_nofb(struct intel_crtc *crtc) -{ - struct drm_device *dev = crtc->base.dev; - struct intel_encoder *encoder; - struct intel_connector *connector; - - DRM_DEBUG_KMS("Trying to restore without FB -> disabling pipe %c\n", - pipe_name(crtc->pipe)); - - for_each_intel_connector(dev, connector) { - if (connector->new_encoder && - connector->new_encoder->new_crtc == crtc) - connector->new_encoder = NULL; - } - - for_each_intel_encoder(dev, encoder) { - if (encoder->new_crtc == crtc) - encoder->new_crtc = NULL; - } - - crtc->new_enabled = false; -} - static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; - struct drm_mode_set save_set; struct drm_atomic_state *state = NULL; struct intel_set_config *config; struct intel_crtc_state *pipe_config; @@ -12846,12 +12822,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) goto out_config; - save_set.crtc = set->crtc; - save_set.mode = &set->crtc->mode; - save_set.x = set->crtc->x; - save_set.y = set->crtc->y; - save_set.fb = set->crtc->primary->fb; - state = drm_atomic_state_alloc(dev); if (!state) { ret = -ENOMEM; @@ -12935,24 +12905,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) set->crtc->base.id, ret); fail: intel_set_config_restore_state(dev, config); - - drm_atomic_state_clear(state); - - /* - * HACK: if the pipe was on, but we didn't have a framebuffer, - * force the pipe off to avoid oopsing in the modeset code - * due to fb==NULL. This should only happen during boot since - * we don't yet reconstruct the FB from the hardware state. - */ - if (to_intel_crtc(save_set.crtc)->new_enabled && !save_set.fb) - disable_crtc_nofb(to_intel_crtc(save_set.crtc)); - - /* Try to restore the config */ - if (config->mode_changed && - intel_set_mode(save_set.crtc, save_set.mode, - save_set.x, save_set.y, save_set.fb, - state)) - DRM_ERROR("failed to restore config after modeset failure\n"); } out_config: -- cgit v1.2.3 From d3a40d1bc8aea935c2df4634e374aecdc4fdbfc2 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:09 +0300 Subject: drm/i915: Add primary plane to atomic state in legacy modeset Add the primary plane state to the legacy modeset atomic state and use it when configuring the primary plane in __intel_set_mode(). This is a first step towards merging the flip path in intel_crtc_set_config() and __intel_set_mode(). v2: Set crtc to NULL if fb is NULL. (Maarten) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 83 ++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36775a30664a..44f6d5965f98 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9710,6 +9710,41 @@ mode_fits_in_fbdev(struct drm_device *dev, #endif } +static int intel_modeset_setup_plane_state(struct drm_atomic_state *state, + struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_plane_state *plane_state; + int hdisplay, vdisplay; + int ret; + + plane_state = drm_atomic_get_plane_state(state, crtc->primary); + if (IS_ERR(plane_state)) + return PTR_ERR(plane_state); + + if (mode) + drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); + else + hdisplay = vdisplay = 0; + + ret = drm_atomic_set_crtc_for_plane(plane_state, fb ? crtc : NULL); + if (ret) + return ret; + drm_atomic_set_fb_for_plane(plane_state, fb); + plane_state->crtc_x = 0; + plane_state->crtc_y = 0; + plane_state->crtc_w = hdisplay; + plane_state->crtc_h = vdisplay; + plane_state->src_x = x << 16; + plane_state->src_y = y << 16; + plane_state->src_w = hdisplay << 16; + plane_state->src_h = vdisplay << 16; + + return 0; +} + bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, struct intel_load_detect_pipe *old, @@ -9852,6 +9887,10 @@ retry: goto fail; } + ret = intel_modeset_setup_plane_state(state, crtc, mode, fb, 0, 0); + if (ret) + goto fail; + if (intel_set_mode(crtc, mode, 0, 0, fb, state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) @@ -9891,6 +9930,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct drm_atomic_state *state; struct drm_connector_state *connector_state; struct intel_crtc_state *crtc_state; + int ret; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, connector->name, @@ -9920,6 +9960,11 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, crtc_state->base.enable = false; + ret = intel_modeset_setup_plane_state(state, crtc, NULL, NULL, + 0, 0); + if (ret) + goto fail; + intel_set_mode(crtc, NULL, 0, 0, NULL, state); drm_atomic_state_free(state); @@ -12270,6 +12315,8 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct intel_crtc *intel_crtc; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + struct drm_plane *plane; + struct drm_plane_state *plane_state; int ret = 0; int i; @@ -12321,20 +12368,24 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, modeset_update_crtc_power_domains(state); - if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { - struct drm_plane *primary; - int vdisplay, hdisplay; - - intel_crtc = to_intel_crtc(modeset_crtc); - primary = intel_crtc->base.primary; + for_each_plane_in_state(state, plane, plane_state, i) { + if (WARN_ON(plane != modeset_crtc->primary)) + continue; - drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay); + /* Primary plane is disabled in intel_crtc_disable() */ + if (!pipe_config->base.enable) + continue; - ret = drm_plane_helper_update(primary, &intel_crtc->base, - fb, 0, 0, - hdisplay, vdisplay, - x << 16, y << 16, - hdisplay << 16, vdisplay << 16); + ret = drm_plane_helper_update(plane, plane_state->crtc, + plane_state->fb, + plane_state->crtc_x, + plane_state->crtc_y, + plane_state->crtc_w, + plane_state->crtc_h, + plane_state->src_x, + plane_state->src_y, + plane_state->src_w, + plane_state->src_h); WARN_ON(ret != 0); } @@ -12460,6 +12511,9 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) crtc_state->base.enable = intel_crtc->new_enabled; } + intel_modeset_setup_plane_state(state, crtc, &crtc->mode, + crtc->primary->fb, crtc->x, crtc->y); + intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb, state); @@ -12834,6 +12888,11 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) goto fail; + ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, + set->fb, set->x, set->y); + if (ret) + goto fail; + /* Compute whether we need a full modeset, only an fb base update or no * change at all. In the future we might also check whether only the * mode changed, e.g. for LVDS where we only change the panel fitter in -- cgit v1.2.3 From cf6d0d76cf797494b95e4971f662c6311ff92320 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:10 +0300 Subject: drm/i915: Delete fb, x and y parameters from mode set functions We don't need to pass it down the call chain anymore now that the plane state is set up properly. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 44f6d5965f98..daf3467a7934 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -83,7 +83,6 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *old_fb, struct drm_atomic_state *state); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, @@ -9891,7 +9890,7 @@ retry: if (ret) goto fail; - if (intel_set_mode(crtc, mode, 0, 0, fb, state)) { + if (intel_set_mode(crtc, mode, state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -9965,7 +9964,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - intel_set_mode(crtc, NULL, 0, 0, NULL, state); + intel_set_mode(crtc, NULL, state); drm_atomic_state_free(state); @@ -12305,7 +12304,6 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb, struct intel_crtc_state *pipe_config) { struct drm_device *dev = modeset_crtc->dev; @@ -12415,12 +12413,11 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, static int intel_set_mode_with_config(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb, struct intel_crtc_state *pipe_config) { int ret; - ret = __intel_set_mode(crtc, mode, x, y, fb, pipe_config); + ret = __intel_set_mode(crtc, mode, pipe_config); if (ret == 0) intel_modeset_check_state(crtc->dev); @@ -12430,7 +12427,6 @@ static int intel_set_mode_with_config(struct drm_crtc *crtc, static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb, struct drm_atomic_state *state) { struct intel_crtc_state *pipe_config; @@ -12442,7 +12438,7 @@ static int intel_set_mode(struct drm_crtc *crtc, goto out; } - ret = intel_set_mode_with_config(crtc, mode, x, y, fb, pipe_config); + ret = intel_set_mode_with_config(crtc, mode, pipe_config); if (ret) goto out; @@ -12514,8 +12510,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) intel_modeset_setup_plane_state(state, crtc, &crtc->mode, crtc->primary->fb, crtc->x, crtc->y); - intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb, - state); + intel_set_mode(crtc, &crtc->mode, state); drm_atomic_state_free(state); } @@ -12921,7 +12916,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (config->mode_changed) { ret = intel_set_mode_with_config(set->crtc, set->mode, - set->x, set->y, set->fb, pipe_config); } else if (config->fb_changed) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); -- cgit v1.2.3 From 8d8c9b519733c1f4ee6e0362f1e15244579873ae Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:11 +0300 Subject: drm/i915: Don't use struct intel_set_config *_changed flags Use the similar fields in crtc_state instead, so that this code can be moved to our future implementation of atomic_check(). Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 66 +++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index daf3467a7934..fe9f545412ec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12226,6 +12226,18 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (ret) return ERR_PTR(ret); + /* Check things that can only be changed through modeset */ + if (pipe_config->has_audio != + to_intel_crtc(crtc)->config->has_audio) + pipe_config->base.mode_changed = true; + + /* + * Note we have an issue here with infoframes: current code + * only updates them on the full mode set path per hw + * requirements. So here we should be checking for any + * required changes and forcing a mode set. + */ + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,"[modeset]"); return pipe_config; @@ -12624,7 +12636,7 @@ is_crtc_connector_off(struct drm_mode_set *set) static void intel_set_config_compute_mode_changes(struct drm_mode_set *set, - struct intel_set_config *config) + struct intel_crtc_state *pipe_config) { struct drm_device *dev = set->crtc->dev; struct intel_connector *connector; @@ -12634,7 +12646,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ if (is_crtc_connector_off(set)) { - config->mode_changed = true; + pipe_config->base.mode_changed = true; } else if (set->crtc->primary->fb != set->fb) { /* * If we have no fb, we can only flip as long as the crtc is @@ -12648,36 +12660,36 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, if (intel_crtc->active) { DRM_DEBUG_KMS("crtc has no fb, will flip\n"); - config->fb_changed = true; + pipe_config->base.planes_changed = true; } else { DRM_DEBUG_KMS("inactive crtc, full mode set\n"); - config->mode_changed = true; + pipe_config->base.mode_changed = true; } } else if (set->fb == NULL) { - config->mode_changed = true; + pipe_config->base.mode_changed = true; } else if (set->fb->pixel_format != set->crtc->primary->fb->pixel_format) { - config->mode_changed = true; + pipe_config->base.mode_changed = true; } else { - config->fb_changed = true; + pipe_config->base.planes_changed = true; } } if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) - config->fb_changed = true; + pipe_config->base.planes_changed = true; if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { DRM_DEBUG_KMS("modes are different, full mode set\n"); drm_mode_debug_printmodeline(&set->crtc->mode); drm_mode_debug_printmodeline(set->mode); - config->mode_changed = true; + pipe_config->base.mode_changed = true; } for_each_intel_connector(dev, connector) { if (&connector->new_encoder->base == connector->base.encoder) continue; - config->mode_changed = true; + pipe_config->base.mode_changed = true; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n", connector->base.base.id, connector->base.name); @@ -12690,7 +12702,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, DRM_DEBUG_KMS("[ENCODER:%d:%s] crtc changed, full mode switch\n", encoder->base.base.id, encoder->base.name); - config->mode_changed = true; + pipe_config->base.mode_changed = true; } for_each_intel_crtc(dev, crtc) { @@ -12700,11 +12712,12 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n", crtc->base.base.id, crtc->new_enabled ? "en" : "dis"); - config->mode_changed = true; + pipe_config->base.mode_changed = true; } DRM_DEBUG_KMS("computed changes for [CRTC:%d], mode_changed=%d, fb_changed=%d\n", - set->crtc->base.id, config->mode_changed, config->fb_changed); + set->crtc->base.id, pipe_config->base.mode_changed, + pipe_config->base.planes_changed); } static int @@ -12888,36 +12901,25 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) goto fail; - /* Compute whether we need a full modeset, only an fb base update or no - * change at all. In the future we might also check whether only the - * mode changed, e.g. for LVDS where we only change the panel fitter in - * such cases. */ - intel_set_config_compute_mode_changes(set, config); - pipe_config = intel_modeset_compute_config(set->crtc, set->mode, state); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); goto fail; - } else if (pipe_config) { - if (pipe_config->has_audio != - to_intel_crtc(set->crtc)->config->has_audio) - config->mode_changed = true; - - /* - * Note we have an issue here with infoframes: current code - * only updates them on the full mode set path per hw - * requirements. So here we should be checking for any - * required changes and forcing a mode set. - */ } + /* Compute whether we need a full modeset, only an fb base update or no + * change at all. In the future we might also check whether only the + * mode changed, e.g. for LVDS where we only change the panel fitter in + * such cases. */ + intel_set_config_compute_mode_changes(set, pipe_config); + intel_update_pipe_size(to_intel_crtc(set->crtc)); - if (config->mode_changed) { + if (pipe_config->base.mode_changed) { ret = intel_set_mode_with_config(set->crtc, set->mode, pipe_config); - } else if (config->fb_changed) { + } else if (pipe_config->base.planes_changed) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); struct drm_plane *primary = set->crtc->primary; struct intel_plane_state *plane_state = -- cgit v1.2.3 From 41227c8c52bccef5ceb86b2ab1a2ffc4be04c44e Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:12 +0300 Subject: drm/i915: Don't use staged config to calculate mode_changed flags Use the atomic state instead. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 49 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fe9f545412ec..fea807ce77d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12638,10 +12638,12 @@ static void intel_set_config_compute_mode_changes(struct drm_mode_set *set, struct intel_crtc_state *pipe_config) { - struct drm_device *dev = set->crtc->dev; - struct intel_connector *connector; - struct intel_encoder *encoder; - struct intel_crtc *crtc; + struct drm_atomic_state *state; + struct drm_connector *connector; + struct drm_connector_state *connector_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ @@ -12685,33 +12687,32 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, pipe_config->base.mode_changed = true; } - for_each_intel_connector(dev, connector) { - if (&connector->new_encoder->base == connector->base.encoder) - continue; - - pipe_config->base.mode_changed = true; - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n", - connector->base.base.id, - connector->base.name); - } + state = pipe_config->base.state; - for_each_intel_encoder(dev, encoder) { - if (&encoder->new_crtc->base == encoder->base.crtc) - continue; + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->best_encoder != + connector->state->best_encoder) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n", + connector->base.id, + connector->name); + pipe_config->base.mode_changed = true; + } - DRM_DEBUG_KMS("[ENCODER:%d:%s] crtc changed, full mode switch\n", - encoder->base.base.id, - encoder->base.name); - pipe_config->base.mode_changed = true; + if (connector_state->crtc != connector->state->crtc) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] crtc changed, full mode switch\n", + connector->base.id, + connector->name); + pipe_config->base.mode_changed = true; + } } - for_each_intel_crtc(dev, crtc) { - if (crtc->new_enabled == crtc->base.state->enable) + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc_state->enable == crtc->state->enable) continue; DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n", - crtc->base.base.id, - crtc->new_enabled ? "en" : "dis"); + crtc->base.id, + crtc_state->enable ? "en" : "dis"); pipe_config->base.mode_changed = true; } -- cgit v1.2.3 From bb54662350662815b4bfc2ff4464330a2dbd7041 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:13 +0300 Subject: drm/i915: Unify modeset and flip paths of intel_crtc_set_config() Call intel_set_mode() uncondionally from intel_crtc_set_config(), since the former function is now properly wired to ignore all the modesets if the mode_changed and active_changed flags are false in crtc_state. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 37 +++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fea807ce77d3..d1f737a8ad9e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12850,12 +12850,21 @@ intel_modeset_stage_output_state(struct drm_device *dev, return 0; } +static bool primary_plane_visible(struct drm_crtc *crtc) +{ + struct intel_plane_state *plane_state = + to_intel_plane_state(crtc->primary->state); + + return plane_state->visible; +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; struct intel_set_config *config; struct intel_crtc_state *pipe_config; + bool primary_plane_was_visible; int ret; BUG_ON(!set); @@ -12917,29 +12926,23 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_update_pipe_size(to_intel_crtc(set->crtc)); - if (pipe_config->base.mode_changed) { - ret = intel_set_mode_with_config(set->crtc, set->mode, - pipe_config); - } else if (pipe_config->base.planes_changed) { + primary_plane_was_visible = primary_plane_visible(set->crtc); + + ret = intel_set_mode_with_config(set->crtc, set->mode, + pipe_config); + + if (ret == 0 && + pipe_config->base.enable && + pipe_config->base.planes_changed && + !needs_modeset(&pipe_config->base)) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); - struct drm_plane *primary = set->crtc->primary; - struct intel_plane_state *plane_state = - to_intel_plane_state(primary->state); - bool was_visible = plane_state->visible; - int vdisplay, hdisplay; - - drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay); - ret = drm_plane_helper_update(primary, set->crtc, set->fb, - 0, 0, hdisplay, vdisplay, - set->x << 16, set->y << 16, - hdisplay << 16, vdisplay << 16); /* * We need to make sure the primary plane is re-enabled if it * has previously been turned off. */ - plane_state = to_intel_plane_state(primary->state); - if (ret == 0 && !was_visible && plane_state->visible) { + if (ret == 0 && !primary_plane_was_visible && + primary_plane_visible(set->crtc)) { WARN_ON(!intel_crtc->active); intel_post_enable_primary(set->crtc); } -- cgit v1.2.3 From b78852646450f3cb1e0677c1ae8a56875dd22562 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:14 +0300 Subject: drm/i915: Simplify intel_set_config_compute_mode_changes() a bit Add a helper function to make the code slightly more readable. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 44 ++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d1f737a8ad9e..20c0b94b8fcb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12721,6 +12721,18 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, pipe_config->base.planes_changed); } +static bool intel_connector_in_mode_set(struct intel_connector *connector, + struct drm_mode_set *set) +{ + int ro; + + for (ro = 0; ro < set->num_connectors; ro++) + if (set->connectors[ro] == &connector->base) + return true; + + return false; +} + static int intel_modeset_stage_output_state(struct drm_device *dev, struct drm_mode_set *set, @@ -12731,7 +12743,6 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct intel_encoder *encoder; struct intel_crtc *crtc; struct intel_crtc_state *crtc_state; - int ro; /* The upper layers ensure that we either disable a crtc or have a list * of connectors. For paranoia, double-check this. */ @@ -12739,21 +12750,22 @@ intel_modeset_stage_output_state(struct drm_device *dev, WARN_ON(set->fb && (set->num_connectors == 0)); for_each_intel_connector(dev, connector) { - /* Otherwise traverse passed in connector list and get encoders - * for them. */ - for (ro = 0; ro < set->num_connectors; ro++) { - if (set->connectors[ro] == &connector->base) { - connector->new_encoder = intel_find_encoder(connector, to_intel_crtc(set->crtc)->pipe); - break; - } + bool in_mode_set = intel_connector_in_mode_set(connector, set); + + if (in_mode_set) { + int pipe = to_intel_crtc(set->crtc)->pipe; + connector->new_encoder = + intel_find_encoder(connector, pipe); } + if (!connector->base.encoder || + connector->base.encoder->crtc != set->crtc) + continue; + /* If we disable the crtc, disable all its connectors. Also, if * the connector is on the changing crtc but not on the new * connector list, disable it. */ - if ((!set->fb || ro == set->num_connectors) && - connector->base.encoder && - connector->base.encoder->crtc == set->crtc) { + if (!set->fb || !in_mode_set) { connector->new_encoder = NULL; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", @@ -12770,12 +12782,10 @@ intel_modeset_stage_output_state(struct drm_device *dev, if (!connector->new_encoder) continue; - new_crtc = connector->new_encoder->base.crtc; - - for (ro = 0; ro < set->num_connectors; ro++) { - if (set->connectors[ro] == &connector->base) - new_crtc = set->crtc; - } + if (intel_connector_in_mode_set(connector, set)) + new_crtc = set->crtc; + else + new_crtc = connector->new_encoder->base.crtc; /* Make sure the new CRTC will work with the encoder */ if (!drm_encoder_crtc_ok(&connector->new_encoder->base, -- cgit v1.2.3 From d5432a9d19b61ba6a2b3d88f3026e0ca60eb57a1 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:15 +0300 Subject: drm/i915: Stage new modeset state straight into atomic state The logic that stages the state before the modeset was still updating first the old staged config and then populating the atomic state based on that. Change this to use only the atomic state. Note that now the staged config is updated in the function intel_modeset_commit_output_state(). This is done so that the modeset check and the force restore path in the hw state read out code continue to work. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 170 +++++++++++++++++------------------ 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 20c0b94b8fcb..80555800f5f4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11152,27 +11152,47 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) * intel_modeset_commit_output_state * * This function copies the stage display pipe configuration to the real one. + * + * FIXME: we want to replace this with a proper state swap in the future */ -static void intel_modeset_commit_output_state(struct drm_device *dev) +static void intel_modeset_commit_output_state(struct drm_atomic_state *state) { - struct intel_crtc *crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_connector *connector; + struct drm_connector_state *connector_state; struct intel_encoder *encoder; - struct intel_connector *connector; + struct intel_connector *intel_connector; + int i; - for_each_intel_connector(dev, connector) { - connector->base.encoder = &connector->new_encoder->base; + for_each_connector_in_state(state, connector, connector_state, i) { + *connector->state = *connector_state; + + connector->encoder = connector_state->best_encoder; + if (connector->encoder) + connector->encoder->crtc = connector_state->crtc; } - for_each_intel_encoder(dev, encoder) { - encoder->base.crtc = &encoder->new_crtc->base; + /* Update crtc of disabled encoders */ + for_each_intel_encoder(state->dev, encoder) { + int num_connectors = 0; + + for_each_intel_connector(state->dev, intel_connector) + if (intel_connector->base.encoder == &encoder->base) + num_connectors++; + + if (num_connectors == 0) + encoder->base.crtc = NULL; } - for_each_intel_crtc(dev, crtc) { - crtc->base.state->enable = crtc->new_enabled; - crtc->base.enabled = crtc->new_enabled; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + crtc->state->enable = crtc_state->enable; + crtc->enabled = crtc_state->enable; } - intel_modeset_update_connector_atomic_state(dev); + /* Copy the new configuration to the staged state, to keep the few + * pieces of code that haven't been converted yet happy */ + intel_modeset_update_staged_output_state(state->dev); } static void @@ -11622,7 +11642,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) intel_encoder->connectors_active = false; } - intel_modeset_commit_output_state(dev); + intel_modeset_commit_output_state(state); /* Double check state. */ for_each_crtc(dev, crtc) { @@ -12739,10 +12759,11 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct drm_atomic_state *state) { struct intel_connector *connector; + struct drm_connector *drm_connector; struct drm_connector_state *connector_state; - struct intel_encoder *encoder; - struct intel_crtc *crtc; - struct intel_crtc_state *crtc_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, ret; /* The upper layers ensure that we either disable a crtc or have a list * of connectors. For paranoia, double-check this. */ @@ -12752,21 +12773,28 @@ intel_modeset_stage_output_state(struct drm_device *dev, for_each_intel_connector(dev, connector) { bool in_mode_set = intel_connector_in_mode_set(connector, set); + if (!in_mode_set && connector->base.state->crtc != set->crtc) + continue; + + connector_state = + drm_atomic_get_connector_state(state, &connector->base); + if (IS_ERR(connector_state)) + return PTR_ERR(connector_state); + if (in_mode_set) { int pipe = to_intel_crtc(set->crtc)->pipe; - connector->new_encoder = - intel_find_encoder(connector, pipe); + connector_state->best_encoder = + &intel_find_encoder(connector, pipe)->base; } - if (!connector->base.encoder || - connector->base.encoder->crtc != set->crtc) + if (connector->base.state->crtc != set->crtc) continue; /* If we disable the crtc, disable all its connectors. Also, if * the connector is on the changing crtc but not on the new * connector list, disable it. */ if (!set->fb || !in_mode_set) { - connector->new_encoder = NULL; + connector_state->best_encoder = NULL; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", connector->base.base.id, @@ -12775,86 +12803,58 @@ intel_modeset_stage_output_state(struct drm_device *dev, } /* connector->new_encoder is now updated for all connectors. */ - /* Update crtc of enabled connectors. */ - for_each_intel_connector(dev, connector) { - struct drm_crtc *new_crtc; + for_each_connector_in_state(state, drm_connector, connector_state, i) { + connector = to_intel_connector(drm_connector); + + if (!connector_state->best_encoder) { + ret = drm_atomic_set_crtc_for_connector(connector_state, + NULL); + if (ret) + return ret; - if (!connector->new_encoder) continue; + } - if (intel_connector_in_mode_set(connector, set)) - new_crtc = set->crtc; - else - new_crtc = connector->new_encoder->base.crtc; + if (intel_connector_in_mode_set(connector, set)) { + struct drm_crtc *crtc = connector->base.state->crtc; + + /* If this connector was in a previous crtc, add it + * to the state. We might need to disable it. */ + if (crtc) { + crtc_state = + drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + ret = drm_atomic_set_crtc_for_connector(connector_state, + set->crtc); + if (ret) + return ret; + } /* Make sure the new CRTC will work with the encoder */ - if (!drm_encoder_crtc_ok(&connector->new_encoder->base, - new_crtc)) { + if (!drm_encoder_crtc_ok(connector_state->best_encoder, + connector_state->crtc)) { return -EINVAL; } - connector->new_encoder->new_crtc = to_intel_crtc(new_crtc); - - connector_state = - drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) - return PTR_ERR(connector_state); - - connector_state->crtc = new_crtc; - connector_state->best_encoder = &connector->new_encoder->base; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", connector->base.base.id, connector->base.name, - new_crtc->base.id); - } - - /* Check for any encoders that needs to be disabled. */ - for_each_intel_encoder(dev, encoder) { - int num_connectors = 0; - for_each_intel_connector(dev, connector) { - if (connector->new_encoder == encoder) { - WARN_ON(!connector->new_encoder->new_crtc); - num_connectors++; - } - } - - if (num_connectors == 0) - encoder->new_crtc = NULL; - else if (num_connectors > 1) - return -EINVAL; - } - /* Now we've also updated encoder->new_crtc for all encoders. */ - for_each_intel_connector(dev, connector) { - connector_state = - drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) - return PTR_ERR(connector_state); + connector_state->crtc->base.id); - if (connector->new_encoder) { - if (connector->new_encoder != connector->encoder) - connector->encoder = connector->new_encoder; - } else { - connector_state->crtc = NULL; - connector_state->best_encoder = NULL; - } + if (connector_state->best_encoder != &connector->encoder->base) + connector->encoder = + to_intel_encoder(connector_state->best_encoder); } - for_each_intel_crtc(dev, crtc) { - crtc->new_enabled = false; - - for_each_intel_encoder(dev, encoder) { - if (encoder->new_crtc == crtc) { - crtc->new_enabled = true; - break; - } - } - if (crtc->new_enabled != crtc->base.state->enable) { - crtc_state = intel_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); + for_each_crtc_in_state(state, crtc, crtc_state, i) { + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; - crtc_state->base.enable = crtc->new_enabled; - } + crtc_state->enable = drm_atomic_connectors_for_crtc(state, crtc); } return 0; -- cgit v1.2.3 From 7cbf41d6105fe55074c03582831da72923d0874b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:16 +0300 Subject: drm/i915: Remove save/restore logic from intel_crtc_set_config() This is no longer necessary since we only update the staged config on successfull modeset. The new configuration is stored in an atomic state struct which is freed in case of failure. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 113 ++--------------------------------- drivers/gpu/drm/i915/intel_drv.h | 9 --- 2 files changed, 6 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 80555800f5f4..210e7c4f881b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12549,91 +12549,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) #undef for_each_intel_crtc_masked -static void intel_set_config_free(struct intel_set_config *config) -{ - if (!config) - return; - - kfree(config->save_connector_encoders); - kfree(config->save_encoder_crtcs); - kfree(config->save_crtc_enabled); - kfree(config); -} - -static int intel_set_config_save_state(struct drm_device *dev, - struct intel_set_config *config) -{ - struct drm_crtc *crtc; - struct drm_encoder *encoder; - struct drm_connector *connector; - int count; - - config->save_crtc_enabled = - kcalloc(dev->mode_config.num_crtc, - sizeof(bool), GFP_KERNEL); - if (!config->save_crtc_enabled) - return -ENOMEM; - - config->save_encoder_crtcs = - kcalloc(dev->mode_config.num_encoder, - sizeof(struct drm_crtc *), GFP_KERNEL); - if (!config->save_encoder_crtcs) - return -ENOMEM; - - config->save_connector_encoders = - kcalloc(dev->mode_config.num_connector, - sizeof(struct drm_encoder *), GFP_KERNEL); - if (!config->save_connector_encoders) - return -ENOMEM; - - /* Copy data. Note that driver private data is not affected. - * Should anything bad happen only the expected state is - * restored, not the drivers personal bookkeeping. - */ - count = 0; - for_each_crtc(dev, crtc) { - config->save_crtc_enabled[count++] = crtc->state->enable; - } - - count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - config->save_encoder_crtcs[count++] = encoder->crtc; - } - - count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - config->save_connector_encoders[count++] = connector->encoder; - } - - return 0; -} - -static void intel_set_config_restore_state(struct drm_device *dev, - struct intel_set_config *config) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - int count; - - count = 0; - for_each_intel_crtc(dev, crtc) { - crtc->new_enabled = config->save_crtc_enabled[count++]; - } - - count = 0; - for_each_intel_encoder(dev, encoder) { - encoder->new_crtc = - to_intel_crtc(config->save_encoder_crtcs[count++]); - } - - count = 0; - for_each_intel_connector(dev, connector) { - connector->new_encoder = - to_intel_encoder(config->save_connector_encoders[count++]); - } -} - static bool is_crtc_connector_off(struct drm_mode_set *set) { @@ -12872,7 +12787,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; - struct intel_set_config *config; struct intel_crtc_state *pipe_config; bool primary_plane_was_visible; int ret; @@ -12895,37 +12809,26 @@ static int intel_crtc_set_config(struct drm_mode_set *set) dev = set->crtc->dev; - ret = -ENOMEM; - config = kzalloc(sizeof(*config), GFP_KERNEL); - if (!config) - goto out_config; - - ret = intel_set_config_save_state(dev, config); - if (ret) - goto out_config; - state = drm_atomic_state_alloc(dev); - if (!state) { - ret = -ENOMEM; - goto out_config; - } + if (!state) + return -ENOMEM; state->acquire_ctx = dev->mode_config.acquire_ctx; ret = intel_modeset_stage_output_state(dev, set, state); if (ret) - goto fail; + goto out; ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, set->fb, set->x, set->y); if (ret) - goto fail; + goto out; pipe_config = intel_modeset_compute_config(set->crtc, set->mode, state); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); - goto fail; + goto out; } /* Compute whether we need a full modeset, only an fb base update or no @@ -12972,14 +12875,10 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) { DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", set->crtc->base.id, ret); -fail: - intel_set_config_restore_state(dev, config); } -out_config: +out: drm_atomic_state_free(state); - - intel_set_config_free(config); return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6fe36ddbb42f..930ea6916d9f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -813,15 +813,6 @@ struct intel_unpin_work { bool enable_stall_check; }; -struct intel_set_config { - struct drm_encoder **save_connector_encoders; - struct drm_crtc **save_encoder_crtcs; - bool *save_crtc_enabled; - - bool fb_changed; - bool mode_changed; -}; - struct intel_load_detect_pipe { struct drm_framebuffer *release_fb; bool load_detect_temp; -- cgit v1.2.3 From 0f63cca2afdc38877e86acfa9821020f6e2213fd Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:17 +0300 Subject: drm/i915: Update crtc state active flag based on DPMS In a follow up patch the function that computes mode changes will be replaced with the one from the atomic helpers. To preserve the behavior of legacy modeset forcing DPMS on, that function will need to detect a change in the active state of the crtc, so that has to be kept up to date. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 210e7c4f881b..44b3b5a7ad34 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6107,6 +6107,8 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) enable |= intel_encoder->connectors_active; intel_crtc_control(crtc, enable); + + crtc->state->active = enable; } static void intel_crtc_disable(struct drm_crtc *crtc) -- cgit v1.2.3 From 840bfe953384a134c8639f2964d9b74bfa671e16 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:18 +0300 Subject: drm/atomic: Make mode_fixup() optional for check_modeset() So the i915 driver can use the same logic for setting mode and active changed flags, without having to implement encoder helpers and the mode_fixup() callback. Cc: dri-devel@lists.freedestkop.org Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Acked-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5d30592c83cd..5e68c3c7d5cf 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -280,6 +280,8 @@ mode_fixup(struct drm_atomic_state *state) */ encoder = conn_state->best_encoder; funcs = encoder->helper_private; + if (!funcs) + continue; if (encoder->bridge && encoder->bridge->funcs->mode_fixup) { ret = encoder->bridge->funcs->mode_fixup( @@ -317,6 +319,9 @@ mode_fixup(struct drm_atomic_state *state) continue; funcs = crtc->helper_private; + if (!funcs->mode_fixup) + continue; + ret = funcs->mode_fixup(crtc, &crtc_state->mode, &crtc_state->adjusted_mode); if (!ret) { -- cgit v1.2.3 From 8c7b5ccb729870e606321b3703e2c2e698c49a95 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:19 +0300 Subject: drm/i915: Use atomic helpers for computing changed flags Replace the drivers own logic for computing mode_changed, active_changed and planes_changed flags with the check_modeset() atomic helper. Since that function needs to compare the crtc's new mode with the current, this patch also moves the set up of crtc_state->mode earlier in the call chain. Note that for the call to check_plane() to work properly, we need to check new plane state against new crtc state. But since we still use the plane update helper, which doesn't have a full atomic state, we need to hack around that in intel_plane_atomic_check(). Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 16 ++- drivers/gpu/drm/i915/intel_display.c | 197 ++++++------------------------ 2 files changed, 52 insertions(+), 161 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 77462e1360bc..86ba4b2c3a65 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -111,6 +111,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, { struct drm_crtc *crtc = state->crtc; struct intel_crtc *intel_crtc; + struct intel_crtc_state *crtc_state; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane_state *intel_state = to_intel_plane_state(state); @@ -126,6 +127,17 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0; + /* FIXME: temporary hack necessary while we still use the plane update + * helper. */ + if (state->state) { + crtc_state = + intel_atomic_get_crtc_state(state->state, intel_crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } else { + crtc_state = intel_crtc->config; + } + /* * The original src/dest coordinates are stored in state->base, but * we want to keep another copy internal to our driver that we can @@ -144,9 +156,9 @@ static int intel_plane_atomic_check(struct drm_plane *plane, intel_state->clip.x1 = 0; intel_state->clip.y1 = 0; intel_state->clip.x2 = - intel_crtc->active ? intel_crtc->config->pipe_src_w : 0; + crtc_state->base.active ? crtc_state->pipe_src_w : 0; intel_state->clip.y2 = - intel_crtc->active ? intel_crtc->config->pipe_src_h : 0; + crtc_state->base.active ? crtc_state->pipe_src_h : 0; /* * Disabling a plane is always okay; we just need to update diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 44b3b5a7ad34..db450772b4a5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -82,7 +82,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); -static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, +static int intel_set_mode(struct drm_crtc *crtc, struct drm_atomic_state *state); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, @@ -9892,7 +9892,9 @@ retry: if (ret) goto fail; - if (intel_set_mode(crtc, mode, state)) { + drm_mode_copy(&crtc_state->base.mode, mode); + + if (intel_set_mode(crtc, state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -9966,7 +9968,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - intel_set_mode(crtc, NULL, state); + intel_set_mode(crtc, state); drm_atomic_state_free(state); @@ -11476,7 +11478,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) static int intel_modeset_pipe_config(struct drm_crtc *crtc, - struct drm_display_mode *mode, struct drm_atomic_state *state, struct intel_crtc_state *pipe_config) { @@ -11499,10 +11500,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, clear_intel_crtc_state(pipe_config); - pipe_config->base.crtc = crtc; - drm_mode_copy(&pipe_config->base.adjusted_mode, mode); - drm_mode_copy(&pipe_config->base.mode, mode); - pipe_config->cpu_transcoder = (enum transcoder) to_intel_crtc(crtc)->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; @@ -12199,27 +12196,8 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static void -intel_atomic_modeset_compute_changed_flags(struct drm_atomic_state *state, - struct drm_crtc *modeset_crtc) -{ - struct drm_crtc_state *crtc_state; - struct drm_crtc *crtc; - int i; - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc_state->enable != crtc->state->enable) - crtc_state->mode_changed = true; - - /* FIXME: Do we need to always set mode_changed for - * modeset_crtc if it is enabled? modeset_affect_pipes() - * did that. */ - } -} - static struct intel_crtc_state * intel_modeset_compute_config(struct drm_crtc *crtc, - struct drm_display_mode *mode, struct drm_atomic_state *state) { struct intel_crtc_state *pipe_config; @@ -12229,7 +12207,9 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (ret) return ERR_PTR(ret); - intel_atomic_modeset_compute_changed_flags(state, crtc); + ret = drm_atomic_helper_check_modeset(state->dev, state); + if (ret) + return ERR_PTR(ret); /* * Note this needs changes when we start tracking multiple modes @@ -12244,7 +12224,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (!pipe_config->base.enable) return pipe_config; - ret = intel_modeset_pipe_config(crtc, mode, state, pipe_config); + ret = intel_modeset_pipe_config(crtc, state, pipe_config); if (ret) return ERR_PTR(ret); @@ -12262,6 +12242,10 @@ intel_modeset_compute_config(struct drm_crtc *crtc, intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,"[modeset]"); + ret = drm_atomic_helper_check_planes(state->dev, state); + if (ret) + return ERR_PTR(ret); + return pipe_config; } @@ -12337,7 +12321,6 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) } static int __intel_set_mode(struct drm_crtc *modeset_crtc, - struct drm_display_mode *mode, struct intel_crtc_state *pipe_config) { struct drm_device *dev = modeset_crtc->dev; @@ -12380,7 +12363,7 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, * single crtc and mode. */ if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { - modeset_crtc->mode = *mode; + modeset_crtc->mode = pipe_config->base.mode; /* mode_set/enable/disable functions rely on a correct pipe * config. */ intel_crtc_set_state(to_intel_crtc(modeset_crtc), pipe_config); @@ -12446,12 +12429,11 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, } static int intel_set_mode_with_config(struct drm_crtc *crtc, - struct drm_display_mode *mode, struct intel_crtc_state *pipe_config) { int ret; - ret = __intel_set_mode(crtc, mode, pipe_config); + ret = __intel_set_mode(crtc, pipe_config); if (ret == 0) intel_modeset_check_state(crtc->dev); @@ -12460,19 +12442,18 @@ static int intel_set_mode_with_config(struct drm_crtc *crtc, } static int intel_set_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode, struct drm_atomic_state *state) { struct intel_crtc_state *pipe_config; int ret = 0; - pipe_config = intel_modeset_compute_config(crtc, mode, state); + pipe_config = intel_modeset_compute_config(crtc, state); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); goto out; } - ret = intel_set_mode_with_config(crtc, mode, pipe_config); + ret = intel_set_mode_with_config(crtc, pipe_config); if (ret) goto out; @@ -12539,125 +12520,21 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } crtc_state->base.enable = intel_crtc->new_enabled; + + if (&intel_crtc->base == crtc) + drm_mode_copy(&crtc_state->base.mode, &crtc->mode); } intel_modeset_setup_plane_state(state, crtc, &crtc->mode, crtc->primary->fb, crtc->x, crtc->y); - intel_set_mode(crtc, &crtc->mode, state); + intel_set_mode(crtc, state); drm_atomic_state_free(state); } #undef for_each_intel_crtc_masked -static bool -is_crtc_connector_off(struct drm_mode_set *set) -{ - int i; - - if (set->num_connectors == 0) - return false; - - if (WARN_ON(set->connectors == NULL)) - return false; - - for (i = 0; i < set->num_connectors; i++) - if (set->connectors[i]->encoder && - set->connectors[i]->encoder->crtc == set->crtc && - set->connectors[i]->dpms != DRM_MODE_DPMS_ON) - return true; - - return false; -} - -static void -intel_set_config_compute_mode_changes(struct drm_mode_set *set, - struct intel_crtc_state *pipe_config) -{ - struct drm_atomic_state *state; - struct drm_connector *connector; - struct drm_connector_state *connector_state; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i; - - /* We should be able to check here if the fb has the same properties - * and then just flip_or_move it */ - if (is_crtc_connector_off(set)) { - pipe_config->base.mode_changed = true; - } else if (set->crtc->primary->fb != set->fb) { - /* - * If we have no fb, we can only flip as long as the crtc is - * active, otherwise we need a full mode set. The crtc may - * be active if we've only disabled the primary plane, or - * in fastboot situations. - */ - if (set->crtc->primary->fb == NULL) { - struct intel_crtc *intel_crtc = - to_intel_crtc(set->crtc); - - if (intel_crtc->active) { - DRM_DEBUG_KMS("crtc has no fb, will flip\n"); - pipe_config->base.planes_changed = true; - } else { - DRM_DEBUG_KMS("inactive crtc, full mode set\n"); - pipe_config->base.mode_changed = true; - } - } else if (set->fb == NULL) { - pipe_config->base.mode_changed = true; - } else if (set->fb->pixel_format != - set->crtc->primary->fb->pixel_format) { - pipe_config->base.mode_changed = true; - } else { - pipe_config->base.planes_changed = true; - } - } - - if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) - pipe_config->base.planes_changed = true; - - if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { - DRM_DEBUG_KMS("modes are different, full mode set\n"); - drm_mode_debug_printmodeline(&set->crtc->mode); - drm_mode_debug_printmodeline(set->mode); - pipe_config->base.mode_changed = true; - } - - state = pipe_config->base.state; - - for_each_connector_in_state(state, connector, connector_state, i) { - if (connector_state->best_encoder != - connector->state->best_encoder) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] encoder changed, full mode switch\n", - connector->base.id, - connector->name); - pipe_config->base.mode_changed = true; - } - - if (connector_state->crtc != connector->state->crtc) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] crtc changed, full mode switch\n", - connector->base.id, - connector->name); - pipe_config->base.mode_changed = true; - } - } - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc_state->enable == crtc->state->enable) - continue; - - DRM_DEBUG_KMS("[CRTC:%d] %sabled, full mode switch\n", - crtc->base.id, - crtc_state->enable ? "en" : "dis"); - pipe_config->base.mode_changed = true; - } - - DRM_DEBUG_KMS("computed changes for [CRTC:%d], mode_changed=%d, fb_changed=%d\n", - set->crtc->base.id, pipe_config->base.mode_changed, - pipe_config->base.planes_changed); -} - static bool intel_connector_in_mode_set(struct intel_connector *connector, struct drm_mode_set *set) { @@ -12774,6 +12651,21 @@ intel_modeset_stage_output_state(struct drm_device *dev, crtc_state->enable = drm_atomic_connectors_for_crtc(state, crtc); } + ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, + set->fb, set->x, set->y); + if (ret) + return ret; + + crtc_state = drm_atomic_get_crtc_state(state, set->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (set->mode) + drm_mode_copy(&crtc_state->mode, set->mode); + + if (set->num_connectors) + crtc_state->active = true; + return 0; } @@ -12821,30 +12713,17 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) goto out; - ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, - set->fb, set->x, set->y); - if (ret) - goto out; - - pipe_config = intel_modeset_compute_config(set->crtc, set->mode, - state); + pipe_config = intel_modeset_compute_config(set->crtc, state); if (IS_ERR(pipe_config)) { ret = PTR_ERR(pipe_config); goto out; } - /* Compute whether we need a full modeset, only an fb base update or no - * change at all. In the future we might also check whether only the - * mode changed, e.g. for LVDS where we only change the panel fitter in - * such cases. */ - intel_set_config_compute_mode_changes(set, pipe_config); - intel_update_pipe_size(to_intel_crtc(set->crtc)); primary_plane_was_visible = primary_plane_visible(set->crtc); - ret = intel_set_mode_with_config(set->crtc, set->mode, - pipe_config); + ret = intel_set_mode_with_config(set->crtc, pipe_config); if (ret == 0 && pipe_config->base.enable && -- cgit v1.2.3 From 2bfb4627580ae91d2978e1c071ed1a4b5039f2fd Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:20 +0300 Subject: drm/i915: Take ownership of atomic state on success in intel_set_mode() To match the behavior of ->atomic_commit(). Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index db450772b4a5..e3e4a04a18bf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9968,9 +9968,9 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - intel_set_mode(crtc, state); - - drm_atomic_state_free(state); + ret = intel_set_mode(crtc, state); + if (ret) + goto fail; if (old->release_fb) { drm_framebuffer_unregister_private(old->release_fb); @@ -12425,6 +12425,8 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, intel_crtc->config = crtc_state_copy; intel_crtc->base.state = &crtc_state_copy->base; + drm_atomic_state_free(state); + return 0; } @@ -12470,6 +12472,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) struct intel_connector *connector; struct drm_connector_state *connector_state; struct intel_crtc_state *crtc_state; + int ret; state = drm_atomic_state_alloc(dev); if (!state) { @@ -12528,9 +12531,9 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) intel_modeset_setup_plane_state(state, crtc, &crtc->mode, crtc->primary->fb, crtc->x, crtc->y); - intel_set_mode(crtc, state); - - drm_atomic_state_free(state); + ret = intel_set_mode(crtc, state); + if (ret) + drm_atomic_state_free(state); } #undef for_each_intel_crtc_masked @@ -12759,7 +12762,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) } out: - drm_atomic_state_free(state); + if (ret) + drm_atomic_state_free(state); return ret; } -- cgit v1.2.3 From 4978cc93d9ac240b435ce60431aef24239b4c270 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:21 +0300 Subject: drm/i915: Preserve shared DPLL information in new pipe_config When a new pipe_config is calculated, the fields related to shared dplls are reset, under the assumption that they will be recalculated as part of the modeset, which is true with the current state of the code. As we convert to atomic, however, it will be possible to calculate a new pipe_config and skip the modeset. In that case, after the state swap we still want the shared dplls to be preserved. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e3e4a04a18bf..b392ce3dd6c1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11467,13 +11467,21 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) { struct drm_crtc_state tmp_state; struct intel_crtc_scaler_state scaler_state; + struct intel_dpll_hw_state dpll_hw_state; + enum intel_dpll_id shared_dpll; /* Clear only the intel specific part of the crtc state excluding scalers */ tmp_state = crtc_state->base; scaler_state = crtc_state->scaler_state; + shared_dpll = crtc_state->shared_dpll; + dpll_hw_state = crtc_state->dpll_hw_state; + memset(crtc_state, 0, sizeof *crtc_state); + crtc_state->base = tmp_state; crtc_state->scaler_state = scaler_state; + crtc_state->shared_dpll = shared_dpll; + crtc_state->dpll_hw_state = dpll_hw_state; } static int @@ -11502,7 +11510,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, pipe_config->cpu_transcoder = (enum transcoder) to_intel_crtc(crtc)->pipe; - pipe_config->shared_dpll = DPLL_ID_PRIVATE; /* * Sanitize sync polarity flags based on requested ones. If neither @@ -12266,9 +12273,14 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) for_each_crtc_in_state(state, crtc, crtc_state, i) { intel_crtc = to_intel_crtc(crtc); + intel_crtc_state = to_intel_crtc_state(crtc_state); - if (needs_modeset(crtc_state)) + if (needs_modeset(crtc_state)) { clear_pipes |= 1 << intel_crtc->pipe; + intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE; + memset(&intel_crtc_state->dpll_hw_state, 0, + sizeof(intel_crtc_state->dpll_hw_state)); + } } ret = intel_shared_dpll_start_config(dev_priv, clear_pipes); -- cgit v1.2.3 From d4afb8cc3a6a68fe2eddf027b80826d3b7f5b304 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:22 +0300 Subject: drm/i915: Don't use plane update helper in legacy mode set Use lower level calls to better integrate with the modeset code and allow a full state swap in a follow up patch. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b392ce3dd6c1..73cd69c53db2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12332,6 +12332,23 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) return 0; } +static void __intel_set_mode_swap_plane_state(struct drm_device *dev, + struct drm_atomic_state *state) +{ + int i; + + for (i = 0; i < dev->mode_config.num_total_plane; i++) { + struct drm_plane *plane = state->planes[i]; + + if (!plane) + continue; + + plane->state->state = state; + swap(state->plane_states[i], plane->state); + plane->state->state = NULL; + } +} + static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct intel_crtc_state *pipe_config) { @@ -12342,8 +12359,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct intel_crtc *intel_crtc; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - struct drm_plane *plane; - struct drm_plane_state *plane_state; int ret = 0; int i; @@ -12351,6 +12366,10 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, if (ret < 0) return ret; + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) + return ret; + crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL); if (!crtc_state_copy) return -ENOMEM; @@ -12395,26 +12414,8 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, modeset_update_crtc_power_domains(state); - for_each_plane_in_state(state, plane, plane_state, i) { - if (WARN_ON(plane != modeset_crtc->primary)) - continue; - - /* Primary plane is disabled in intel_crtc_disable() */ - if (!pipe_config->base.enable) - continue; - - ret = drm_plane_helper_update(plane, plane_state->crtc, - plane_state->fb, - plane_state->crtc_x, - plane_state->crtc_y, - plane_state->crtc_w, - plane_state->crtc_h, - plane_state->src_x, - plane_state->src_y, - plane_state->src_w, - plane_state->src_h); - WARN_ON(ret != 0); - } + __intel_set_mode_swap_plane_state(dev, state); + drm_atomic_helper_commit_planes(dev, state); /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { @@ -12437,6 +12438,8 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, intel_crtc->config = crtc_state_copy; intel_crtc->base.state = &crtc_state_copy->base; + drm_atomic_helper_cleanup_planes(dev, state); + drm_atomic_state_free(state); return 0; -- cgit v1.2.3 From a821fc46bc7bb6d4cf9a5f8d2787fd70231c2c10 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:23 +0300 Subject: drm/i915: Swap atomic state in legacy modeset Replace the commit output state function with a simple swap of states. Note that we still need to reconcile the legacy state after the swap, since there are still code that relies on those. Also note that even though changes to the state of a crtc different than the one passed as an argument to __intel_set_mode() will be saved, the modeset logic still deals with only one crtc. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 117 ++++++++++++----------------------- 1 file changed, 39 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 73cd69c53db2..e4983c19829e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5728,16 +5728,21 @@ static int broxton_calc_cdclk(struct drm_i915_private *dev_priv, return 144000; } -/* compute the max pixel clock for new configuration */ -static int intel_mode_max_pixclk(struct drm_atomic_state *state) +/* Compute the max pixel clock for new configuration. Uses atomic state if + * that's non-NULL, look at current state otherwise. */ +static int intel_mode_max_pixclk(struct drm_device *dev, + struct drm_atomic_state *state) { - struct drm_device *dev = state->dev; struct intel_crtc *intel_crtc; struct intel_crtc_state *crtc_state; int max_pixclk = 0; for_each_intel_crtc(dev, intel_crtc) { - crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (state) + crtc_state = + intel_atomic_get_crtc_state(state, intel_crtc); + else + crtc_state = intel_crtc->config; if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); @@ -5756,7 +5761,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) struct drm_i915_private *dev_priv = to_i915(state->dev); struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - int max_pixclk = intel_mode_max_pixclk(state); + int max_pixclk = intel_mode_max_pixclk(state->dev, state); int cdclk, i; if (max_pixclk < 0) @@ -5824,18 +5829,15 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND); } -static void valleyview_modeset_global_resources(struct drm_atomic_state *state) +static void valleyview_modeset_global_resources(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; + struct drm_device *dev = old_state->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(state); + int max_pixclk = intel_mode_max_pixclk(dev, NULL); int req_cdclk; - /* The only reason this can fail is if we fail to add the crtc_state - * to the atomic state. But that can't happen since the call to - * intel_mode_max_pixclk() in valleyview_modeset_global_pipes() (which - * can't have failed otherwise the mode set would be aborted) added all - * the states already. */ + /* The path in intel_mode_max_pixclk() with a NULL atomic state should + * never fail. */ if (WARN_ON(max_pixclk < 0)) return; @@ -9154,11 +9156,11 @@ 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) +static void broxton_modeset_global_resources(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; + struct drm_device *dev = old_state->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(state); + int max_pixclk = intel_mode_max_pixclk(dev, NULL); int req_cdclk; /* see the comment in valleyview_modeset_global_resources */ @@ -11152,46 +11154,36 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) } } -/** - * intel_modeset_commit_output_state - * - * This function copies the stage display pipe configuration to the real one. - * - * FIXME: we want to replace this with a proper state swap in the future +/* Fixup legacy state after an atomic state swap. */ -static void intel_modeset_commit_output_state(struct drm_atomic_state *state) +static void intel_modeset_fixup_state(struct drm_atomic_state *state) { - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - struct drm_connector *connector; - struct drm_connector_state *connector_state; + struct intel_crtc *crtc; struct intel_encoder *encoder; - struct intel_connector *intel_connector; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) { - *connector->state = *connector_state; + struct intel_connector *connector; - connector->encoder = connector_state->best_encoder; - if (connector->encoder) - connector->encoder->crtc = connector_state->crtc; + for_each_intel_connector(state->dev, connector) { + connector->base.encoder = connector->base.state->best_encoder; + if (connector->base.encoder) + connector->base.encoder->crtc = + connector->base.state->crtc; } /* Update crtc of disabled encoders */ for_each_intel_encoder(state->dev, encoder) { int num_connectors = 0; - for_each_intel_connector(state->dev, intel_connector) - if (intel_connector->base.encoder == &encoder->base) + for_each_intel_connector(state->dev, connector) + if (connector->base.encoder == &encoder->base) num_connectors++; if (num_connectors == 0) encoder->base.crtc = NULL; } - for_each_crtc_in_state(state, crtc, crtc_state, i) { - crtc->state->enable = crtc_state->enable; - crtc->enabled = crtc_state->enable; + for_each_intel_crtc(state->dev, crtc) { + crtc->base.enabled = crtc->base.state->enable; + crtc->config = to_intel_crtc_state(crtc->base.state); } /* Copy the new configuration to the staged state, to keep the few @@ -11648,7 +11640,8 @@ intel_modeset_update_state(struct drm_atomic_state *state) intel_encoder->connectors_active = false; } - intel_modeset_commit_output_state(state); + drm_atomic_helper_swap_state(state->dev, state); + intel_modeset_fixup_state(state); /* Double check state. */ for_each_crtc(dev, crtc) { @@ -11666,7 +11659,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (crtc != connector->encoder->crtc) continue; - if (crtc_state->enable && needs_modeset(crtc_state)) { + if (crtc->state->enable && needs_modeset(crtc->state)) { struct drm_property *dpms_property = dev->mode_config.dpms_property; @@ -12332,31 +12325,12 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) return 0; } -static void __intel_set_mode_swap_plane_state(struct drm_device *dev, - struct drm_atomic_state *state) -{ - int i; - - for (i = 0; i < dev->mode_config.num_total_plane; i++) { - struct drm_plane *plane = state->planes[i]; - - if (!plane) - continue; - - plane->state->state = state; - swap(state->plane_states[i], plane->state); - plane->state->state = NULL; - } -} - static int __intel_set_mode(struct drm_crtc *modeset_crtc, struct intel_crtc_state *pipe_config) { struct drm_device *dev = modeset_crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_atomic_state *state = pipe_config->base.state; - struct intel_crtc_state *crtc_state_copy = NULL; - struct intel_crtc *intel_crtc; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret = 0; @@ -12370,10 +12344,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, if (ret) return ret; - crtc_state_copy = kmalloc(sizeof(*crtc_state_copy), GFP_KERNEL); - if (!crtc_state_copy) - return -ENOMEM; - for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!needs_modeset(crtc_state)) continue; @@ -12395,9 +12365,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, */ if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { modeset_crtc->mode = pipe_config->base.mode; - /* mode_set/enable/disable functions rely on a correct pipe - * config. */ - intel_crtc_set_state(to_intel_crtc(modeset_crtc), pipe_config); /* * Calculate and store various constants which @@ -12412,14 +12379,16 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, * update the the output configuration. */ intel_modeset_update_state(state); + /* The state has been swaped above, so state actually contains the + * old state now. */ + modeset_update_crtc_power_domains(state); - __intel_set_mode_swap_plane_state(dev, state); drm_atomic_helper_commit_planes(dev, state); /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state) || !crtc_state->enable) + if (!needs_modeset(crtc->state) || !crtc->state->enable) continue; update_scanline_offset(to_intel_crtc(crtc)); @@ -12430,14 +12399,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, /* FIXME: add subpixel order */ - intel_crtc = to_intel_crtc(modeset_crtc); - - /* The pipe_config will be freed with the atomic state, so - * make a copy. */ - memcpy(crtc_state_copy, intel_crtc->config, sizeof *crtc_state_copy); - intel_crtc->config = crtc_state_copy; - intel_crtc->base.state = &crtc_state_copy->base; - drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); -- cgit v1.2.3 From 550acefd229dc3ef1be00c3355ecccca8fe8bf2b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 21 Apr 2015 17:13:24 +0300 Subject: drm/i915: Get rid of intel_crtc_set_state() Now that we do proper state swaps, we don't depend on this function anymore to keep the state in sync. Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4983c19829e..b5806400d40e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10256,14 +10256,6 @@ void intel_mark_idle(struct drm_device *dev) intel_runtime_pm_put(dev_priv); } -static void intel_crtc_set_state(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state) -{ - kfree(crtc->config); - crtc->config = crtc_state; - crtc->base.state = &crtc_state->base; -} - static void intel_crtc_destroy(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -10280,7 +10272,6 @@ static void intel_crtc_destroy(struct drm_crtc *crtc) kfree(work); } - intel_crtc_set_state(intel_crtc, NULL); drm_crtc_cleanup(crtc); kfree(intel_crtc); @@ -13502,7 +13493,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); if (!crtc_state) goto fail; - intel_crtc_set_state(intel_crtc, crtc_state); + intel_crtc->config = crtc_state; + intel_crtc->base.state = &crtc_state->base; crtc_state->base.crtc = &intel_crtc->base; /* initialize shared scalers */ -- cgit v1.2.3 From 637a9c63f84263ebfdb27440b81d6e18e5d35754 Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Thu, 7 May 2015 09:52:08 +0530 Subject: drm/i915: Rename dp rates array as per platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renaming gen9_rates to skl_rates because other platforms may have different supported rates. Signed-off-by: Sonika Jindal Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d0a88602efab..b4c5b9bb6207 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -90,8 +90,8 @@ static const struct dp_link_dpll chv_dpll[] = { { DP_LINK_BW_5_4, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; -/* Skylake supports following rates */ -static const int gen9_rates[] = { 162000, 216000, 270000, + +static const int skl_rates[] = { 162000, 216000, 270000, 324000, 432000, 540000 }; static const int chv_rates[] = { 162000, 202500, 210000, 216000, 243000, 270000, 324000, 405000, @@ -1167,9 +1167,9 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) static int intel_dp_source_rates(struct drm_device *dev, const int **source_rates) { - if (INTEL_INFO(dev)->gen >= 9) { - *source_rates = gen9_rates; - return ARRAY_SIZE(gen9_rates); + if (IS_SKYLAKE(dev)) { + *source_rates = skl_rates; + return ARRAY_SIZE(skl_rates); } else if (IS_CHERRYVIEW(dev)) { *source_rates = chv_rates; return ARRAY_SIZE(chv_rates); -- cgit v1.2.3 From 432be69d9d7e7e23f994422690639f3aa1d6abc2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 7 May 2015 12:14:55 +0100 Subject: drm/i915: Remove locking for get-caching query Reading a single value from the object, the locking only provides futile protection against userspace races. The locking is useless so remove it. Signed-off-by: Chris Wilson Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c378f0421145..9c195cc9065b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3842,17 +3842,10 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, { struct drm_i915_gem_caching *args = data; struct drm_i915_gem_object *obj; - int ret; - - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (&obj->base == NULL) { - ret = -ENOENT; - goto unlock; - } + if (&obj->base == NULL) + return -ENOENT; switch (obj->cache_level) { case I915_CACHE_LLC: @@ -3869,10 +3862,8 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, break; } - drm_gem_object_unreference(&obj->base); -unlock: - mutex_unlock(&dev->struct_mutex); - return ret; + drm_gem_object_unreference_unlocked(&obj->base); + return 0; } int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, -- cgit v1.2.3 From b0e6f6d4b073f11c351163adf98fc7d7eb972541 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:29 +0100 Subject: drm/i915/bxt: Mark WaDisablePartialInstShootdown as for Broxton also. Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7ef9a29405cd..49e46106aa90 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -919,7 +919,7 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - /* WaDisablePartialInstShootdown:skl */ + /* WaDisablePartialInstShootdown:skl,bxt */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); -- cgit v1.2.3 From a119a6e66e0a57fcab927514cd6dbd148490d6d5 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:30 +0100 Subject: drm/i915/bxt: Mark workaround as for Skylake & Broxton Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 49e46106aa90..cdbdf49bbab9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -923,7 +923,7 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); - /* Syncing dependencies between camera and graphics */ + /* Syncing dependencies between camera and graphics:skl,bxt */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); -- cgit v1.2.3 From d2a31dbd67d44ac9b9435fddba5a99696298afa6 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:31 +0100 Subject: drm/i915/bxt: Enable WaDisableDgMirrorFixInHalfSliceChicken5 for Broxton Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index cdbdf49bbab9..4b0d48bccb9b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -927,9 +927,10 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); - if (INTEL_REVID(dev) == SKL_REVID_A0 || - INTEL_REVID(dev) == SKL_REVID_B0) { - /* WaDisableDgMirrorFixInHalfSliceChicken5:skl */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) == SKL_REVID_A0 || + INTEL_REVID(dev) == SKL_REVID_B0)) || + (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) { + /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */ WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, GEN9_DG_MIRROR_FIX_ENABLE); } -- cgit v1.2.3 From a13d215fe75d0b98b9841654b56dcd6e8cc796e4 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:32 +0100 Subject: drm/i915/bxt: Enable WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken for Broxton Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4b0d48bccb9b..8404e0c318e7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -935,8 +935,9 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) GEN9_DG_MIRROR_FIX_ENABLE); } - if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) { - /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl */ + if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) || + (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) { + /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1, GEN9_RHWO_OPTIMIZATION_DISABLE); WA_SET_BIT_MASKED(GEN9_SLICE_COMMON_ECO_CHICKEN0, -- cgit v1.2.3 From 27a1b688d9f1fa2abd14bfe6a8729a19fb3b1b25 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:33 +0100 Subject: drm/i915/bxt: Enable WaEnableYV12BugFixInHalfSliceChicken7 for Broxton Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8404e0c318e7..e8eeea190687 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -944,8 +944,9 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) DISABLE_PIXEL_MASK_CAMMING); } - if (INTEL_REVID(dev) >= SKL_REVID_C0) { - /* WaEnableYV12BugFixInHalfSliceChicken7:skl */ + if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) || + IS_BROXTON(dev)) { + /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */ WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, GEN9_ENABLE_YV12_BUGFIX); } -- cgit v1.2.3 From b62adbd1ea1f65e82ac7b3ec79f9f4873e193a10 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:34 +0100 Subject: drm/i915/bxt: Move WaForceEnableNonCoherent to Skylake only Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e8eeea190687..885932488282 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -951,17 +951,6 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) GEN9_ENABLE_YV12_BUGFIX); } - if (INTEL_REVID(dev) <= SKL_REVID_D0) { - /* - *Use Force Non-Coherent whenever executing a 3D context. This - * is a workaround for a possible hang in the unlikely event - * a TLB invalidation occurs during a PSD flush. - */ - /* WaForceEnableNonCoherent:skl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FORCE_NON_COHERENT); - } - /* Wa4x4STCOptimizationDisable:skl */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); @@ -1039,6 +1028,17 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HIZ_CHICKEN, BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); + if (INTEL_REVID(dev) <= SKL_REVID_D0) { + /* + *Use Force Non-Coherent whenever executing a 3D context. This + * is a workaround for a possible hang in the unlikely event + * a TLB invalidation occurs during a PSD flush. + */ + /* WaForceEnableNonCoherent:skl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FORCE_NON_COHERENT); + } + return skl_tune_iz_hashing(ring); } -- cgit v1.2.3 From 5068368c2e3455c91f8c0c1a8f39eb511b184822 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:35 +0100 Subject: drm/i915/bxt: Mark Wa4x4STCOptimizationDisable as for Broxton also. Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 885932488282..cf516ad1b029 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -951,7 +951,7 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) GEN9_ENABLE_YV12_BUGFIX); } - /* Wa4x4STCOptimizationDisable:skl */ + /* Wa4x4STCOptimizationDisable:skl,bxt */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); /* WaDisablePartialResolveInVc:skl */ -- cgit v1.2.3 From 27160c96e1897c541fa72a86fcfa2f2f67f73876 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:36 +0100 Subject: drm/i915/bxt: Mark WaDisablePartialResolveInVc as for Broxton also. Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index cf516ad1b029..e74feedd6bee 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -954,7 +954,7 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) /* Wa4x4STCOptimizationDisable:skl,bxt */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE); - /* WaDisablePartialResolveInVc:skl */ + /* WaDisablePartialResolveInVc:skl,bxt */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE); /* WaCcsTlbPrefetchDisable:skl */ -- cgit v1.2.3 From 16be17af2ae9fd1544b5d0c58b4facf198031cb8 Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Thu, 7 May 2015 14:15:37 +0100 Subject: drm/i915/bxt: Mark WaCcsTlbPrefetchDisable as for Broxton also. Signed-off-by: Nick Hoath Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e74feedd6bee..9b96ed7de9bb 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -957,7 +957,7 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) /* WaDisablePartialResolveInVc:skl,bxt */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE); - /* WaCcsTlbPrefetchDisable:skl */ + /* WaCcsTlbPrefetchDisable:skl,bxt */ WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, GEN9_CCS_TLB_PREFETCH_ENABLE); -- cgit v1.2.3 From 91e6711e30c55d7493eed5c3852764e38a782cad Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 6 May 2015 14:33:58 +0300 Subject: drm/i915: Do not make assumptions on GGTT VMA sizes GGTT VMA sizes might be smaller than the whole object size due to different GGTT views. v2: - Separate GGTT view constraint calculations from normal view constraint calculations (Chris Wilson) v3: - Do not bother with debug wording. (Tvrtko Ursulin) v4: - Clearer logic for calculating map_and_fenceable (Tvrtko Ursulin) Cc: Chris Wilson Cc: Tvrtko Ursulin Signed-off-by: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin [danvet: Drop BUG_ON, it's redudant.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 74 +++++++++++++++++++++++++------------ drivers/gpu/drm/i915/i915_gem_gtt.c | 20 ++++++++++ drivers/gpu/drm/i915/i915_gem_gtt.h | 4 ++ 3 files changed, 74 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9c195cc9065b..18307dfdc679 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3498,7 +3498,8 @@ static bool i915_gem_valid_gtt_space(struct i915_vma *vma, } /** - * Finds free space in the GTT aperture and binds the object there. + * Finds free space in the GTT aperture and binds the object or a view of it + * there. */ static struct i915_vma * i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, @@ -3517,36 +3518,60 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, struct i915_vma *vma; int ret; - if(WARN_ON(i915_is_ggtt(vm) != !!ggtt_view)) - return ERR_PTR(-EINVAL); + if (i915_is_ggtt(vm)) { + u32 view_size; + + if (WARN_ON(!ggtt_view)) + return ERR_PTR(-EINVAL); - fence_size = i915_gem_get_gtt_size(dev, - obj->base.size, - obj->tiling_mode); - fence_alignment = i915_gem_get_gtt_alignment(dev, - obj->base.size, - obj->tiling_mode, true); - unfenced_alignment = - i915_gem_get_gtt_alignment(dev, - obj->base.size, - obj->tiling_mode, false); + view_size = i915_ggtt_view_size(obj, ggtt_view); + + fence_size = i915_gem_get_gtt_size(dev, + view_size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(dev, + view_size, + obj->tiling_mode, + true); + unfenced_alignment = i915_gem_get_gtt_alignment(dev, + view_size, + obj->tiling_mode, + false); + size = flags & PIN_MAPPABLE ? fence_size : view_size; + } else { + fence_size = i915_gem_get_gtt_size(dev, + obj->base.size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode, + true); + unfenced_alignment = + i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode, + false); + size = flags & PIN_MAPPABLE ? fence_size : obj->base.size; + } if (alignment == 0) alignment = flags & PIN_MAPPABLE ? fence_alignment : unfenced_alignment; if (flags & PIN_MAPPABLE && alignment & (fence_alignment - 1)) { - DRM_DEBUG("Invalid object alignment requested %u\n", alignment); + DRM_DEBUG("Invalid object (view type=%u) alignment requested %u\n", + ggtt_view ? ggtt_view->type : 0, + alignment); return ERR_PTR(-EINVAL); } - size = flags & PIN_MAPPABLE ? fence_size : obj->base.size; - - /* If the object is bigger than the entire aperture, reject it early - * before evicting everything in a vain attempt to find space. + /* If binding the object/GGTT view requires more space than the entire + * aperture has, reject it early before evicting everything in a vain + * attempt to find space. */ - if (obj->base.size > end) { - DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%lu\n", - obj->base.size, + if (size > end) { + DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%lu\n", + ggtt_view ? ggtt_view->type : 0, + size, flags & PIN_MAPPABLE ? "mappable" : "total", end); return ERR_PTR(-E2BIG); @@ -4199,7 +4224,8 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj, return ret; } - if ((bound ^ vma->bound) & GLOBAL_BIND) { + if (ggtt_view && ggtt_view->type == I915_GGTT_VIEW_NORMAL && + (bound ^ vma->bound) & GLOBAL_BIND) { bool mappable, fenceable; u32 fence_size, fence_alignment; @@ -4218,9 +4244,9 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj, dev_priv->gtt.mappable_end); obj->map_and_fenceable = mappable && fenceable; - } - WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable); + WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable); + } vma->pin_count++; return 0; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 8fee6789fae2..2b7c77b987bc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2838,3 +2838,23 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, return 0; } + +/** + * i915_ggtt_view_size - Get the size of a GGTT view. + * @obj: Object the view is of. + * @view: The view in question. + * + * @return The size of the GGTT view in bytes. + */ +size_t +i915_ggtt_view_size(struct drm_i915_gem_object *obj, + const struct i915_ggtt_view *view) +{ + if (view->type == I915_GGTT_VIEW_NORMAL || + view->type == I915_GGTT_VIEW_ROTATED) { + return obj->base.size; + } else { + WARN_ONCE(1, "GGTT view %u not implemented!\n", view->type); + return obj->base.size; + } +} diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 4e6cac575cd8..34b7cca3df13 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -498,4 +498,8 @@ i915_ggtt_view_equal(const struct i915_ggtt_view *a, return a->type == b->type; } +size_t +i915_ggtt_view_size(struct drm_i915_gem_object *obj, + const struct i915_ggtt_view *view); + #endif -- cgit v1.2.3 From a6631ae1fd868b893986f3a613c231e34877b7b5 Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 6 May 2015 14:34:58 +0300 Subject: drm/i915: Consider object pinned if any VMA is pinned Do not skip special GGTT views when considering whether an object is pinned or not. Wrong behaviour was introduced in; commit ec7adb6ee79c8c9fe64d63ad638a31cd62e55515 Author: Joonas Lahtinen Date: Mon Mar 16 14:11:13 2015 +0200 drm/i915: Do not use ggtt_view with (aliasing) PPGTT Cc: Daniel Vetter Cc: Tvrtko Ursulin Signed-off-by: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 18307dfdc679..04d18bc7bf53 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5244,13 +5244,10 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o, bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) { struct i915_vma *vma; - list_for_each_entry(vma, &obj->vma_list, vma_link) { - if (i915_is_ggtt(vma->vm) && - vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) - continue; + list_for_each_entry(vma, &obj->vma_list, vma_link) if (vma->pin_count > 0) return true; - } + return false; } -- cgit v1.2.3 From 8bd7ef1638611db5f4fe47813758588b610ee5aa Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 6 May 2015 14:35:38 +0300 Subject: drm/i915: Add a partial GGTT view type Partial view type allows manipulating parts of huge BOs through the GGTT, which was not previously possible due to constraint that whole object had to be mapped for any access to it through GGTT. v2: - Retain error value from sg_alloc_table (Tvrtko Ursulin) - Do not zero already zeroed variable (Tvrtko Ursulin) - Use more common variable types for page size/offset (Tvrtko Ursulin) v3: - Only compare additional view parameters when need to (Tvrtko Ursulin) v4: - Do zero out the variable that needs to be (bug introduced in v2). Cc: Tvrtko Ursulin Signed-off-by: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 46 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_gtt.h | 16 +++++++++++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2b7c77b987bc..e3bcc3ba7e40 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2753,6 +2753,47 @@ err_st_alloc: return ERR_PTR(ret); } +static struct sg_table * +intel_partial_pages(const struct i915_ggtt_view *view, + struct drm_i915_gem_object *obj) +{ + struct sg_table *st; + struct scatterlist *sg; + struct sg_page_iter obj_sg_iter; + int ret = -ENOMEM; + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (!st) + goto err_st_alloc; + + ret = sg_alloc_table(st, view->params.partial.size, GFP_KERNEL); + if (ret) + goto err_sg_alloc; + + sg = st->sgl; + st->nents = 0; + for_each_sg_page(obj->pages->sgl, &obj_sg_iter, obj->pages->nents, + view->params.partial.offset) + { + if (st->nents >= view->params.partial.size) + break; + + sg_set_page(sg, NULL, PAGE_SIZE, 0); + sg_dma_address(sg) = sg_page_iter_dma_address(&obj_sg_iter); + sg_dma_len(sg) = PAGE_SIZE; + + sg = sg_next(sg); + st->nents++; + } + + return st; + +err_sg_alloc: + kfree(st); +err_st_alloc: + return ERR_PTR(ret); +} + static int i915_get_ggtt_vma_pages(struct i915_vma *vma) { @@ -2766,6 +2807,9 @@ i915_get_ggtt_vma_pages(struct i915_vma *vma) else if (vma->ggtt_view.type == I915_GGTT_VIEW_ROTATED) vma->ggtt_view.pages = intel_rotate_fb_obj_pages(&vma->ggtt_view, vma->obj); + else if (vma->ggtt_view.type == I915_GGTT_VIEW_PARTIAL) + vma->ggtt_view.pages = + intel_partial_pages(&vma->ggtt_view, vma->obj); else WARN_ONCE(1, "GGTT view %u not implemented!\n", vma->ggtt_view.type); @@ -2853,6 +2897,8 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj, if (view->type == I915_GGTT_VIEW_NORMAL || view->type == I915_GGTT_VIEW_ROTATED) { return obj->base.size; + } else if (view->type == I915_GGTT_VIEW_PARTIAL) { + return view->params.partial.size << PAGE_SHIFT; } else { WARN_ONCE(1, "GGTT view %u not implemented!\n", view->type); return obj->base.size; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 34b7cca3df13..0d46dd20bf71 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -117,7 +117,8 @@ typedef uint64_t gen8_pde_t; enum i915_ggtt_view_type { I915_GGTT_VIEW_NORMAL = 0, - I915_GGTT_VIEW_ROTATED + I915_GGTT_VIEW_ROTATED, + I915_GGTT_VIEW_PARTIAL, }; struct intel_rotation_info { @@ -130,6 +131,13 @@ struct intel_rotation_info { struct i915_ggtt_view { enum i915_ggtt_view_type type; + union { + struct { + unsigned long offset; + unsigned int size; + } partial; + } params; + struct sg_table *pages; union { @@ -495,7 +503,11 @@ i915_ggtt_view_equal(const struct i915_ggtt_view *a, if (WARN_ON(!a || !b)) return false; - return a->type == b->type; + if (a->type != b->type) + return false; + if (a->type == I915_GGTT_VIEW_PARTIAL) + return !memcmp(&a->params, &b->params, sizeof(a->params)); + return true; } size_t -- cgit v1.2.3 From c5ad54cf7dd8922bd1cee2d5871aebf73dc9638e Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Wed, 6 May 2015 14:36:09 +0300 Subject: drm/i915: Use partial view in mmap fault handler Use partial view for huge BOs (bigger than half the mappable aperture) in fault handler so that they can be accessed withough trying to make room for them by evicting other objects. v2: - Only use partial views in the case where early rejection was previously done. - Account variable type changes from previous reroll. v3: - Add a comment about overwriting existing page entries. (Tvrtko Ursulin) - Whitespace fixes. Cc: Chris Wilson Cc: Tvrtko Ursulin Signed-off-by: Joonas Lahtinen Reviewed-by: Tvrtko Ursulin Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 73 ++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 04d18bc7bf53..b45f93bb030e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1635,6 +1635,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data); struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_ggtt_view view = i915_ggtt_view_normal; pgoff_t page_offset; unsigned long pfn; int ret = 0; @@ -1667,8 +1668,21 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) goto unlock; } - /* Now bind it into the GTT if needed */ - ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_MAPPABLE); + /* Use a partial view if the object is bigger than the aperture. */ + if (obj->base.size >= dev_priv->gtt.mappable_end) { + static const unsigned int chunk_size = 256; // 1 MiB + memset(&view, 0, sizeof(view)); + view.type = I915_GGTT_VIEW_PARTIAL; + view.params.partial.offset = rounddown(page_offset, chunk_size); + view.params.partial.size = + min_t(unsigned int, + chunk_size, + (vma->vm_end - vma->vm_start)/PAGE_SIZE - + view.params.partial.offset); + } + + /* Now pin it into the GTT if needed */ + ret = i915_gem_object_ggtt_pin(obj, &view, 0, PIN_MAPPABLE); if (ret) goto unlock; @@ -1681,30 +1695,50 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) goto unpin; /* Finally, remap it using the new GTT offset */ - pfn = dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj); + pfn = dev_priv->gtt.mappable_base + + i915_gem_obj_ggtt_offset_view(obj, &view); pfn >>= PAGE_SHIFT; - if (!obj->fault_mappable) { - unsigned long size = min_t(unsigned long, - vma->vm_end - vma->vm_start, - obj->base.size); - int i; + if (unlikely(view.type == I915_GGTT_VIEW_PARTIAL)) { + /* Overriding existing pages in partial view does not cause + * us any trouble as TLBs are still valid because the fault + * is due to userspace losing part of the mapping or never + * having accessed it before (at this partials' range). + */ + unsigned long base = vma->vm_start + + (view.params.partial.offset << PAGE_SHIFT); + unsigned int i; - for (i = 0; i < size >> PAGE_SHIFT; i++) { - ret = vm_insert_pfn(vma, - (unsigned long)vma->vm_start + i * PAGE_SIZE, - pfn + i); + for (i = 0; i < view.params.partial.size; i++) { + ret = vm_insert_pfn(vma, base + i * PAGE_SIZE, pfn + i); if (ret) break; } obj->fault_mappable = true; - } else - ret = vm_insert_pfn(vma, - (unsigned long)vmf->virtual_address, - pfn + page_offset); + } else { + if (!obj->fault_mappable) { + unsigned long size = min_t(unsigned long, + vma->vm_end - vma->vm_start, + obj->base.size); + int i; + + for (i = 0; i < size >> PAGE_SHIFT; i++) { + ret = vm_insert_pfn(vma, + (unsigned long)vma->vm_start + i * PAGE_SIZE, + pfn + i); + if (ret) + break; + } + + obj->fault_mappable = true; + } else + ret = vm_insert_pfn(vma, + (unsigned long)vmf->virtual_address, + pfn + page_offset); + } unpin: - i915_gem_object_ggtt_unpin(obj); + i915_gem_object_ggtt_unpin_view(obj, &view); unlock: mutex_unlock(&dev->struct_mutex); out: @@ -1897,11 +1931,6 @@ i915_gem_mmap_gtt(struct drm_file *file, goto unlock; } - if (obj->base.size > dev_priv->gtt.mappable_end) { - ret = -E2BIG; - goto out; - } - if (obj->madv != I915_MADV_WILLNEED) { DRM_DEBUG("Attempting to mmap a purgeable buffer\n"); ret = -EFAULT; -- cgit v1.2.3 From ebf7ed1a5bf859b092396c66a072c2cb797358bf Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:37 +0100 Subject: drm/i915/skl: Re-indent part of skl_ddi_calculate_wrpll() A part of this function was indented with 2 tabs and 1 space instead of just 2 tabs. We're going to touch that code, so start by re-indenting it. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 64 ++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index ec5d2eaef43c..807e15d41a1b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1189,69 +1189,69 @@ found: if (min_dco_index > 2) { WARN(1, "No valid values found for the given pixel clock\n"); } else { - wrpll_params->central_freq = dco_central_freq[min_dco_index]; + wrpll_params->central_freq = dco_central_freq[min_dco_index]; - switch (dco_central_freq[min_dco_index]) { - case 9600000000ULL: + switch (dco_central_freq[min_dco_index]) { + case 9600000000ULL: wrpll_params->central_freq = 0; break; - case 9000000000ULL: + case 9000000000ULL: wrpll_params->central_freq = 1; break; - case 8400000000ULL: + case 8400000000ULL: wrpll_params->central_freq = 3; - } + } - switch (candidate_p0[min_dco_index]) { - case 1: + switch (candidate_p0[min_dco_index]) { + case 1: wrpll_params->pdiv = 0; break; - case 2: + case 2: wrpll_params->pdiv = 1; break; - case 3: + case 3: wrpll_params->pdiv = 2; break; - case 7: + case 7: wrpll_params->pdiv = 4; break; - default: + default: WARN(1, "Incorrect PDiv\n"); - } + } - switch (candidate_p2[min_dco_index]) { - case 5: + switch (candidate_p2[min_dco_index]) { + case 5: wrpll_params->kdiv = 0; break; - case 2: + case 2: wrpll_params->kdiv = 1; break; - case 3: + case 3: wrpll_params->kdiv = 2; break; - case 1: + case 1: wrpll_params->kdiv = 3; break; - default: + default: WARN(1, "Incorrect KDiv\n"); - } + } - wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; - wrpll_params->qdiv_mode = + wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; + wrpll_params->qdiv_mode = (wrpll_params->qdiv_ratio == 1) ? 0 : 1; - dco_freq = candidate_p0[min_dco_index] * - candidate_p1[min_dco_index] * - candidate_p2[min_dco_index] * afe_clock; + dco_freq = candidate_p0[min_dco_index] * + candidate_p1[min_dco_index] * + candidate_p2[min_dco_index] * afe_clock; /* - * Intermediate values are in Hz. - * Divide by MHz to match bsepc - */ - wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); - wrpll_params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + * Intermediate values are in Hz. + * Divide by MHz to match bsepc + */ + wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + wrpll_params->dco_fraction = + div_u64(((div_u64(dco_freq, 24) - + wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); } } -- cgit v1.2.3 From 90d469067d0808ddbd9be2c97a4a8e14037b5e46 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Thu, 7 May 2015 14:31:28 -0700 Subject: drm/i915: Set crtc_state->active to false when CRTC is disabled (v2) With the recent modeset internal rework, we wind up setting crtc_state->enable to false, but leave crtc_state->active as true, which is incorrect. This mismatch gets caught by drm_atomic_crtc_check() and causes subsequent atomic operations (such as plane updates while the CRTC is disabled) to fail. Bisect points to commit dad9a7d6d96630182fb52aae7c3856e9e7285e13 Author: Ander Conselvan de Oliveira Date: Tue Apr 21 17:13:19 2015 +0300 drm/i915: Use atomic helpers for computing changed flags as the commit that actually triggers the regression. v2: Update to alter in-flight state rather than already-committed state (first version was accidentally based on a midpoint of Ander's modeset rework series, before his final patches that add proper state swapping to the legacy modeset path). Cc: Ander Conselvan de Oliveira Cc: Maarten Lankhorst Testcase: igt/kms_universal_plane Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b5806400d40e..fd228a27a7d0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12340,6 +12340,7 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, continue; if (!crtc_state->enable) { + crtc_state->active = false; intel_crtc_disable(crtc); } else if (crtc->state->enable) { intel_crtc_disable_planes(crtc); -- cgit v1.2.3 From ac935a8b6db00079e2de65cadf4c735ed8f0175b Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 1 Apr 2015 14:22:58 -0700 Subject: drm/i915/vlv: remove wait for previous GFX clk disable request Looks like it was introduced in: commit 650ad970a39f8b6164fe8613edc150f585315289 Author: Imre Deak Date: Fri Apr 18 16:35:02 2014 +0300 drm/i915: vlv: factor out vlv_force_gfx_clock and check for pending force-of but I'm not sure why. It has caused problems for us in the past (see 85250ddff7a6 "drm/i915/chv: Remove Wait for a previous gfx force-off" and 8d4eee9cd7a1 "drm/i915: vlv: increase timeout when forcing on the GFX clock") and doesn't seem to be required, so let's just drop it. References: https://bugs.freedesktop.org/show_bug.cgi?id=89611 Signed-off-by: Jesse Barnes Tested-by: Darren Hart Reviewed-by: Deepak S Cc: stable@vger.kernel.org # c9c52e24194a: drm/i915/chv: Remove Wait ... Cc: stable@vger.kernel.org Signed-off-by: Jani Nikula [danvet: Repick this commit from 5df0582bf036bb5f9a8ad8db5884fe13a55347d1 becuase Dave Airlie lost it in his merge commit e1dee1973c74a0408b108d88c57a15be8a2d6d84.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 334bcc1badaa..6bb6c47db49f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1286,21 +1286,7 @@ int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on) u32 val; int err; - val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); - #define COND (I915_READ(VLV_GTLC_SURVIVABILITY_REG) & VLV_GFX_CLK_STATUS_BIT) - /* Wait for a previous force-off to settle */ - if (force_on && !IS_CHERRYVIEW(dev_priv->dev)) { - /* WARN_ON only for the Valleyview */ - WARN_ON(!!(val & VLV_GFX_CLK_FORCE_ON_BIT) == force_on); - - err = wait_for(!COND, 20); - if (err) { - DRM_ERROR("timeout waiting for GFX clock force-off (%08x)\n", - I915_READ(VLV_GTLC_SURVIVABILITY_REG)); - return err; - } - } val = I915_READ(VLV_GTLC_SURVIVABILITY_REG); val &= ~VLV_GFX_CLK_FORCE_ON_BIT; -- cgit v1.2.3 From 2e523e98bb593950de2c749d4ceb45cc20313c1a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 10 Apr 2015 18:21:27 +0300 Subject: drm/i915: Implement chv display PHY lane stagger setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set up the chv display PHY lane stagger registers according to "Programming Guide for 1273 CHV eDP/DP/HDMI Display PHY" v1.04 Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 13 +++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 35 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_hdmi.c | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 60ef5406fe57..98f10810bdbd 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -961,6 +961,7 @@ enum skl_disp_power_wells { #define _VLV_PCS_DW11_CH0 0x822c #define _VLV_PCS_DW11_CH1 0x842c +#define DPIO_TX2_STAGGER_MASK(x) ((x)<<24) #define DPIO_LANEDESKEW_STRAP_OVRD (1<<3) #define DPIO_LEFT_TXFIFO_RST_MASTER (1<<1) #define DPIO_RIGHT_TXFIFO_RST_MASTER (1<<0) @@ -973,8 +974,20 @@ enum skl_disp_power_wells { #define VLV_PCS01_DW11(ch) _PORT(ch, _VLV_PCS01_DW11_CH0, _VLV_PCS01_DW11_CH1) #define VLV_PCS23_DW11(ch) _PORT(ch, _VLV_PCS23_DW11_CH0, _VLV_PCS23_DW11_CH1) +#define _VLV_PCS01_DW12_CH0 0x0230 +#define _VLV_PCS23_DW12_CH0 0x0430 +#define _VLV_PCS01_DW12_CH1 0x2630 +#define _VLV_PCS23_DW12_CH1 0x2830 +#define VLV_PCS01_DW12(ch) _PORT(ch, _VLV_PCS01_DW12_CH0, _VLV_PCS01_DW12_CH1) +#define VLV_PCS23_DW12(ch) _PORT(ch, _VLV_PCS23_DW12_CH0, _VLV_PCS23_DW12_CH1) + #define _VLV_PCS_DW12_CH0 0x8230 #define _VLV_PCS_DW12_CH1 0x8430 +#define DPIO_TX2_STAGGER_MULT(x) ((x)<<20) +#define DPIO_TX1_STAGGER_MULT(x) ((x)<<16) +#define DPIO_TX1_STAGGER_MASK(x) ((x)<<8) +#define DPIO_LANESTAGGER_STRAP_OVRD (1<<6) +#define DPIO_LANESTAGGER_STRAP(x) ((x)<<0) #define VLV_PCS_DW12(ch) _PORT(ch, _VLV_PCS_DW12_CH0, _VLV_PCS_DW12_CH1) #define _VLV_PCS_DW14_CH0 0x8238 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b4c5b9bb6207..2b1ed66c748f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2732,7 +2732,7 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) to_intel_crtc(encoder->base.crtc); enum dpio_channel ch = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; - int data, i; + int data, i, stagger; u32 val; mutex_lock(&dev_priv->dpio_lock); @@ -2772,7 +2772,38 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder) } /* Data lane stagger programming */ - /* FIXME: Fix up value only after power analysis */ + if (intel_crtc->config->port_clock > 270000) + stagger = 0x18; + else if (intel_crtc->config->port_clock > 135000) + stagger = 0xd; + else if (intel_crtc->config->port_clock > 67500) + stagger = 0x7; + else if (intel_crtc->config->port_clock > 33750) + stagger = 0x4; + else + stagger = 0x2; + + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); + val |= DPIO_TX2_STAGGER_MASK(0x1f); + vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); + + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val |= DPIO_TX2_STAGGER_MASK(0x1f); + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + + vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), + DPIO_LANESTAGGER_STRAP(stagger) | + DPIO_LANESTAGGER_STRAP_OVRD | + DPIO_TX1_STAGGER_MASK(0x1f) | + DPIO_TX1_STAGGER_MULT(6) | + DPIO_TX2_STAGGER_MULT(0)); + + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), + DPIO_LANESTAGGER_STRAP(stagger) | + DPIO_LANESTAGGER_STRAP_OVRD | + DPIO_TX1_STAGGER_MASK(0x1f) | + DPIO_TX1_STAGGER_MULT(7) | + DPIO_TX2_STAGGER_MULT(5)); mutex_unlock(&dev_priv->dpio_lock); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 590d46b124e0..86355f1c6f21 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1487,7 +1487,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) &intel_crtc->config->base.adjusted_mode; enum dpio_channel ch = vlv_dport_to_channel(dport); int pipe = intel_crtc->pipe; - int data, i; + int data, i, stagger; u32 val; mutex_lock(&dev_priv->dpio_lock); @@ -1527,7 +1527,38 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) } /* Data lane stagger programming */ - /* FIXME: Fix up value only after power analysis */ + if (intel_crtc->config->port_clock > 270000) + stagger = 0x18; + else if (intel_crtc->config->port_clock > 135000) + stagger = 0xd; + else if (intel_crtc->config->port_clock > 67500) + stagger = 0x7; + else if (intel_crtc->config->port_clock > 33750) + stagger = 0x4; + else + stagger = 0x2; + + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); + val |= DPIO_TX2_STAGGER_MASK(0x1f); + vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); + + val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val |= DPIO_TX2_STAGGER_MASK(0x1f); + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + + vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), + DPIO_LANESTAGGER_STRAP(stagger) | + DPIO_LANESTAGGER_STRAP_OVRD | + DPIO_TX1_STAGGER_MASK(0x1f) | + DPIO_TX1_STAGGER_MULT(6) | + DPIO_TX2_STAGGER_MULT(0)); + + vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), + DPIO_LANESTAGGER_STRAP(stagger) | + DPIO_LANESTAGGER_STRAP_OVRD | + DPIO_TX1_STAGGER_MASK(0x1f) | + DPIO_TX1_STAGGER_MULT(7) | + DPIO_TX2_STAGGER_MULT(5)); /* Clear calc init */ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); -- cgit v1.2.3 From 70722468872b0752abaff54d34ed16af0d95cb9f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 10 Apr 2015 18:21:28 +0300 Subject: drm/i915: Work around DISPLAY_PHY_CONTROL register corruption on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes (exactly when is a bit unclear) DISPLAY_PHY_CONTROL appears to get corrupted. The values I've managed to read from it seem to have some pattern but vary quite a lot. The corruption doesn't seem to just happen when the register is accessed, but can also happen spontaneosly during modeset. When this happens during a modeset things go south and the display doesn't light up. I've managed to hit the problemn when toggling HDMI on port D on and off. When things get corrupted the display doesn't light up, but as soon as I manually write the correct value to the register the display comes up. First I was suspicious that we ourselves accidentally overwrite it with garbage, but didn't catch anything with the reg_rw tracepoint. Also I sprinkled check all over the modeset path to see exactly when the corruption happens, and eg. the read back value was fine just before intel_dp_set_m(), and corrupted immediately after it. I also made my check function repair the register value whenever it was wrong, and with this approach the corruption repeated several times during the modeset operation, always seeming to trigger in the same exact calls to the check function, while other calls to the function never caught anything. So far I've not seen this problem occurring when carefully avoiding all read accesses to DISPLAY_PHY_CONTROL. Not sure if that's just pure luck or an actual workaround, but we can hope it works. So let's avoid reading the register and instead track the desired value of the register in dev_priv. v2: Read out the power well state to determine initial register value v3: Use DPIO_CHx names instead of raw numbers Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_reg.h | 5 ++++- drivers/gpu/drm/i915/intel_runtime_pm.c | 36 ++++++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 87fe4f7d5ce5..1321956ec066 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1782,6 +1782,8 @@ struct drm_i915_private { u32 fdi_rx_config; + u32 chv_phy_control; + u32 suspend_count; struct i915_suspend_saved_registers regfile; struct vlv_s0ix_state vlv_s0ix_state; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 98f10810bdbd..58627a319416 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2137,7 +2137,10 @@ enum skl_disp_power_wells { #define DPIO_PHY_STATUS (VLV_DISPLAY_BASE + 0x6240) #define DPLL_PORTD_READY_MASK (0xf) #define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100) -#define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy)) +#define PHY_CH_SU_PSR 0x1 +#define PHY_CH_DEEP_PSR 0x7 +#define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6*(phy)+3*(ch)+2)) +#define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy)) #define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104) #define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30)) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index bd7ad1d2d5f5..3d7352577bdc 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -949,8 +949,8 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1)) DRM_ERROR("Display PHY %d is not power up\n", phy); - I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) | - PHY_COM_LANE_RESET_DEASSERT(phy)); + dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(phy); + I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); } static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, @@ -970,8 +970,8 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, assert_pll_disabled(dev_priv, PIPE_C); } - I915_WRITE(DISPLAY_PHY_CONTROL, I915_READ(DISPLAY_PHY_CONTROL) & - ~PHY_COM_LANE_RESET_DEASSERT(phy)); + dev_priv->chv_phy_control &= ~PHY_COM_LANE_RESET_DEASSERT(phy); + I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control); vlv_set_power_well(dev_priv, power_well, false); } @@ -1719,6 +1719,30 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) mutex_unlock(&power_domains->lock); } +static void chv_phy_control_init(struct drm_i915_private *dev_priv) +{ + struct i915_power_well *cmn_bc = + lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC); + struct i915_power_well *cmn_d = + lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D); + + /* + * DISPLAY_PHY_CONTROL can get corrupted if read. As a + * workaround never ever read DISPLAY_PHY_CONTROL, and + * instead maintain a shadow copy ourselves. Use the actual + * power well state to reconstruct the expected initial + * value. + */ + dev_priv->chv_phy_control = + PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH0) | + PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH1) | + PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY1, DPIO_CH0); + if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) + dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY0); + if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) + dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY1); +} + static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) { struct i915_power_well *cmn = @@ -1761,7 +1785,9 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) power_domains->initializing = true; - if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) { + if (IS_CHERRYVIEW(dev)) { + chv_phy_control_init(dev_priv); + } else if (IS_VALLEYVIEW(dev)) { mutex_lock(&power_domains->lock); vlv_cmnlane_wa(dev_priv); mutex_unlock(&power_domains->lock); -- cgit v1.2.3 From 71849b67e788ca8899982df7adf21f61f44cb474 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 10 Apr 2015 18:21:29 +0300 Subject: Revert "drm/i915: Hack to tie both common lanes together on chv" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With recent hardware/firmware there don't appear to be any glitches on the other PHY when we toggle the cmnreset for the other PHY. So detangle the cmnlane power wells from one another and let them be controlled independently. This reverts commit 3dd7b97458e8aa2d8985b46622d226fa635071e7. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 3d7352577bdc..317b9b43d1c1 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1464,23 +1464,13 @@ static struct i915_power_well chv_power_wells[] = { #endif { .name = "dpio-common-bc", - /* - * XXX: cmnreset for one PHY seems to disturb the other. - * As a workaround keep both powered on at the same - * time for now. - */ - .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS, + .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS, .data = PUNIT_POWER_WELL_DPIO_CMN_BC, .ops = &chv_dpio_cmn_power_well_ops, }, { .name = "dpio-common-d", - /* - * XXX: cmnreset for one PHY seems to disturb the other. - * As a workaround keep both powered on at the same - * time for now. - */ - .domains = CHV_DPIO_CMN_BC_POWER_DOMAINS | CHV_DPIO_CMN_D_POWER_DOMAINS, + .domains = CHV_DPIO_CMN_D_POWER_DOMAINS, .data = PUNIT_POWER_WELL_DPIO_CMN_D, .ops = &chv_dpio_cmn_power_well_ops, }, -- cgit v1.2.3 From e7ded2d74673c2cdabd1f80da8c8a1b7b531e84a Mon Sep 17 00:00:00 2001 From: Joonas Lahtinen Date: Fri, 8 May 2015 14:37:39 +0300 Subject: drm/i915: Reject huge tiled objects We do not yet support tiled objects bigger than the mappable aperture size so reject them. Reported-by: Chris Wilson Signed-off-by: Joonas Lahtinen [danvet: Rework the check a bit to avoid warnings.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b45f93bb030e..f128ed8d6f65 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1669,8 +1669,10 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } /* Use a partial view if the object is bigger than the aperture. */ - if (obj->base.size >= dev_priv->gtt.mappable_end) { + if (obj->base.size >= dev_priv->gtt.mappable_end && + obj->tiling_mode == I915_TILING_NONE) { static const unsigned int chunk_size = 256; // 1 MiB + memset(&view, 0, sizeof(view)); view.type = I915_GGTT_VIEW_PARTIAL; view.params.partial.offset = rounddown(page_offset, chunk_size); -- cgit v1.2.3 From ac6f2e29bb08a2313b0480c6cea94b01ab274970 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 May 2015 16:15:41 +0200 Subject: drm/edid: Kerneldoc for newly added edid_corrupt Also treat it as a proper boolean. Cc: Todd Previte Cc: Paulo Zanoni Cc: dri-devel@lists.freedesktop.org Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_edid.c | 8 ++++---- drivers/gpu/drm/i915/intel_dp.c | 2 +- include/drm/drm_crtc.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index be6713c2fc9d..e426223482fb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1064,7 +1064,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, int score = drm_edid_header_is_valid(raw_edid); if (score == 8) { if (edid_corrupt) - *edid_corrupt = 0; + *edid_corrupt = false; } else if (score >= edid_fixup) { /* Displayport Link CTS Core 1.2 rev1.1 test 4.2.2.6 * The corrupt flag needs to be set here otherwise, the @@ -1072,12 +1072,12 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, * checksum is correct and the test fails */ if (edid_corrupt) - *edid_corrupt = 1; + *edid_corrupt = true; DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); memcpy(raw_edid, edid_header, sizeof(edid_header)); } else { if (edid_corrupt) - *edid_corrupt = 1; + *edid_corrupt = true; goto bad; } } @@ -1089,7 +1089,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, } if (edid_corrupt) - *edid_corrupt = 1; + *edid_corrupt = true; /* allow CEA to slide through, switches mangle this */ if (raw_edid[0] != 0x02) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2b1ed66c748f..9cf9208aeaff 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4120,7 +4120,7 @@ static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp) struct drm_connector *connector = &intel_connector->base; if (intel_connector->detect_edid == NULL || - connector->edid_corrupt == 1 || + connector->edid_corrupt || intel_dp->aux.i2c_defer_count > 6) { /* Check EDID read for NACKs, DEFERs and corruption * (DP CTS 1.2 Core r1.1) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index b9fcdc824997..0a4a040d6bb7 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -647,6 +647,7 @@ struct drm_encoder { * @audio_latency: audio latency info from ELD, if found * @null_edid_counter: track sinks that give us all zeros for the EDID * @bad_edid_counter: track sinks that give us an EDID with invalid checksum + * @edid_corrupt: indicates whether the last read EDID was corrupt * @debugfs_entry: debugfs directory for this connector * @state: current atomic state for this connector * @has_tile: is this connector connected to a tiled monitor -- cgit v1.2.3 From c7c7372edc4ebc173ad359aeb5752e9ce09f2741 Mon Sep 17 00:00:00 2001 From: "Rebecca N. Palmer" Date: Fri, 8 May 2015 14:26:50 +0100 Subject: drm/i915: Fix possible security hole in command parsing i915_parse_cmds returns -EACCES on chained batches, which "tells the caller to abort and dispatch the workload as a non-secure batch", but the mechanism implementing that was broken when flags |= I915_DISPATCH_SECURE was moved from i915_gem_execbuffer_parse to i915_gem_do_execbuffer (17cabf571e50677d980e9ab2a43c5f11213003ae): i915_gem_execbuffer_parse returns the original batch_obj in this case, and i915_gem_do_execbuffer doesn't check for that. Don't set the secure bit in this case to make sure such batches don't run with elevated priviledges. Signed-off-by: Rebecca Palmer Reviewed-by: Mika Kuoppala [danvet: Stitch together commit message. Also remove a comment as suggested by Mika. And style-align the comment while at it.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7ab63d9d7dc5..560c79a8a43d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1540,28 +1540,39 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } if (i915_needs_cmd_parser(ring) && args->batch_len) { - batch_obj = i915_gem_execbuffer_parse(ring, + struct drm_i915_gem_object *parsed_batch_obj; + + parsed_batch_obj = i915_gem_execbuffer_parse(ring, &shadow_exec_entry, eb, batch_obj, args->batch_start_offset, args->batch_len, file->is_master); - if (IS_ERR(batch_obj)) { - ret = PTR_ERR(batch_obj); + if (IS_ERR(parsed_batch_obj)) { + ret = PTR_ERR(parsed_batch_obj); goto err; } /* - * Set the DISPATCH_SECURE bit to remove the NON_SECURE - * bit from MI_BATCH_BUFFER_START commands issued in the - * dispatch_execbuffer implementations. We specifically - * don't want that set when the command parser is - * enabled. + * parsed_batch_obj == batch_obj means batch not fully parsed: + * Accept, but don't promote to secure. */ - dispatch_flags |= I915_DISPATCH_SECURE; - exec_start = 0; + if (parsed_batch_obj != batch_obj) { + /* + * Batch parsed and accepted: + * + * Set the DISPATCH_SECURE bit to remove the NON_SECURE + * bit from MI_BATCH_BUFFER_START commands issued in + * the dispatch_execbuffer implementations. We + * specifically don't want that set on batches the + * command parser has accepted. + */ + dispatch_flags |= I915_DISPATCH_SECURE; + exec_start = 0; + batch_obj = parsed_batch_obj; + } } batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND; -- cgit v1.2.3 From 9b6de0a1552175620ced3a7a7a552d4e7a379538 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 10 Apr 2015 18:21:31 +0300 Subject: drm/i915: Only wait for required lanes in vlv_wait_port_ready() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently vlv_wait_port_ready() waits for all four lanes on the appropriate channel. This no longer works on CHV when the unused lanes may be power gated. So pass in a mask of lanes that the caller is expecting to be ready. Signed-off-by: Ville Syrjälä Reviewed-by: Deepak S Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- drivers/gpu/drm/i915/intel_dp.c | 4 +++- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_hdmi.c | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fd228a27a7d0..22e6644f755e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1844,7 +1844,8 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) } void vlv_wait_port_ready(struct drm_i915_private *dev_priv, - struct intel_digital_port *dport) + struct intel_digital_port *dport, + unsigned int expected_mask) { u32 port_mask; int dpll_reg; @@ -1857,6 +1858,7 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, case PORT_C: port_mask = DPLL_PORTC_READY_MASK; dpll_reg = DPLL(0); + expected_mask <<= 4; break; case PORT_D: port_mask = DPLL_PORTD_READY_MASK; @@ -1866,9 +1868,9 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, BUG(); } - if (wait_for((I915_READ(dpll_reg) & port_mask) == 0, 1000)) - WARN(1, "timed out waiting for port %c ready: 0x%08x\n", - port_name(dport->port), I915_READ(dpll_reg)); + if (wait_for((I915_READ(dpll_reg) & port_mask) == expected_mask, 1000)) + WARN(1, "timed out waiting for port %c ready: got 0x%x, expected 0x%x\n", + port_name(dport->port), I915_READ(dpll_reg) & port_mask, expected_mask); } static void intel_prepare_shared_dpll(struct intel_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9cf9208aeaff..82dcc6ed8b1d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2497,6 +2497,7 @@ static void intel_enable_dp(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); uint32_t dp_reg = I915_READ(intel_dp->output_reg); + unsigned int lane_mask = 0x0; if (WARN_ON(dp_reg & DP_PORT_EN)) return; @@ -2515,7 +2516,8 @@ static void intel_enable_dp(struct intel_encoder *encoder) pps_unlock(intel_dp); if (IS_VALLEYVIEW(dev)) - vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp)); + vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp), + lane_mask); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 930ea6916d9f..ea3368e83626 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1013,7 +1013,8 @@ intel_wait_for_vblank(struct drm_device *dev, int pipe) } int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); void vlv_wait_port_ready(struct drm_i915_private *dev_priv, - struct intel_digital_port *dport); + struct intel_digital_port *dport, + unsigned int expected_mask); bool intel_get_load_detect_pipe(struct drm_connector *connector, struct drm_display_mode *mode, struct intel_load_detect_pipe *old, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 86355f1c6f21..d04e6dc97fe5 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1324,7 +1324,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) intel_enable_hdmi(encoder); - vlv_wait_port_ready(dev_priv, dport); + vlv_wait_port_ready(dev_priv, dport, 0x0); } static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder) @@ -1641,7 +1641,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) intel_enable_hdmi(encoder); - vlv_wait_port_ready(dev_priv, dport); + vlv_wait_port_ready(dev_priv, dport, 0x0); } static void intel_hdmi_destroy(struct drm_connector *connector) -- cgit v1.2.3 From 214a2b7fab215b1e979fbae51225b01b8fc58288 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 May 2015 17:38:19 +0200 Subject: drm/i915: Update DRIVER_DATE to 20150508 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1321956ec066..acfa4fc93803 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150423" +#define DRIVER_DATE "20150508" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v1.2.3