diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b6d9b2da36c2f0b8748aba51131f8bca7765093b..dd0429c612a49cfbb98fdb969756a2d1ef6cbcd5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -628,6 +628,10 @@ struct drm_i915_display_funcs { struct dpll *match_clock, struct dpll *best_clock); void (*update_wm)(struct drm_crtc *crtc); + void (*update_sprite_wm)(struct drm_plane *plane, + struct drm_crtc *crtc, + uint32_t sprite_width, uint32_t sprite_height, + int pixel_size, bool enable, bool scaled); int (*modeset_calc_cdclk)(struct drm_atomic_state *state); void (*modeset_commit_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 05b12032d2628fe2dab8d059b1b7c881ceb881a4..f1975f267710ba22f0569c3abfa026dc10b5985b 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -94,7 +94,6 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); crtc_state->update_pipe = false; - crtc_state->disable_lp_wm = false; return &crtc_state->base; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7a354921b5f2ad1f2fb29a4ed4d731f32c91382e..d37b7a1d562b1557097bb9798990ba50a962478b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4774,6 +4774,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_plane *plane; if (atomic->wait_vblank) intel_wait_for_vblank(dev, crtc->pipe); @@ -4792,6 +4793,10 @@ static void intel_post_plane_update(struct intel_crtc *crtc) if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); + drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks) + intel_update_sprite_watermarks(plane, &crtc->base, + 0, 0, 0, false, false); + memset(atomic, 0, sizeof(*atomic)); } @@ -11554,30 +11559,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, static bool intel_wm_need_update(struct drm_plane *plane, struct drm_plane_state *state) { - struct intel_plane_state *new = to_intel_plane_state(state); - struct intel_plane_state *cur = to_intel_plane_state(plane->state); - - /* Update watermarks on tiling or size changes. */ + /* Update watermarks on tiling changes. */ if (!plane->state->fb || !state->fb || plane->state->fb->modifier[0] != state->fb->modifier[0] || - plane->state->rotation != state->rotation || - drm_rect_width(&new->src) != drm_rect_width(&cur->src) || - drm_rect_height(&new->src) != drm_rect_height(&cur->src) || - drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) || - drm_rect_height(&new->dst) != drm_rect_height(&cur->dst)) + plane->state->rotation != state->rotation) return true; - return false; -} - -static bool needs_scaling(struct intel_plane_state *state) -{ - int src_w = drm_rect_width(&state->src) >> 16; - int src_h = drm_rect_height(&state->src) >> 16; - int dst_w = drm_rect_width(&state->dst); - int dst_h = drm_rect_height(&state->dst); + if (plane->state->crtc_w != state->crtc_w) + return true; - return (src_w != dst_w || src_h != dst_h); + return false; } int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, @@ -11595,6 +11586,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, bool mode_changed = needs_modeset(crtc_state); bool was_crtc_enabled = crtc->state->active; bool is_crtc_enabled = crtc_state->active; + bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb; @@ -11712,23 +11704,11 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, case DRM_PLANE_TYPE_CURSOR: break; case DRM_PLANE_TYPE_OVERLAY: - /* - * WaCxSRDisabledForSpriteScaling:ivb - * - * cstate->update_wm was already set above, so this flag will - * take effect when we commit and program watermarks. - */ - if (IS_IVYBRIDGE(dev) && - needs_scaling(to_intel_plane_state(plane_state)) && - !needs_scaling(old_plane_state)) { - to_intel_crtc_state(crtc_state)->disable_lp_wm = true; - } else if (turn_off && !mode_changed) { + if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; } - - break; } return 0; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 91b6b4060333b688ea81f892dbdd475a367c7d26..0598932ce6235b623df9ff6a62d74e100087f78e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -468,9 +468,6 @@ struct intel_crtc_state { /* w/a for waiting 2 vblanks during crtc enable */ enum pipe hsw_workaround_pipe; - - /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */ - bool disable_lp_wm; }; struct vlv_wm_state { @@ -1399,6 +1396,12 @@ void intel_init_clock_gating(struct drm_device *dev); void intel_suspend_hw(struct drm_device *dev); int ilk_wm_max_level(const struct drm_device *dev); void intel_update_watermarks(struct drm_crtc *crtc); +void intel_update_sprite_watermarks(struct drm_plane *plane, + struct drm_crtc *crtc, + uint32_t sprite_width, + uint32_t sprite_height, + int pixel_size, + bool enabled, bool scaled); void intel_init_pm(struct drm_device *dev); void intel_pm_setup(struct drm_device *dev); void intel_gpu_ips_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d031d74abd2705550b5295e072cfeeb5173f3a37..d13551ff95cdb8ea4f11be55fbb2fde4e79f4dbd 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1765,6 +1765,13 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; } +struct skl_pipe_wm_parameters { + bool active; + uint32_t pipe_htotal; + uint32_t pixel_rate; /* in KHz */ + struct intel_plane_wm_parameters plane[I915_MAX_PLANES]; +}; + struct ilk_wm_maximums { uint16_t pri; uint16_t spr; @@ -2805,40 +2812,18 @@ static bool ilk_disable_lp_wm(struct drm_device *dev) #define SKL_DDB_SIZE 896 /* in blocks */ #define BXT_DDB_SIZE 512 -/* - * Return the index of a plane in the SKL DDB and wm result arrays. Primary - * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and - * other universal planes are in indices 1..n. Note that this may leave unused - * indices between the top "sprite" plane and the cursor. - */ -static int -skl_wm_plane_id(const struct intel_plane *plane) -{ - switch (plane->base.type) { - case DRM_PLANE_TYPE_PRIMARY: - return 0; - case DRM_PLANE_TYPE_CURSOR: - return PLANE_CURSOR; - case DRM_PLANE_TYPE_OVERLAY: - return plane->plane + 1; - default: - MISSING_CASE(plane->base.type); - return plane->plane; - } -} - static void skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, - const struct intel_crtc_state *cstate, + struct drm_crtc *for_crtc, const struct intel_wm_config *config, + const struct skl_pipe_wm_parameters *params, struct skl_ddb_entry *alloc /* out */) { - struct drm_crtc *for_crtc = cstate->base.crtc; struct drm_crtc *crtc; unsigned int pipe_size, ddb_size; int nth_active_pipe; - if (!cstate->base.active) { + if (!params->active) { alloc->start = 0; alloc->end = 0; return; @@ -2904,29 +2889,19 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, } static unsigned int -skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, - const struct drm_plane_state *pstate, - int y) +skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y) { - struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); - struct drm_framebuffer *fb = pstate->fb; /* for planar format */ - if (fb->pixel_format == DRM_FORMAT_NV12) { + if (p->y_bytes_per_pixel) { if (y) /* y-plane data rate */ - return intel_crtc->config->pipe_src_w * - intel_crtc->config->pipe_src_h * - drm_format_plane_cpp(fb->pixel_format, 0); + return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel; else /* uv-plane data rate */ - return (intel_crtc->config->pipe_src_w/2) * - (intel_crtc->config->pipe_src_h/2) * - drm_format_plane_cpp(fb->pixel_format, 1); + return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel; } /* for packed formats */ - return intel_crtc->config->pipe_src_w * - intel_crtc->config->pipe_src_h * - drm_format_plane_cpp(fb->pixel_format, 0); + return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel; } /* @@ -2935,51 +2910,46 @@ skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, * 3 * 4096 * 8192 * 4 < 2^32 */ static unsigned int -skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate) +skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc, + const struct skl_pipe_wm_parameters *params) { - struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); - struct drm_device *dev = intel_crtc->base.dev; - const struct intel_plane *intel_plane; unsigned int total_data_rate = 0; + int plane; - for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - const struct drm_plane_state *pstate = intel_plane->base.state; + for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { + const struct intel_plane_wm_parameters *p; - if (pstate->fb == NULL) + p = ¶ms->plane[plane]; + if (!p->enabled) continue; - /* packed/uv */ - total_data_rate += skl_plane_relative_data_rate(cstate, - pstate, - 0); - - if (pstate->fb->pixel_format == DRM_FORMAT_NV12) - /* y-plane */ - total_data_rate += skl_plane_relative_data_rate(cstate, - pstate, - 1); + total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */ + if (p->y_bytes_per_pixel) { + total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */ + } } return total_data_rate; } static void -skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, +skl_allocate_pipe_ddb(struct drm_crtc *crtc, const struct intel_wm_config *config, + const struct skl_pipe_wm_parameters *params, struct skl_ddb_allocation *ddb /* out */) { - struct drm_crtc *crtc = cstate->base.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; enum pipe pipe = intel_crtc->pipe; struct skl_ddb_entry *alloc = &ddb->pipe[pipe]; uint16_t alloc_size, start, cursor_blocks; uint16_t minimum[I915_MAX_PLANES]; uint16_t y_minimum[I915_MAX_PLANES]; unsigned int total_data_rate; + int plane; - skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc); + skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc); alloc_size = skl_ddb_entry_size(alloc); if (alloc_size == 0) { memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); @@ -2996,20 +2966,17 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, alloc->end -= cursor_blocks; /* 1. Allocate the mininum required blocks for each active plane */ - for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - struct drm_plane *plane = &intel_plane->base; - struct drm_framebuffer *fb = plane->fb; - int id = skl_wm_plane_id(intel_plane); + for_each_plane(dev_priv, pipe, plane) { + const struct intel_plane_wm_parameters *p; - if (fb == NULL) - continue; - if (plane->type == DRM_PLANE_TYPE_CURSOR) + p = ¶ms->plane[plane]; + if (!p->enabled) continue; - minimum[id] = 8; - alloc_size -= minimum[id]; - y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0; - alloc_size -= y_minimum[id]; + minimum[plane] = 8; + alloc_size -= minimum[plane]; + y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0; + alloc_size -= y_minimum[plane]; } /* @@ -3018,50 +2985,45 @@ skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, * * FIXME: we may not allocate every single block here. */ - total_data_rate = skl_get_total_relative_data_rate(cstate); + total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params); start = alloc->start; - for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - struct drm_plane *plane = &intel_plane->base; - struct drm_plane_state *pstate = intel_plane->base.state; + for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { + const struct intel_plane_wm_parameters *p; unsigned int data_rate, y_data_rate; uint16_t plane_blocks, y_plane_blocks = 0; - int id = skl_wm_plane_id(intel_plane); - if (pstate->fb == NULL) - continue; - if (plane->type == DRM_PLANE_TYPE_CURSOR) + p = ¶ms->plane[plane]; + if (!p->enabled) continue; - data_rate = skl_plane_relative_data_rate(cstate, pstate, 0); + data_rate = skl_plane_relative_data_rate(p, 0); /* * allocation for (packed formats) or (uv-plane part of planar format): * promote the expression to 64 bits to avoid overflowing, the * result is < available as data_rate / total_data_rate < 1 */ - plane_blocks = minimum[id]; + plane_blocks = minimum[plane]; plane_blocks += div_u64((uint64_t)alloc_size * data_rate, total_data_rate); - ddb->plane[pipe][id].start = start; - ddb->plane[pipe][id].end = start + plane_blocks; + ddb->plane[pipe][plane].start = start; + ddb->plane[pipe][plane].end = start + plane_blocks; start += plane_blocks; /* * allocation for y_plane part of planar format: */ - if (pstate->fb->pixel_format == DRM_FORMAT_NV12) { - y_data_rate = skl_plane_relative_data_rate(cstate, - pstate, - 1); - y_plane_blocks = y_minimum[id]; + if (p->y_bytes_per_pixel) { + y_data_rate = skl_plane_relative_data_rate(p, 1); + y_plane_blocks = y_minimum[plane]; y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate, total_data_rate); - ddb->y_plane[pipe][id].start = start; - ddb->y_plane[pipe][id].end = start + y_plane_blocks; + ddb->y_plane[pipe][plane].start = start; + ddb->y_plane[pipe][plane].end = start + y_plane_blocks; start += y_plane_blocks; } @@ -3148,21 +3110,87 @@ static void skl_compute_wm_global_parameters(struct drm_device *dev, struct intel_wm_config *config) { struct drm_crtc *crtc; + struct drm_plane *plane; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) config->num_pipes_active += to_intel_crtc(crtc)->active; + + /* FIXME: I don't think we need those two global parameters on SKL */ + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct intel_plane *intel_plane = to_intel_plane(plane); + + config->sprites_enabled |= intel_plane->wm.enabled; + config->sprites_scaled |= intel_plane->wm.scaled; + } +} + +static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *p) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct drm_plane *plane; + struct drm_framebuffer *fb; + int i = 1; /* Index for sprite planes start */ + + p->active = intel_crtc->active; + if (p->active) { + p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; + p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config); + + fb = crtc->primary->state->fb; + /* For planar: Bpp is for uv plane, y_Bpp is for y plane */ + if (fb) { + p->plane[0].enabled = true; + p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ? + drm_format_plane_cpp(fb->pixel_format, 1) : + drm_format_plane_cpp(fb->pixel_format, 0); + p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ? + drm_format_plane_cpp(fb->pixel_format, 0) : 0; + p->plane[0].tiling = fb->modifier[0]; + } else { + p->plane[0].enabled = false; + p->plane[0].bytes_per_pixel = 0; + p->plane[0].y_bytes_per_pixel = 0; + p->plane[0].tiling = DRM_FORMAT_MOD_NONE; + } + p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w; + p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h; + p->plane[0].rotation = crtc->primary->state->rotation; + + fb = crtc->cursor->state->fb; + p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0; + if (fb) { + p->plane[PLANE_CURSOR].enabled = true; + p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8; + p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w; + p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h; + } else { + p->plane[PLANE_CURSOR].enabled = false; + p->plane[PLANE_CURSOR].bytes_per_pixel = 0; + p->plane[PLANE_CURSOR].horiz_pixels = 64; + p->plane[PLANE_CURSOR].vert_pixels = 64; + } + } + + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + struct intel_plane *intel_plane = to_intel_plane(plane); + + if (intel_plane->pipe == pipe && + plane->type == DRM_PLANE_TYPE_OVERLAY) + p->plane[i++] = intel_plane->wm; + } } static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, - struct intel_crtc_state *cstate, - struct intel_plane *intel_plane, + struct skl_pipe_wm_parameters *p, + struct intel_plane_wm_parameters *p_params, uint16_t ddb_allocation, int level, uint16_t *out_blocks, /* out */ uint8_t *out_lines /* out */) { - struct drm_plane *plane = &intel_plane->base; - struct drm_framebuffer *fb = plane->state->fb; uint32_t latency = dev_priv->wm.skl_latency[level]; uint32_t method1, method2; uint32_t plane_bytes_per_line, plane_blocks_per_line; @@ -3170,35 +3198,31 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint32_t selected_result; uint8_t bytes_per_pixel; - if (latency == 0 || !cstate->base.active || !fb) + if (latency == 0 || !p->active || !p_params->enabled) return false; - bytes_per_pixel = (fb->pixel_format == DRM_FORMAT_NV12) ? - drm_format_plane_cpp(DRM_FORMAT_NV12, 0) : - drm_format_plane_cpp(DRM_FORMAT_NV12, 1); - method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate), + bytes_per_pixel = p_params->y_bytes_per_pixel ? + p_params->y_bytes_per_pixel : + p_params->bytes_per_pixel; + method1 = skl_wm_method1(p->pixel_rate, bytes_per_pixel, latency); - method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate), - cstate->base.adjusted_mode.crtc_htotal, - cstate->pipe_src_w, + method2 = skl_wm_method2(p->pixel_rate, + p->pipe_htotal, + p_params->horiz_pixels, bytes_per_pixel, - fb->modifier[0], + p_params->tiling, latency); - plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel; + plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel; plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512); - if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || - fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { + if (p_params->tiling == I915_FORMAT_MOD_Y_TILED || + p_params->tiling == I915_FORMAT_MOD_Yf_TILED) { uint32_t min_scanlines = 4; uint32_t y_tile_minimum; - if (intel_rotation_90_or_270(plane->state->rotation)) { - int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ? - drm_format_plane_cpp(fb->pixel_format, 1) : - drm_format_plane_cpp(fb->pixel_format, 0); - - switch (bpp) { + if (intel_rotation_90_or_270(p_params->rotation)) { + switch (p_params->bytes_per_pixel) { case 1: min_scanlines = 16; break; @@ -3222,8 +3246,8 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line); if (level >= 1 && level <= 7) { - if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || - fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) + if (p_params->tiling == I915_FORMAT_MOD_Y_TILED || + p_params->tiling == I915_FORMAT_MOD_Yf_TILED) res_lines += 4; else res_blocks++; @@ -3240,80 +3264,84 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, static void skl_compute_wm_level(const struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb, - struct intel_crtc_state *cstate, + struct skl_pipe_wm_parameters *p, + enum pipe pipe, int level, + int num_planes, struct skl_wm_level *result) { - struct drm_device *dev = dev_priv->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); - struct intel_plane *intel_plane; uint16_t ddb_blocks; - enum pipe pipe = intel_crtc->pipe; - - for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - int i = skl_wm_plane_id(intel_plane); + int i; + for (i = 0; i < num_planes; i++) { ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]); result->plane_en[i] = skl_compute_plane_wm(dev_priv, - cstate, - intel_plane, + p, &p->plane[i], ddb_blocks, level, &result->plane_res_b[i], &result->plane_res_l[i]); } + + ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]); + result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p, + &p->plane[PLANE_CURSOR], + ddb_blocks, level, + &result->plane_res_b[PLANE_CURSOR], + &result->plane_res_l[PLANE_CURSOR]); } static uint32_t -skl_compute_linetime_wm(struct intel_crtc_state *cstate) +skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) { - if (!cstate->base.active) + if (!to_intel_crtc(crtc)->active) return 0; - if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0)) + if (WARN_ON(p->pixel_rate == 0)) return 0; - return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000, - skl_pipe_pixel_rate(cstate)); + return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); } -static void skl_compute_transition_wm(struct intel_crtc_state *cstate, +static void skl_compute_transition_wm(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *params, struct skl_wm_level *trans_wm /* out */) { - struct drm_crtc *crtc = cstate->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane *intel_plane; + int i; - if (!cstate->base.active) + if (!params->active) return; /* Until we know more, just disable transition WMs */ - for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) { - int i = skl_wm_plane_id(intel_plane); - + for (i = 0; i < intel_num_planes(intel_crtc); i++) trans_wm->plane_en[i] = false; - } + trans_wm->plane_en[PLANE_CURSOR] = false; } -static void skl_compute_pipe_wm(struct intel_crtc_state *cstate, +static void skl_compute_pipe_wm(struct drm_crtc *crtc, struct skl_ddb_allocation *ddb, + struct skl_pipe_wm_parameters *params, struct skl_pipe_wm *pipe_wm) { - struct drm_device *dev = cstate->base.crtc->dev; + struct drm_device *dev = crtc->dev; const struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int level, max_level = ilk_wm_max_level(dev); for (level = 0; level <= max_level; level++) { - skl_compute_wm_level(dev_priv, ddb, cstate, - level, &pipe_wm->wm[level]); + skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe, + level, intel_num_planes(intel_crtc), + &pipe_wm->wm[level]); } - pipe_wm->linetime = skl_compute_linetime_wm(cstate); + pipe_wm->linetime = skl_compute_linetime_wm(crtc, params); - skl_compute_transition_wm(cstate, &pipe_wm->trans_wm); + skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm); } static void skl_compute_wm_results(struct drm_device *dev, + struct skl_pipe_wm_parameters *p, struct skl_pipe_wm *p_wm, struct skl_wm_values *r, struct intel_crtc *intel_crtc) @@ -3557,15 +3585,16 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, } static bool skl_update_pipe_wm(struct drm_crtc *crtc, + struct skl_pipe_wm_parameters *params, struct intel_wm_config *config, struct skl_ddb_allocation *ddb, /* out */ struct skl_pipe_wm *pipe_wm /* out */) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - skl_allocate_pipe_ddb(cstate, config, ddb); - skl_compute_pipe_wm(cstate, ddb, pipe_wm); + skl_compute_wm_pipe_parameters(crtc, params); + skl_allocate_pipe_ddb(crtc, config, params, ddb); + skl_compute_pipe_wm(crtc, ddb, params, pipe_wm); if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) return false; @@ -3598,6 +3627,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, */ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { + struct skl_pipe_wm_parameters params = {}; struct skl_pipe_wm pipe_wm = {}; bool wm_changed; @@ -3607,7 +3637,8 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, if (!intel_crtc->active) continue; - wm_changed = skl_update_pipe_wm(&intel_crtc->base, config, + wm_changed = skl_update_pipe_wm(&intel_crtc->base, + ¶ms, config, &r->ddb, &pipe_wm); /* @@ -3617,7 +3648,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, */ WARN_ON(!wm_changed); - skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc); + skl_compute_wm_results(dev, ¶ms, &pipe_wm, r, intel_crtc); r->dirty[intel_crtc->pipe] = true; } } @@ -3647,6 +3678,7 @@ static void skl_update_wm(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct skl_pipe_wm_parameters params = {}; struct skl_wm_values *results = &dev_priv->wm.skl_results; struct skl_pipe_wm pipe_wm = {}; struct intel_wm_config config = {}; @@ -3659,10 +3691,11 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_compute_wm_global_parameters(dev, &config); - if (!skl_update_pipe_wm(crtc, &config, &results->ddb, &pipe_wm)) + if (!skl_update_pipe_wm(crtc, ¶ms, &config, + &results->ddb, &pipe_wm)) return; - skl_compute_wm_results(dev, &pipe_wm, results, intel_crtc); + skl_compute_wm_results(dev, ¶ms, &pipe_wm, results, intel_crtc); results->dirty[intel_crtc->pipe] = true; skl_update_other_pipe_wm(dev, crtc, &config, results); @@ -3673,6 +3706,39 @@ static void skl_update_wm(struct drm_crtc *crtc) dev_priv->wm.skl_hw = *results; } +static void +skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc, + uint32_t sprite_width, uint32_t sprite_height, + int pixel_size, bool enabled, bool scaled) +{ + struct intel_plane *intel_plane = to_intel_plane(plane); + struct drm_framebuffer *fb = plane->state->fb; + + intel_plane->wm.enabled = enabled; + intel_plane->wm.scaled = scaled; + intel_plane->wm.horiz_pixels = sprite_width; + intel_plane->wm.vert_pixels = sprite_height; + intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE; + + /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */ + intel_plane->wm.bytes_per_pixel = + (fb && fb->pixel_format == DRM_FORMAT_NV12) ? + drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size; + intel_plane->wm.y_bytes_per_pixel = + (fb && fb->pixel_format == DRM_FORMAT_NV12) ? + drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0; + + /* + * Framebuffer can be NULL on plane disable, but it does not + * matter for watermarks if we assume no tiling in that case. + */ + if (fb) + intel_plane->wm.tiling = fb->modifier[0]; + intel_plane->wm.rotation = plane->state->rotation; + + skl_update_wm(crtc); +} + static void ilk_update_wm(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -3688,18 +3754,6 @@ static void ilk_update_wm(struct drm_crtc *crtc) WARN_ON(cstate->base.active != intel_crtc->active); - /* - * IVB workaround: must disable low power watermarks for at least - * one frame before enabling scaling. LP watermarks can be re-enabled - * when scaling is disabled. - * - * WaCxSRDisabledForSpriteScaling:ivb - */ - if (cstate->disable_lp_wm) { - ilk_disable_lp_wm(dev); - intel_wait_for_vblank(dev, intel_crtc->pipe); - } - intel_compute_pipe_wm(cstate, &pipe_wm); if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) @@ -3731,6 +3785,28 @@ static void ilk_update_wm(struct drm_crtc *crtc) ilk_write_wm_values(dev_priv, &results); } +static void +ilk_update_sprite_wm(struct drm_plane *plane, + struct drm_crtc *crtc, + uint32_t sprite_width, uint32_t sprite_height, + int pixel_size, bool enabled, bool scaled) +{ + struct drm_device *dev = plane->dev; + struct intel_plane *intel_plane = to_intel_plane(plane); + + /* + * IVB workaround: must disable low power watermarks for at least + * one frame before enabling scaling. LP watermarks can be re-enabled + * when scaling is disabled. + * + * WaCxSRDisabledForSpriteScaling:ivb + */ + if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev)) + intel_wait_for_vblank(dev, intel_plane->pipe); + + ilk_update_wm(crtc); +} + static void skl_pipe_wm_active_state(uint32_t val, struct skl_pipe_wm *active, bool is_transwm, @@ -4108,6 +4184,21 @@ void intel_update_watermarks(struct drm_crtc *crtc) dev_priv->display.update_wm(crtc); } +void intel_update_sprite_watermarks(struct drm_plane *plane, + struct drm_crtc *crtc, + uint32_t sprite_width, + uint32_t sprite_height, + int pixel_size, + bool enabled, bool scaled) +{ + struct drm_i915_private *dev_priv = plane->dev->dev_private; + + if (dev_priv->display.update_sprite_wm) + dev_priv->display.update_sprite_wm(plane, crtc, + sprite_width, sprite_height, + pixel_size, enabled, scaled); +} + /** * Lock protecting IPS related data structures */ @@ -7022,6 +7113,7 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = skl_init_clock_gating; dev_priv->display.update_wm = skl_update_wm; + dev_priv->display.update_sprite_wm = skl_update_sprite_wm; } else if (HAS_PCH_SPLIT(dev)) { ilk_setup_wm_latency(dev); @@ -7030,6 +7122,7 @@ void intel_init_pm(struct drm_device *dev) (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.update_wm = ilk_update_wm; + dev_priv->display.update_sprite_wm = ilk_update_sprite_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index dd2d5683fcb166df3bbae2d82f6a74ea530d6391..b229c6752671745e84a7a32b1f43e1fc33ebc89d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -192,6 +192,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, const int pipe = intel_plane->pipe; const int plane = intel_plane->plane + 1; u32 plane_ctl, stride_div, stride; + int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &to_intel_plane_state(drm_plane->state)->ckey; unsigned long surf_addr; @@ -210,6 +211,10 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, rotation = drm_plane->state->rotation; plane_ctl |= skl_plane_ctl_rotation(rotation); + intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h, + pixel_size, true, + src_w != crtc_w || src_h != crtc_h); + stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], fb->pixel_format); @@ -291,6 +296,8 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) I915_WRITE(PLANE_SURF(pipe, plane), 0); POSTING_READ(PLANE_SURF(pipe, plane)); + + intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } static void @@ -533,6 +540,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (IS_HASWELL(dev) || IS_BROADWELL(dev)) sprctl |= SPRITE_PIPE_CSC_ENABLE; + intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size, + true, + src_w != crtc_w || src_h != crtc_h); + /* Sizes are 0 based */ src_w--; src_h--; @@ -666,6 +677,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (IS_GEN6(dev)) dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ + intel_update_sprite_watermarks(plane, crtc, src_w, src_h, + pixel_size, true, + src_w != crtc_w || src_h != crtc_h); + /* Sizes are 0 based */ src_w--; src_h--;