if (ret)
goto cleanup_vga_client;
- /* Initialise stolen first so that we may reserve preallocated
- * objects for the BIOS to KMS transition.
- */
- ret = i915_gem_init_stolen(dev);
- if (ret)
- goto cleanup_vga_switcheroo;
-
intel_power_domains_init_hw(dev_priv, false);
intel_csr_ucode_init(dev_priv);
ret = intel_irq_install(dev_priv);
if (ret)
- goto cleanup_gem_stolen;
+ goto cleanup_csr;
intel_setup_gmbus(dev);
cleanup_gem:
mutex_lock(&dev->struct_mutex);
- i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev);
+ i915_gem_cleanup_engines(dev);
mutex_unlock(&dev->struct_mutex);
cleanup_irq:
intel_guc_ucode_fini(dev);
drm_irq_uninstall(dev);
intel_teardown_gmbus(dev);
- cleanup_gem_stolen:
- i915_gem_cleanup_stolen(dev);
- cleanup_vga_switcheroo:
+ cleanup_csr:
+ intel_csr_ucode_fini(dev_priv);
vga_switcheroo_unregister_client(dev->pdev);
cleanup_vga_client:
vga_client_register(dev->pdev, NULL, NULL, NULL);
!(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) {
DRM_INFO("Display fused off, disabling\n");
info->num_pipes = 0;
+ } else if (fuse_strap & IVB_PIPE_C_DISABLE) {
+ DRM_INFO("PipeC fused off\n");
+ info->num_pipes -= 1;
}
+ } else if (info->num_pipes > 0 && INTEL_INFO(dev)->gen == 9) {
+ u32 dfsm = I915_READ(SKL_DFSM);
+ u8 disabled_mask = 0;
+ bool invalid;
+ int num_bits;
+
+ if (dfsm & SKL_DFSM_PIPE_A_DISABLE)
+ disabled_mask |= BIT(PIPE_A);
+ if (dfsm & SKL_DFSM_PIPE_B_DISABLE)
+ disabled_mask |= BIT(PIPE_B);
+ if (dfsm & SKL_DFSM_PIPE_C_DISABLE)
+ disabled_mask |= BIT(PIPE_C);
+
+ num_bits = hweight8(disabled_mask);
+
+ switch (disabled_mask) {
+ case BIT(PIPE_A):
+ case BIT(PIPE_B):
+ case BIT(PIPE_A) | BIT(PIPE_B):
+ case BIT(PIPE_A) | BIT(PIPE_C):
+ invalid = true;
+ break;
+ default:
+ invalid = false;
+ }
+
+ if (num_bits > info->num_pipes || invalid)
+ DRM_ERROR("invalid pipe fuse configuration: 0x%x\n",
+ disabled_mask);
+ else
+ info->num_pipes -= num_bits;
}
/* Initialize slice/subslice/EU info */
}
}
+ static int i915_workqueues_init(struct drm_i915_private *dev_priv)
+ {
+ /*
+ * The i915 workqueue is primarily used for batched retirement of
+ * requests (and thus managing bo) once the task has been completed
+ * by the GPU. i915_gem_retire_requests() is called directly when we
+ * need high-priority retirement, such as waiting for an explicit
+ * bo.
+ *
+ * It is also used for periodic low-priority events, such as
+ * idle-timers and recording error state.
+ *
+ * All tasks on the workqueue are expected to acquire the dev mutex
+ * so there is no point in running more than one instance of the
+ * workqueue at any time. Use an ordered one.
+ */
+ dev_priv->wq = alloc_ordered_workqueue("i915", 0);
+ if (dev_priv->wq == NULL)
+ goto out_err;
+
+ dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0);
+ if (dev_priv->hotplug.dp_wq == NULL)
+ goto out_free_wq;
+
+ dev_priv->gpu_error.hangcheck_wq =
+ alloc_ordered_workqueue("i915-hangcheck", 0);
+ if (dev_priv->gpu_error.hangcheck_wq == NULL)
+ goto out_free_dp_wq;
+
+ return 0;
+
+ out_free_dp_wq:
+ destroy_workqueue(dev_priv->hotplug.dp_wq);
+ out_free_wq:
+ destroy_workqueue(dev_priv->wq);
+ out_err:
+ DRM_ERROR("Failed to allocate workqueues.\n");
+
+ return -ENOMEM;
+ }
+
+ static void i915_workqueues_cleanup(struct drm_i915_private *dev_priv)
+ {
+ destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
+ destroy_workqueue(dev_priv->hotplug.dp_wq);
+ destroy_workqueue(dev_priv->wq);
+ }
+
+ static int i915_mmio_setup(struct drm_device *dev)
+ {
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ int mmio_bar;
+ int mmio_size;
+
+ mmio_bar = IS_GEN2(dev) ? 1 : 0;
+ /*
+ * Before gen4, the registers and the GTT are behind different BARs.
+ * However, from gen4 onwards, the registers and the GTT are shared
+ * in the same BAR, so we want to restrict this ioremap from
+ * clobbering the GTT which we want ioremap_wc instead. Fortunately,
+ * the register BAR remains the same size for all the earlier
+ * generations up to Ironlake.
+ */
+ if (INTEL_INFO(dev)->gen < 5)
+ mmio_size = 512 * 1024;
+ else
+ mmio_size = 2 * 1024 * 1024;
+ dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
+ if (dev_priv->regs == NULL) {
+ DRM_ERROR("failed to map registers\n");
+
+ return -EIO;
+ }
+
+ /* Try to make sure MCHBAR is enabled before poking at it */
+ intel_setup_mchbar(dev);
+
+ return 0;
+ }
+
+ static void i915_mmio_cleanup(struct drm_device *dev)
+ {
+ struct drm_i915_private *dev_priv = to_i915(dev);
+
+ intel_teardown_mchbar(dev);
+ pci_iounmap(dev->pdev, dev_priv->regs);
+ }
+
/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
{
struct drm_i915_private *dev_priv;
struct intel_device_info *info, *device_info;
- int ret = 0, mmio_bar, mmio_size;
+ int ret = 0;
uint32_t aperture_size;
info = (struct intel_device_info *) flags;
mutex_init(&dev_priv->modeset_restore_lock);
mutex_init(&dev_priv->av_mutex);
+ ret = i915_workqueues_init(dev_priv);
+ if (ret < 0)
+ goto out_free_priv;
+
intel_pm_setup(dev);
intel_runtime_pm_get(dev_priv);
if (i915_get_bridge_dev(dev)) {
ret = -EIO;
- goto free_priv;
+ goto out_runtime_pm_put;
}
- mmio_bar = IS_GEN2(dev) ? 1 : 0;
- /* Before gen4, the registers and the GTT are behind different BARs.
- * However, from gen4 onwards, the registers and the GTT are shared
- * in the same BAR, so we want to restrict this ioremap from
- * clobbering the GTT which we want ioremap_wc instead. Fortunately,
- * the register BAR remains the same size for all the earlier
- * generations up to Ironlake.
- */
- if (info->gen < 5)
- mmio_size = 512*1024;
- else
- mmio_size = 2*1024*1024;
-
- dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
- if (!dev_priv->regs) {
- DRM_ERROR("failed to map registers\n");
- ret = -EIO;
+ ret = i915_mmio_setup(dev);
+ if (ret < 0)
goto put_bridge;
- }
/* This must be called before any calls to HAS_PCH_* */
intel_detect_pch(dev);
ret = i915_gem_gtt_init(dev);
if (ret)
- goto out_freecsr;
+ goto out_uncore_fini;
/* WARNING: Apparently we must kick fbdev drivers before vgacon,
* otherwise the vga fbdev driver falls over. */
dev_priv->gtt.mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
aperture_size);
- /* The i915 workqueue is primarily used for batched retirement of
- * requests (and thus managing bo) once the task has been completed
- * by the GPU. i915_gem_retire_requests() is called directly when we
- * need high-priority retirement, such as waiting for an explicit
- * bo.
- *
- * It is also used for periodic low-priority events, such as
- * idle-timers and recording error state.
- *
- * All tasks on the workqueue are expected to acquire the dev mutex
- * so there is no point in running more than one instance of the
- * workqueue at any time. Use an ordered one.
- */
- dev_priv->wq = alloc_ordered_workqueue("i915", 0);
- if (dev_priv->wq == NULL) {
- DRM_ERROR("Failed to create our workqueue.\n");
- ret = -ENOMEM;
- goto out_mtrrfree;
- }
-
- dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0);
- if (dev_priv->hotplug.dp_wq == NULL) {
- DRM_ERROR("Failed to create our dp workqueue.\n");
- ret = -ENOMEM;
- goto out_freewq;
- }
-
- dev_priv->gpu_error.hangcheck_wq =
- alloc_ordered_workqueue("i915-hangcheck", 0);
- if (dev_priv->gpu_error.hangcheck_wq == NULL) {
- DRM_ERROR("Failed to create our hangcheck workqueue.\n");
- ret = -ENOMEM;
- goto out_freedpwq;
- }
-
intel_irq_init(dev_priv);
intel_uncore_sanitize(dev);
- /* Try to make sure MCHBAR is enabled before poking at it */
- intel_setup_mchbar(dev);
intel_opregion_setup(dev);
- i915_gem_load(dev);
+ i915_gem_load_init(dev);
+ i915_gem_shrinker_init(dev_priv);
/* On the 945G/GM, the chipset reports the MSI capability on the
* integrated graphics even though the support isn't actually there
* be lost or delayed, but we use them anyways to avoid
* stuck interrupts on some machines.
*/
- if (!IS_I945G(dev) && !IS_I945GM(dev))
- pci_enable_msi(dev->pdev);
+ if (!IS_I945G(dev) && !IS_I945GM(dev)) {
+ if (pci_enable_msi(dev->pdev) < 0)
+ DRM_DEBUG_DRIVER("can't enable MSI");
+ }
intel_device_info_runtime_init(dev);
intel_power_domains_fini(dev_priv);
drm_vblank_cleanup(dev);
out_gem_unload:
- WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
- unregister_shrinker(&dev_priv->mm.shrinker);
+ i915_gem_shrinker_cleanup(dev_priv);
if (dev->pdev->msi_enabled)
pci_disable_msi(dev->pdev);
intel_teardown_mchbar(dev);
pm_qos_remove_request(&dev_priv->pm_qos);
- destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
- out_freedpwq:
- destroy_workqueue(dev_priv->hotplug.dp_wq);
- out_freewq:
- destroy_workqueue(dev_priv->wq);
- out_mtrrfree:
arch_phys_wc_del(dev_priv->gtt.mtrr);
io_mapping_free(dev_priv->gtt.mappable);
out_gtt:
i915_global_gtt_cleanup(dev);
- out_freecsr:
- intel_csr_ucode_fini(dev_priv);
+ out_uncore_fini:
intel_uncore_fini(dev);
- pci_iounmap(dev->pdev, dev_priv->regs);
+ i915_mmio_cleanup(dev);
put_bridge:
pci_dev_put(dev_priv->bridge_dev);
- free_priv:
- kmem_cache_destroy(dev_priv->requests);
- kmem_cache_destroy(dev_priv->vmas);
- kmem_cache_destroy(dev_priv->objects);
-
+ i915_gem_load_cleanup(dev);
+ out_runtime_pm_put:
intel_runtime_pm_put(dev_priv);
-
+ i915_workqueues_cleanup(dev_priv);
+ out_free_priv:
kfree(dev_priv);
+
return ret;
}
i915_teardown_sysfs(dev);
- WARN_ON(unregister_oom_notifier(&dev_priv->mm.oom_notifier));
- unregister_shrinker(&dev_priv->mm.shrinker);
+ i915_gem_shrinker_cleanup(dev_priv);
io_mapping_free(dev_priv->gtt.mappable);
arch_phys_wc_del(dev_priv->gtt.mtrr);
vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
+ intel_csr_ucode_fini(dev_priv);
+
/* Free error state after interrupts are fully disabled. */
cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
i915_destroy_error_state(dev);
intel_guc_ucode_fini(dev);
mutex_lock(&dev->struct_mutex);
- i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev);
+ i915_gem_cleanup_engines(dev);
mutex_unlock(&dev->struct_mutex);
intel_fbc_cleanup_cfb(dev_priv);
- i915_gem_cleanup_stolen(dev);
- intel_csr_ucode_fini(dev_priv);
-
- intel_teardown_mchbar(dev);
-
- destroy_workqueue(dev_priv->hotplug.dp_wq);
- destroy_workqueue(dev_priv->wq);
- destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
pm_qos_remove_request(&dev_priv->pm_qos);
i915_global_gtt_cleanup(dev);
intel_uncore_fini(dev);
- if (dev_priv->regs != NULL)
- pci_iounmap(dev->pdev, dev_priv->regs);
+ i915_mmio_cleanup(dev);
- kmem_cache_destroy(dev_priv->requests);
- kmem_cache_destroy(dev_priv->vmas);
- kmem_cache_destroy(dev_priv->objects);
+ i915_gem_load_cleanup(dev);
pci_dev_put(dev_priv->bridge_dev);
+ i915_workqueues_cleanup(dev_priv);
kfree(dev_priv);
return 0;
i915_gem_context_close(dev, file);
i915_gem_release(dev, file);
mutex_unlock(&dev->struct_mutex);
-
- intel_modeset_preclose(dev, file);
}
void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
const struct drm_plane_state *plane_state)
{
struct drm_i915_private *dev_priv = to_i915(fb->dev);
- struct intel_rotation_info *info = &view->params.rotation_info;
+ struct intel_rotation_info *info = &view->params.rotated;
unsigned int tile_size, tile_width, tile_height, cpp;
*view = i915_ggtt_view_normal;
tile_size = intel_tile_size(dev_priv);
cpp = drm_format_plane_cpp(fb->pixel_format, 0);
- tile_width = intel_tile_width(dev_priv, cpp, fb->modifier[0]);
+ tile_width = intel_tile_width(dev_priv, fb->modifier[0], cpp);
tile_height = tile_size / tile_width;
info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width);
/* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
* is assumed to be a power-of-two. */
- unsigned long intel_compute_tile_offset(struct drm_i915_private *dev_priv,
- int *x, int *y,
- uint64_t fb_modifier,
- unsigned int cpp,
- unsigned int pitch)
+ u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv,
+ int *x, int *y,
+ uint64_t fb_modifier,
+ unsigned int cpp,
+ unsigned int pitch)
{
if (fb_modifier != DRM_FORMAT_MOD_NONE) {
unsigned int tile_size, tile_width, tile_height;
struct drm_framebuffer *fb = plane_state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
int plane = intel_crtc->plane;
- unsigned long linear_offset;
- int x = plane_state->src.x1 >> 16;
- int y = plane_state->src.y1 >> 16;
+ u32 linear_offset;
u32 dspcntr;
i915_reg_t reg = DSPCNTR(plane);
- int pixel_size;
-
- pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+ int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+ int x = plane_state->src.x1 >> 16;
+ int y = plane_state->src.y1 >> 16;
dspcntr = DISPPLANE_GAMMA_ENABLE;
if (IS_G4X(dev))
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
- linear_offset = y * fb->pitches[0] + x * pixel_size;
+ linear_offset = y * fb->pitches[0] + x * cpp;
if (INTEL_INFO(dev)->gen >= 4) {
intel_crtc->dspaddr_offset =
intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0],
- pixel_size,
+ fb->modifier[0], cpp,
fb->pitches[0]);
linear_offset -= intel_crtc->dspaddr_offset;
} else {
data and adding to linear_offset*/
linear_offset +=
(crtc_state->pipe_src_h - 1) * fb->pitches[0] +
- (crtc_state->pipe_src_w - 1) * pixel_size;
+ (crtc_state->pipe_src_w - 1) * cpp;
}
intel_crtc->adjusted_x = x;
struct drm_framebuffer *fb = plane_state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
int plane = intel_crtc->plane;
- unsigned long linear_offset;
+ u32 linear_offset;
u32 dspcntr;
i915_reg_t reg = DSPCNTR(plane);
- int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+ int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
int x = plane_state->src.x1 >> 16;
int y = plane_state->src.y1 >> 16;
if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
- linear_offset = y * fb->pitches[0] + x * pixel_size;
+ linear_offset = y * fb->pitches[0] + x * cpp;
intel_crtc->dspaddr_offset =
intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0],
- pixel_size,
+ fb->modifier[0], cpp,
fb->pitches[0]);
linear_offset -= intel_crtc->dspaddr_offset;
if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
data and adding to linear_offset*/
linear_offset +=
(crtc_state->pipe_src_h - 1) * fb->pitches[0] +
- (crtc_state->pipe_src_w - 1) * pixel_size;
+ (crtc_state->pipe_src_w - 1) * cpp;
}
}
offset = vma->node.start;
if (plane == 1) {
- offset += vma->ggtt_view.params.rotation_info.uv_start_page *
+ offset += vma->ggtt_view.params.rotated.uv_start_page *
PAGE_SIZE;
}
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = to_intel_crtc(crtc)->pipe;
- if (dev_priv->fbc.deactivate)
- dev_priv->fbc.deactivate(dev_priv);
-
I915_WRITE(PLANE_CTL(pipe, 0), 0);
I915_WRITE(PLANE_SURF(pipe, 0), 0);
POSTING_READ(PLANE_SURF(pipe, 0));
intel_update_watermarks(&crtc->base);
if (atomic->update_fbc)
- intel_fbc_update(crtc);
+ intel_fbc_post_update(crtc);
if (atomic->post_enable_primary)
intel_post_enable_primary(&crtc->base);
memset(atomic, 0, sizeof(*atomic));
}
- static void intel_pre_plane_update(struct intel_crtc *crtc)
+ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
{
+ struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
struct intel_crtc_state *pipe_config =
to_intel_crtc_state(crtc->base.state);
+ struct drm_atomic_state *old_state = old_crtc_state->base.state;
+ struct drm_plane *primary = crtc->base.primary;
+ struct drm_plane_state *old_pri_state =
+ drm_atomic_get_existing_plane_state(old_state, primary);
+ bool modeset = needs_modeset(&pipe_config->base);
- if (atomic->disable_fbc)
- intel_fbc_deactivate(crtc);
+ if (atomic->update_fbc)
+ intel_fbc_pre_update(crtc);
- if (crtc->atomic.disable_ips)
- hsw_disable_ips(crtc);
+ if (old_pri_state) {
+ struct intel_plane_state *primary_state =
+ to_intel_plane_state(primary->state);
+ struct intel_plane_state *old_primary_state =
+ to_intel_plane_state(old_pri_state);
- if (atomic->pre_disable_primary)
- intel_pre_disable_primary(&crtc->base);
+ if (old_primary_state->visible &&
+ (modeset || !primary_state->visible))
+ intel_pre_disable_primary(&crtc->base);
+ }
if (pipe_config->disable_cxsr) {
crtc->wm.cxsr_allowed = false;
- intel_set_memory_cxsr(dev_priv, false);
+
+ if (old_crtc_state->base.active)
+ intel_set_memory_cxsr(dev_priv, false);
}
if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed)
if (intel_crtc->config->has_pch_encoder)
intel_wait_for_vblank(dev, pipe);
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
-
- intel_fbc_enable(intel_crtc);
}
/* IPS only exists on ULT machines and is tied to pipe A. */
intel_wait_for_vblank(dev, hsw_workaround_pipe);
intel_wait_for_vblank(dev, hsw_workaround_pipe);
}
-
- intel_fbc_enable(intel_crtc);
}
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
}
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true);
-
- intel_fbc_disable_crtc(intel_crtc);
}
static void haswell_crtc_disable(struct drm_crtc *crtc)
intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
true);
}
-
- intel_fbc_disable_crtc(intel_crtc);
}
static void i9xx_pfit_enable(struct intel_crtc *crtc)
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
-
- intel_fbc_enable(intel_crtc);
}
static void i9xx_pfit_disable(struct intel_crtc *crtc)
if (!IS_GEN2(dev))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
-
- intel_fbc_disable_crtc(intel_crtc);
}
static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
dev_priv->display.crtc_disable(crtc);
intel_crtc->active = false;
+ intel_fbc_disable(intel_crtc);
intel_update_watermarks(crtc);
intel_disable_shared_dpll(intel_crtc);
static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state)
{
- if (!intel_ddi_pll_select(crtc, crtc_state))
- return -EINVAL;
+ struct intel_encoder *intel_encoder =
+ intel_ddi_get_crtc_new_encoder(crtc_state);
+
+ if (intel_encoder->type != INTEL_OUTPUT_DSI) {
+ if (!intel_ddi_pll_select(crtc, crtc_state))
+ return -EINVAL;
+ }
crtc->lowfreq_avail = false;
mutex_unlock(&dev->struct_mutex);
intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit);
+ intel_fbc_post_update(crtc);
drm_framebuffer_unreference(work->old_fb);
BUG_ON(atomic_read(&crtc->unpin_work_count) == 0);
crtc->primary->fb = fb;
update_state_fb(crtc->primary);
+ intel_fbc_pre_update(intel_crtc);
work->pending_flip_obj = obj;
to_intel_plane(primary)->frontbuffer_bit);
mutex_unlock(&dev->struct_mutex);
- intel_fbc_deactivate(intel_crtc);
intel_frontbuffer_flip_prepare(dev,
to_intel_plane(primary)->frontbuffer_bit);
cleanup_unpin:
intel_unpin_fb_obj(fb, crtc->primary->state);
cleanup_pending:
- if (request)
+ if (!IS_ERR_OR_NULL(request))
i915_gem_request_cancel(request);
atomic_dec(&intel_crtc->unpin_work_count);
mutex_unlock(&dev->struct_mutex);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_plane *plane = plane_state->plane;
struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_plane_state *old_plane_state =
to_intel_plane_state(plane->state);
int idx = intel_crtc->base.base.id, ret;
switch (plane->type) {
case DRM_PLANE_TYPE_PRIMARY:
- intel_crtc->atomic.pre_disable_primary = turn_off;
intel_crtc->atomic.post_enable_primary = turn_on;
-
- if (turn_off) {
- /*
- * FIXME: Actually if we will still have any other
- * plane enabled on the pipe we could let IPS enabled
- * still, but for now lets consider that when we make
- * primary invisible by setting DSPCNTR to 0 on
- * update_primary_plane function IPS needs to be
- * disable.
- */
- intel_crtc->atomic.disable_ips = true;
-
- intel_crtc->atomic.disable_fbc = true;
- }
-
- /*
- * FBC does not work on some platforms for rotated
- * planes, so disable it when rotation is not 0 and
- * update it when rotation is set back to 0.
- *
- * FIXME: This is redundant with the fbc update done in
- * the primary plane enable function except that that
- * one is done too late. We eventually need to unify
- * this.
- */
-
- if (visible &&
- INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
- dev_priv->fbc.crtc == intel_crtc &&
- plane_state->rotation != BIT(DRM_ROTATE_0))
- intel_crtc->atomic.disable_fbc = true;
+ intel_crtc->atomic.update_fbc = true;
/*
* BDW signals flip done immediately if the plane
if (turn_on && IS_BROADWELL(dev))
intel_crtc->atomic.wait_vblank = true;
- intel_crtc->atomic.update_fbc |= visible || mode_changed;
break;
case DRM_PLANE_TYPE_CURSOR:
break;
static int intel_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
return ret;
if (i915.fastboot &&
- intel_pipe_config_compare(state->dev,
+ intel_pipe_config_compare(dev,
to_intel_crtc_state(crtc->state),
pipe_config, true)) {
crtc_state->mode_changed = false;
if (ret)
return ret;
} else
- intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
+ intel_state->cdclk = dev_priv->cdclk_freq;
- ret = drm_atomic_helper_check_planes(state->dev, state);
+ ret = drm_atomic_helper_check_planes(dev, state);
if (ret)
return ret;
+ intel_fbc_choose_crtc(dev_priv, state);
calc_watermark_data(state);
return 0;
if (!needs_modeset(crtc->state))
continue;
- intel_pre_plane_update(intel_crtc);
+ intel_pre_plane_update(to_intel_crtc_state(crtc_state));
if (crtc_state->active) {
intel_crtc_disable_planes(crtc, crtc_state->plane_mask);
dev_priv->display.crtc_disable(crtc);
intel_crtc->active = false;
+ intel_fbc_disable(intel_crtc);
intel_disable_shared_dpll(intel_crtc);
/*
}
if (!modeset)
- intel_pre_plane_update(intel_crtc);
+ intel_pre_plane_update(to_intel_crtc_state(crtc_state));
+
+ if (crtc->state->active && intel_crtc->atomic.update_fbc)
+ intel_fbc_enable(intel_crtc);
if (crtc->state->active &&
(crtc->state->planes_changed || update_pipe))
u32 gen = INTEL_INFO(dev)->gen;
if (gen >= 9) {
+ int cpp = drm_format_plane_cpp(pixel_format, 0);
+
/* "The stride in bytes must not exceed the of the size of 8K
* pixels and 32K bytes."
*/
- return min(8192*drm_format_plane_cpp(pixel_format, 0), 32768);
+ return min(8192 * cpp, 32768);
} else if (gen >= 5 && !IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev)) {
return 32*1024;
} else if (gen >= 4) {
modeset_put_power_domains(dev_priv, put_domains);
}
intel_display_set_init_power(dev_priv, false);
+
+ intel_fbc_init_pipe_state(dev_priv);
}
void intel_display_resume(struct drm_device *dev)
intel_unregister_dsm_handler();
- intel_fbc_disable(dev_priv);
+ intel_fbc_global_disable(dev_priv);
/* flush any delayed tasks or pending work */
flush_scheduled_work();
err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync);
}
}
-
-void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file)
-{
- struct intel_crtc *crtc;
-
- for_each_intel_crtc(dev, crtc) {
- struct intel_unpin_work *work;
-
- spin_lock_irq(&dev->event_lock);
-
- work = crtc->unpin_work;
-
- if (work && work->event &&
- work->event->base.file_priv == file) {
- kfree(work->event);
- work->event = NULL;
- }
-
- spin_unlock_irq(&dev->event_lock);
- }
-}
bool ips_enabled;
+ bool enable_fbc;
+
bool double_wide;
bool dp_encoder_is_mst;
*/
struct intel_crtc_atomic_commit {
/* Sleepable operations to perform before commit */
- bool disable_fbc;
- bool disable_ips;
- bool pre_disable_primary;
/* Sleepable operations to perform after commit */
unsigned fb_bits;
bool wait_vblank;
- bool update_fbc;
bool post_enable_primary;
unsigned update_sprite_watermarks;
+
+ /* Sleepable operations to perform before and after commit */
+ bool update_fbc;
};
struct intel_crtc {
/* Display surface base address adjustement for pageflips. Note that on
* gen4+ this only adjusts up to a tile, offsets within a tile are
* handled in the hw itself (with the TILEOFF register). */
- unsigned long dspaddr_offset;
+ u32 dspaddr_offset;
int adjusted_x;
int adjusted_y;
void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state);
#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
- unsigned long intel_compute_tile_offset(struct drm_i915_private *dev_priv,
- int *x, int *y,
- uint64_t fb_modifier,
- unsigned int cpp,
- unsigned int pitch);
+ u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv,
+ int *x, int *y,
+ uint64_t fb_modifier,
+ unsigned int cpp,
+ unsigned int pitch);
void intel_prepare_reset(struct drm_device *dev);
void intel_finish_reset(struct drm_device *dev);
void hsw_enable_pc8(struct drm_i915_private *dev_priv);
intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder);
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
struct intel_crtc_state *pipe_config);
-void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
#endif
/* intel_fbc.c */
+ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
+ struct drm_atomic_state *state);
bool intel_fbc_is_active(struct drm_i915_private *dev_priv);
- void intel_fbc_deactivate(struct intel_crtc *crtc);
- void intel_fbc_update(struct intel_crtc *crtc);
+ void intel_fbc_pre_update(struct intel_crtc *crtc);
+ void intel_fbc_post_update(struct intel_crtc *crtc);
void intel_fbc_init(struct drm_i915_private *dev_priv);
+ void intel_fbc_init_pipe_state(struct drm_i915_private *dev_priv);
void intel_fbc_enable(struct intel_crtc *crtc);
- void intel_fbc_disable(struct drm_i915_private *dev_priv);
- void intel_fbc_disable_crtc(struct intel_crtc *crtc);
+ void intel_fbc_disable(struct intel_crtc *crtc);
+ void intel_fbc_global_disable(struct drm_i915_private *dev_priv);
void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits,
enum fb_op_origin origin);
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
struct skl_ddb_allocation *ddb /* out */);
uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
+ int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6);
/* intel_sdvo.c */
bool intel_sdvo_init(struct drm_device *dev,