diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 282 |
1 files changed, 172 insertions, 110 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bb6d1daecf5..184725770ae7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -112,6 +112,9 @@ 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 skylake_pfit_enable(struct intel_crtc *crtc); +static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force); +static void ironlake_pfit_enable(struct intel_crtc *crtc); static void intel_modeset_setup_hw_state(struct drm_device *dev); typedef struct { @@ -2187,7 +2190,7 @@ static bool need_vtd_wa(struct drm_device *dev) unsigned int intel_tile_height(struct drm_device *dev, uint32_t pixel_format, - uint64_t fb_format_modifier) + uint64_t fb_format_modifier, unsigned int plane) { unsigned int tile_height; uint32_t pixel_bytes; @@ -2203,7 +2206,7 @@ intel_tile_height(struct drm_device *dev, uint32_t pixel_format, tile_height = 32; break; case I915_FORMAT_MOD_Yf_TILED: - pixel_bytes = drm_format_plane_cpp(pixel_format, 0); + pixel_bytes = drm_format_plane_cpp(pixel_format, plane); switch (pixel_bytes) { default: case 1: @@ -2237,7 +2240,7 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height, uint32_t pixel_format, uint64_t fb_format_modifier) { return ALIGN(height, intel_tile_height(dev, pixel_format, - fb_format_modifier)); + fb_format_modifier, 0)); } static int @@ -2260,15 +2263,27 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, info->height = fb->height; info->pixel_format = fb->pixel_format; info->pitch = fb->pitches[0]; + info->uv_offset = fb->offsets[1]; info->fb_modifier = fb->modifier[0]; tile_height = intel_tile_height(fb->dev, fb->pixel_format, - fb->modifier[0]); + fb->modifier[0], 0); tile_pitch = PAGE_SIZE / tile_height; info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_pitch); info->height_pages = DIV_ROUND_UP(fb->height, tile_height); info->size = info->width_pages * info->height_pages * PAGE_SIZE; + if (info->pixel_format == DRM_FORMAT_NV12) { + tile_height = intel_tile_height(fb->dev, fb->pixel_format, + fb->modifier[0], 1); + tile_pitch = PAGE_SIZE / tile_height; + info->width_pages_uv = DIV_ROUND_UP(fb->pitches[0], tile_pitch); + info->height_pages_uv = DIV_ROUND_UP(fb->height / 2, + tile_height); + info->size_uv = info->width_pages_uv * info->height_pages_uv * + PAGE_SIZE; + } + return 0; } @@ -2727,6 +2742,9 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, (intel_crtc->config->pipe_src_w - 1) * pixel_size; } + intel_crtc->adjusted_x = x; + intel_crtc->adjusted_y = y; + I915_WRITE(reg, dspcntr); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); @@ -2827,6 +2845,9 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, } } + intel_crtc->adjusted_x = x; + intel_crtc->adjusted_y = y; + I915_WRITE(reg, dspcntr); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); @@ -2876,14 +2897,29 @@ u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier, } unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, - struct drm_i915_gem_object *obj) + struct drm_i915_gem_object *obj, + unsigned int plane) { const struct i915_ggtt_view *view = &i915_ggtt_view_normal; + struct i915_vma *vma; + unsigned char *offset; if (intel_rotation_90_or_270(intel_plane->base.state->rotation)) view = &i915_ggtt_view_rotated; - return i915_gem_obj_ggtt_offset_view(obj, view); + vma = i915_gem_obj_to_ggtt_view(obj, view); + if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n", + view->type)) + return -1; + + offset = (unsigned char *)vma->node.start; + + if (plane == 1) { + offset += vma->ggtt_view.rotation_info.uv_start_page * + PAGE_SIZE; + } + + return (unsigned long)offset; } static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) @@ -3039,7 +3075,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, 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); + surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0); /* * FIXME: intel_plane_state->src, dst aren't set when transitional @@ -3066,7 +3102,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, if (intel_rotation_90_or_270(rotation)) { /* stride = Surface height in tiles */ tile_height = intel_tile_height(dev, fb->pixel_format, - fb->modifier[0]); + fb->modifier[0], 0); stride = DIV_ROUND_UP(fb->height, tile_height); x_offset = stride * tile_height - y - src_h; y_offset = x; @@ -3079,6 +3115,9 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, } plane_offset = y_offset << 16 | x_offset; + intel_crtc->adjusted_x = x_offset; + intel_crtc->adjusted_y = y_offset; + I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl); I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset); I915_WRITE(PLANE_SIZE(pipe, 0), plane_size); @@ -3265,14 +3304,23 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) return pending; } -static void intel_update_pipe_size(struct intel_crtc *crtc) +static void intel_update_pipe_config(struct intel_crtc *crtc, + struct intel_crtc_state *old_crtc_state) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - const struct drm_display_mode *adjusted_mode; + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->base.state); - if (!i915.fastboot) - return; + /* drm_atomic_helper_update_legacy_modeset_state might not be called. */ + crtc->base.mode = crtc->base.state->mode; + + DRM_DEBUG_KMS("Updating pipe size %ix%i -> %ix%i\n", + old_crtc_state->pipe_src_w, old_crtc_state->pipe_src_h, + pipe_config->pipe_src_w, pipe_config->pipe_src_h); + + if (HAS_DDI(dev)) + intel_set_pipe_csc(&crtc->base); /* * Update pipe size and adjust fitter if needed: the reason for this is @@ -3281,27 +3329,24 @@ static void intel_update_pipe_size(struct intel_crtc *crtc) * fastboot case, we'll flip, but if we don't update the pipesrc and * pfit state, we'll end up with a big fb scanned out into the wrong * sized surface. - * - * To fix this properly, we need to hoist the checks up into - * compute_mode_changes (or above), check the actual pfit state and - * whether the platform allows pfit disable with pipe active, and only - * then update the pipesrc and pfit state, even on the flip path. */ - adjusted_mode = &crtc->config->base.adjusted_mode; - I915_WRITE(PIPESRC(crtc->pipe), - ((adjusted_mode->crtc_hdisplay - 1) << 16) | - (adjusted_mode->crtc_vdisplay - 1)); - if (!crtc->config->pch_pfit.enabled && - (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || - intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { - I915_WRITE(PF_CTL(crtc->pipe), 0); - I915_WRITE(PF_WIN_POS(crtc->pipe), 0); - I915_WRITE(PF_WIN_SZ(crtc->pipe), 0); + ((pipe_config->pipe_src_w - 1) << 16) | + (pipe_config->pipe_src_h - 1)); + + /* on skylake this is done by detaching scalers */ + if (INTEL_INFO(dev)->gen >= 9) { + skl_detach_scalers(crtc); + + if (pipe_config->pch_pfit.enabled) + skylake_pfit_enable(crtc); + } else if (HAS_PCH_SPLIT(dev)) { + if (pipe_config->pch_pfit.enabled) + ironlake_pfit_enable(crtc); + else if (old_crtc_state->pch_pfit.enabled) + ironlake_pfit_disable(crtc, true); } - crtc->config->pipe_src_w = adjusted_mode->crtc_hdisplay; - crtc->config->pipe_src_h = adjusted_mode->crtc_vdisplay; } static void intel_fdi_normal_train(struct drm_crtc *crtc) @@ -4958,7 +5003,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) } } -static void ironlake_pfit_disable(struct intel_crtc *crtc) +static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4966,7 +5011,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc) /* To avoid upsetting the power well on haswell only disable the pfit if * it's in use. The hw state code will make sure we get this right. */ - if (crtc->config->pch_pfit.enabled) { + if (force || crtc->config->pch_pfit.enabled) { I915_WRITE(PF_CTL(pipe), 0); I915_WRITE(PF_WIN_POS(pipe), 0); I915_WRITE(PF_WIN_SZ(pipe), 0); @@ -4993,7 +5038,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_disable_pipe(intel_crtc); - ironlake_pfit_disable(intel_crtc); + ironlake_pfit_disable(intel_crtc, false); if (intel_crtc->config->has_pch_encoder) ironlake_fdi_disable(crtc); @@ -5056,7 +5101,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) if (INTEL_INFO(dev)->gen >= 9) skylake_scaler_disable(intel_crtc); else - ironlake_pfit_disable(intel_crtc); + ironlake_pfit_disable(intel_crtc, false); intel_ddi_disable_pipe_clock(intel_crtc); @@ -11393,8 +11438,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, if (ret) goto cleanup_pending; - work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), obj) - + intel_crtc->dspaddr_offset; + work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), + obj, 0); + work->gtt_offset += intel_crtc->dspaddr_offset; if (mmio_flip) { ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring, @@ -12215,7 +12261,6 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) - static bool intel_compare_m_n(unsigned int m, unsigned int n, unsigned int m2, unsigned int n2, @@ -12436,22 +12481,24 @@ intel_pipe_config_compare(struct drm_device *dev, DRM_MODE_FLAG_NVSYNC); } - PIPE_CONF_CHECK_I(pipe_src_w); - PIPE_CONF_CHECK_I(pipe_src_h); - PIPE_CONF_CHECK_X(gmch_pfit.control); /* pfit ratios are autocomputed by the hw on gen4+ */ if (INTEL_INFO(dev)->gen < 4) PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits); - PIPE_CONF_CHECK_I(pch_pfit.enabled); - if (current_config->pch_pfit.enabled) { - PIPE_CONF_CHECK_X(pch_pfit.pos); - PIPE_CONF_CHECK_X(pch_pfit.size); - } + if (!adjust) { + PIPE_CONF_CHECK_I(pipe_src_w); + PIPE_CONF_CHECK_I(pipe_src_h); - PIPE_CONF_CHECK_I(scaler_state.scaler_id); + PIPE_CONF_CHECK_I(pch_pfit.enabled); + if (current_config->pch_pfit.enabled) { + PIPE_CONF_CHECK_X(pch_pfit.pos); + PIPE_CONF_CHECK_X(pch_pfit.size); + } + + PIPE_CONF_CHECK_I(scaler_state.scaler_id); + } /* BDW+ don't expose a synchronous way to read the state */ if (IS_HASWELL(dev)) @@ -12613,7 +12660,8 @@ check_crtc_state(struct drm_device *dev, struct drm_atomic_state *old_state) struct intel_crtc_state *pipe_config, *sw_config; bool active; - if (!needs_modeset(crtc->state)) + if (!needs_modeset(crtc->state) && + !to_intel_crtc_state(crtc->state)->update_pipe) continue; __drm_atomic_helper_crtc_destroy_state(crtc, old_crtc_state); @@ -12909,7 +12957,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state) return ret; } - static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -12995,11 +13042,11 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - if (i915.fastboot && - intel_pipe_config_compare(state->dev, + if (intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), pipe_config, true)) { crtc_state->mode_changed = false; + to_intel_crtc_state(crtc_state)->update_pipe = true; } if (needs_modeset(crtc_state)) { @@ -13097,16 +13144,30 @@ static int intel_atomic_commit(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); bool modeset = needs_modeset(crtc->state); + bool update_pipe = !modeset && + to_intel_crtc_state(crtc->state)->update_pipe; + unsigned long put_domains = 0; if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); } + if (update_pipe) { + put_domains = modeset_get_crtc_power_domains(crtc); + + /* make sure intel_modeset_check_state runs */ + any_ms = true; + } + if (!modeset) intel_pre_plane_update(intel_crtc); drm_atomic_helper_commit_planes_on_crtc(crtc_state); + + if (put_domains) + modeset_put_power_domains(dev_priv, put_domains); + intel_post_plane_update(intel_crtc); } @@ -13422,10 +13483,6 @@ intel_commit_primary_plane(struct drm_plane *plane, if (!crtc->state->active) return; - if (state->visible) - /* FIXME: kill this fastboot hack */ - intel_update_pipe_size(intel_crtc); - dev_priv->display.update_primary_plane(crtc, fb, state->src.x1 >> 16, state->src.y1 >> 16); @@ -13446,6 +13503,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *old_intel_state = + to_intel_crtc_state(old_crtc_state); + bool modeset = needs_modeset(crtc->state); if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); @@ -13454,7 +13514,12 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, if (crtc->state->active) intel_pipe_update_start(intel_crtc); - if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9) + if (modeset) + return; + + if (to_intel_crtc_state(crtc->state)->update_pipe) + intel_update_pipe_config(intel_crtc, old_intel_state); + else if (INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(intel_crtc); } @@ -14876,9 +14941,17 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) /* restore vblank interrupts to correct state */ drm_crtc_vblank_reset(&crtc->base); if (crtc->active) { - drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); - update_scanline_offset(crtc); + struct intel_plane *plane; + drm_crtc_vblank_on(&crtc->base); + + /* Disable everything but the primary plane */ + for_each_intel_plane_on_crtc(dev, crtc, plane) { + if (plane->base.type == DRM_PLANE_TYPE_PRIMARY) + continue; + + plane->disable_plane(&plane->base, &crtc->base); + } } /* We need to sanitize the plane -> pipe mapping first because this will @@ -15041,38 +15114,21 @@ void i915_redisable_vga(struct drm_device *dev) i915_redisable_vga_power_on(dev); } -static bool primary_get_hw_state(struct intel_crtc *crtc) +static bool primary_get_hw_state(struct intel_plane *plane) { - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - return !!(I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE); + return I915_READ(DSPCNTR(plane->plane)) & DISPLAY_PLANE_ENABLE; } -static void readout_plane_state(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state) +/* FIXME read out full plane state for all planes */ +static void readout_plane_state(struct intel_crtc *crtc) { - struct intel_plane *p; - struct intel_plane_state *plane_state; - bool active = crtc_state->base.active; - - for_each_intel_plane(crtc->base.dev, p) { - if (crtc->pipe != p->pipe) - continue; - - plane_state = to_intel_plane_state(p->base.state); + struct intel_plane_state *plane_state = + to_intel_plane_state(crtc->base.primary->state); - if (p->base.type == DRM_PLANE_TYPE_PRIMARY) { - plane_state->visible = primary_get_hw_state(crtc); - if (plane_state->visible) - crtc->base.state->plane_mask |= - 1 << drm_plane_index(&p->base); - } else { - if (active) - p->disable_plane(&p->base, &crtc->base); - - plane_state->visible = false; - } - } + plane_state->visible = + primary_get_hw_state(to_intel_plane(crtc->base.primary)); } static void intel_modeset_readout_hw_state(struct drm_device *dev) @@ -15095,34 +15151,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; - memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); - if (crtc->base.state->active) { - intel_mode_from_pipe_config(&crtc->base.mode, crtc->config); - intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config); - WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode)); - - /* - * The initial mode needs to be set in order to keep - * the atomic core happy. It wants a valid mode if the - * crtc's enabled, so we do the above call. - * - * At this point some state updated by the connectors - * in their ->detect() callback has not run yet, so - * no recalculation can be done yet. - * - * Even if we could do a recalculation and modeset - * right now it would cause a double modeset if - * fbdev or userspace chooses a different initial mode. - * - * If that happens, someone indicated they wanted a - * mode change, which means it's safe to do a full - * recalculation. - */ - crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED; - } - - crtc->base.hwmode = crtc->config->base.adjusted_mode; - readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state)); + readout_plane_state(crtc); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, @@ -15181,6 +15210,39 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) connector->base.name, connector->base.encoder ? "enabled" : "disabled"); } + + for_each_intel_crtc(dev, crtc) { + crtc->base.hwmode = crtc->config->base.adjusted_mode; + + memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); + if (crtc->base.state->active) { + intel_mode_from_pipe_config(&crtc->base.mode, crtc->config); + intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config); + WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode)); + + /* + * The initial mode needs to be set in order to keep + * the atomic core happy. It wants a valid mode if the + * crtc's enabled, so we do the above call. + * + * At this point some state updated by the connectors + * in their ->detect() callback has not run yet, so + * no recalculation can be done yet. + * + * Even if we could do a recalculation and modeset + * right now it would cause a double modeset if + * fbdev or userspace chooses a different initial mode. + * + * If that happens, someone indicated they wanted a + * mode change, which means it's safe to do a full + * recalculation. + */ + crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED; + + drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); + update_scanline_offset(crtc); + } + } } /* Scan out the current hw modeset state, |