Merge tag 'drm-intel-next-2018-07-09' of git://anongit.freedesktop.org/drm/drm-intel...
authorDave Airlie <airlied@redhat.com>
Wed, 18 Jul 2018 19:46:24 +0000 (05:46 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 18 Jul 2018 19:46:30 +0000 (05:46 +1000)
Higlights here goes to many PSR fixes and improvements; to the Ice lake work with
power well support and begin of DSI support addition. Also there were many improvements
on execlists and interrupts for minimal latency on command submission; and many fixes
on selftests, mostly caught by our CI.

General driver:
- Clean-up on aux irq (Lucas)
- Mark expected switch fall-through for dealing with static analysis tools (Gustavo)

Gem:
- Different fixes for GuC (Chris, Anusha, Michal)
- Avoid self-relocation BIAS if no relocation (Chris)
- Improve debugging cases in on EINVAL return and vma allocation (Chris)
- Fixes and improvements on context destroying and freeing (Chris)
- Wait for engines to idle before retiring (Chris)
- Many improvements on execlists and interrupts for minimal latency on command submission (Chris)
- Many fixes in selftests, specially on cases highlighted on CI (Chris)
- Other fixes and improvements around GGTT (Chris)
- Prevent background reaping of active objects (Chris)

Display:
- Parallel modeset cleanup to fix driver reset (Chris)
- Get AUX power domain for DP main link (Imre)
- Clean-up on PSR unused func pointers (Rodrigo)
- Many PSR/PSR2 fixes and improvements (DK, Jose, Tarun)
- Add a PSR1 live status (Vathsala)
- Replace old drm_*_{un/reference} with put,get functions (Thomas)
- FBC fixes (Maarten)
- Abstract and document the usage of picking macros (Jani)
- Remove unnecessary check for unsupported modifiers for NV12. (DK)
- Interrupt fixes for display (Ville)
- Clean up on sdvo code (Ville)
- Clean up on current DSI code (Jani)
- Remove support for legacy debugfs crc interface (Maarten)
- Simplify get_encoder_power_domains (Imre)

Icelake:
- MG PLL fixes (Imre)
- Add hw workaround for alpha blending (Vandita)
- Add power well support (Imre)
- Add Interrupt Support (Anusha)
- Start to add support for DSI on Ice Lake (Madhav)

Signed-off-by: Dave Airlie <airlied@redhat.com>
# gpg: Signature made Tue 10 Jul 2018 08:41:37 AM AEST
# gpg:                using RSA key FA625F640EEB13CA
# gpg: Good signature from "Rodrigo Vivi <rodrigo.vivi@intel.com>"
# gpg:                 aka "Rodrigo Vivi <rodrigo.vivi@gmail.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 6D20 7068 EEDD 6509 1C2C  E2A3 FA62 5F64 0EEB 13CA
Link: https://patchwork.freedesktop.org/patch/msgid/20180710234349.GA16562@intel.com
78 files changed:
drivers/gpu/drm/i915/Kconfig.debug
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem.h
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_evict.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_object.h
drivers/gpu/drm/i915/i915_gem_render_state.c
drivers/gpu/drm/i915/i915_gem_shrinker.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_gpu_error.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_request.h
drivers/gpu/drm/i915/i915_timeline.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/i915_vma.h
drivers/gpu/drm/i915/icl_dsi.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_breadcrumbs.c
drivers/gpu/drm/i915/intel_cdclk.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_device_info.c
drivers/gpu/drm/i915/intel_device_info.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_display.h
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_dp_mst.c
drivers/gpu/drm/i915/intel_dpll_mgr.c
drivers/gpu/drm/i915/intel_dpll_mgr.h
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_dsi.c [deleted file]
drivers/gpu/drm/i915/intel_dsi.h
drivers/gpu/drm/i915/intel_dsi_pll.c [deleted file]
drivers/gpu/drm/i915/intel_dsi_vbt.c
drivers/gpu/drm/i915/intel_engine_cs.c
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_guc.c
drivers/gpu/drm/i915/intel_guc.h
drivers/gpu/drm/i915/intel_huc.c
drivers/gpu/drm/i915/intel_huc.h
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_pipe_crc.c
drivers/gpu/drm/i915/intel_psr.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_uc.c
drivers/gpu/drm/i915/selftests/huge_pages.c
drivers/gpu/drm/i915/selftests/i915_gem_coherency.c
drivers/gpu/drm/i915/selftests/i915_gem_context.c
drivers/gpu/drm/i915/selftests/i915_gem_dmabuf.c
drivers/gpu/drm/i915/selftests/i915_gem_evict.c
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/i915/selftests/i915_gem_object.c
drivers/gpu/drm/i915/selftests/i915_request.c
drivers/gpu/drm/i915/selftests/i915_vma.c
drivers/gpu/drm/i915/selftests/igt_flush_test.c
drivers/gpu/drm/i915/selftests/intel_breadcrumbs.c
drivers/gpu/drm/i915/selftests/intel_hangcheck.c
drivers/gpu/drm/i915/selftests/intel_lrc.c
drivers/gpu/drm/i915/selftests/intel_workarounds.c
drivers/gpu/drm/i915/selftests/mock_engine.c
drivers/gpu/drm/i915/selftests/mock_gem_device.c
drivers/gpu/drm/i915/selftests/mock_gtt.c
drivers/gpu/drm/i915/vlv_dsi.c [new file with mode: 0644]
drivers/gpu/drm/i915/vlv_dsi_pll.c [new file with mode: 0644]

index 9de8b1c51a5ccda8f6f7140f90ed4707b40d1da3..459f8f88a34cda0747ca37e7ccf43c4ca64fe283 100644 (file)
@@ -51,6 +51,18 @@ config DRM_I915_DEBUG_GEM
 
           If in doubt, say "N".
 
+config DRM_I915_ERRLOG_GEM
+       bool "Insert extra logging (very verbose) for common GEM errors"
+       default n
+       depends on DRM_I915_DEBUG_GEM
+       help
+         Enable additional logging that may help track down the cause of
+         principally userspace errors.
+
+         Recommended for driver developers only.
+
+         If in doubt, say "N".
+
 config DRM_I915_TRACE_GEM
        bool "Insert extra ftrace output from the GEM internals"
        depends on DRM_I915_DEBUG_GEM
index 4c6adae23e18e18195e468e2abb959cf0ed67219..5794f102f9b8f0cde364f2a04123e1893ffbfd84 100644 (file)
@@ -135,15 +135,14 @@ i915-y += dvo_ch7017.o \
          dvo_ns2501.o \
          dvo_sil164.o \
          dvo_tfp410.o \
+         icl_dsi.o \
          intel_crt.o \
          intel_ddi.o \
          intel_dp_aux_backlight.o \
          intel_dp_link_training.o \
          intel_dp_mst.o \
          intel_dp.o \
-         intel_dsi.o \
          intel_dsi_dcs_backlight.o \
-         intel_dsi_pll.o \
          intel_dsi_vbt.o \
          intel_dvo.o \
          intel_hdmi.o \
@@ -152,7 +151,9 @@ i915-y += dvo_ch7017.o \
          intel_lvds.o \
          intel_panel.o \
          intel_sdvo.o \
-         intel_tv.o
+         intel_tv.o \
+         vlv_dsi.o \
+         vlv_dsi_pll.o
 
 # Post-mortem debug and GPU hang state capture
 i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o
index 928818f218f7fb91091208fbb365c5a53846e395..b0e566956b8d5ce1609c0f19f31ffa45e610adee 100644 (file)
@@ -476,7 +476,11 @@ static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
                        i915_gem_obj_finish_shmem_access(bb->obj);
                        bb->accessing = false;
 
-                       i915_vma_move_to_active(bb->vma, workload->req, 0);
+                       ret = i915_vma_move_to_active(bb->vma,
+                                                     workload->req,
+                                                     0);
+                       if (ret)
+                               goto err;
                }
        }
        return 0;
index c400f42a54ec73b3cdd7a0b65920af2703152b4b..099f97ef2303905539d59d6d80c6bf53923c29d9 100644 (file)
@@ -1659,11 +1659,6 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        else
                seq_printf(m, "FBC disabled: %s\n", fbc->no_fbc_reason);
 
-       if (fbc->work.scheduled)
-               seq_printf(m, "FBC worker scheduled on vblank %llu, now %llu\n",
-                          fbc->work.scheduled_vblank,
-                          drm_crtc_vblank_count(&fbc->crtc->base));
-
        if (intel_fbc_is_active(dev_priv)) {
                u32 mask;
 
@@ -2597,27 +2592,55 @@ static const struct file_operations i915_guc_log_relay_fops = {
        .release = i915_guc_log_relay_release,
 };
 
-static const char *psr2_live_status(u32 val)
-{
-       static const char * const live_status[] = {
-               "IDLE",
-               "CAPTURE",
-               "CAPTURE_FS",
-               "SLEEP",
-               "BUFON_FW",
-               "ML_UP",
-               "SU_STANDBY",
-               "FAST_SLEEP",
-               "DEEP_SLEEP",
-               "BUF_ON",
-               "TG_ON"
-       };
+static void
+psr_source_status(struct drm_i915_private *dev_priv, struct seq_file *m)
+{
+       u32 val, psr_status;
 
-       val = (val & EDP_PSR2_STATUS_STATE_MASK) >> EDP_PSR2_STATUS_STATE_SHIFT;
-       if (val < ARRAY_SIZE(live_status))
-               return live_status[val];
+       if (dev_priv->psr.psr2_enabled) {
+               static const char * const live_status[] = {
+                       "IDLE",
+                       "CAPTURE",
+                       "CAPTURE_FS",
+                       "SLEEP",
+                       "BUFON_FW",
+                       "ML_UP",
+                       "SU_STANDBY",
+                       "FAST_SLEEP",
+                       "DEEP_SLEEP",
+                       "BUF_ON",
+                       "TG_ON"
+               };
+               psr_status = I915_READ(EDP_PSR2_STATUS);
+               val = (psr_status & EDP_PSR2_STATUS_STATE_MASK) >>
+                       EDP_PSR2_STATUS_STATE_SHIFT;
+               if (val < ARRAY_SIZE(live_status)) {
+                       seq_printf(m, "Source PSR status: 0x%x [%s]\n",
+                                  psr_status, live_status[val]);
+                       return;
+               }
+       } else {
+               static const char * const live_status[] = {
+                       "IDLE",
+                       "SRDONACK",
+                       "SRDENT",
+                       "BUFOFF",
+                       "BUFON",
+                       "AUXACK",
+                       "SRDOFFACK",
+                       "SRDENT_ON",
+               };
+               psr_status = I915_READ(EDP_PSR_STATUS);
+               val = (psr_status & EDP_PSR_STATUS_STATE_MASK) >>
+                       EDP_PSR_STATUS_STATE_SHIFT;
+               if (val < ARRAY_SIZE(live_status)) {
+                       seq_printf(m, "Source PSR status: 0x%x [%s]\n",
+                                  psr_status, live_status[val]);
+                       return;
+               }
+       }
 
-       return "unknown";
+       seq_printf(m, "Source PSR status: 0x%x [%s]\n", psr_status, "unknown");
 }
 
 static const char *psr_sink_status(u8 val)
@@ -2681,12 +2704,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
 
                seq_printf(m, "Performance_Counter: %u\n", psrperf);
        }
-       if (dev_priv->psr.psr2_enabled) {
-               u32 psr2 = I915_READ(EDP_PSR2_STATUS);
 
-               seq_printf(m, "EDP_PSR2_STATUS: %x [%s]\n",
-                          psr2, psr2_live_status(psr2));
-       }
+       psr_source_status(dev_priv, m);
 
        if (dev_priv->psr.enabled) {
                struct drm_dp_aux *aux = &dev_priv->psr.enabled->aux;
@@ -4086,7 +4105,8 @@ fault_irq_set(struct drm_i915_private *i915,
 
        err = i915_gem_wait_for_idle(i915,
                                     I915_WAIT_LOCKED |
-                                    I915_WAIT_INTERRUPTIBLE);
+                                    I915_WAIT_INTERRUPTIBLE,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (err)
                goto err_unlock;
 
@@ -4191,7 +4211,8 @@ i915_drop_caches_set(void *data, u64 val)
                if (val & DROP_ACTIVE)
                        ret = i915_gem_wait_for_idle(dev_priv,
                                                     I915_WAIT_INTERRUPTIBLE |
-                                                    I915_WAIT_LOCKED);
+                                                    I915_WAIT_LOCKED,
+                                                    MAX_SCHEDULE_TIMEOUT);
 
                if (val & DROP_RETIRE)
                        i915_retire_requests(dev_priv);
@@ -4799,7 +4820,6 @@ static const struct i915_debugfs_files {
 #endif
        {"i915_fifo_underrun_reset", &i915_fifo_underrun_reset_ops},
        {"i915_next_seqno", &i915_next_seqno_fops},
-       {"i915_display_crc_ctl", &i915_display_crc_ctl_fops},
        {"i915_pri_wm_latency", &i915_pri_wm_latency_fops},
        {"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
        {"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
@@ -4819,7 +4839,7 @@ int i915_debugfs_register(struct drm_i915_private *dev_priv)
 {
        struct drm_minor *minor = dev_priv->drm.primary;
        struct dentry *ent;
-       int ret, i;
+       int i;
 
        ent = debugfs_create_file("i915_forcewake_user", S_IRUSR,
                                  minor->debugfs_root, to_i915(minor->dev),
@@ -4827,10 +4847,6 @@ int i915_debugfs_register(struct drm_i915_private *dev_priv)
        if (!ent)
                return -ENOMEM;
 
-       ret = intel_pipe_crc_create(minor);
-       if (ret)
-               return ret;
-
        for (i = 0; i < ARRAY_SIZE(i915_debugfs_files); i++) {
                ent = debugfs_create_file(i915_debugfs_files[i].name,
                                          S_IRUGO | S_IWUSR,
index beb0951001ce3f43b5d2c3405055e47510de4933..0db3c83cce294b56642bc7edcf05920dd41da193 100644 (file)
@@ -1165,6 +1165,12 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
         * get lost on g4x as well, and interrupt delivery seems to stay
         * properly dead afterwards. So we'll just disable them for all
         * pre-gen5 chipsets.
+        *
+        * dp aux and gmbus irq on gen4 seems to be able to generate legacy
+        * interrupts even when in MSI mode. This results in spurious
+        * interrupt warnings if the legacy irq no. is shared with another
+        * device. The kernel then disables that interrupt source and so
+        * prevents the other device from working properly.
         */
        if (INTEL_GEN(dev_priv) >= 5) {
                if (pci_enable_msi(pdev) < 0)
index f4751b383858b4fc6559699b9ed23f79a4388c3c..eeb002a470321efa6905d7e18ec11cf991df2703 100644 (file)
@@ -86,8 +86,8 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20180620"
-#define DRIVER_TIMESTAMP       1529529048
+#define DRIVER_DATE            "20180709"
+#define DRIVER_TIMESTAMP       1531175967
 
 /* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
  * WARN_ON()) for hw state sanity checks to check for unexpected conditions
@@ -512,6 +512,7 @@ struct intel_fbc {
 
        bool enabled;
        bool active;
+       bool flip_pending;
 
        bool underrun_detected;
        struct work_struct underrun_work;
@@ -579,12 +580,6 @@ struct intel_fbc {
                unsigned int gen9_wa_cfb_stride;
        } params;
 
-       struct intel_fbc_work {
-               bool scheduled;
-               u64 scheduled_vblank;
-               struct work_struct work;
-       } work;
-
        const char *no_fbc_reason;
 };
 
@@ -631,14 +626,6 @@ struct i915_psr {
        bool debug;
        ktime_t last_entry_attempt;
        ktime_t last_exit;
-
-       void (*enable_source)(struct intel_dp *,
-                             const struct intel_crtc_state *);
-       void (*disable_source)(struct intel_dp *,
-                              const struct intel_crtc_state *);
-       void (*enable_sink)(struct intel_dp *);
-       void (*activate)(struct intel_dp *);
-       void (*setup_vsc)(struct intel_dp *, const struct intel_crtc_state *);
 };
 
 enum intel_pch {
@@ -965,7 +952,7 @@ struct i915_gem_mm {
        /**
         * Small stash of WC pages
         */
-       struct pagevec wc_stash;
+       struct pagestash wc_stash;
 
        /**
         * tmpfs instance used for shmem backed objects
@@ -1284,20 +1271,11 @@ enum intel_pipe_crc_source {
        INTEL_PIPE_CRC_SOURCE_MAX,
 };
 
-struct intel_pipe_crc_entry {
-       uint32_t frame;
-       uint32_t crc[5];
-};
-
 #define INTEL_PIPE_CRC_ENTRIES_NR      128
 struct intel_pipe_crc {
        spinlock_t lock;
-       bool opened;            /* exclusive access to the result file */
-       struct intel_pipe_crc_entry *entries;
-       enum intel_pipe_crc_source source;
-       int head, tail;
-       wait_queue_head_t wq;
        int skipped;
+       enum intel_pipe_crc_source source;
 };
 
 struct i915_frontbuffer_tracking {
@@ -1757,7 +1735,6 @@ struct drm_i915_private {
        struct drm_atomic_state *modeset_restore_state;
        struct drm_modeset_acquire_ctx reset_ctx;
 
-       struct list_head vm_list; /* Global list of all address spaces */
        struct i915_ggtt ggtt; /* VM representing the global address space */
 
        struct i915_gem_mm mm;
@@ -2326,6 +2303,7 @@ intel_info(const struct drm_i915_private *dev_priv)
 }
 
 #define INTEL_INFO(dev_priv)   intel_info((dev_priv))
+#define DRIVER_CAPS(dev_priv)  (&(dev_priv)->caps)
 
 #define INTEL_GEN(dev_priv)    ((dev_priv)->info.gen)
 #define INTEL_DEVID(dev_priv)  ((dev_priv)->info.device_id)
@@ -2578,16 +2556,6 @@ intel_info(const struct drm_i915_private *dev_priv)
        (IS_CANNONLAKE(dev_priv) || \
         IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv))
 
-/*
- * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts
- * even when in MSI mode. This results in spurious interrupt warnings if the
- * legacy irq no. is shared with another device. The kernel then disables that
- * interrupt source and so prevents the other device from working properly.
- *
- * Since we don't enable MSI anymore on gen4, we can always use GMBUS/AUX
- * interrupts.
- */
-#define HAS_AUX_IRQ(dev_priv)   true
 #define HAS_GMBUS_IRQ(dev_priv) (INTEL_GEN(dev_priv) >= 4)
 
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
@@ -3119,9 +3087,6 @@ i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj)
 }
 
 int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
-void i915_vma_move_to_active(struct i915_vma *vma,
-                            struct i915_request *rq,
-                            unsigned int flags);
 int i915_gem_dumb_create(struct drm_file *file_priv,
                         struct drm_device *dev,
                         struct drm_mode_create_dumb *args);
@@ -3189,7 +3154,7 @@ void i915_gem_init_swizzling(struct drm_i915_private *dev_priv);
 void i915_gem_fini(struct drm_i915_private *dev_priv);
 void i915_gem_cleanup_engines(struct drm_i915_private *dev_priv);
 int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
-                          unsigned int flags);
+                          unsigned int flags, long timeout);
 int __must_check i915_gem_suspend(struct drm_i915_private *dev_priv);
 void i915_gem_suspend_late(struct drm_i915_private *dev_priv);
 void i915_gem_resume(struct drm_i915_private *dev_priv);
index 858d188dd33bc7c5ba33b144195ae5a772fc19fc..b35cbfd16c9c45cb5ffd95f3256d140f5c306c2d 100644 (file)
@@ -837,6 +837,10 @@ flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains)
                }
                break;
 
+       case I915_GEM_DOMAIN_WC:
+               wmb();
+               break;
+
        case I915_GEM_DOMAIN_CPU:
                i915_gem_clflush_object(obj, I915_CLFLUSH_SYNC);
                break;
@@ -2006,7 +2010,6 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf)
        bool write = !!(vmf->flags & FAULT_FLAG_WRITE);
        struct i915_vma *vma;
        pgoff_t page_offset;
-       unsigned int flags;
        int ret;
 
        /* We don't use vmf->pgoff since that has the fake offset */
@@ -2042,27 +2045,34 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf)
                goto err_unlock;
        }
 
-       /* If the object is smaller than a couple of partial vma, it is
-        * not worth only creating a single partial vma - we may as well
-        * clear enough space for the full object.
-        */
-       flags = PIN_MAPPABLE;
-       if (obj->base.size > 2 * MIN_CHUNK_PAGES << PAGE_SHIFT)
-               flags |= PIN_NONBLOCK | PIN_NONFAULT;
 
        /* Now pin it into the GTT as needed */
-       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, flags);
+       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
+                                      PIN_MAPPABLE |
+                                      PIN_NONBLOCK |
+                                      PIN_NONFAULT);
        if (IS_ERR(vma)) {
                /* Use a partial view if it is bigger than available space */
                struct i915_ggtt_view view =
                        compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES);
+               unsigned int flags;
 
-               /* Userspace is now writing through an untracked VMA, abandon
+               flags = PIN_MAPPABLE;
+               if (view.type == I915_GGTT_VIEW_NORMAL)
+                       flags |= PIN_NONBLOCK; /* avoid warnings for pinned */
+
+               /*
+                * Userspace is now writing through an untracked VMA, abandon
                 * all hope that the hardware is able to track future writes.
                 */
                obj->frontbuffer_ggtt_origin = ORIGIN_CPU;
 
-               vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
+               vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags);
+               if (IS_ERR(vma) && !view.type) {
+                       flags = PIN_MAPPABLE;
+                       view.type = I915_GGTT_VIEW_PARTIAL;
+                       vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags);
+               }
        }
        if (IS_ERR(vma)) {
                ret = PTR_ERR(vma);
@@ -2114,6 +2124,7 @@ err:
                 */
                if (!i915_terminally_wedged(&dev_priv->gpu_error))
                        return VM_FAULT_SIGBUS;
+               /* else: fall through */
        case -EAGAIN:
                /*
                 * EAGAIN means the gpu is hung and we'll wait for the error
@@ -2256,7 +2267,9 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
 
        /* Attempt to reap some mmap space from dead objects */
        do {
-               err = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE);
+               err = i915_gem_wait_for_idle(dev_priv,
+                                            I915_WAIT_INTERRUPTIBLE,
+                                            MAX_SCHEDULE_TIMEOUT);
                if (err)
                        break;
 
@@ -3074,25 +3087,6 @@ int i915_gem_reset_prepare(struct drm_i915_private *dev_priv)
        return err;
 }
 
-static void skip_request(struct i915_request *request)
-{
-       void *vaddr = request->ring->vaddr;
-       u32 head;
-
-       /* As this request likely depends on state from the lost
-        * context, clear out all the user operations leaving the
-        * breadcrumb at the end (so we get the fence notifications).
-        */
-       head = request->head;
-       if (request->postfix < head) {
-               memset(vaddr + head, 0, request->ring->size - head);
-               head = 0;
-       }
-       memset(vaddr + head, 0, request->postfix - head);
-
-       dma_fence_set_error(&request->fence, -EIO);
-}
-
 static void engine_skip_context(struct i915_request *request)
 {
        struct intel_engine_cs *engine = request->engine;
@@ -3103,14 +3097,14 @@ static void engine_skip_context(struct i915_request *request)
        GEM_BUG_ON(timeline == &engine->timeline);
 
        spin_lock_irqsave(&engine->timeline.lock, flags);
-       spin_lock_nested(&timeline->lock, SINGLE_DEPTH_NESTING);
+       spin_lock(&timeline->lock);
 
        list_for_each_entry_continue(request, &engine->timeline.requests, link)
                if (request->gem_context == hung_ctx)
-                       skip_request(request);
+                       i915_request_skip(request, -EIO);
 
        list_for_each_entry(request, &timeline->requests, link)
-               skip_request(request);
+               i915_request_skip(request, -EIO);
 
        spin_unlock(&timeline->lock);
        spin_unlock_irqrestore(&engine->timeline.lock, flags);
@@ -3153,7 +3147,7 @@ i915_gem_reset_request(struct intel_engine_cs *engine,
 
        if (stalled) {
                i915_gem_context_mark_guilty(request->gem_context);
-               skip_request(request);
+               i915_request_skip(request, -EIO);
 
                /* If this context is now banned, skip all pending requests. */
                if (i915_gem_context_is_banned(request->gem_context))
@@ -3750,14 +3744,14 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
        return ret;
 }
 
-static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags)
+static long wait_for_timeline(struct i915_timeline *tl,
+                             unsigned int flags, long timeout)
 {
        struct i915_request *rq;
-       long ret;
 
        rq = i915_gem_active_get_unlocked(&tl->last_request);
        if (!rq)
-               return 0;
+               return timeout;
 
        /*
         * "Race-to-idle".
@@ -3771,10 +3765,10 @@ static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags)
        if (flags & I915_WAIT_FOR_IDLE_BOOST)
                gen6_rps_boost(rq, NULL);
 
-       ret = i915_request_wait(rq, flags, MAX_SCHEDULE_TIMEOUT);
+       timeout = i915_request_wait(rq, flags, timeout);
        i915_request_put(rq);
 
-       return ret < 0 ? ret : 0;
+       return timeout;
 }
 
 static int wait_for_engines(struct drm_i915_private *i915)
@@ -3790,10 +3784,12 @@ static int wait_for_engines(struct drm_i915_private *i915)
        return 0;
 }
 
-int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
+int i915_gem_wait_for_idle(struct drm_i915_private *i915,
+                          unsigned int flags, long timeout)
 {
-       GEM_TRACE("flags=%x (%s)\n",
-                 flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked");
+       GEM_TRACE("flags=%x (%s), timeout=%ld%s\n",
+                 flags, flags & I915_WAIT_LOCKED ? "locked" : "unlocked",
+                 timeout, timeout == MAX_SCHEDULE_TIMEOUT ? " (forever)" : "");
 
        /* If the device is asleep, we have no requests outstanding */
        if (!READ_ONCE(i915->gt.awake))
@@ -3806,27 +3802,31 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
                lockdep_assert_held(&i915->drm.struct_mutex);
 
                list_for_each_entry(tl, &i915->gt.timelines, link) {
-                       err = wait_for_timeline(tl, flags);
-                       if (err)
-                               return err;
+                       timeout = wait_for_timeline(tl, flags, timeout);
+                       if (timeout < 0)
+                               return timeout;
                }
+
+               err = wait_for_engines(i915);
+               if (err)
+                       return err;
+
                i915_retire_requests(i915);
                GEM_BUG_ON(i915->gt.active_requests);
-
-               return wait_for_engines(i915);
        } else {
                struct intel_engine_cs *engine;
                enum intel_engine_id id;
-               int err;
 
                for_each_engine(engine, i915, id) {
-                       err = wait_for_timeline(&engine->timeline, flags);
-                       if (err)
-                               return err;
-               }
+                       struct i915_timeline *tl = &engine->timeline;
 
-               return 0;
+                       timeout = wait_for_timeline(tl, flags, timeout);
+                       if (timeout < 0)
+                               return timeout;
+               }
        }
+
+       return 0;
 }
 
 static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj)
@@ -5057,7 +5057,8 @@ int i915_gem_suspend(struct drm_i915_private *dev_priv)
                ret = i915_gem_wait_for_idle(dev_priv,
                                             I915_WAIT_INTERRUPTIBLE |
                                             I915_WAIT_LOCKED |
-                                            I915_WAIT_FOR_IDLE_BOOST);
+                                            I915_WAIT_FOR_IDLE_BOOST,
+                                            MAX_SCHEDULE_TIMEOUT);
                if (ret && ret != -EIO)
                        goto err_unlock;
 
@@ -5361,9 +5362,11 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
        if (err)
                goto err_active;
 
-       err = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
-       if (err)
+       if (i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED, HZ / 5)) {
+               i915_gem_set_wedged(i915);
+               err = -EIO; /* Caller will declare us wedged */
                goto err_active;
+       }
 
        assert_kernel_context_is_current(i915);
 
@@ -5426,7 +5429,9 @@ err_active:
        if (WARN_ON(i915_gem_switch_to_kernel_context(i915)))
                goto out_ctx;
 
-       if (WARN_ON(i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED)))
+       if (WARN_ON(i915_gem_wait_for_idle(i915,
+                                          I915_WAIT_LOCKED,
+                                          MAX_SCHEDULE_TIMEOUT)))
                goto out_ctx;
 
        i915_gem_contexts_lost(i915);
@@ -5456,13 +5461,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
        if (ret)
                return ret;
 
-       ret = intel_wopcm_init(&dev_priv->wopcm);
+       ret = intel_uc_init_misc(dev_priv);
        if (ret)
                return ret;
 
-       ret = intel_uc_init_misc(dev_priv);
+       ret = intel_wopcm_init(&dev_priv->wopcm);
        if (ret)
-               return ret;
+               goto err_uc_misc;
 
        /* This is just a security blanket to placate dragons.
         * On some systems, we very sporadically observe that the first TLBs
@@ -5560,6 +5565,7 @@ err_unlock:
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
        mutex_unlock(&dev_priv->drm.struct_mutex);
 
+err_uc_misc:
        intel_uc_fini_misc(dev_priv);
 
        if (ret != -EIO)
index 261da577829a61b1c84ae8ab2d91bc6d307a6e0d..e465929568726c31a39dfb6037da594c1a93f3ac 100644 (file)
@@ -88,4 +88,9 @@ static inline void __tasklet_enable_sync_once(struct tasklet_struct *t)
                tasklet_kill(t);
 }
 
+static inline bool __tasklet_is_enabled(const struct tasklet_struct *t)
+{
+       return !atomic_read(&t->count);
+}
+
 #endif /* __I915_GEM_H__ */
index ccf463ab6562faed7762cdd29ffd4f9a5292c178..b10770cfccd24bedd80a7fd67ac06d78dde695c1 100644 (file)
@@ -374,7 +374,7 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
        if (USES_FULL_PPGTT(dev_priv)) {
                struct i915_hw_ppgtt *ppgtt;
 
-               ppgtt = i915_ppgtt_create(dev_priv, file_priv, ctx->name);
+               ppgtt = i915_ppgtt_create(dev_priv, file_priv);
                if (IS_ERR(ppgtt)) {
                        DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
                                         PTR_ERR(ppgtt));
@@ -512,8 +512,8 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
        }
 
        DRM_DEBUG_DRIVER("%s context support initialized\n",
-                        dev_priv->engine[RCS]->context_size ? "logical" :
-                        "fake");
+                        DRIVER_CAPS(dev_priv)->has_logical_contexts ?
+                        "logical" : "fake");
        return 0;
 }
 
@@ -720,7 +720,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        struct i915_gem_context *ctx;
        int ret;
 
-       if (!dev_priv->engine[RCS]->context_size)
+       if (!DRIVER_CAPS(dev_priv)->has_logical_contexts)
                return -ENODEV;
 
        if (args->pad != 0)
index 54814a196ee4d3fe99d16a72083a926595eda6d6..02b83a5ed96c9ec7b539bec4bdc88ed3ac1946cd 100644 (file)
@@ -69,7 +69,8 @@ static int ggtt_flush(struct drm_i915_private *i915)
 
        err = i915_gem_wait_for_idle(i915,
                                     I915_WAIT_INTERRUPTIBLE |
-                                    I915_WAIT_LOCKED);
+                                    I915_WAIT_LOCKED,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (err)
                return err;
 
index 60dc2a865f5f960ce0ca46d89fa4e8eb66a0d652..3f0c612d42e786d44cff5c86b59bb1da27c0fea9 100644 (file)
@@ -66,6 +66,15 @@ enum {
 #define __I915_EXEC_ILLEGAL_FLAGS \
        (__I915_EXEC_UNKNOWN_FLAGS | I915_EXEC_CONSTANTS_MASK)
 
+/* Catch emission of unexpected errors for CI! */
+#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
+#undef EINVAL
+#define EINVAL ({ \
+       DRM_DEBUG_DRIVER("EINVAL at %s:%d\n", __func__, __LINE__); \
+       22; \
+})
+#endif
+
 /**
  * DOC: User command execution
  *
@@ -534,7 +543,8 @@ eb_add_vma(struct i915_execbuffer *eb,
         * paranoia do it everywhere.
         */
        if (i == batch_idx) {
-               if (!(eb->flags[i] & EXEC_OBJECT_PINNED))
+               if (entry->relocation_count &&
+                   !(eb->flags[i] & EXEC_OBJECT_PINNED))
                        eb->flags[i] |= __EXEC_OBJECT_NEEDS_BIAS;
                if (eb->reloc_cache.has_fence)
                        eb->flags[i] |= EXEC_OBJECT_NEEDS_FENCE;
@@ -1155,18 +1165,16 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
                goto err_request;
 
        GEM_BUG_ON(!reservation_object_test_signaled_rcu(batch->resv, true));
-       i915_vma_move_to_active(batch, rq, 0);
-       reservation_object_lock(batch->resv, NULL);
-       reservation_object_add_excl_fence(batch->resv, &rq->fence);
-       reservation_object_unlock(batch->resv);
-       i915_vma_unpin(batch);
+       err = i915_vma_move_to_active(batch, rq, 0);
+       if (err)
+               goto skip_request;
 
-       i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
-       reservation_object_lock(vma->resv, NULL);
-       reservation_object_add_excl_fence(vma->resv, &rq->fence);
-       reservation_object_unlock(vma->resv);
+       err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
+       if (err)
+               goto skip_request;
 
        rq->batch = batch;
+       i915_vma_unpin(batch);
 
        cache->rq = rq;
        cache->rq_cmd = cmd;
@@ -1175,6 +1183,8 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb,
        /* Return with batch mapping (cmd) still pinned */
        return 0;
 
+skip_request:
+       i915_request_skip(rq, err);
 err_request:
        i915_request_add(rq);
 err_unpin:
@@ -1761,25 +1771,6 @@ slow:
        return eb_relocate_slow(eb);
 }
 
-static void eb_export_fence(struct i915_vma *vma,
-                           struct i915_request *rq,
-                           unsigned int flags)
-{
-       struct reservation_object *resv = vma->resv;
-
-       /*
-        * Ignore errors from failing to allocate the new fence, we can't
-        * handle an error right now. Worst case should be missed
-        * synchronisation leading to rendering corruption.
-        */
-       reservation_object_lock(resv, NULL);
-       if (flags & EXEC_OBJECT_WRITE)
-               reservation_object_add_excl_fence(resv, &rq->fence);
-       else if (reservation_object_reserve_shared(resv) == 0)
-               reservation_object_add_shared_fence(resv, &rq->fence);
-       reservation_object_unlock(resv);
-}
-
 static int eb_move_to_gpu(struct i915_execbuffer *eb)
 {
        const unsigned int count = eb->buffer_count;
@@ -1833,8 +1824,11 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb)
                unsigned int flags = eb->flags[i];
                struct i915_vma *vma = eb->vma[i];
 
-               i915_vma_move_to_active(vma, eb->request, flags);
-               eb_export_fence(vma, eb->request, flags);
+               err = i915_vma_move_to_active(vma, eb->request, flags);
+               if (unlikely(err)) {
+                       i915_request_skip(eb->request, err);
+                       return err;
+               }
 
                __eb_unreserve_vma(vma, flags);
                vma->exec_flags = NULL;
@@ -1874,45 +1868,6 @@ static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
        return true;
 }
 
-void i915_vma_move_to_active(struct i915_vma *vma,
-                            struct i915_request *rq,
-                            unsigned int flags)
-{
-       struct drm_i915_gem_object *obj = vma->obj;
-       const unsigned int idx = rq->engine->id;
-
-       lockdep_assert_held(&rq->i915->drm.struct_mutex);
-       GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
-
-       /*
-        * Add a reference if we're newly entering the active list.
-        * The order in which we add operations to the retirement queue is
-        * vital here: mark_active adds to the start of the callback list,
-        * such that subsequent callbacks are called first. Therefore we
-        * add the active reference first and queue for it to be dropped
-        * *last*.
-        */
-       if (!i915_vma_is_active(vma))
-               obj->active_count++;
-       i915_vma_set_active(vma, idx);
-       i915_gem_active_set(&vma->last_read[idx], rq);
-       list_move_tail(&vma->vm_link, &vma->vm->active_list);
-
-       obj->write_domain = 0;
-       if (flags & EXEC_OBJECT_WRITE) {
-               obj->write_domain = I915_GEM_DOMAIN_RENDER;
-
-               if (intel_fb_obj_invalidate(obj, ORIGIN_CS))
-                       i915_gem_active_set(&obj->frontbuffer_write, rq);
-
-               obj->read_domains = 0;
-       }
-       obj->read_domains |= I915_GEM_GPU_DOMAINS;
-
-       if (flags & EXEC_OBJECT_NEEDS_FENCE)
-               i915_gem_active_set(&vma->last_fence, rq);
-}
-
 static int i915_reset_gen7_sol_offsets(struct i915_request *rq)
 {
        u32 *cs;
index c6aa761ca0851a78304e1ad5b3029249aa606f1c..abd81fb9b0b6f3ce20a467751b08dd38477361ec 100644 (file)
@@ -375,37 +375,70 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr,
        return pte;
 }
 
+static void stash_init(struct pagestash *stash)
+{
+       pagevec_init(&stash->pvec);
+       spin_lock_init(&stash->lock);
+}
+
+static struct page *stash_pop_page(struct pagestash *stash)
+{
+       struct page *page = NULL;
+
+       spin_lock(&stash->lock);
+       if (likely(stash->pvec.nr))
+               page = stash->pvec.pages[--stash->pvec.nr];
+       spin_unlock(&stash->lock);
+
+       return page;
+}
+
+static void stash_push_pagevec(struct pagestash *stash, struct pagevec *pvec)
+{
+       int nr;
+
+       spin_lock_nested(&stash->lock, SINGLE_DEPTH_NESTING);
+
+       nr = min_t(int, pvec->nr, pagevec_space(&stash->pvec));
+       memcpy(stash->pvec.pages + stash->pvec.nr,
+              pvec->pages + pvec->nr - nr,
+              sizeof(pvec->pages[0]) * nr);
+       stash->pvec.nr += nr;
+
+       spin_unlock(&stash->lock);
+
+       pvec->nr -= nr;
+}
+
 static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp)
 {
-       struct pagevec *pvec = &vm->free_pages;
-       struct pagevec stash;
+       struct pagevec stack;
+       struct page *page;
 
        if (I915_SELFTEST_ONLY(should_fail(&vm->fault_attr, 1)))
                i915_gem_shrink_all(vm->i915);
 
-       if (likely(pvec->nr))
-               return pvec->pages[--pvec->nr];
+       page = stash_pop_page(&vm->free_pages);
+       if (page)
+               return page;
 
        if (!vm->pt_kmap_wc)
                return alloc_page(gfp);
 
-       /* A placeholder for a specific mutex to guard the WC stash */
-       lockdep_assert_held(&vm->i915->drm.struct_mutex);
-
        /* Look in our global stash of WC pages... */
-       pvec = &vm->i915->mm.wc_stash;
-       if (likely(pvec->nr))
-               return pvec->pages[--pvec->nr];
+       page = stash_pop_page(&vm->i915->mm.wc_stash);
+       if (page)
+               return page;
 
        /*
-        * Otherwise batch allocate pages to amoritize cost of set_pages_wc.
+        * Otherwise batch allocate pages to amortize cost of set_pages_wc.
         *
         * We have to be careful as page allocation may trigger the shrinker
         * (via direct reclaim) which will fill up the WC stash underneath us.
         * So we add our WB pages into a temporary pvec on the stack and merge
         * them into the WC stash after all the allocations are complete.
         */
-       pagevec_init(&stash);
+       pagevec_init(&stack);
        do {
                struct page *page;
 
@@ -413,59 +446,67 @@ static struct page *vm_alloc_page(struct i915_address_space *vm, gfp_t gfp)
                if (unlikely(!page))
                        break;
 
-               stash.pages[stash.nr++] = page;
-       } while (stash.nr < pagevec_space(pvec));
+               stack.pages[stack.nr++] = page;
+       } while (pagevec_space(&stack));
 
-       if (stash.nr) {
-               int nr = min_t(int, stash.nr, pagevec_space(pvec));
-               struct page **pages = stash.pages + stash.nr - nr;
+       if (stack.nr && !set_pages_array_wc(stack.pages, stack.nr)) {
+               page = stack.pages[--stack.nr];
 
-               if (nr && !set_pages_array_wc(pages, nr)) {
-                       memcpy(pvec->pages + pvec->nr,
-                              pages, sizeof(pages[0]) * nr);
-                       pvec->nr += nr;
-                       stash.nr -= nr;
-               }
+               /* Merge spare WC pages to the global stash */
+               stash_push_pagevec(&vm->i915->mm.wc_stash, &stack);
 
-               pagevec_release(&stash);
+               /* Push any surplus WC pages onto the local VM stash */
+               if (stack.nr)
+                       stash_push_pagevec(&vm->free_pages, &stack);
        }
 
-       return likely(pvec->nr) ? pvec->pages[--pvec->nr] : NULL;
+       /* Return unwanted leftovers */
+       if (unlikely(stack.nr)) {
+               WARN_ON_ONCE(set_pages_array_wb(stack.pages, stack.nr));
+               __pagevec_release(&stack);
+       }
+
+       return page;
 }
 
 static void vm_free_pages_release(struct i915_address_space *vm,
                                  bool immediate)
 {
-       struct pagevec *pvec = &vm->free_pages;
+       struct pagevec *pvec = &vm->free_pages.pvec;
+       struct pagevec stack;
 
+       lockdep_assert_held(&vm->free_pages.lock);
        GEM_BUG_ON(!pagevec_count(pvec));
 
        if (vm->pt_kmap_wc) {
-               struct pagevec *stash = &vm->i915->mm.wc_stash;
-
-               /* When we use WC, first fill up the global stash and then
+               /*
+                * When we use WC, first fill up the global stash and then
                 * only if full immediately free the overflow.
                 */
+               stash_push_pagevec(&vm->i915->mm.wc_stash, pvec);
 
-               lockdep_assert_held(&vm->i915->drm.struct_mutex);
-               if (pagevec_space(stash)) {
-                       do {
-                               stash->pages[stash->nr++] =
-                                       pvec->pages[--pvec->nr];
-                               if (!pvec->nr)
-                                       return;
-                       } while (pagevec_space(stash));
-
-                       /* As we have made some room in the VM's free_pages,
-                        * we can wait for it to fill again. Unless we are
-                        * inside i915_address_space_fini() and must
-                        * immediately release the pages!
-                        */
-                       if (!immediate)
-                               return;
-               }
+               /*
+                * As we have made some room in the VM's free_pages,
+                * we can wait for it to fill again. Unless we are
+                * inside i915_address_space_fini() and must
+                * immediately release the pages!
+                */
+               if (pvec->nr <= (immediate ? 0 : PAGEVEC_SIZE - 1))
+                       return;
+
+               /*
+                * We have to drop the lock to allow ourselves to sleep,
+                * so take a copy of the pvec and clear the stash for
+                * others to use it as we sleep.
+                */
+               stack = *pvec;
+               pagevec_reinit(pvec);
+               spin_unlock(&vm->free_pages.lock);
 
+               pvec = &stack;
                set_pages_array_wb(pvec->pages, pvec->nr);
+
+               spin_lock(&vm->free_pages.lock);
        }
 
        __pagevec_release(pvec);
@@ -481,8 +522,35 @@ static void vm_free_page(struct i915_address_space *vm, struct page *page)
         * unconditional might_sleep() for everybody.
         */
        might_sleep();
-       if (!pagevec_add(&vm->free_pages, page))
+       spin_lock(&vm->free_pages.lock);
+       if (!pagevec_add(&vm->free_pages.pvec, page))
                vm_free_pages_release(vm, false);
+       spin_unlock(&vm->free_pages.lock);
+}
+
+static void i915_address_space_init(struct i915_address_space *vm,
+                                   struct drm_i915_private *dev_priv)
+{
+       GEM_BUG_ON(!vm->total);
+       drm_mm_init(&vm->mm, 0, vm->total);
+       vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
+
+       stash_init(&vm->free_pages);
+
+       INIT_LIST_HEAD(&vm->active_list);
+       INIT_LIST_HEAD(&vm->inactive_list);
+       INIT_LIST_HEAD(&vm->unbound_list);
+}
+
+static void i915_address_space_fini(struct i915_address_space *vm)
+{
+       spin_lock(&vm->free_pages.lock);
+       if (pagevec_count(&vm->free_pages.pvec))
+               vm_free_pages_release(vm, true);
+       GEM_BUG_ON(pagevec_count(&vm->free_pages.pvec));
+       spin_unlock(&vm->free_pages.lock);
+
+       drm_mm_takedown(&vm->mm);
 }
 
 static int __setup_page_dma(struct i915_address_space *vm,
@@ -493,8 +561,11 @@ static int __setup_page_dma(struct i915_address_space *vm,
        if (unlikely(!p->page))
                return -ENOMEM;
 
-       p->daddr = dma_map_page(vm->dma, p->page, 0, PAGE_SIZE,
-                               PCI_DMA_BIDIRECTIONAL);
+       p->daddr = dma_map_page_attrs(vm->dma,
+                                     p->page, 0, PAGE_SIZE,
+                                     PCI_DMA_BIDIRECTIONAL,
+                                     DMA_ATTR_SKIP_CPU_SYNC |
+                                     DMA_ATTR_NO_WARN);
        if (unlikely(dma_mapping_error(vm->dma, p->daddr))) {
                vm_free_page(vm, p->page);
                return -ENOMEM;
@@ -575,8 +646,11 @@ setup_scratch_page(struct i915_address_space *vm, gfp_t gfp)
                if (unlikely(!page))
                        goto skip;
 
-               addr = dma_map_page(vm->dma, page, 0, size,
-                                   PCI_DMA_BIDIRECTIONAL);
+               addr = dma_map_page_attrs(vm->dma,
+                                         page, 0, size,
+                                         PCI_DMA_BIDIRECTIONAL,
+                                         DMA_ATTR_SKIP_CPU_SYNC |
+                                         DMA_ATTR_NO_WARN);
                if (unlikely(dma_mapping_error(vm->dma, addr)))
                        goto free_page;
 
@@ -1562,6 +1636,8 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915)
        if (!ppgtt)
                return ERR_PTR(-ENOMEM);
 
+       kref_init(&ppgtt->ref);
+
        ppgtt->vm.i915 = i915;
        ppgtt->vm.dma = &i915->drm.pdev->dev;
 
@@ -1569,6 +1645,8 @@ static struct i915_hw_ppgtt *gen8_ppgtt_create(struct drm_i915_private *i915)
                1ULL << 48 :
                1ULL << 32;
 
+       i915_address_space_init(&ppgtt->vm, i915);
+
        /* There are only few exceptions for gen >=6. chv and bxt.
         * And we are not sure about the latter so play safe for now.
         */
@@ -1996,7 +2074,6 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size)
        struct drm_i915_private *i915 = ppgtt->base.vm.i915;
        struct i915_ggtt *ggtt = &i915->ggtt;
        struct i915_vma *vma;
-       int i;
 
        GEM_BUG_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE));
        GEM_BUG_ON(size > ggtt->vm.total);
@@ -2005,14 +2082,14 @@ static struct i915_vma *pd_vma_create(struct gen6_hw_ppgtt *ppgtt, int size)
        if (!vma)
                return ERR_PTR(-ENOMEM);
 
-       for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
-               init_request_active(&vma->last_read[i], NULL);
        init_request_active(&vma->last_fence, NULL);
 
        vma->vm = &ggtt->vm;
        vma->ops = &pd_vma_ops;
        vma->private = ppgtt;
 
+       vma->active = RB_ROOT;
+
        vma->size = size;
        vma->fence_size = size;
        vma->flags = I915_VMA_GGTT;
@@ -2068,11 +2145,15 @@ static struct i915_hw_ppgtt *gen6_ppgtt_create(struct drm_i915_private *i915)
        if (!ppgtt)
                return ERR_PTR(-ENOMEM);
 
+       kref_init(&ppgtt->base.ref);
+
        ppgtt->base.vm.i915 = i915;
        ppgtt->base.vm.dma = &i915->drm.pdev->dev;
 
        ppgtt->base.vm.total = I915_PDES * GEN6_PTES * PAGE_SIZE;
 
+       i915_address_space_init(&ppgtt->base.vm, i915);
+
        ppgtt->base.vm.allocate_va_range = gen6_alloc_va_range;
        ppgtt->base.vm.clear_range = gen6_ppgtt_clear_range;
        ppgtt->base.vm.insert_entries = gen6_ppgtt_insert_entries;
@@ -2105,30 +2186,6 @@ err_free:
        return ERR_PTR(err);
 }
 
-static void i915_address_space_init(struct i915_address_space *vm,
-                                   struct drm_i915_private *dev_priv,
-                                   const char *name)
-{
-       drm_mm_init(&vm->mm, 0, vm->total);
-       vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
-
-       INIT_LIST_HEAD(&vm->active_list);
-       INIT_LIST_HEAD(&vm->inactive_list);
-       INIT_LIST_HEAD(&vm->unbound_list);
-
-       list_add_tail(&vm->global_link, &dev_priv->vm_list);
-       pagevec_init(&vm->free_pages);
-}
-
-static void i915_address_space_fini(struct i915_address_space *vm)
-{
-       if (pagevec_count(&vm->free_pages))
-               vm_free_pages_release(vm, true);
-
-       drm_mm_takedown(&vm->mm);
-       list_del(&vm->global_link);
-}
-
 static void gtt_write_workarounds(struct drm_i915_private *dev_priv)
 {
        /* This function is for gtt related workarounds. This function is
@@ -2199,8 +2256,7 @@ __hw_ppgtt_create(struct drm_i915_private *i915)
 
 struct i915_hw_ppgtt *
 i915_ppgtt_create(struct drm_i915_private *i915,
-                 struct drm_i915_file_private *fpriv,
-                 const char *name)
+                 struct drm_i915_file_private *fpriv)
 {
        struct i915_hw_ppgtt *ppgtt;
 
@@ -2208,8 +2264,6 @@ i915_ppgtt_create(struct drm_i915_private *i915,
        if (IS_ERR(ppgtt))
                return ppgtt;
 
-       kref_init(&ppgtt->ref);
-       i915_address_space_init(&ppgtt->vm, i915, name);
        ppgtt->vm.file = fpriv;
 
        trace_i915_ppgtt_create(&ppgtt->vm);
@@ -2739,7 +2793,7 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
 
        if (unlikely(ggtt->do_idle_maps)) {
-               if (i915_gem_wait_for_idle(dev_priv, 0)) {
+               if (i915_gem_wait_for_idle(dev_priv, 0, MAX_SCHEDULE_TIMEOUT)) {
                        DRM_ERROR("Failed to wait for idle; VT'd may hang.\n");
                        /* Wait a bit, in hopes it avoids the hang */
                        udelay(10);
@@ -2788,7 +2842,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_i915_private *i915)
        struct i915_hw_ppgtt *ppgtt;
        int err;
 
-       ppgtt = i915_ppgtt_create(i915, ERR_PTR(-EPERM), "[alias]");
+       ppgtt = i915_ppgtt_create(i915, ERR_PTR(-EPERM));
        if (IS_ERR(ppgtt))
                return PTR_ERR(ppgtt);
 
@@ -2918,7 +2972,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv)
 
        ggtt->vm.cleanup(&ggtt->vm);
 
-       pvec = &dev_priv->mm.wc_stash;
+       pvec = &dev_priv->mm.wc_stash.pvec;
        if (pvec->nr) {
                set_pages_array_wb(pvec->pages, pvec->nr);
                __pagevec_release(pvec);
@@ -3518,7 +3572,7 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv)
        struct i915_ggtt *ggtt = &dev_priv->ggtt;
        int ret;
 
-       INIT_LIST_HEAD(&dev_priv->vm_list);
+       stash_init(&dev_priv->mm.wc_stash);
 
        /* Note that we use page colouring to enforce a guard page at the
         * end of the address space. This is required as the CS may prefetch
@@ -3526,7 +3580,7 @@ int i915_ggtt_init_hw(struct drm_i915_private *dev_priv)
         * and beyond the end of the GTT if we do not provide a guard.
         */
        mutex_lock(&dev_priv->drm.struct_mutex);
-       i915_address_space_init(&ggtt->vm, dev_priv, "[global]");
+       i915_address_space_init(&ggtt->vm, dev_priv);
        if (!HAS_LLC(dev_priv) && !USES_PPGTT(dev_priv))
                ggtt->vm.mm.color_adjust = i915_gtt_color_adjust;
        mutex_unlock(&dev_priv->drm.struct_mutex);
index 9a4824cae68d2dcc6a34a311de841e5ca0ca3974..feda45dfd48117ad782efb3ae78ab74da1ab8132 100644 (file)
@@ -270,6 +270,11 @@ struct i915_vma_ops {
        void (*clear_pages)(struct i915_vma *vma);
 };
 
+struct pagestash {
+       spinlock_t lock;
+       struct pagevec pvec;
+};
+
 struct i915_address_space {
        struct drm_mm mm;
        struct drm_i915_private *i915;
@@ -283,7 +288,6 @@ struct i915_address_space {
         * assign blame.
         */
        struct drm_i915_file_private *file;
-       struct list_head global_link;
        u64 total;              /* size addr space maps (ex. 2GB for ggtt) */
        u64 reserved;           /* size addr space reserved */
 
@@ -324,7 +328,7 @@ struct i915_address_space {
         */
        struct list_head unbound_list;
 
-       struct pagevec free_pages;
+       struct pagestash free_pages;
        bool pt_kmap_wc;
 
        /* FIXME: Need a more generic return type */
@@ -615,8 +619,7 @@ void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv);
 int i915_ppgtt_init_hw(struct drm_i915_private *dev_priv);
 void i915_ppgtt_release(struct kref *kref);
 struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv,
-                                       struct drm_i915_file_private *fpriv,
-                                       const char *name);
+                                       struct drm_i915_file_private *fpriv);
 void i915_ppgtt_close(struct i915_address_space *vm);
 static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
 {
index 54f00b350779733d41a0f3ca0a79445a00595eab..c3c6f2e588fbe12a06fd380492d874377b90007b 100644 (file)
@@ -337,26 +337,17 @@ __attribute__((nonnull))
 static inline struct drm_i915_gem_object *
 i915_gem_object_get(struct drm_i915_gem_object *obj)
 {
-       drm_gem_object_reference(&obj->base);
+       drm_gem_object_get(&obj->base);
        return obj;
 }
 
-__deprecated
-extern void drm_gem_object_reference(struct drm_gem_object *);
-
 __attribute__((nonnull))
 static inline void
 i915_gem_object_put(struct drm_i915_gem_object *obj)
 {
-       __drm_gem_object_unreference(&obj->base);
+       __drm_gem_object_put(&obj->base);
 }
 
-__deprecated
-extern void drm_gem_object_unreference(struct drm_gem_object *);
-
-__deprecated
-extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *);
-
 static inline void i915_gem_object_lock(struct drm_i915_gem_object *obj)
 {
        reservation_object_lock(obj->resv, NULL);
index 3210cedfa46c374829fa014932899a5637c610e7..90baf9086d0a49f0fd2667a20ec337f520361051 100644 (file)
@@ -222,7 +222,7 @@ int i915_gem_render_state_emit(struct i915_request *rq)
                        goto err_unpin;
        }
 
-       i915_vma_move_to_active(so.vma, rq, 0);
+       err = i915_vma_move_to_active(so.vma, rq, 0);
 err_unpin:
        i915_vma_unpin(so.vma);
 err_vma:
index 55e84e71f526d23bb34a71f1db60cd864e151e6c..c61f5b80fee3a15c83dab2d8aa037921c33af4a8 100644 (file)
@@ -172,7 +172,9 @@ i915_gem_shrink(struct drm_i915_private *i915,
         * we will free as much as we can and hope to get a second chance.
         */
        if (flags & I915_SHRINK_ACTIVE)
-               i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
+               i915_gem_wait_for_idle(i915,
+                                      I915_WAIT_LOCKED,
+                                      MAX_SCHEDULE_TIMEOUT);
 
        trace_i915_gem_shrink(i915, target, flags);
        i915_retire_requests(i915);
@@ -392,7 +394,8 @@ shrinker_lock_uninterruptible(struct drm_i915_private *i915, bool *unlock,
        unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms);
 
        do {
-               if (i915_gem_wait_for_idle(i915, 0) == 0 &&
+               if (i915_gem_wait_for_idle(i915,
+                                          0, MAX_SCHEDULE_TIMEOUT) == 0 &&
                    shrinker_lock(i915, unlock))
                        break;
 
@@ -466,7 +469,9 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr
                return NOTIFY_DONE;
 
        /* Force everything onto the inactive lists */
-       ret = i915_gem_wait_for_idle(i915, I915_WAIT_LOCKED);
+       ret = i915_gem_wait_for_idle(i915,
+                                    I915_WAIT_LOCKED,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (ret)
                goto out;
 
index 79a347295e006e53de34acbdc8d5e86892ca21bd..055f8687776d0317f6c8363228e63833482c1578 100644 (file)
@@ -254,6 +254,7 @@ static void vlv_get_stolen_reserved(struct drm_i915_private *dev_priv,
        switch (reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK) {
        default:
                MISSING_CASE(reg_val & GEN7_STOLEN_RESERVED_SIZE_MASK);
+               /* fall through */
        case GEN7_STOLEN_RESERVED_1M:
                *size = 1024 * 1024;
                break;
index df524c9cad40826626e8dfc30fae17d2f59b799c..8c81cf3aa182e0a2d5d1bee8353342c4a4654a5c 100644 (file)
@@ -335,21 +335,16 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
                                struct drm_i915_error_buffer *err,
                                int count)
 {
-       int i;
-
        err_printf(m, "%s [%d]:\n", name, count);
 
        while (count--) {
-               err_printf(m, "    %08x_%08x %8u %02x %02x ",
+               err_printf(m, "    %08x_%08x %8u %02x %02x %02x",
                           upper_32_bits(err->gtt_offset),
                           lower_32_bits(err->gtt_offset),
                           err->size,
                           err->read_domains,
-                          err->write_domain);
-               for (i = 0; i < I915_NUM_ENGINES; i++)
-                       err_printf(m, "%02x ", err->rseqno[i]);
-
-               err_printf(m, "] %02x", err->wseqno);
+                          err->write_domain,
+                          err->wseqno);
                err_puts(m, tiling_flag(err->tiling));
                err_puts(m, dirty_flag(err->dirty));
                err_puts(m, purgeable_flag(err->purgeable));
@@ -1021,13 +1016,10 @@ static void capture_bo(struct drm_i915_error_buffer *err,
                       struct i915_vma *vma)
 {
        struct drm_i915_gem_object *obj = vma->obj;
-       int i;
 
        err->size = obj->base.size;
        err->name = obj->base.name;
 
-       for (i = 0; i < I915_NUM_ENGINES; i++)
-               err->rseqno[i] = __active_get_seqno(&vma->last_read[i]);
        err->wseqno = __active_get_seqno(&obj->frontbuffer_write);
        err->engine = __active_get_engine_id(&obj->frontbuffer_write);
 
index 58910f1dc67c226673f4c2f47f97d600f18e9401..f893a4e8b7831d7b214cf60ab7bcf9b058070714 100644 (file)
@@ -177,7 +177,7 @@ struct i915_gpu_state {
        struct drm_i915_error_buffer {
                u32 size;
                u32 name;
-               u32 rseqno[I915_NUM_ENGINES], wseqno;
+               u32 wseqno;
                u64 gtt_offset;
                u32 read_domains;
                u32 write_domain;
index 46aaef5c1851e763c396ba94a8fed9c83aa3a307..495b9d27990e731578e77e3790768a93e4896d52 100644 (file)
@@ -122,6 +122,15 @@ static const u32 hpd_gen11[HPD_NUM_PINS] = {
        [HPD_PORT_F] = GEN11_TC4_HOTPLUG | GEN11_TBT4_HOTPLUG
 };
 
+static const u32 hpd_icp[HPD_NUM_PINS] = {
+       [HPD_PORT_A] = SDE_DDIA_HOTPLUG_ICP,
+       [HPD_PORT_B] = SDE_DDIB_HOTPLUG_ICP,
+       [HPD_PORT_C] = SDE_TC1_HOTPLUG_ICP,
+       [HPD_PORT_D] = SDE_TC2_HOTPLUG_ICP,
+       [HPD_PORT_E] = SDE_TC3_HOTPLUG_ICP,
+       [HPD_PORT_F] = SDE_TC4_HOTPLUG_ICP
+};
+
 /* IIR can theoretically queue up two events. Be paranoid. */
 #define GEN8_IRQ_RESET_NDX(type, which) do { \
        I915_WRITE(GEN8_##type##_IMR(which), 0xffffffff); \
@@ -1145,21 +1154,21 @@ static void ironlake_rps_change_irq_handler(struct drm_i915_private *dev_priv)
 
 static void notify_ring(struct intel_engine_cs *engine)
 {
+       const u32 seqno = intel_engine_get_seqno(engine);
        struct i915_request *rq = NULL;
+       struct task_struct *tsk = NULL;
        struct intel_wait *wait;
 
-       if (!engine->breadcrumbs.irq_armed)
+       if (unlikely(!engine->breadcrumbs.irq_armed))
                return;
 
-       atomic_inc(&engine->irq_count);
-       set_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
+       rcu_read_lock();
 
        spin_lock(&engine->breadcrumbs.irq_lock);
        wait = engine->breadcrumbs.irq_wait;
        if (wait) {
-               bool wakeup = engine->irq_seqno_barrier;
-
-               /* We use a callback from the dma-fence to submit
+               /*
+                * We use a callback from the dma-fence to submit
                 * requests after waiting on our own requests. To
                 * ensure minimum delay in queuing the next request to
                 * hardware, signal the fence now rather than wait for
@@ -1170,19 +1179,26 @@ static void notify_ring(struct intel_engine_cs *engine)
                 * and to handle coalescing of multiple seqno updates
                 * and many waiters.
                 */
-               if (i915_seqno_passed(intel_engine_get_seqno(engine),
-                                     wait->seqno)) {
+               if (i915_seqno_passed(seqno, wait->seqno)) {
                        struct i915_request *waiter = wait->request;
 
-                       wakeup = true;
-                       if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
+                       if (waiter &&
+                           !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
                                      &waiter->fence.flags) &&
                            intel_wait_check_request(wait, waiter))
                                rq = i915_request_get(waiter);
+
+                       tsk = wait->tsk;
+               } else {
+                       if (engine->irq_seqno_barrier &&
+                           i915_seqno_passed(seqno, wait->seqno - 1)) {
+                               set_bit(ENGINE_IRQ_BREADCRUMB,
+                                       &engine->irq_posted);
+                               tsk = wait->tsk;
+                       }
                }
 
-               if (wakeup)
-                       wake_up_process(wait->tsk);
+               engine->breadcrumbs.irq_count++;
        } else {
                if (engine->breadcrumbs.irq_armed)
                        __intel_engine_disarm_breadcrumbs(engine);
@@ -1190,11 +1206,19 @@ static void notify_ring(struct intel_engine_cs *engine)
        spin_unlock(&engine->breadcrumbs.irq_lock);
 
        if (rq) {
-               dma_fence_signal(&rq->fence);
+               spin_lock(&rq->lock);
+               dma_fence_signal_locked(&rq->fence);
                GEM_BUG_ON(!i915_request_completed(rq));
+               spin_unlock(&rq->lock);
+
                i915_request_put(rq);
        }
 
+       if (tsk && tsk->state & TASK_NORMAL)
+               wake_up_process(tsk);
+
+       rcu_read_unlock();
+
        trace_intel_engine_notify(engine, wait);
 }
 
@@ -1469,14 +1493,10 @@ static void snb_gt_irq_handler(struct drm_i915_private *dev_priv,
 static void
 gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
 {
-       struct intel_engine_execlists * const execlists = &engine->execlists;
        bool tasklet = false;
 
-       if (iir & GT_CONTEXT_SWITCH_INTERRUPT) {
-               if (READ_ONCE(engine->execlists.active))
-                       tasklet = !test_and_set_bit(ENGINE_IRQ_EXECLIST,
-                                                   &engine->irq_posted);
-       }
+       if (iir & GT_CONTEXT_SWITCH_INTERRUPT)
+               tasklet = true;
 
        if (iir & GT_RENDER_USER_INTERRUPT) {
                notify_ring(engine);
@@ -1484,7 +1504,7 @@ gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir)
        }
 
        if (tasklet)
-               tasklet_hi_schedule(&execlists->tasklet);
+               tasklet_hi_schedule(&engine->execlists.tasklet);
 }
 
 static void gen8_gt_irq_ack(struct drm_i915_private *i915,
@@ -1586,6 +1606,34 @@ static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
        }
 }
 
+static bool icp_ddi_port_hotplug_long_detect(enum port port, u32 val)
+{
+       switch (port) {
+       case PORT_A:
+               return val & ICP_DDIA_HPD_LONG_DETECT;
+       case PORT_B:
+               return val & ICP_DDIB_HPD_LONG_DETECT;
+       default:
+               return false;
+       }
+}
+
+static bool icp_tc_port_hotplug_long_detect(enum port port, u32 val)
+{
+       switch (port) {
+       case PORT_C:
+               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC1);
+       case PORT_D:
+               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC2);
+       case PORT_E:
+               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC3);
+       case PORT_F:
+               return val & ICP_TC_HPD_LONG_DETECT(PORT_TC4);
+       default:
+               return false;
+       }
+}
+
 static bool spt_port_hotplug2_long_detect(enum port port, u32 val)
 {
        switch (port) {
@@ -1703,69 +1751,34 @@ static void display_pipe_crc_irq_handler(struct drm_i915_private *dev_priv,
                                         uint32_t crc4)
 {
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
-       struct intel_pipe_crc_entry *entry;
        struct intel_crtc *crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
-       struct drm_driver *driver = dev_priv->drm.driver;
        uint32_t crcs[5];
-       int head, tail;
 
        spin_lock(&pipe_crc->lock);
-       if (pipe_crc->source && !crtc->base.crc.opened) {
-               if (!pipe_crc->entries) {
-                       spin_unlock(&pipe_crc->lock);
-                       DRM_DEBUG_KMS("spurious interrupt\n");
-                       return;
-               }
-
-               head = pipe_crc->head;
-               tail = pipe_crc->tail;
-
-               if (CIRC_SPACE(head, tail, INTEL_PIPE_CRC_ENTRIES_NR) < 1) {
-                       spin_unlock(&pipe_crc->lock);
-                       DRM_ERROR("CRC buffer overflowing\n");
-                       return;
-               }
-
-               entry = &pipe_crc->entries[head];
-
-               entry->frame = driver->get_vblank_counter(&dev_priv->drm, pipe);
-               entry->crc[0] = crc0;
-               entry->crc[1] = crc1;
-               entry->crc[2] = crc2;
-               entry->crc[3] = crc3;
-               entry->crc[4] = crc4;
-
-               head = (head + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
-               pipe_crc->head = head;
-
-               spin_unlock(&pipe_crc->lock);
-
-               wake_up_interruptible(&pipe_crc->wq);
-       } else {
-               /*
-                * For some not yet identified reason, the first CRC is
-                * bonkers. So let's just wait for the next vblank and read
-                * out the buggy result.
-                *
-                * On GEN8+ sometimes the second CRC is bonkers as well, so
-                * don't trust that one either.
-                */
-               if (pipe_crc->skipped <= 0 ||
-                   (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
-                       pipe_crc->skipped++;
-                       spin_unlock(&pipe_crc->lock);
-                       return;
-               }
+       /*
+        * For some not yet identified reason, the first CRC is
+        * bonkers. So let's just wait for the next vblank and read
+        * out the buggy result.
+        *
+        * On GEN8+ sometimes the second CRC is bonkers as well, so
+        * don't trust that one either.
+        */
+       if (pipe_crc->skipped <= 0 ||
+           (INTEL_GEN(dev_priv) >= 8 && pipe_crc->skipped == 1)) {
+               pipe_crc->skipped++;
                spin_unlock(&pipe_crc->lock);
-               crcs[0] = crc0;
-               crcs[1] = crc1;
-               crcs[2] = crc2;
-               crcs[3] = crc3;
-               crcs[4] = crc4;
-               drm_crtc_add_crc_entry(&crtc->base, true,
-                                      drm_crtc_accurate_vblank_count(&crtc->base),
-                                      crcs);
+               return;
        }
+       spin_unlock(&pipe_crc->lock);
+
+       crcs[0] = crc0;
+       crcs[1] = crc1;
+       crcs[2] = crc2;
+       crcs[3] = crc3;
+       crcs[4] = crc4;
+       drm_crtc_add_crc_entry(&crtc->base, true,
+                               drm_crtc_accurate_vblank_count(&crtc->base),
+                               crcs);
 }
 #else
 static inline void
@@ -2021,10 +2034,38 @@ static void valleyview_pipestat_irq_handler(struct drm_i915_private *dev_priv,
 
 static u32 i9xx_hpd_irq_ack(struct drm_i915_private *dev_priv)
 {
-       u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+       u32 hotplug_status = 0, hotplug_status_mask;
+       int i;
+
+       if (IS_G4X(dev_priv) ||
+           IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+               hotplug_status_mask = HOTPLUG_INT_STATUS_G4X |
+                       DP_AUX_CHANNEL_MASK_INT_STATUS_G4X;
+       else
+               hotplug_status_mask = HOTPLUG_INT_STATUS_I915;
+
+       /*
+        * We absolutely have to clear all the pending interrupt
+        * bits in PORT_HOTPLUG_STAT. Otherwise the ISR port
+        * interrupt bit won't have an edge, and the i965/g4x
+        * edge triggered IIR will not notice that an interrupt
+        * is still pending. We can't use PORT_HOTPLUG_EN to
+        * guarantee the edge as the act of toggling the enable
+        * bits can itself generate a new hotplug interrupt :(
+        */
+       for (i = 0; i < 10; i++) {
+               u32 tmp = I915_READ(PORT_HOTPLUG_STAT) & hotplug_status_mask;
+
+               if (tmp == 0)
+                       return hotplug_status;
 
-       if (hotplug_status)
+               hotplug_status |= tmp;
                I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
+       }
+
+       WARN_ONCE(1,
+                 "PORT_HOTPLUG_STAT did not clear (0x%08x)\n",
+                 I915_READ(PORT_HOTPLUG_STAT));
 
        return hotplug_status;
 }
@@ -2131,7 +2172,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                I915_WRITE(VLV_IER, ier);
                I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
-               POSTING_READ(VLV_MASTER_IER);
 
                if (gt_iir)
                        snb_gt_irq_handler(dev_priv, gt_iir);
@@ -2216,7 +2256,6 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
 
                I915_WRITE(VLV_IER, ier);
                I915_WRITE(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL);
-               POSTING_READ(GEN8_MASTER_IRQ);
 
                gen8_gt_irq_handler(dev_priv, master_ctl, gt_iir);
 
@@ -2385,6 +2424,43 @@ static void cpt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
                cpt_serr_int_handler(dev_priv);
 }
 
+static void icp_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
+{
+       u32 ddi_hotplug_trigger = pch_iir & SDE_DDI_MASK_ICP;
+       u32 tc_hotplug_trigger = pch_iir & SDE_TC_MASK_ICP;
+       u32 pin_mask = 0, long_mask = 0;
+
+       if (ddi_hotplug_trigger) {
+               u32 dig_hotplug_reg;
+
+               dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_DDI);
+               I915_WRITE(SHOTPLUG_CTL_DDI, dig_hotplug_reg);
+
+               intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
+                                  ddi_hotplug_trigger,
+                                  dig_hotplug_reg, hpd_icp,
+                                  icp_ddi_port_hotplug_long_detect);
+       }
+
+       if (tc_hotplug_trigger) {
+               u32 dig_hotplug_reg;
+
+               dig_hotplug_reg = I915_READ(SHOTPLUG_CTL_TC);
+               I915_WRITE(SHOTPLUG_CTL_TC, dig_hotplug_reg);
+
+               intel_get_hpd_pins(dev_priv, &pin_mask, &long_mask,
+                                  tc_hotplug_trigger,
+                                  dig_hotplug_reg, hpd_icp,
+                                  icp_tc_port_hotplug_long_detect);
+       }
+
+       if (pin_mask)
+               intel_hpd_irq_handler(dev_priv, pin_mask, long_mask);
+
+       if (pch_iir & SDE_GMBUS_ICP)
+               gmbus_irq_handler(dev_priv);
+}
+
 static void spt_irq_handler(struct drm_i915_private *dev_priv, u32 pch_iir)
 {
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
@@ -2548,7 +2624,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        /* disable master interrupt before clearing iir  */
        de_ier = I915_READ(DEIER);
        I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
-       POSTING_READ(DEIER);
 
        /* Disable south interrupts. We'll only write to SDEIIR once, so further
         * interrupts will will be stored on its back queue, and then we'll be
@@ -2558,7 +2633,6 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        if (!HAS_PCH_NOP(dev_priv)) {
                sde_ier = I915_READ(SDEIER);
                I915_WRITE(SDEIER, 0);
-               POSTING_READ(SDEIER);
        }
 
        /* Find, clear, then process each source of interrupt */
@@ -2593,11 +2667,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
        }
 
        I915_WRITE(DEIER, de_ier);
-       POSTING_READ(DEIER);
-       if (!HAS_PCH_NOP(dev_priv)) {
+       if (!HAS_PCH_NOP(dev_priv))
                I915_WRITE(SDEIER, sde_ier);
-               POSTING_READ(SDEIER);
-       }
 
        /* IRQs are synced during runtime_suspend, we don't require a wakeref */
        enable_rpm_wakeref_asserts(dev_priv);
@@ -2804,8 +2875,11 @@ gen8_de_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl)
                        I915_WRITE(SDEIIR, iir);
                        ret = IRQ_HANDLED;
 
-                       if (HAS_PCH_SPT(dev_priv) || HAS_PCH_KBP(dev_priv) ||
-                           HAS_PCH_CNP(dev_priv))
+                       if (HAS_PCH_ICP(dev_priv))
+                               icp_irq_handler(dev_priv, iir);
+                       else if (HAS_PCH_SPT(dev_priv) ||
+                                HAS_PCH_KBP(dev_priv) ||
+                                HAS_PCH_CNP(dev_priv))
                                spt_irq_handler(dev_priv, iir);
                        else
                                cpt_irq_handler(dev_priv, iir);
@@ -3170,7 +3244,7 @@ static void i915_clear_error_registers(struct drm_i915_private *dev_priv)
                 */
                DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masking\n", eir);
                I915_WRITE(EMR, I915_READ(EMR) | eir);
-               I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+               I915_WRITE(IIR, I915_MASTER_ERROR_INTERRUPT);
        }
 }
 
@@ -3584,6 +3658,9 @@ static void gen11_irq_reset(struct drm_device *dev)
        GEN3_IRQ_RESET(GEN11_DE_HPD_);
        GEN3_IRQ_RESET(GEN11_GU_MISC_);
        GEN3_IRQ_RESET(GEN8_PCU_);
+
+       if (HAS_PCH_ICP(dev_priv))
+               GEN3_IRQ_RESET(SDE);
 }
 
 void gen8_irq_power_well_post_enable(struct drm_i915_private *dev_priv,
@@ -3700,6 +3777,35 @@ static void ibx_hpd_irq_setup(struct drm_i915_private *dev_priv)
        ibx_hpd_detection_setup(dev_priv);
 }
 
+static void icp_hpd_detection_setup(struct drm_i915_private *dev_priv)
+{
+       u32 hotplug;
+
+       hotplug = I915_READ(SHOTPLUG_CTL_DDI);
+       hotplug |= ICP_DDIA_HPD_ENABLE |
+                  ICP_DDIB_HPD_ENABLE;
+       I915_WRITE(SHOTPLUG_CTL_DDI, hotplug);
+
+       hotplug = I915_READ(SHOTPLUG_CTL_TC);
+       hotplug |= ICP_TC_HPD_ENABLE(PORT_TC1) |
+                  ICP_TC_HPD_ENABLE(PORT_TC2) |
+                  ICP_TC_HPD_ENABLE(PORT_TC3) |
+                  ICP_TC_HPD_ENABLE(PORT_TC4);
+       I915_WRITE(SHOTPLUG_CTL_TC, hotplug);
+}
+
+static void icp_hpd_irq_setup(struct drm_i915_private *dev_priv)
+{
+       u32 hotplug_irqs, enabled_irqs;
+
+       hotplug_irqs = SDE_DDI_MASK_ICP | SDE_TC_MASK_ICP;
+       enabled_irqs = intel_hpd_enabled_irqs(dev_priv, hpd_icp);
+
+       ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
+
+       icp_hpd_detection_setup(dev_priv);
+}
+
 static void gen11_hpd_detection_setup(struct drm_i915_private *dev_priv)
 {
        u32 hotplug;
@@ -3733,6 +3839,9 @@ static void gen11_hpd_irq_setup(struct drm_i915_private *dev_priv)
        POSTING_READ(GEN11_DE_HPD_IMR);
 
        gen11_hpd_detection_setup(dev_priv);
+
+       if (HAS_PCH_ICP(dev_priv))
+               icp_hpd_irq_setup(dev_priv);
 }
 
 static void spt_hpd_detection_setup(struct drm_i915_private *dev_priv)
@@ -4168,11 +4277,29 @@ static void gen11_gt_irq_postinstall(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN11_GPM_WGBOXPERF_INTR_MASK,  ~0);
 }
 
+static void icp_irq_postinstall(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       u32 mask = SDE_GMBUS_ICP;
+
+       WARN_ON(I915_READ(SDEIER) != 0);
+       I915_WRITE(SDEIER, 0xffffffff);
+       POSTING_READ(SDEIER);
+
+       gen3_assert_iir_is_zero(dev_priv, SDEIIR);
+       I915_WRITE(SDEIMR, ~mask);
+
+       icp_hpd_detection_setup(dev_priv);
+}
+
 static int gen11_irq_postinstall(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 gu_misc_masked = GEN11_GU_MISC_GSE;
 
+       if (HAS_PCH_ICP(dev_priv))
+               icp_irq_postinstall(dev);
+
        gen11_gt_irq_postinstall(dev_priv);
        gen8_de_irq_postinstall(dev_priv);
 
@@ -4225,11 +4352,13 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask =
                ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
-                 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
+                 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+                 I915_MASTER_ERROR_INTERRUPT);
 
        enable_mask =
                I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
                I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+               I915_MASTER_ERROR_INTERRUPT |
                I915_USER_INTERRUPT;
 
        GEN2_IRQ_INIT(, dev_priv->irq_mask, enable_mask);
@@ -4244,6 +4373,81 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+static void i8xx_error_irq_ack(struct drm_i915_private *dev_priv,
+                              u16 *eir, u16 *eir_stuck)
+{
+       u16 emr;
+
+       *eir = I915_READ16(EIR);
+
+       if (*eir)
+               I915_WRITE16(EIR, *eir);
+
+       *eir_stuck = I915_READ16(EIR);
+       if (*eir_stuck == 0)
+               return;
+
+       /*
+        * Toggle all EMR bits to make sure we get an edge
+        * in the ISR master error bit if we don't clear
+        * all the EIR bits. Otherwise the edge triggered
+        * IIR on i965/g4x wouldn't notice that an interrupt
+        * is still pending. Also some EIR bits can't be
+        * cleared except by handling the underlying error
+        * (or by a GPU reset) so we mask any bit that
+        * remains set.
+        */
+       emr = I915_READ16(EMR);
+       I915_WRITE16(EMR, 0xffff);
+       I915_WRITE16(EMR, emr | *eir_stuck);
+}
+
+static void i8xx_error_irq_handler(struct drm_i915_private *dev_priv,
+                                  u16 eir, u16 eir_stuck)
+{
+       DRM_DEBUG("Master Error: EIR 0x%04x\n", eir);
+
+       if (eir_stuck)
+               DRM_DEBUG_DRIVER("EIR stuck: 0x%04x, masked\n", eir_stuck);
+}
+
+static void i9xx_error_irq_ack(struct drm_i915_private *dev_priv,
+                              u32 *eir, u32 *eir_stuck)
+{
+       u32 emr;
+
+       *eir = I915_READ(EIR);
+
+       I915_WRITE(EIR, *eir);
+
+       *eir_stuck = I915_READ(EIR);
+       if (*eir_stuck == 0)
+               return;
+
+       /*
+        * Toggle all EMR bits to make sure we get an edge
+        * in the ISR master error bit if we don't clear
+        * all the EIR bits. Otherwise the edge triggered
+        * IIR on i965/g4x wouldn't notice that an interrupt
+        * is still pending. Also some EIR bits can't be
+        * cleared except by handling the underlying error
+        * (or by a GPU reset) so we mask any bit that
+        * remains set.
+        */
+       emr = I915_READ(EMR);
+       I915_WRITE(EMR, 0xffffffff);
+       I915_WRITE(EMR, emr | *eir_stuck);
+}
+
+static void i9xx_error_irq_handler(struct drm_i915_private *dev_priv,
+                                  u32 eir, u32 eir_stuck)
+{
+       DRM_DEBUG("Master Error, EIR 0x%08x\n", eir);
+
+       if (eir_stuck)
+               DRM_DEBUG_DRIVER("EIR stuck: 0x%08x, masked\n", eir_stuck);
+}
+
 static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
@@ -4258,6 +4462,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
        do {
                u32 pipe_stats[I915_MAX_PIPES] = {};
+               u16 eir = 0, eir_stuck = 0;
                u16 iir;
 
                iir = I915_READ16(IIR);
@@ -4270,13 +4475,16 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                 * signalled in iir */
                i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & I915_MASTER_ERROR_INTERRUPT)
+                       i8xx_error_irq_ack(dev_priv, &eir, &eir_stuck);
+
                I915_WRITE16(IIR, iir);
 
                if (iir & I915_USER_INTERRUPT)
                        notify_ring(dev_priv->engine[RCS]);
 
-               if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
+               if (iir & I915_MASTER_ERROR_INTERRUPT)
+                       i8xx_error_irq_handler(dev_priv, eir, eir_stuck);
 
                i8xx_pipestat_irq_handler(dev_priv, iir, pipe_stats);
        } while (0);
@@ -4314,12 +4522,14 @@ static int i915_irq_postinstall(struct drm_device *dev)
        dev_priv->irq_mask =
                ~(I915_ASLE_INTERRUPT |
                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
-                 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT);
+                 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+                 I915_MASTER_ERROR_INTERRUPT);
 
        enable_mask =
                I915_ASLE_INTERRUPT |
                I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
                I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+               I915_MASTER_ERROR_INTERRUPT |
                I915_USER_INTERRUPT;
 
        if (I915_HAS_HOTPLUG(dev_priv)) {
@@ -4357,6 +4567,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
        do {
                u32 pipe_stats[I915_MAX_PIPES] = {};
+               u32 eir = 0, eir_stuck = 0;
                u32 hotplug_status = 0;
                u32 iir;
 
@@ -4374,13 +4585,16 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                 * signalled in iir */
                i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & I915_MASTER_ERROR_INTERRUPT)
+                       i9xx_error_irq_ack(dev_priv, &eir, &eir_stuck);
+
                I915_WRITE(IIR, iir);
 
                if (iir & I915_USER_INTERRUPT)
                        notify_ring(dev_priv->engine[RCS]);
 
-               if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
+               if (iir & I915_MASTER_ERROR_INTERRUPT)
+                       i9xx_error_irq_handler(dev_priv, eir, eir_stuck);
 
                if (hotplug_status)
                        i9xx_hpd_irq_handler(dev_priv, hotplug_status);
@@ -4434,14 +4648,14 @@ static int i965_irq_postinstall(struct drm_device *dev)
                  I915_DISPLAY_PORT_INTERRUPT |
                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
-                 I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+                 I915_MASTER_ERROR_INTERRUPT);
 
        enable_mask =
                I915_ASLE_INTERRUPT |
                I915_DISPLAY_PORT_INTERRUPT |
                I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
                I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
-               I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
+               I915_MASTER_ERROR_INTERRUPT |
                I915_USER_INTERRUPT;
 
        if (IS_G4X(dev_priv))
@@ -4501,6 +4715,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
        do {
                u32 pipe_stats[I915_MAX_PIPES] = {};
+               u32 eir = 0, eir_stuck = 0;
                u32 hotplug_status = 0;
                u32 iir;
 
@@ -4517,6 +4732,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                 * signalled in iir */
                i9xx_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & I915_MASTER_ERROR_INTERRUPT)
+                       i9xx_error_irq_ack(dev_priv, &eir, &eir_stuck);
+
                I915_WRITE(IIR, iir);
 
                if (iir & I915_USER_INTERRUPT)
@@ -4525,8 +4743,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                if (iir & I915_BSD_USER_INTERRUPT)
                        notify_ring(dev_priv->engine[VCS]);
 
-               if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       DRM_DEBUG("Command parser error, iir 0x%08x\n", iir);
+               if (iir & I915_MASTER_ERROR_INTERRUPT)
+                       i9xx_error_irq_handler(dev_priv, eir, eir_stuck);
 
                if (hotplug_status)
                        i9xx_hpd_irq_handler(dev_priv, hotplug_status);
index 447407fee3b89dc5f24c66dda9c626e8120d98e5..6bf10952c7240363fdcd2df907979ef9aef0d247 100644 (file)
@@ -1836,7 +1836,9 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
         * So far the best way to work around this issue seems to be draining
         * the GPU from any submitted work.
         */
-       ret = i915_gem_wait_for_idle(dev_priv, wait_flags);
+       ret = i915_gem_wait_for_idle(dev_priv,
+                                    wait_flags,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (ret)
                goto out;
 
index 4bfd7a9bd75f55e08b6335df5fbeb012842c136a..0424e45f88dbc6f4c105b0ac54e689301ad54d15 100644 (file)
@@ -139,19 +139,35 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
        return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG);
 }
 
+/*
+ * Given the first two numbers __a and __b of arbitrarily many evenly spaced
+ * numbers, pick the 0-based __index'th value.
+ *
+ * Always prefer this over _PICK() if the numbers are evenly spaced.
+ */
+#define _PICK_EVEN(__index, __a, __b) ((__a) + (__index) * ((__b) - (__a)))
+
+/*
+ * Given the arbitrary numbers in varargs, pick the 0-based __index'th number.
+ *
+ * Always prefer _PICK_EVEN() over this if the numbers are evenly spaced.
+ */
 #define _PICK(__index, ...) (((const u32 []){ __VA_ARGS__ })[__index])
 
-#define _PIPE(pipe, a, b) ((a) + (pipe) * ((b) - (a)))
+/*
+ * Named helper wrappers around _PICK_EVEN() and _PICK().
+ */
+#define _PIPE(pipe, a, b) _PICK_EVEN(pipe, a, b)
 #define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b))
-#define _PLANE(plane, a, b) _PIPE(plane, a, b)
+#define _PLANE(plane, a, b) _PICK_EVEN(plane, a, b)
 #define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b)
-#define _TRANS(tran, a, b) ((a) + (tran) * ((b) - (a)))
+#define _TRANS(tran, a, b) _PICK_EVEN(tran, a, b)
 #define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b))
-#define _PORT(port, a, b) ((a) + (port) * ((b) - (a)))
+#define _PORT(port, a, b) _PICK_EVEN(port, a, b)
 #define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b))
 #define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
 #define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PICK(pipe, a, b, c))
-#define _PLL(pll, a, b) ((a) + (pll) * ((b) - (a)))
+#define _PLL(pll, a, b) _PICK_EVEN(pll, a, b)
 #define _MMIO_PLL(pll, a, b) _MMIO(_PLL(pll, a, b))
 #define _PHY3(phy, ...) _PICK(phy, __VA_ARGS__)
 #define _MMIO_PHY3(phy, a, b, c) _MMIO(_PHY3(phy, a, b, c))
@@ -1045,13 +1061,13 @@ enum i915_power_well_id {
 
        /*
         * HSW/BDW
-        *  - HSW_PWR_WELL_CTL_DRIVER(0) (status bit: id*2, req bit: id*2+1)
+        *  - _HSW_PWR_WELL_CTL1-4 (status bit: id*2, req bit: id*2+1)
         */
        HSW_DISP_PW_GLOBAL = 15,
 
        /*
         * GEN9+
-        *  - HSW_PWR_WELL_CTL_DRIVER(0) (status bit: id*2, req bit: id*2+1)
+        *  - _HSW_PWR_WELL_CTL1-4 (status bit: id*2, req bit: id*2+1)
         */
        SKL_DISP_PW_MISC_IO = 0,
        SKL_DISP_PW_DDI_A_E,
@@ -1075,17 +1091,54 @@ enum i915_power_well_id {
        SKL_DISP_PW_2,
 
        /* - custom power wells */
-       SKL_DISP_PW_DC_OFF,
        BXT_DPIO_CMN_A,
        BXT_DPIO_CMN_BC,
-       GLK_DPIO_CMN_C,                 /* 19 */
+       GLK_DPIO_CMN_C,                 /* 18 */
+
+       /*
+        * GEN11+
+        *  - _HSW_PWR_WELL_CTL1-4
+        *    (status bit: (id&15)*2, req bit:(id&15)*2+1)
+        */
+       ICL_DISP_PW_1 = 0,
+       ICL_DISP_PW_2,
+       ICL_DISP_PW_3,
+       ICL_DISP_PW_4,
+
+       /*
+        *  - _HSW_PWR_WELL_CTL_AUX1/2/4
+        *    (status bit: (id&15)*2, req bit:(id&15)*2+1)
+        */
+       ICL_DISP_PW_AUX_A = 16,
+       ICL_DISP_PW_AUX_B,
+       ICL_DISP_PW_AUX_C,
+       ICL_DISP_PW_AUX_D,
+       ICL_DISP_PW_AUX_E,
+       ICL_DISP_PW_AUX_F,
+
+       ICL_DISP_PW_AUX_TBT1 = 24,
+       ICL_DISP_PW_AUX_TBT2,
+       ICL_DISP_PW_AUX_TBT3,
+       ICL_DISP_PW_AUX_TBT4,
+
+       /*
+        *  - _HSW_PWR_WELL_CTL_DDI1/2/4
+        *    (status bit: (id&15)*2, req bit:(id&15)*2+1)
+        */
+       ICL_DISP_PW_DDI_A = 32,
+       ICL_DISP_PW_DDI_B,
+       ICL_DISP_PW_DDI_C,
+       ICL_DISP_PW_DDI_D,
+       ICL_DISP_PW_DDI_E,
+       ICL_DISP_PW_DDI_F,                      /* 37 */
 
        /*
         * Multiple platforms.
         * Must start following the highest ID of any platform.
         * - custom power wells
         */
-       I915_DISP_PW_ALWAYS_ON = 20,
+       SKL_DISP_PW_DC_OFF = 38,
+       I915_DISP_PW_ALWAYS_ON,
 };
 
 #define PUNIT_REG_PWRGT_CTRL                   0x60
@@ -1667,6 +1720,26 @@ enum i915_power_well_id {
 #define ICL_PORT_CL_DW5(port)  _MMIO_PORT(port, _ICL_PORT_CL_DW5_A, \
                                                 _ICL_PORT_CL_DW5_B)
 
+#define _CNL_PORT_CL_DW10_A            0x162028
+#define _ICL_PORT_CL_DW10_B            0x6c028
+#define ICL_PORT_CL_DW10(port)         _MMIO_PORT(port,        \
+                                                  _CNL_PORT_CL_DW10_A, \
+                                                  _ICL_PORT_CL_DW10_B)
+#define  PG_SEQ_DELAY_OVERRIDE_MASK    (3 << 25)
+#define  PG_SEQ_DELAY_OVERRIDE_SHIFT   25
+#define  PG_SEQ_DELAY_OVERRIDE_ENABLE  (1 << 24)
+#define  PWR_UP_ALL_LANES              (0x0 << 4)
+#define  PWR_DOWN_LN_3_2_1             (0xe << 4)
+#define  PWR_DOWN_LN_3_2               (0xc << 4)
+#define  PWR_DOWN_LN_3                 (0x8 << 4)
+#define  PWR_DOWN_LN_2_1_0             (0x7 << 4)
+#define  PWR_DOWN_LN_1_0               (0x3 << 4)
+#define  PWR_DOWN_LN_1                 (0x2 << 4)
+#define  PWR_DOWN_LN_3_1               (0xa << 4)
+#define  PWR_DOWN_LN_3_1_0             (0xb << 4)
+#define  PWR_DOWN_LN_MASK              (0xf << 4)
+#define  PWR_DOWN_LN_SHIFT             4
+
 #define _PORT_CL1CM_DW9_A              0x162024
 #define _PORT_CL1CM_DW9_BC             0x6C024
 #define   IREF0RC_OFFSET_SHIFT         8
@@ -1679,6 +1752,13 @@ enum i915_power_well_id {
 #define   IREF1RC_OFFSET_MASK          (0xFF << IREF1RC_OFFSET_SHIFT)
 #define BXT_PORT_CL1CM_DW10(phy)       _BXT_PHY((phy), _PORT_CL1CM_DW10_BC)
 
+#define _ICL_PORT_CL_DW12_A            0x162030
+#define _ICL_PORT_CL_DW12_B            0x6C030
+#define   ICL_LANE_ENABLE_AUX          (1 << 0)
+#define ICL_PORT_CL_DW12(port)         _MMIO_PORT((port),              \
+                                                  _ICL_PORT_CL_DW12_A, \
+                                                  _ICL_PORT_CL_DW12_B)
+
 #define _PORT_CL1CM_DW28_A             0x162070
 #define _PORT_CL1CM_DW28_BC            0x6C070
 #define   OCL1_POWER_DOWN_EN           (1 << 23)
@@ -1716,16 +1796,22 @@ enum i915_power_well_id {
                                                    _CNL_PORT_PCS_DW1_LN0_D, \
                                                    _CNL_PORT_PCS_DW1_LN0_AE, \
                                                    _CNL_PORT_PCS_DW1_LN0_F))
+
 #define _ICL_PORT_PCS_DW1_GRP_A                0x162604
 #define _ICL_PORT_PCS_DW1_GRP_B                0x6C604
 #define _ICL_PORT_PCS_DW1_LN0_A                0x162804
 #define _ICL_PORT_PCS_DW1_LN0_B                0x6C804
+#define _ICL_PORT_PCS_DW1_AUX_A                0x162304
+#define _ICL_PORT_PCS_DW1_AUX_B                0x6c304
 #define ICL_PORT_PCS_DW1_GRP(port)     _MMIO_PORT(port,\
                                                   _ICL_PORT_PCS_DW1_GRP_A, \
                                                   _ICL_PORT_PCS_DW1_GRP_B)
 #define ICL_PORT_PCS_DW1_LN0(port)     _MMIO_PORT(port, \
                                                   _ICL_PORT_PCS_DW1_LN0_A, \
                                                   _ICL_PORT_PCS_DW1_LN0_B)
+#define ICL_PORT_PCS_DW1_AUX(port)     _MMIO_PORT(port, \
+                                                  _ICL_PORT_PCS_DW1_AUX_A, \
+                                                  _ICL_PORT_PCS_DW1_AUX_B)
 #define   COMMON_KEEPER_EN             (1 << 26)
 
 /* CNL Port TX registers */
@@ -1762,16 +1848,23 @@ enum i915_power_well_id {
 #define _ICL_PORT_TX_DW2_GRP_B         0x6C688
 #define _ICL_PORT_TX_DW2_LN0_A         0x162888
 #define _ICL_PORT_TX_DW2_LN0_B         0x6C888
+#define _ICL_PORT_TX_DW2_AUX_A         0x162388
+#define _ICL_PORT_TX_DW2_AUX_B         0x6c388
 #define ICL_PORT_TX_DW2_GRP(port)      _MMIO_PORT(port, \
                                                   _ICL_PORT_TX_DW2_GRP_A, \
                                                   _ICL_PORT_TX_DW2_GRP_B)
 #define ICL_PORT_TX_DW2_LN0(port)      _MMIO_PORT(port, \
                                                   _ICL_PORT_TX_DW2_LN0_A, \
                                                   _ICL_PORT_TX_DW2_LN0_B)
+#define ICL_PORT_TX_DW2_AUX(port)      _MMIO_PORT(port, \
+                                                  _ICL_PORT_TX_DW2_AUX_A, \
+                                                  _ICL_PORT_TX_DW2_AUX_B)
 #define   SWING_SEL_UPPER(x)           (((x) >> 3) << 15)
 #define   SWING_SEL_UPPER_MASK         (1 << 15)
 #define   SWING_SEL_LOWER(x)           (((x) & 0x7) << 11)
 #define   SWING_SEL_LOWER_MASK         (0x7 << 11)
+#define   FRC_LATENCY_OPTIM_MASK       (0x7 << 8)
+#define   FRC_LATENCY_OPTIM_VAL(x)     ((x) << 8)
 #define   RCOMP_SCALAR(x)              ((x) << 0)
 #define   RCOMP_SCALAR_MASK            (0xFF << 0)
 
@@ -1787,6 +1880,8 @@ enum i915_power_well_id {
 #define _ICL_PORT_TX_DW4_LN0_A         0x162890
 #define _ICL_PORT_TX_DW4_LN1_A         0x162990
 #define _ICL_PORT_TX_DW4_LN0_B         0x6C890
+#define _ICL_PORT_TX_DW4_AUX_A         0x162390
+#define _ICL_PORT_TX_DW4_AUX_B         0x6c390
 #define ICL_PORT_TX_DW4_GRP(port)      _MMIO_PORT(port, \
                                                   _ICL_PORT_TX_DW4_GRP_A, \
                                                   _ICL_PORT_TX_DW4_GRP_B)
@@ -1795,6 +1890,9 @@ enum i915_power_well_id {
                                                   _ICL_PORT_TX_DW4_LN0_B) + \
                                             ((ln) * (_ICL_PORT_TX_DW4_LN1_A - \
                                                      _ICL_PORT_TX_DW4_LN0_A)))
+#define ICL_PORT_TX_DW4_AUX(port)      _MMIO_PORT(port, \
+                                                  _ICL_PORT_TX_DW4_AUX_A, \
+                                                  _ICL_PORT_TX_DW4_AUX_B)
 #define   LOADGEN_SELECT               (1 << 31)
 #define   POST_CURSOR_1(x)             ((x) << 12)
 #define   POST_CURSOR_1_MASK           (0x3F << 12)
@@ -1809,12 +1907,17 @@ enum i915_power_well_id {
 #define _ICL_PORT_TX_DW5_GRP_B         0x6C694
 #define _ICL_PORT_TX_DW5_LN0_A         0x162894
 #define _ICL_PORT_TX_DW5_LN0_B         0x6C894
+#define _ICL_PORT_TX_DW5_AUX_A         0x162394
+#define _ICL_PORT_TX_DW5_AUX_B         0x6c394
 #define ICL_PORT_TX_DW5_GRP(port)      _MMIO_PORT(port, \
                                                   _ICL_PORT_TX_DW5_GRP_A, \
                                                   _ICL_PORT_TX_DW5_GRP_B)
 #define ICL_PORT_TX_DW5_LN0(port)      _MMIO_PORT(port, \
                                                   _ICL_PORT_TX_DW5_LN0_A, \
                                                   _ICL_PORT_TX_DW5_LN0_B)
+#define ICL_PORT_TX_DW5_AUX(port)      _MMIO_PORT(port, \
+                                                  _ICL_PORT_TX_DW5_AUX_A, \
+                                                  _ICL_PORT_TX_DW5_AUX_B)
 #define   TX_TRAINING_EN               (1 << 31)
 #define   TAP2_DISABLE                 (1 << 30)
 #define   TAP3_DISABLE                 (1 << 29)
@@ -2811,7 +2914,6 @@ enum i915_power_well_id {
 #define I915_DISPLAY_PORT_INTERRUPT                    (1 << 17)
 #define I915_DISPLAY_PIPE_C_HBLANK_INTERRUPT           (1 << 16)
 #define I915_MASTER_ERROR_INTERRUPT                    (1 << 15)
-#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT     (1 << 15)
 #define I915_DISPLAY_PIPE_B_HBLANK_INTERRUPT           (1 << 14)
 #define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT       (1 << 14) /* p-state */
 #define I915_DISPLAY_PIPE_A_HBLANK_INTERRUPT           (1 << 13)
@@ -4044,6 +4146,7 @@ enum {
 #define   EDP_PSR_SKIP_AUX_EXIT                        (1 << 12)
 #define   EDP_PSR_TP1_TP2_SEL                  (0 << 11)
 #define   EDP_PSR_TP1_TP3_SEL                  (1 << 11)
+#define   EDP_PSR_CRC_ENABLE                   (1 << 10) /* BDW+ */
 #define   EDP_PSR_TP2_TP3_TIME_500us           (0 << 8)
 #define   EDP_PSR_TP2_TP3_TIME_100us           (1 << 8)
 #define   EDP_PSR_TP2_TP3_TIME_2500us          (2 << 8)
@@ -4072,6 +4175,7 @@ enum {
 
 #define EDP_PSR_STATUS                         _MMIO(dev_priv->psr_mmio_base + 0x40)
 #define   EDP_PSR_STATUS_STATE_MASK            (7 << 29)
+#define   EDP_PSR_STATUS_STATE_SHIFT           29
 #define   EDP_PSR_STATUS_STATE_IDLE            (0 << 29)
 #define   EDP_PSR_STATUS_STATE_SRDONACK                (1 << 29)
 #define   EDP_PSR_STATUS_STATE_SRDENT          (2 << 29)
@@ -6829,7 +6933,7 @@ enum {
 #define _PS_ECC_STAT_2B     0x68AD0
 #define _PS_ECC_STAT_1C     0x691D0
 
-#define _ID(id, a, b) ((a) + (id) * ((b) - (a)))
+#define _ID(id, a, b) _PICK_EVEN(id, a, b)
 #define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe,        \
                        _ID(id, _PS_1A_CTRL, _PS_2A_CTRL),       \
                        _ID(id, _PS_1B_CTRL, _PS_2B_CTRL))
@@ -7366,6 +7470,14 @@ enum {
 #define BDW_SCRATCH1                                   _MMIO(0xb11c)
 #define  GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE     (1 << 2)
 
+/*GEN11 chicken */
+#define _PIPEA_CHICKEN                 0x70038
+#define _PIPEB_CHICKEN                 0x71038
+#define _PIPEC_CHICKEN                 0x72038
+#define  PER_PIXEL_ALPHA_BYPASS_EN     (1 << 7)
+#define PIPE_CHICKEN(pipe)             _MMIO_PIPE(pipe, _PIPEA_CHICKEN,\
+                                                  _PIPEB_CHICKEN)
+
 /* PCH */
 
 /* south display engine interrupt: IBX */
@@ -7409,7 +7521,7 @@ enum {
 #define SDE_TRANSA_FIFO_UNDER  (1 << 0)
 #define SDE_TRANS_MASK         (0x3f)
 
-/* south display engine interrupt: CPT/PPT */
+/* south display engine interrupt: CPT - CNP */
 #define SDE_AUDIO_POWER_D_CPT  (1 << 31)
 #define SDE_AUDIO_POWER_C_CPT  (1 << 30)
 #define SDE_AUDIO_POWER_B_CPT  (1 << 29)
@@ -7457,6 +7569,21 @@ enum {
                                 SDE_FDI_RXB_CPT | \
                                 SDE_FDI_RXA_CPT)
 
+/* south display engine interrupt: ICP */
+#define SDE_TC4_HOTPLUG_ICP            (1 << 27)
+#define SDE_TC3_HOTPLUG_ICP            (1 << 26)
+#define SDE_TC2_HOTPLUG_ICP            (1 << 25)
+#define SDE_TC1_HOTPLUG_ICP            (1 << 24)
+#define SDE_GMBUS_ICP                  (1 << 23)
+#define SDE_DDIB_HOTPLUG_ICP           (1 << 17)
+#define SDE_DDIA_HOTPLUG_ICP           (1 << 16)
+#define SDE_DDI_MASK_ICP               (SDE_DDIB_HOTPLUG_ICP | \
+                                        SDE_DDIA_HOTPLUG_ICP)
+#define SDE_TC_MASK_ICP                        (SDE_TC4_HOTPLUG_ICP |  \
+                                        SDE_TC3_HOTPLUG_ICP |  \
+                                        SDE_TC2_HOTPLUG_ICP |  \
+                                        SDE_TC1_HOTPLUG_ICP)
+
 #define SDEISR  _MMIO(0xc4000)
 #define SDEIMR  _MMIO(0xc4004)
 #define SDEIIR  _MMIO(0xc4008)
@@ -7517,6 +7644,30 @@ enum {
 #define  PORTE_HOTPLUG_SHORT_DETECT    (1 << 0)
 #define  PORTE_HOTPLUG_LONG_DETECT     (2 << 0)
 
+/* This register is a reuse of PCH_PORT_HOTPLUG register. The
+ * functionality covered in PCH_PORT_HOTPLUG is split into
+ * SHOTPLUG_CTL_DDI and SHOTPLUG_CTL_TC.
+ */
+
+#define SHOTPLUG_CTL_DDI                       _MMIO(0xc4030)
+#define   ICP_DDIB_HPD_ENABLE                  (1 << 7)
+#define   ICP_DDIB_HPD_STATUS_MASK             (3 << 4)
+#define   ICP_DDIB_HPD_NO_DETECT               (0 << 4)
+#define   ICP_DDIB_HPD_SHORT_DETECT            (1 << 4)
+#define   ICP_DDIB_HPD_LONG_DETECT             (2 << 4)
+#define   ICP_DDIB_HPD_SHORT_LONG_DETECT       (3 << 4)
+#define   ICP_DDIA_HPD_ENABLE                  (1 << 3)
+#define   ICP_DDIA_HPD_STATUS_MASK             (3 << 0)
+#define   ICP_DDIA_HPD_NO_DETECT               (0 << 0)
+#define   ICP_DDIA_HPD_SHORT_DETECT            (1 << 0)
+#define   ICP_DDIA_HPD_LONG_DETECT             (2 << 0)
+#define   ICP_DDIA_HPD_SHORT_LONG_DETECT       (3 << 0)
+
+#define SHOTPLUG_CTL_TC                                _MMIO(0xc4034)
+#define   ICP_TC_HPD_ENABLE(tc_port)           (8 << (tc_port) * 4)
+#define   ICP_TC_HPD_LONG_DETECT(tc_port)      (2 << (tc_port) * 4)
+#define   ICP_TC_HPD_SHORT_DETECT(tc_port)     (1 << (tc_port) * 4)
+
 #define PCH_GPIOA               _MMIO(0xc5010)
 #define PCH_GPIOB               _MMIO(0xc5014)
 #define PCH_GPIOC               _MMIO(0xc5018)
@@ -8555,6 +8706,14 @@ enum {
 #define _HSW_PWR_WELL_CTL3                     0x45408
 #define _HSW_PWR_WELL_CTL4                     0x4540C
 
+#define _ICL_PWR_WELL_CTL_AUX1                 0x45440
+#define _ICL_PWR_WELL_CTL_AUX2                 0x45444
+#define _ICL_PWR_WELL_CTL_AUX4                 0x4544C
+
+#define _ICL_PWR_WELL_CTL_DDI1                 0x45450
+#define _ICL_PWR_WELL_CTL_DDI2                 0x45454
+#define _ICL_PWR_WELL_CTL_DDI4                 0x4545C
+
 /*
  * Each power well control register contains up to 16 (request, status) HW
  * flag tuples. The register index and HW flag shift is determined by the
@@ -8564,14 +8723,20 @@ enum {
  */
 #define _HSW_PW_REG_IDX(pw)                    ((pw) >> 4)
 #define _HSW_PW_SHIFT(pw)                      (((pw) & 0xf) * 2)
-/* TODO: Add all PWR_WELL_CTL registers below for new platforms */
 #define HSW_PWR_WELL_CTL_BIOS(pw)      _MMIO(_PICK(_HSW_PW_REG_IDX(pw),       \
-                                                   _HSW_PWR_WELL_CTL1))
+                                                   _HSW_PWR_WELL_CTL1,        \
+                                                   _ICL_PWR_WELL_CTL_AUX1,    \
+                                                   _ICL_PWR_WELL_CTL_DDI1))
 #define HSW_PWR_WELL_CTL_DRIVER(pw)    _MMIO(_PICK(_HSW_PW_REG_IDX(pw),       \
-                                                   _HSW_PWR_WELL_CTL2))
+                                                   _HSW_PWR_WELL_CTL2,        \
+                                                   _ICL_PWR_WELL_CTL_AUX2,    \
+                                                   _ICL_PWR_WELL_CTL_DDI2))
+/* KVMR doesn't have a reg for AUX or DDI power well control */
 #define HSW_PWR_WELL_CTL_KVMR          _MMIO(_HSW_PWR_WELL_CTL3)
 #define HSW_PWR_WELL_CTL_DEBUG(pw)     _MMIO(_PICK(_HSW_PW_REG_IDX(pw),       \
-                                                   _HSW_PWR_WELL_CTL4))
+                                                   _HSW_PWR_WELL_CTL4,        \
+                                                   _ICL_PWR_WELL_CTL_AUX4,    \
+                                                   _ICL_PWR_WELL_CTL_DDI4))
 
 #define   HSW_PWR_WELL_CTL_REQ(pw)             (1 << (_HSW_PW_SHIFT(pw) + 1))
 #define   HSW_PWR_WELL_CTL_STATE(pw)           (1 << _HSW_PW_SHIFT(pw))
@@ -8592,6 +8757,8 @@ enum skl_power_gate {
 #define  SKL_FUSE_DOWNLOAD_STATUS              (1 << 31)
 /* PG0 (HW control->no power well ID), PG1..PG2 (SKL_DISP_PW1..SKL_DISP_PW2) */
 #define  SKL_PW_TO_PG(pw)                      ((pw) - SKL_DISP_PW_1 + SKL_PG1)
+/* PG0 (HW control->no power well ID), PG1..PG4 (ICL_DISP_PW1..ICL_DISP_PW4) */
+#define  ICL_PW_TO_PG(pw)                      ((pw) - ICL_DISP_PW_1 + SKL_PG1)
 #define  SKL_FUSE_PG_DIST_STATUS(pg)           (1 << (27 - (pg)))
 
 #define _CNL_AUX_REG_IDX(pw)           ((pw) - 9)
@@ -9047,6 +9214,7 @@ enum skl_power_gate {
 #define _MG_REFCLKIN_CTL_PORT3                         0x16A92C
 #define _MG_REFCLKIN_CTL_PORT4                         0x16B92C
 #define   MG_REFCLKIN_CTL_OD_2_MUX(x)                  ((x) << 8)
+#define   MG_REFCLKIN_CTL_OD_2_MUX_MASK                        (0x7 << 8)
 #define MG_REFCLKIN_CTL(port) _MMIO_PORT((port) - PORT_C, \
                                         _MG_REFCLKIN_CTL_PORT1, \
                                         _MG_REFCLKIN_CTL_PORT2)
@@ -9056,7 +9224,9 @@ enum skl_power_gate {
 #define _MG_CLKTOP2_CORECLKCTL1_PORT3                  0x16A8D8
 #define _MG_CLKTOP2_CORECLKCTL1_PORT4                  0x16B8D8
 #define   MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO(x)         ((x) << 16)
+#define   MG_CLKTOP2_CORECLKCTL1_B_DIVRATIO_MASK       (0xff << 16)
 #define   MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO(x)         ((x) << 8)
+#define   MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK       (0xff << 8)
 #define MG_CLKTOP2_CORECLKCTL1(port) _MMIO_PORT((port) - PORT_C, \
                                                _MG_CLKTOP2_CORECLKCTL1_PORT1, \
                                                _MG_CLKTOP2_CORECLKCTL1_PORT2)
@@ -9066,9 +9236,13 @@ enum skl_power_gate {
 #define _MG_CLKTOP2_HSCLKCTL_PORT3                     0x16A8D4
 #define _MG_CLKTOP2_HSCLKCTL_PORT4                     0x16B8D4
 #define   MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL(x)         ((x) << 16)
+#define   MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK       (0x1 << 16)
 #define   MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL(x)       ((x) << 14)
+#define   MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK     (0x3 << 14)
 #define   MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO(x)           ((x) << 12)
+#define   MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK         (0x3 << 12)
 #define   MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO(x)           ((x) << 8)
+#define   MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK         (0xf << 8)
 #define MG_CLKTOP2_HSCLKCTL(port) _MMIO_PORT((port) - PORT_C, \
                                             _MG_CLKTOP2_HSCLKCTL_PORT1, \
                                             _MG_CLKTOP2_HSCLKCTL_PORT2)
@@ -9142,12 +9316,18 @@ enum skl_power_gate {
 #define _MG_PLL_BIAS_PORT3                             0x16AA14
 #define _MG_PLL_BIAS_PORT4                             0x16BA14
 #define   MG_PLL_BIAS_BIAS_GB_SEL(x)                   ((x) << 30)
+#define   MG_PLL_BIAS_BIAS_GB_SEL_MASK                 (0x3 << 30)
 #define   MG_PLL_BIAS_INIT_DCOAMP(x)                   ((x) << 24)
+#define   MG_PLL_BIAS_INIT_DCOAMP_MASK                 (0x3f << 24)
 #define   MG_PLL_BIAS_BIAS_BONUS(x)                    ((x) << 16)
+#define   MG_PLL_BIAS_BIAS_BONUS_MASK                  (0xff << 16)
 #define   MG_PLL_BIAS_BIASCAL_EN                       (1 << 15)
 #define   MG_PLL_BIAS_CTRIM(x)                         ((x) << 8)
+#define   MG_PLL_BIAS_CTRIM_MASK                       (0x1f << 8)
 #define   MG_PLL_BIAS_VREF_RDAC(x)                     ((x) << 5)
+#define   MG_PLL_BIAS_VREF_RDAC_MASK                   (0x7 << 5)
 #define   MG_PLL_BIAS_IREFTRIM(x)                      ((x) << 0)
+#define   MG_PLL_BIAS_IREFTRIM_MASK                    (0x1f << 0)
 #define MG_PLL_BIAS(port) _MMIO_PORT((port) - PORT_C, _MG_PLL_BIAS_PORT1, \
                                     _MG_PLL_BIAS_PORT2)
 
@@ -9401,6 +9581,22 @@ enum skl_power_gate {
 #define MIPIO_TXESC_CLK_DIV2                   _MMIO(0x160008)
 #define  GLK_TX_ESC_CLK_DIV2_MASK                      0x3FF
 
+#define _ICL_DSI_ESC_CLK_DIV0          0x6b090
+#define _ICL_DSI_ESC_CLK_DIV1          0x6b890
+#define ICL_DSI_ESC_CLK_DIV(port)      _MMIO_PORT((port),      \
+                                                       _ICL_DSI_ESC_CLK_DIV0, \
+                                                       _ICL_DSI_ESC_CLK_DIV1)
+#define _ICL_DPHY_ESC_CLK_DIV0         0x162190
+#define _ICL_DPHY_ESC_CLK_DIV1         0x6C190
+#define ICL_DPHY_ESC_CLK_DIV(port)     _MMIO_PORT((port),      \
+                                               _ICL_DPHY_ESC_CLK_DIV0, \
+                                               _ICL_DPHY_ESC_CLK_DIV1)
+#define  ICL_BYTE_CLK_PER_ESC_CLK_MASK         (0x1f << 16)
+#define  ICL_BYTE_CLK_PER_ESC_CLK_SHIFT        16
+#define  ICL_ESC_CLK_DIV_MASK                  0x1ff
+#define  ICL_ESC_CLK_DIV_SHIFT                 0
+#define DSI_MAX_ESC_CLK                        20000           /* in KHz */
+
 /* Gen4+ Timestamp and Pipe Frame time stamp registers */
 #define GEN4_TIMESTAMP         _MMIO(0x2358)
 #define ILK_TIMESTAMP_HI       _MMIO(0x70070)
@@ -9535,6 +9731,14 @@ enum skl_power_gate {
 #define _BXT_MIPIC_PORT_CTRL                           0x6B8C0
 #define BXT_MIPI_PORT_CTRL(tc) _MMIO_MIPI(tc, _BXT_MIPIA_PORT_CTRL, _BXT_MIPIC_PORT_CTRL)
 
+/* ICL DSI MODE control */
+#define _ICL_DSI_IO_MODECTL_0                          0x6B094
+#define _ICL_DSI_IO_MODECTL_1                          0x6B894
+#define ICL_DSI_IO_MODECTL(port)       _MMIO_PORT(port,        \
+                                                   _ICL_DSI_IO_MODECTL_0, \
+                                                   _ICL_DSI_IO_MODECTL_1)
+#define  COMBO_PHY_MODE_DSI                            (1 << 0)
+
 #define BXT_P_DSI_REGULATOR_CFG                        _MMIO(0x160020)
 #define  STAP_SELECT                                   (1 << 0)
 
index e1dbb544046fef9c6b10b28a05922f10a155f9dc..5c2c93cbab12f8ebff29507a00953a24a9a877c6 100644 (file)
@@ -206,7 +206,8 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
        /* Carefully retire all requests without writing to the rings */
        ret = i915_gem_wait_for_idle(i915,
                                     I915_WAIT_INTERRUPTIBLE |
-                                    I915_WAIT_LOCKED);
+                                    I915_WAIT_LOCKED,
+                                    MAX_SCHEDULE_TIMEOUT);
        if (ret)
                return ret;
 
@@ -503,7 +504,7 @@ static void move_to_timeline(struct i915_request *request,
        GEM_BUG_ON(request->timeline == &request->engine->timeline);
        lockdep_assert_held(&request->engine->timeline.lock);
 
-       spin_lock_nested(&request->timeline->lock, SINGLE_DEPTH_NESTING);
+       spin_lock(&request->timeline->lock);
        list_move_tail(&request->link, &timeline->requests);
        spin_unlock(&request->timeline->lock);
 }
@@ -735,7 +736,8 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
                /* Ratelimit ourselves to prevent oom from malicious clients */
                ret = i915_gem_wait_for_idle(i915,
                                             I915_WAIT_LOCKED |
-                                            I915_WAIT_INTERRUPTIBLE);
+                                            I915_WAIT_INTERRUPTIBLE,
+                                            MAX_SCHEDULE_TIMEOUT);
                if (ret)
                        goto err_unreserve;
 
@@ -1013,6 +1015,27 @@ i915_request_await_object(struct i915_request *to,
        return ret;
 }
 
+void i915_request_skip(struct i915_request *rq, int error)
+{
+       void *vaddr = rq->ring->vaddr;
+       u32 head;
+
+       GEM_BUG_ON(!IS_ERR_VALUE((long)error));
+       dma_fence_set_error(&rq->fence, error);
+
+       /*
+        * As this request likely depends on state from the lost
+        * context, clear out all the user operations leaving the
+        * breadcrumb at the end (so we get the fence notifications).
+        */
+       head = rq->infix;
+       if (rq->postfix < head) {
+               memset(vaddr + head, 0, rq->ring->size - head);
+               head = 0;
+       }
+       memset(vaddr + head, 0, rq->postfix - head);
+}
+
 /*
  * NB: This function is not allowed to fail. Doing so would mean the the
  * request is not being tracked for completion but the work itself is
@@ -1196,7 +1219,7 @@ static bool __i915_spin_request(const struct i915_request *rq,
         * takes to sleep on a request, on the order of a microsecond.
         */
 
-       irq = atomic_read(&engine->irq_count);
+       irq = READ_ONCE(engine->breadcrumbs.irq_count);
        timeout_us += local_clock_us(&cpu);
        do {
                if (i915_seqno_passed(intel_engine_get_seqno(engine), seqno))
@@ -1208,7 +1231,7 @@ static bool __i915_spin_request(const struct i915_request *rq,
                 * assume we won't see one in the near future but require
                 * the engine->seqno_barrier() to fixup coherency.
                 */
-               if (atomic_read(&engine->irq_count) != irq)
+               if (READ_ONCE(engine->breadcrumbs.irq_count) != irq)
                        break;
 
                if (signal_pending_state(state, current))
@@ -1285,7 +1308,7 @@ long i915_request_wait(struct i915_request *rq,
        if (flags & I915_WAIT_LOCKED)
                add_wait_queue(errq, &reset);
 
-       intel_wait_init(&wait, rq);
+       intel_wait_init(&wait);
 
 restart:
        do {
index 7ee220ded9c9aa30ad0d9c775c89c8ef6ac5ee56..e1c9365dfefb1ef9ddf80183ecea07185b6d7ed4 100644 (file)
@@ -258,6 +258,8 @@ void i915_request_add(struct i915_request *rq);
 void __i915_request_submit(struct i915_request *request);
 void i915_request_submit(struct i915_request *request);
 
+void i915_request_skip(struct i915_request *request, int error);
+
 void __i915_request_unsubmit(struct i915_request *request);
 void i915_request_unsubmit(struct i915_request *request);
 
@@ -378,6 +380,7 @@ static inline void
 init_request_active(struct i915_gem_active *active,
                    i915_gem_retire_fn retire)
 {
+       RCU_INIT_POINTER(active->request, NULL);
        INIT_LIST_HEAD(&active->link);
        active->retire = retire ?: i915_gem_retire_noop;
 }
index dc2a4632faa7da7c253633f152a6e4220d56e34e..a2c2c3ab5fb0ceea22c2c1426b1c307b5d1aa460 100644 (file)
@@ -37,6 +37,8 @@ struct i915_timeline {
        u32 seqno;
 
        spinlock_t lock;
+#define TIMELINE_CLIENT 0 /* default subclass */
+#define TIMELINE_ENGINE 1
 
        /**
         * List of breadcrumbs associated with GPU requests currently
index e82aa804cdba3bd65a847654030366ff92f2608e..ed4e0fb558f7c7d96b4eff10dab0cb5df0503a34 100644 (file)
@@ -21,7 +21,7 @@
  * IN THE SOFTWARE.
  *
  */
+
 #include "i915_vma.h"
 
 #include "i915_drv.h"
 
 #include <drm/drm_gem.h>
 
+#if IS_ENABLED(CONFIG_DRM_I915_ERRLOG_GEM) && IS_ENABLED(CONFIG_DRM_DEBUG_MM)
+
+#include <linux/stackdepot.h>
+
+static void vma_print_allocator(struct i915_vma *vma, const char *reason)
+{
+       unsigned long entries[12];
+       struct stack_trace trace = {
+               .entries = entries,
+               .max_entries = ARRAY_SIZE(entries),
+       };
+       char buf[512];
+
+       if (!vma->node.stack) {
+               DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: unknown owner\n",
+                                vma->node.start, vma->node.size, reason);
+               return;
+       }
+
+       depot_fetch_stack(vma->node.stack, &trace);
+       snprint_stack_trace(buf, sizeof(buf), &trace, 0);
+       DRM_DEBUG_DRIVER("vma.node [%08llx + %08llx] %s: inserted at %s\n",
+                        vma->node.start, vma->node.size, reason, buf);
+}
+
+#else
+
+static void vma_print_allocator(struct i915_vma *vma, const char *reason)
+{
+}
+
+#endif
+
+struct i915_vma_active {
+       struct i915_gem_active base;
+       struct i915_vma *vma;
+       struct rb_node node;
+       u64 timeline;
+};
+
 static void
-i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq)
+__i915_vma_retire(struct i915_vma *vma, struct i915_request *rq)
 {
-       const unsigned int idx = rq->engine->id;
-       struct i915_vma *vma =
-               container_of(active, struct i915_vma, last_read[idx]);
        struct drm_i915_gem_object *obj = vma->obj;
 
-       GEM_BUG_ON(!i915_vma_has_active_engine(vma, idx));
-
-       i915_vma_clear_active(vma, idx);
-       if (i915_vma_is_active(vma))
+       GEM_BUG_ON(!i915_vma_is_active(vma));
+       if (--vma->active_count)
                return;
 
        GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
@@ -75,6 +110,21 @@ i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq)
        }
 }
 
+static void
+i915_vma_retire(struct i915_gem_active *base, struct i915_request *rq)
+{
+       struct i915_vma_active *active =
+               container_of(base, typeof(*active), base);
+
+       __i915_vma_retire(active->vma, rq);
+}
+
+static void
+i915_vma_last_retire(struct i915_gem_active *base, struct i915_request *rq)
+{
+       __i915_vma_retire(container_of(base, struct i915_vma, last_active), rq);
+}
+
 static struct i915_vma *
 vma_create(struct drm_i915_gem_object *obj,
           struct i915_address_space *vm,
@@ -82,7 +132,6 @@ vma_create(struct drm_i915_gem_object *obj,
 {
        struct i915_vma *vma;
        struct rb_node *rb, **p;
-       int i;
 
        /* The aliasing_ppgtt should never be used directly! */
        GEM_BUG_ON(vm == &vm->i915->mm.aliasing_ppgtt->vm);
@@ -91,8 +140,9 @@ vma_create(struct drm_i915_gem_object *obj,
        if (vma == NULL)
                return ERR_PTR(-ENOMEM);
 
-       for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
-               init_request_active(&vma->last_read[i], i915_vma_retire);
+       vma->active = RB_ROOT;
+
+       init_request_active(&vma->last_active, i915_vma_last_retire);
        init_request_active(&vma->last_fence, NULL);
        vma->vm = vm;
        vma->ops = &vm->vma_ops;
@@ -110,7 +160,7 @@ vma_create(struct drm_i915_gem_object *obj,
                                                     obj->base.size >> PAGE_SHIFT));
                        vma->size = view->partial.size;
                        vma->size <<= PAGE_SHIFT;
-                       GEM_BUG_ON(vma->size >= obj->base.size);
+                       GEM_BUG_ON(vma->size > obj->base.size);
                } else if (view->type == I915_GGTT_VIEW_ROTATED) {
                        vma->size = intel_rotation_info_size(&view->rotated);
                        vma->size <<= PAGE_SHIFT;
@@ -745,13 +795,11 @@ void i915_vma_reopen(struct i915_vma *vma)
 static void __i915_vma_destroy(struct i915_vma *vma)
 {
        struct drm_i915_private *i915 = vma->vm->i915;
-       int i;
+       struct i915_vma_active *iter, *n;
 
        GEM_BUG_ON(vma->node.allocated);
        GEM_BUG_ON(vma->fence);
 
-       for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
-               GEM_BUG_ON(i915_gem_active_isset(&vma->last_read[i]));
        GEM_BUG_ON(i915_gem_active_isset(&vma->last_fence));
 
        list_del(&vma->obj_link);
@@ -762,6 +810,11 @@ static void __i915_vma_destroy(struct i915_vma *vma)
        if (!i915_vma_is_ggtt(vma))
                i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm));
 
+       rbtree_postorder_for_each_entry_safe(iter, n, &vma->active, node) {
+               GEM_BUG_ON(i915_gem_active_isset(&iter->base));
+               kfree(iter);
+       }
+
        kmem_cache_free(i915->vmas, vma);
 }
 
@@ -826,9 +879,151 @@ void i915_vma_revoke_mmap(struct i915_vma *vma)
                list_del(&vma->obj->userfault_link);
 }
 
+static void export_fence(struct i915_vma *vma,
+                        struct i915_request *rq,
+                        unsigned int flags)
+{
+       struct reservation_object *resv = vma->resv;
+
+       /*
+        * Ignore errors from failing to allocate the new fence, we can't
+        * handle an error right now. Worst case should be missed
+        * synchronisation leading to rendering corruption.
+        */
+       reservation_object_lock(resv, NULL);
+       if (flags & EXEC_OBJECT_WRITE)
+               reservation_object_add_excl_fence(resv, &rq->fence);
+       else if (reservation_object_reserve_shared(resv) == 0)
+               reservation_object_add_shared_fence(resv, &rq->fence);
+       reservation_object_unlock(resv);
+}
+
+static struct i915_gem_active *active_instance(struct i915_vma *vma, u64 idx)
+{
+       struct i915_vma_active *active;
+       struct rb_node **p, *parent;
+       struct i915_request *old;
+
+       /*
+        * We track the most recently used timeline to skip a rbtree search
+        * for the common case, under typical loads we never need the rbtree
+        * at all. We can reuse the last_active slot if it is empty, that is
+        * after the previous activity has been retired, or if the active
+        * matches the current timeline.
+        *
+        * Note that we allow the timeline to be active simultaneously in
+        * the rbtree and the last_active cache. We do this to avoid having
+        * to search and replace the rbtree element for a new timeline, with
+        * the cost being that we must be aware that the vma may be retired
+        * twice for the same timeline (as the older rbtree element will be
+        * retired before the new request added to last_active).
+        */
+       old = i915_gem_active_raw(&vma->last_active,
+                                 &vma->vm->i915->drm.struct_mutex);
+       if (!old || old->fence.context == idx)
+               goto out;
+
+       /* Move the currently active fence into the rbtree */
+       idx = old->fence.context;
+
+       parent = NULL;
+       p = &vma->active.rb_node;
+       while (*p) {
+               parent = *p;
+
+               active = rb_entry(parent, struct i915_vma_active, node);
+               if (active->timeline == idx)
+                       goto replace;
+
+               if (active->timeline < idx)
+                       p = &parent->rb_right;
+               else
+                       p = &parent->rb_left;
+       }
+
+       active = kmalloc(sizeof(*active), GFP_KERNEL);
+       if (unlikely(!active))
+               return ERR_PTR(-ENOMEM);
+
+       init_request_active(&active->base, i915_vma_retire);
+       active->vma = vma;
+       active->timeline = idx;
+
+       rb_link_node(&active->node, parent, p);
+       rb_insert_color(&active->node, &vma->active);
+
+replace:
+       /*
+        * Overwrite the previous active slot in the rbtree with last_active,
+        * leaving last_active zeroed. If the previous slot is still active,
+        * we must be careful as we now only expect to receive one retire
+        * callback not two, and so much undo the active counting for the
+        * overwritten slot.
+        */
+       if (i915_gem_active_isset(&active->base)) {
+               /* Retire ourselves from the old rq->active_list */
+               __list_del_entry(&active->base.link);
+               vma->active_count--;
+               GEM_BUG_ON(!vma->active_count);
+       }
+       GEM_BUG_ON(list_empty(&vma->last_active.link));
+       list_replace_init(&vma->last_active.link, &active->base.link);
+       active->base.request = fetch_and_zero(&vma->last_active.request);
+
+out:
+       return &vma->last_active;
+}
+
+int i915_vma_move_to_active(struct i915_vma *vma,
+                           struct i915_request *rq,
+                           unsigned int flags)
+{
+       struct drm_i915_gem_object *obj = vma->obj;
+       struct i915_gem_active *active;
+
+       lockdep_assert_held(&rq->i915->drm.struct_mutex);
+       GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
+
+       active = active_instance(vma, rq->fence.context);
+       if (IS_ERR(active))
+               return PTR_ERR(active);
+
+       /*
+        * Add a reference if we're newly entering the active list.
+        * The order in which we add operations to the retirement queue is
+        * vital here: mark_active adds to the start of the callback list,
+        * such that subsequent callbacks are called first. Therefore we
+        * add the active reference first and queue for it to be dropped
+        * *last*.
+        */
+       if (!i915_gem_active_isset(active) && !vma->active_count++) {
+               list_move_tail(&vma->vm_link, &vma->vm->active_list);
+               obj->active_count++;
+       }
+       i915_gem_active_set(active, rq);
+       GEM_BUG_ON(!i915_vma_is_active(vma));
+       GEM_BUG_ON(!obj->active_count);
+
+       obj->write_domain = 0;
+       if (flags & EXEC_OBJECT_WRITE) {
+               obj->write_domain = I915_GEM_DOMAIN_RENDER;
+
+               if (intel_fb_obj_invalidate(obj, ORIGIN_CS))
+                       i915_gem_active_set(&obj->frontbuffer_write, rq);
+
+               obj->read_domains = 0;
+       }
+       obj->read_domains |= I915_GEM_GPU_DOMAINS;
+
+       if (flags & EXEC_OBJECT_NEEDS_FENCE)
+               i915_gem_active_set(&vma->last_fence, rq);
+
+       export_fence(vma, rq, flags);
+       return 0;
+}
+
 int i915_vma_unbind(struct i915_vma *vma)
 {
-       unsigned long active;
        int ret;
 
        lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
@@ -838,9 +1033,8 @@ int i915_vma_unbind(struct i915_vma *vma)
         * have side-effects such as unpinning or even unbinding this vma.
         */
        might_sleep();
-       active = i915_vma_get_active(vma);
-       if (active) {
-               int idx;
+       if (i915_vma_is_active(vma)) {
+               struct i915_vma_active *active, *n;
 
                /*
                 * When a closed VMA is retired, it is unbound - eek.
@@ -857,26 +1051,32 @@ int i915_vma_unbind(struct i915_vma *vma)
                 */
                __i915_vma_pin(vma);
 
-               for_each_active(active, idx) {
-                       ret = i915_gem_active_retire(&vma->last_read[idx],
-                                                    &vma->vm->i915->drm.struct_mutex);
-                       if (ret)
-                               break;
-               }
+               ret = i915_gem_active_retire(&vma->last_active,
+                                            &vma->vm->i915->drm.struct_mutex);
+               if (ret)
+                       goto unpin;
 
-               if (!ret) {
-                       ret = i915_gem_active_retire(&vma->last_fence,
+               rbtree_postorder_for_each_entry_safe(active, n,
+                                                    &vma->active, node) {
+                       ret = i915_gem_active_retire(&active->base,
                                                     &vma->vm->i915->drm.struct_mutex);
+                       if (ret)
+                               goto unpin;
                }
 
+               ret = i915_gem_active_retire(&vma->last_fence,
+                                            &vma->vm->i915->drm.struct_mutex);
+unpin:
                __i915_vma_unpin(vma);
                if (ret)
                        return ret;
        }
        GEM_BUG_ON(i915_vma_is_active(vma));
 
-       if (i915_vma_is_pinned(vma))
+       if (i915_vma_is_pinned(vma)) {
+               vma_print_allocator(vma, "is pinned");
                return -EBUSY;
+       }
 
        if (!drm_mm_node_allocated(&vma->node))
                return 0;
index 66a228931517fb84eeeebef6a086bf215c71297d..f06d663771070a66cb3df27f81d7f58298bb3708 100644 (file)
@@ -26,6 +26,7 @@
 #define __I915_VMA_H__
 
 #include <linux/io-mapping.h>
+#include <linux/rbtree.h>
 
 #include <drm/drm_mm.h>
 
@@ -94,8 +95,9 @@ struct i915_vma {
 #define I915_VMA_USERFAULT     BIT(I915_VMA_USERFAULT_BIT)
 #define I915_VMA_GGTT_WRITE    BIT(12)
 
-       unsigned int active;
-       struct i915_gem_active last_read[I915_NUM_ENGINES];
+       unsigned int active_count;
+       struct rb_root active;
+       struct i915_gem_active last_active;
        struct i915_gem_active last_fence;
 
        /**
@@ -138,6 +140,15 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
 
 void i915_vma_unpin_and_release(struct i915_vma **p_vma);
 
+static inline bool i915_vma_is_active(struct i915_vma *vma)
+{
+       return vma->active_count;
+}
+
+int __must_check i915_vma_move_to_active(struct i915_vma *vma,
+                                        struct i915_request *rq,
+                                        unsigned int flags);
+
 static inline bool i915_vma_is_ggtt(const struct i915_vma *vma)
 {
        return vma->flags & I915_VMA_GGTT;
@@ -187,34 +198,6 @@ static inline bool i915_vma_has_userfault(const struct i915_vma *vma)
        return test_bit(I915_VMA_USERFAULT_BIT, &vma->flags);
 }
 
-static inline unsigned int i915_vma_get_active(const struct i915_vma *vma)
-{
-       return vma->active;
-}
-
-static inline bool i915_vma_is_active(const struct i915_vma *vma)
-{
-       return i915_vma_get_active(vma);
-}
-
-static inline void i915_vma_set_active(struct i915_vma *vma,
-                                      unsigned int engine)
-{
-       vma->active |= BIT(engine);
-}
-
-static inline void i915_vma_clear_active(struct i915_vma *vma,
-                                        unsigned int engine)
-{
-       vma->active &= ~BIT(engine);
-}
-
-static inline bool i915_vma_has_active_engine(const struct i915_vma *vma,
-                                             unsigned int engine)
-{
-       return vma->active & BIT(engine);
-}
-
 static inline u32 i915_ggtt_offset(const struct i915_vma *vma)
 {
        GEM_BUG_ON(!i915_vma_is_ggtt(vma));
diff --git a/drivers/gpu/drm/i915/icl_dsi.c b/drivers/gpu/drm/i915/icl_dsi.c
new file mode 100644 (file)
index 0000000..13830e4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2018 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.
+ *
+ * Authors:
+ *   Madhav Chauhan <madhav.chauhan@intel.com>
+ *   Jani Nikula <jani.nikula@intel.com>
+ */
+
+#include "intel_dsi.h"
+
+static void gen11_dsi_program_esc_clk_div(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
+       u32 afe_clk_khz; /* 8X Clock */
+       u32 esc_clk_div_m;
+
+       afe_clk_khz = DIV_ROUND_CLOSEST(intel_dsi->pclk * bpp,
+                                       intel_dsi->lane_count);
+
+       esc_clk_div_m = DIV_ROUND_UP(afe_clk_khz, DSI_MAX_ESC_CLK);
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(ICL_DSI_ESC_CLK_DIV(port),
+                          esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
+               POSTING_READ(ICL_DSI_ESC_CLK_DIV(port));
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               I915_WRITE(ICL_DPHY_ESC_CLK_DIV(port),
+                          esc_clk_div_m & ICL_ESC_CLK_DIV_MASK);
+               POSTING_READ(ICL_DPHY_ESC_CLK_DIV(port));
+       }
+}
+
+static void gen11_dsi_enable_io_power(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_DSI_IO_MODECTL(port));
+               tmp |= COMBO_PHY_MODE_DSI;
+               I915_WRITE(ICL_DSI_IO_MODECTL(port), tmp);
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               intel_display_power_get(dev_priv, port == PORT_A ?
+                                       POWER_DOMAIN_PORT_DDI_A_IO :
+                                       POWER_DOMAIN_PORT_DDI_B_IO);
+       }
+}
+
+static void gen11_dsi_power_up_lanes(struct intel_encoder *encoder)
+{
+       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+       enum port port;
+       u32 tmp;
+       u32 lane_mask;
+
+       switch (intel_dsi->lane_count) {
+       case 1:
+               lane_mask = PWR_DOWN_LN_3_1_0;
+               break;
+       case 2:
+               lane_mask = PWR_DOWN_LN_3_1;
+               break;
+       case 3:
+               lane_mask = PWR_DOWN_LN_3;
+               break;
+       case 4:
+       default:
+               lane_mask = PWR_UP_ALL_LANES;
+               break;
+       }
+
+       for_each_dsi_port(port, intel_dsi->ports) {
+               tmp = I915_READ(ICL_PORT_CL_DW10(port));
+               tmp &= ~PWR_DOWN_LN_MASK;
+               I915_WRITE(ICL_PORT_CL_DW10(port), tmp | lane_mask);
+       }
+}
+
+static void gen11_dsi_enable_port_and_phy(struct intel_encoder *encoder)
+{
+       /* step 4a: power up all lanes of the DDI used by DSI */
+       gen11_dsi_power_up_lanes(encoder);
+}
+
+static void __attribute__((unused))
+gen11_dsi_pre_enable(struct intel_encoder *encoder,
+                    const struct intel_crtc_state *pipe_config,
+                    const struct drm_connector_state *conn_state)
+{
+       /* step2: enable IO power */
+       gen11_dsi_enable_io_power(encoder);
+
+       /* step3: enable DSI PLL */
+       gen11_dsi_program_esc_clk_div(encoder);
+
+       /* step4: enable DSI port and DPHY */
+       gen11_dsi_enable_port_and_phy(encoder);
+}
index 86a987b8ac667b6988a64d446b76ee594046005d..1db6ba7d926ee3b27b0c00e9bf82f956173e8b59 100644 (file)
@@ -98,12 +98,14 @@ static void intel_breadcrumbs_hangcheck(struct timer_list *t)
        struct intel_engine_cs *engine =
                from_timer(engine, t, breadcrumbs.hangcheck);
        struct intel_breadcrumbs *b = &engine->breadcrumbs;
+       unsigned int irq_count;
 
        if (!b->irq_armed)
                return;
 
-       if (b->hangcheck_interrupts != atomic_read(&engine->irq_count)) {
-               b->hangcheck_interrupts = atomic_read(&engine->irq_count);
+       irq_count = READ_ONCE(b->irq_count);
+       if (b->hangcheck_interrupts != irq_count) {
+               b->hangcheck_interrupts = irq_count;
                mod_timer(&b->hangcheck, wait_timeout());
                return;
        }
@@ -272,13 +274,14 @@ static bool use_fake_irq(const struct intel_breadcrumbs *b)
        if (!test_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings))
                return false;
 
-       /* Only start with the heavy weight fake irq timer if we have not
+       /*
+        * Only start with the heavy weight fake irq timer if we have not
         * seen any interrupts since enabling it the first time. If the
         * interrupts are still arriving, it means we made a mistake in our
         * engine->seqno_barrier(), a timing error that should be transient
         * and unlikely to reoccur.
         */
-       return atomic_read(&engine->irq_count) == b->hangcheck_interrupts;
+       return READ_ONCE(b->irq_count) == b->hangcheck_interrupts;
 }
 
 static void enable_fake_irq(struct intel_breadcrumbs *b)
index bf9433d7964dc1dcea37c9e75376f93d8c20721a..29075c763428055ddb3625a80b59643e694f3d76 100644 (file)
@@ -316,6 +316,7 @@ static void pnv_get_cdclk(struct drm_i915_private *dev_priv,
                break;
        default:
                DRM_ERROR("Unknown pnv display core clock 0x%04x\n", gcfgc);
+               /* fall through */
        case GC_DISPLAY_CLOCK_133_MHZ_PNV:
                cdclk_state->cdclk = 133333;
                break;
@@ -1797,6 +1798,7 @@ static int icl_calc_cdclk(int min_cdclk, unsigned int ref)
        switch (ref) {
        default:
                MISSING_CASE(ref);
+               /* fall through */
        case 24000:
                ranges = ranges_24;
                break;
@@ -1824,6 +1826,7 @@ static int icl_calc_cdclk_pll_vco(struct drm_i915_private *dev_priv, int cdclk)
        switch (cdclk) {
        default:
                MISSING_CASE(cdclk);
+               /* fall through */
        case 307200:
        case 556800:
        case 652800:
@@ -1896,6 +1899,7 @@ static u8 icl_calc_voltage_level(int cdclk)
                return 1;
        default:
                MISSING_CASE(cdclk);
+               /* fall through */
        case 652800:
        case 648000:
                return 2;
@@ -1913,6 +1917,7 @@ static void icl_get_cdclk(struct drm_i915_private *dev_priv,
        switch (val & ICL_DSSM_CDCLK_PLL_REFCLK_MASK) {
        default:
                MISSING_CASE(val);
+               /* fall through */
        case ICL_DSSM_CDCLK_PLL_REFCLK_24MHz:
                cdclk_state->ref = 24000;
                break;
index 044fe1fb98727bf06bb161b4d8d67e838395b0ea..32838ed89ee7a011f15a070c18611624ec6909a2 100644 (file)
@@ -1069,6 +1069,7 @@ static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder *encoder,
        switch (id) {
        default:
                MISSING_CASE(id);
+               /* fall through */
        case DPLL_ID_ICL_DPLL0:
        case DPLL_ID_ICL_DPLL1:
                return DDI_CLK_SEL_NONE;
@@ -1983,15 +1984,50 @@ out:
        return ret;
 }
 
-static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder)
+static inline enum intel_display_power_domain
+intel_ddi_main_link_aux_domain(struct intel_dp *intel_dp)
+{
+       /* CNL HW requires corresponding AUX IOs to be powered up for PSR with
+        * DC states enabled at the same time, while for driver initiated AUX
+        * transfers we need the same AUX IOs to be powered but with DC states
+        * disabled. Accordingly use the AUX power domain here which leaves DC
+        * states enabled.
+        * However, for non-A AUX ports the corresponding non-EDP transcoders
+        * would have already enabled power well 2 and DC_OFF. This means we can
+        * acquire a wider POWER_DOMAIN_AUX_{B,C,D,F} reference instead of a
+        * specific AUX_IO reference without powering up any extra wells.
+        * Note that PSR is enabled only on Port A even though this function
+        * returns the correct domain for other ports too.
+        */
+       return intel_dp->aux_ch == AUX_CH_A ? POWER_DOMAIN_AUX_IO_A :
+                                             intel_dp->aux_power_domain;
+}
+
+static u64 intel_ddi_get_power_domains(struct intel_encoder *encoder,
+                                      struct intel_crtc_state *crtc_state)
 {
-       struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
-       enum pipe pipe;
+       struct intel_digital_port *dig_port;
+       u64 domains;
 
-       if (intel_ddi_get_hw_state(encoder, &pipe))
-               return BIT_ULL(dig_port->ddi_io_power_domain);
+       /*
+        * TODO: Add support for MST encoders. Atm, the following should never
+        * happen since fake-MST encoders don't set their get_power_domains()
+        * hook.
+        */
+       if (WARN_ON(intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)))
+               return 0;
 
-       return 0;
+       dig_port = enc_to_dig_port(&encoder->base);
+       domains = BIT_ULL(dig_port->ddi_io_power_domain);
+
+       /* AUX power is only needed for (e)DP mode, not for HDMI. */
+       if (intel_crtc_has_dp_encoder(crtc_state)) {
+               struct intel_dp *intel_dp = &dig_port->dp;
+
+               domains |= BIT_ULL(intel_ddi_main_link_aux_domain(intel_dp));
+       }
+
+       return domains;
 }
 
 void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state)
@@ -2631,6 +2667,9 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 
        WARN_ON(is_mst && (port == PORT_A || port == PORT_E));
 
+       intel_display_power_get(dev_priv,
+                               intel_ddi_main_link_aux_domain(intel_dp));
+
        intel_dp_set_link_params(intel_dp, crtc_state->port_clock,
                                 crtc_state->lane_count, is_mst);
 
@@ -2775,6 +2814,9 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
        intel_display_power_put(dev_priv, dig_port->ddi_io_power_domain);
 
        intel_ddi_clk_disable(encoder);
+
+       intel_display_power_put(dev_priv,
+                               intel_ddi_main_link_aux_domain(intel_dp));
 }
 
 static void intel_ddi_post_disable_hdmi(struct intel_encoder *encoder,
index 0fd13df424cf19719958b5de465cebec849895c3..0ef0c6448d53a835fbdf5319a8010c64d613bd0f 100644 (file)
@@ -858,6 +858,8 @@ void intel_device_info_runtime_init(struct intel_device_info *info)
 void intel_driver_caps_print(const struct intel_driver_caps *caps,
                             struct drm_printer *p)
 {
+       drm_printf(p, "Has logical contexts? %s\n",
+                  yesno(caps->has_logical_contexts));
        drm_printf(p, "scheduler: %x\n", caps->scheduler);
 }
 
index 933e31669557e74311ab6f7ff685921517c38f0a..633f9fbf72eab7787102d094f8f442799da4c401 100644 (file)
@@ -186,6 +186,7 @@ struct intel_device_info {
 
 struct intel_driver_caps {
        unsigned int scheduler;
+       bool has_logical_contexts:1;
 };
 
 static inline unsigned int sseu_subslice_total(const struct sseu_dev_info *sseu)
index 694a4703042feac8e2508b433ae69126f386af4f..8f3199b06d1f4c64020b5bb99923246cb5d45f84 100644 (file)
@@ -5632,6 +5632,7 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
        struct intel_atomic_state *old_intel_state =
                to_intel_atomic_state(old_state);
        bool psl_clkgate_wa;
+       u32 pipe_chicken;
 
        if (WARN_ON(intel_crtc->active))
                return;
@@ -5691,6 +5692,17 @@ static void haswell_crtc_enable(struct intel_crtc_state *pipe_config,
         */
        intel_color_load_luts(&pipe_config->base);
 
+       /*
+        * Display WA #1153: enable hardware to bypass the alpha math
+        * and rounding for per-pixel values 00 and 0xff
+        */
+       if (INTEL_GEN(dev_priv) >= 11) {
+               pipe_chicken = I915_READ(PIPE_CHICKEN(pipe));
+               if (!(pipe_chicken & PER_PIXEL_ALPHA_BYPASS_EN))
+                       I915_WRITE_FW(PIPE_CHICKEN(pipe),
+                                     pipe_chicken | PER_PIXEL_ALPHA_BYPASS_EN);
+       }
+
        intel_ddi_set_pipe_settings(pipe_config);
        if (!transcoder_is_dsi(cpu_transcoder))
                intel_ddi_enable_transcoder_func(pipe_config);
@@ -9347,6 +9359,7 @@ static bool hsw_get_transcoder_state(struct intel_crtc *crtc,
                switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
                default:
                        WARN(1, "unknown pipe linked to edp transcoder\n");
+                       /* fall through */
                case TRANS_DDI_EDP_INPUT_A_ONOFF:
                case TRANS_DDI_EDP_INPUT_A_ON:
                        trans_edp_pipe = PIPE_A;
@@ -9402,7 +9415,7 @@ static bool bxt_get_dsi_transcoder_state(struct intel_crtc *crtc,
                 * registers/MIPI[BXT]. We can break out here early, since we
                 * need the same DSI PLL to be enabled for both DSI ports.
                 */
-               if (!intel_dsi_pll_is_enabled(dev_priv))
+               if (!bxt_dsi_pll_is_enabled(dev_priv))
                        break;
 
                /* XXX: this works for video mode only */
@@ -10724,7 +10737,7 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
        drm_connector_list_iter_begin(dev, &conn_iter);
        for_each_intel_connector_iter(connector, &conn_iter) {
                if (connector->base.state->crtc)
-                       drm_connector_unreference(&connector->base);
+                       drm_connector_put(&connector->base);
 
                if (connector->base.encoder) {
                        connector->base.state->best_encoder =
@@ -10732,7 +10745,7 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev)
                        connector->base.state->crtc =
                                connector->base.encoder->crtc;
 
-                       drm_connector_reference(&connector->base);
+                       drm_connector_get(&connector->base);
                } else {
                        connector->base.state->best_encoder = NULL;
                        connector->base.state->crtc = NULL;
@@ -11011,6 +11024,7 @@ static bool check_digital_port_conflicts(struct drm_atomic_state *state)
                case INTEL_OUTPUT_DDI:
                        if (WARN_ON(!HAS_DDI(to_i915(dev))))
                                break;
+                       /* else: fall through */
                case INTEL_OUTPUT_DP:
                case INTEL_OUTPUT_HDMI:
                case INTEL_OUTPUT_EDP:
@@ -12542,6 +12556,19 @@ static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_stat
        finish_wait(&dev_priv->gpu_error.wait_queue, &wait_reset);
 }
 
+static void intel_atomic_cleanup_work(struct work_struct *work)
+{
+       struct drm_atomic_state *state =
+               container_of(work, struct drm_atomic_state, commit_work);
+       struct drm_i915_private *i915 = to_i915(state->dev);
+
+       drm_atomic_helper_cleanup_planes(&i915->drm, state);
+       drm_atomic_helper_commit_cleanup_done(state);
+       drm_atomic_state_put(state);
+
+       intel_atomic_helper_free_state(i915);
+}
+
 static void intel_atomic_commit_tail(struct drm_atomic_state *state)
 {
        struct drm_device *dev = state->dev;
@@ -12702,13 +12729,16 @@ static void intel_atomic_commit_tail(struct drm_atomic_state *state)
                intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
        }
 
-       drm_atomic_helper_cleanup_planes(dev, state);
-
-       drm_atomic_helper_commit_cleanup_done(state);
-
-       drm_atomic_state_put(state);
-
-       intel_atomic_helper_free_state(dev_priv);
+       /*
+        * Defer the cleanup of the old state to a separate worker to not
+        * impede the current task (userspace for blocking modesets) that
+        * are executed inline. For out-of-line asynchronous modesets/flips,
+        * deferring to a new worker seems overkill, but we would place a
+        * schedule point (cond_resched()) here anyway to keep latencies
+        * down.
+        */
+       INIT_WORK(&state->commit_work, intel_atomic_cleanup_work);
+       schedule_work(&state->commit_work);
 }
 
 static void intel_atomic_commit_work(struct work_struct *work)
@@ -14105,7 +14135,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
                intel_ddi_init(dev_priv, PORT_B);
                intel_ddi_init(dev_priv, PORT_C);
 
-               intel_dsi_init(dev_priv);
+               vlv_dsi_init(dev_priv);
        } else if (HAS_DDI(dev_priv)) {
                int found;
 
@@ -14211,7 +14241,7 @@ static void intel_setup_outputs(struct drm_i915_private *dev_priv)
                                intel_hdmi_init(dev_priv, CHV_HDMID, PORT_D);
                }
 
-               intel_dsi_init(dev_priv);
+               vlv_dsi_init(dev_priv);
        } else if (!IS_GEN2(dev_priv) && !IS_PINEVIEW(dev_priv)) {
                bool found = false;
 
@@ -14493,11 +14523,6 @@ static int intel_framebuffer_init(struct intel_framebuffer *intel_fb,
                }
                break;
        case DRM_FORMAT_NV12:
-               if (mode_cmd->modifier[0] == I915_FORMAT_MOD_Y_TILED_CCS ||
-                   mode_cmd->modifier[0] == I915_FORMAT_MOD_Yf_TILED_CCS) {
-                       DRM_DEBUG_KMS("RC not to be enabled with NV12\n");
-                       goto err;
-               }
                if (INTEL_GEN(dev_priv) < 9 || IS_SKYLAKE(dev_priv) ||
                    IS_BROXTON(dev_priv)) {
                        DRM_DEBUG_KMS("unsupported pixel format: %s\n",
@@ -15676,11 +15701,20 @@ get_encoder_power_domains(struct drm_i915_private *dev_priv)
        for_each_intel_encoder(&dev_priv->drm, encoder) {
                u64 get_domains;
                enum intel_display_power_domain domain;
+               struct intel_crtc_state *crtc_state;
 
                if (!encoder->get_power_domains)
                        continue;
 
-               get_domains = encoder->get_power_domains(encoder);
+               /*
+                * MST-primary and inactive encoders don't have a crtc state
+                * and neither of these require any power domain references.
+                */
+               if (!encoder->base.crtc)
+                       continue;
+
+               crtc_state = to_intel_crtc_state(encoder->base.crtc->state);
+               get_domains = encoder->get_power_domains(encoder, crtc_state);
                for_each_power_domain(domain, get_domains)
                        intel_display_power_get(dev_priv, domain);
        }
index dd30cae5eb002502c7b64bb4f8e0c5b8ee1ccf9e..ca5a10f3400dcbb8536369844555c10e01c7981a 100644 (file)
@@ -199,6 +199,10 @@ enum intel_display_power_domain {
        POWER_DOMAIN_AUX_E,
        POWER_DOMAIN_AUX_F,
        POWER_DOMAIN_AUX_IO_A,
+       POWER_DOMAIN_AUX_TBT1,
+       POWER_DOMAIN_AUX_TBT2,
+       POWER_DOMAIN_AUX_TBT3,
+       POWER_DOMAIN_AUX_TBT4,
        POWER_DOMAIN_GMBUS,
        POWER_DOMAIN_MODESET,
        POWER_DOMAIN_GT_IRQ,
index 6ac6c8787dcf658fd44ec98b7b95f89afa09d1a0..5be07e1d816d76baaa40bb401d1513dc479eba18 100644 (file)
@@ -953,7 +953,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp)
 }
 
 static uint32_t
-intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
+intel_dp_aux_wait_done(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
        i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
@@ -961,14 +961,10 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
        bool done;
 
 #define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
-       if (has_aux_irq)
-               done = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
-                                         msecs_to_jiffies_timeout(10));
-       else
-               done = wait_for(C, 10) == 0;
+       done = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
+                                 msecs_to_jiffies_timeout(10));
        if (!done)
-               DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n",
-                         has_aux_irq);
+               DRM_ERROR("dp aux hw did not signal timeout!\n");
 #undef C
 
        return status;
@@ -1033,7 +1029,6 @@ static uint32_t skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
 }
 
 static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
-                                    bool has_aux_irq,
                                     int send_bytes,
                                     uint32_t aux_clock_divider)
 {
@@ -1054,7 +1049,7 @@ static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
 
        return DP_AUX_CH_CTL_SEND_BUSY |
               DP_AUX_CH_CTL_DONE |
-              (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
+              DP_AUX_CH_CTL_INTERRUPT |
               DP_AUX_CH_CTL_TIME_OUT_ERROR |
               timeout |
               DP_AUX_CH_CTL_RECEIVE_ERROR |
@@ -1064,13 +1059,12 @@ static uint32_t g4x_get_aux_send_ctl(struct intel_dp *intel_dp,
 }
 
 static uint32_t skl_get_aux_send_ctl(struct intel_dp *intel_dp,
-                                     bool has_aux_irq,
                                      int send_bytes,
                                      uint32_t unused)
 {
        return DP_AUX_CH_CTL_SEND_BUSY |
               DP_AUX_CH_CTL_DONE |
-              (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
+              DP_AUX_CH_CTL_INTERRUPT |
               DP_AUX_CH_CTL_TIME_OUT_ERROR |
               DP_AUX_CH_CTL_TIME_OUT_MAX |
               DP_AUX_CH_CTL_RECEIVE_ERROR |
@@ -1093,7 +1087,6 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
        int i, ret, recv_bytes;
        uint32_t status;
        int try, clock = 0;
-       bool has_aux_irq = HAS_AUX_IRQ(dev_priv);
        bool vdd;
 
        ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp);
@@ -1148,7 +1141,6 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
 
        while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
                u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
-                                                         has_aux_irq,
                                                          send_bytes,
                                                          aux_clock_divider);
 
@@ -1165,7 +1157,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
                        /* Send the command and wait for it to complete */
                        I915_WRITE(ch_ctl, send_ctl);
 
-                       status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
+                       status = intel_dp_aux_wait_done(intel_dp);
 
                        /* Clear done status and any errors */
                        I915_WRITE(ch_ctl,
@@ -4499,6 +4491,8 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
        if (intel_dp_needs_link_retrain(intel_dp))
                return false;
 
+       intel_psr_short_pulse(intel_dp);
+
        if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
                DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
                /* Send a Hotplug Uevent to userspace to start modeset */
index 0f012fbe34ebd6b105b0e4461924c31ddad914b7..85ecf41eeabb31f80a8356c1f0f0a10aa204bff8 100644 (file)
@@ -514,7 +514,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
        intel_connector->mst_port = NULL;
        drm_modeset_unlock(&connector->dev->mode_config.connection_mutex);
 
-       drm_connector_unreference(connector);
+       drm_connector_put(connector);
 }
 
 static void intel_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
index 156f8e4cbe4c2a69aec7d73d34e0d7d221aa1a45..b51ad2917dbef4528d9a7c528e603f9602cd39fd 100644 (file)
@@ -2566,6 +2566,7 @@ int icl_calc_dp_combo_pll_link(struct drm_i915_private *dev_priv,
        switch (index) {
        default:
                MISSING_CASE(index);
+               /* fall through */
        case 0:
                link_clock = 540000;
                break;
@@ -2639,6 +2640,7 @@ static bool icl_mg_pll_find_divisors(int clock_khz, bool is_dp, bool use_ssc,
                        switch (div1) {
                        default:
                                MISSING_CASE(div1);
+                               /* fall through */
                        case 2:
                                hsdiv = 0;
                                break;
@@ -2812,25 +2814,31 @@ static bool icl_calc_mg_pll_state(struct intel_crtc_state *crtc_state,
                                MG_PLL_SSC_FLLEN |
                                MG_PLL_SSC_STEPSIZE(ssc_stepsize);
 
-       pll_state->mg_pll_tdc_coldst_bias = MG_PLL_TDC_COLDST_COLDSTART;
-
-       if (refclk_khz != 38400) {
-               pll_state->mg_pll_tdc_coldst_bias |=
-                       MG_PLL_TDC_COLDST_IREFINT_EN |
-                       MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) |
-                       MG_PLL_TDC_COLDST_COLDSTART |
-                       MG_PLL_TDC_TDCOVCCORR_EN |
-                       MG_PLL_TDC_TDCSEL(3);
-
-               pll_state->mg_pll_bias = MG_PLL_BIAS_BIAS_GB_SEL(3) |
-                                        MG_PLL_BIAS_INIT_DCOAMP(0x3F) |
-                                        MG_PLL_BIAS_BIAS_BONUS(10) |
-                                        MG_PLL_BIAS_BIASCAL_EN |
-                                        MG_PLL_BIAS_CTRIM(12) |
-                                        MG_PLL_BIAS_VREF_RDAC(4) |
-                                        MG_PLL_BIAS_IREFTRIM(iref_trim);
+       pll_state->mg_pll_tdc_coldst_bias = MG_PLL_TDC_COLDST_COLDSTART |
+                                           MG_PLL_TDC_COLDST_IREFINT_EN |
+                                           MG_PLL_TDC_COLDST_REFBIAS_START_PULSE_W(iref_pulse_w) |
+                                           MG_PLL_TDC_TDCOVCCORR_EN |
+                                           MG_PLL_TDC_TDCSEL(3);
+
+       pll_state->mg_pll_bias = MG_PLL_BIAS_BIAS_GB_SEL(3) |
+                                MG_PLL_BIAS_INIT_DCOAMP(0x3F) |
+                                MG_PLL_BIAS_BIAS_BONUS(10) |
+                                MG_PLL_BIAS_BIASCAL_EN |
+                                MG_PLL_BIAS_CTRIM(12) |
+                                MG_PLL_BIAS_VREF_RDAC(4) |
+                                MG_PLL_BIAS_IREFTRIM(iref_trim);
+
+       if (refclk_khz == 38400) {
+               pll_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART;
+               pll_state->mg_pll_bias_mask = 0;
+       } else {
+               pll_state->mg_pll_tdc_coldst_bias_mask = -1U;
+               pll_state->mg_pll_bias_mask = -1U;
        }
 
+       pll_state->mg_pll_tdc_coldst_bias &= pll_state->mg_pll_tdc_coldst_bias_mask;
+       pll_state->mg_pll_bias &= pll_state->mg_pll_bias_mask;
+
        return true;
 }
 
@@ -2897,6 +2905,7 @@ static i915_reg_t icl_pll_id_to_enable_reg(enum intel_dpll_id id)
        switch (id) {
        default:
                MISSING_CASE(id);
+               /* fall through */
        case DPLL_ID_ICL_DPLL0:
        case DPLL_ID_ICL_DPLL1:
                return CNL_DPLL_ENABLE(id);
@@ -2939,18 +2948,41 @@ static bool icl_pll_get_hw_state(struct drm_i915_private *dev_priv,
        case DPLL_ID_ICL_MGPLL4:
                port = icl_mg_pll_id_to_port(id);
                hw_state->mg_refclkin_ctl = I915_READ(MG_REFCLKIN_CTL(port));
+               hw_state->mg_refclkin_ctl &= MG_REFCLKIN_CTL_OD_2_MUX_MASK;
+
                hw_state->mg_clktop2_coreclkctl1 =
                        I915_READ(MG_CLKTOP2_CORECLKCTL1(port));
+               hw_state->mg_clktop2_coreclkctl1 &=
+                       MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
+
                hw_state->mg_clktop2_hsclkctl =
                        I915_READ(MG_CLKTOP2_HSCLKCTL(port));
+               hw_state->mg_clktop2_hsclkctl &=
+                       MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
+                       MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
+                       MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
+                       MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK;
+
                hw_state->mg_pll_div0 = I915_READ(MG_PLL_DIV0(port));
                hw_state->mg_pll_div1 = I915_READ(MG_PLL_DIV1(port));
                hw_state->mg_pll_lf = I915_READ(MG_PLL_LF(port));
                hw_state->mg_pll_frac_lock = I915_READ(MG_PLL_FRAC_LOCK(port));
                hw_state->mg_pll_ssc = I915_READ(MG_PLL_SSC(port));
+
                hw_state->mg_pll_bias = I915_READ(MG_PLL_BIAS(port));
                hw_state->mg_pll_tdc_coldst_bias =
                        I915_READ(MG_PLL_TDC_COLDST_BIAS(port));
+
+               if (dev_priv->cdclk.hw.ref == 38400) {
+                       hw_state->mg_pll_tdc_coldst_bias_mask = MG_PLL_TDC_COLDST_COLDSTART;
+                       hw_state->mg_pll_bias_mask = 0;
+               } else {
+                       hw_state->mg_pll_tdc_coldst_bias_mask = -1U;
+                       hw_state->mg_pll_bias_mask = -1U;
+               }
+
+               hw_state->mg_pll_tdc_coldst_bias &= hw_state->mg_pll_tdc_coldst_bias_mask;
+               hw_state->mg_pll_bias &= hw_state->mg_pll_bias_mask;
                break;
        default:
                MISSING_CASE(id);
@@ -2978,19 +3010,48 @@ static void icl_mg_pll_write(struct drm_i915_private *dev_priv,
 {
        struct intel_dpll_hw_state *hw_state = &pll->state.hw_state;
        enum port port = icl_mg_pll_id_to_port(pll->info->id);
+       u32 val;
+
+       /*
+        * Some of the following registers have reserved fields, so program
+        * these with RMW based on a mask. The mask can be fixed or generated
+        * during the calc/readout phase if the mask depends on some other HW
+        * state like refclk, see icl_calc_mg_pll_state().
+        */
+       val = I915_READ(MG_REFCLKIN_CTL(port));
+       val &= ~MG_REFCLKIN_CTL_OD_2_MUX_MASK;
+       val |= hw_state->mg_refclkin_ctl;
+       I915_WRITE(MG_REFCLKIN_CTL(port), val);
+
+       val = I915_READ(MG_CLKTOP2_CORECLKCTL1(port));
+       val &= ~MG_CLKTOP2_CORECLKCTL1_A_DIVRATIO_MASK;
+       val |= hw_state->mg_clktop2_coreclkctl1;
+       I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port), val);
+
+       val = I915_READ(MG_CLKTOP2_HSCLKCTL(port));
+       val &= ~(MG_CLKTOP2_HSCLKCTL_TLINEDRV_CLKSEL_MASK |
+                MG_CLKTOP2_HSCLKCTL_CORE_INPUTSEL_MASK |
+                MG_CLKTOP2_HSCLKCTL_HSDIV_RATIO_MASK |
+                MG_CLKTOP2_HSCLKCTL_DSDIV_RATIO_MASK);
+       val |= hw_state->mg_clktop2_hsclkctl;
+       I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), val);
 
-       I915_WRITE(MG_REFCLKIN_CTL(port), hw_state->mg_refclkin_ctl);
-       I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port),
-                  hw_state->mg_clktop2_coreclkctl1);
-       I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), hw_state->mg_clktop2_hsclkctl);
        I915_WRITE(MG_PLL_DIV0(port), hw_state->mg_pll_div0);
        I915_WRITE(MG_PLL_DIV1(port), hw_state->mg_pll_div1);
        I915_WRITE(MG_PLL_LF(port), hw_state->mg_pll_lf);
        I915_WRITE(MG_PLL_FRAC_LOCK(port), hw_state->mg_pll_frac_lock);
        I915_WRITE(MG_PLL_SSC(port), hw_state->mg_pll_ssc);
-       I915_WRITE(MG_PLL_BIAS(port), hw_state->mg_pll_bias);
-       I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port),
-                  hw_state->mg_pll_tdc_coldst_bias);
+
+       val = I915_READ(MG_PLL_BIAS(port));
+       val &= ~hw_state->mg_pll_bias_mask;
+       val |= hw_state->mg_pll_bias;
+       I915_WRITE(MG_PLL_BIAS(port), val);
+
+       val = I915_READ(MG_PLL_TDC_COLDST_BIAS(port));
+       val &= ~hw_state->mg_pll_tdc_coldst_bias_mask;
+       val |= hw_state->mg_pll_tdc_coldst_bias;
+       I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port), val);
+
        POSTING_READ(MG_PLL_TDC_COLDST_BIAS(port));
 }
 
index ba925c7ee4828031f79a08d62df20bc7b073b365..7e522cf4f13f3bb35991a8771cbd3e4755a902cb 100644 (file)
@@ -180,6 +180,8 @@ struct intel_dpll_hw_state {
        uint32_t mg_pll_ssc;
        uint32_t mg_pll_bias;
        uint32_t mg_pll_tdc_coldst_bias;
+       uint32_t mg_pll_bias_mask;
+       uint32_t mg_pll_tdc_coldst_bias_mask;
 };
 
 /**
index 0c3ac0eafde09dbf497e825bf9833da9e9c4131b..61e715ddd0d588f5fdde622b6e9a5575546dbb74 100644 (file)
@@ -254,7 +254,8 @@ struct intel_encoder {
                           struct intel_crtc_state *pipe_config);
        /* Returns a mask of power domains that need to be referenced as part
         * of the hardware state readout code. */
-       u64 (*get_power_domains)(struct intel_encoder *encoder);
+       u64 (*get_power_domains)(struct intel_encoder *encoder,
+                                struct intel_crtc_state *crtc_state);
        /*
         * Called during system suspend after all pending requests for the
         * encoder are flushed (for example for DP AUX transactions) and
@@ -1133,7 +1134,6 @@ struct intel_dp {
         * register with to kick off an AUX transaction.
         */
        uint32_t (*get_aux_send_ctl)(struct intel_dp *dp,
-                                    bool has_aux_irq,
                                     int send_bytes,
                                     uint32_t aux_clock_divider);
 
@@ -1254,6 +1254,7 @@ enc_to_dig_port(struct drm_encoder *encoder)
        switch (intel_encoder->type) {
        case INTEL_OUTPUT_DDI:
                WARN_ON(!HAS_DDI(to_i915(encoder->dev)));
+               /* fall through */
        case INTEL_OUTPUT_DP:
        case INTEL_OUTPUT_EDP:
        case INTEL_OUTPUT_HDMI:
@@ -1730,8 +1731,8 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *intel_connector);
 /* intel_dp_mst.c */
 int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
 void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);
-/* intel_dsi.c */
-void intel_dsi_init(struct drm_i915_private *dev_priv);
+/* vlv_dsi.c */
+void vlv_dsi_init(struct drm_i915_private *dev_priv);
 
 /* intel_dsi_dcs_backlight.c */
 int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
@@ -1921,6 +1922,8 @@ void intel_psr_compute_config(struct intel_dp *intel_dp,
                              struct intel_crtc_state *crtc_state);
 void intel_psr_irq_control(struct drm_i915_private *dev_priv, bool debug);
 void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir);
+void intel_psr_short_pulse(struct intel_dp *intel_dp);
+int intel_psr_wait_for_idle(struct drm_i915_private *dev_priv);
 
 /* intel_runtime_pm.c */
 int intel_power_domains_init(struct drm_i915_private *);
@@ -2151,7 +2154,6 @@ void lspcon_resume(struct intel_lspcon *lspcon);
 void lspcon_wait_pcon_mode(struct intel_lspcon *lspcon);
 
 /* intel_pipe_crc.c */
-int intel_pipe_crc_create(struct drm_minor *minor);
 #ifdef CONFIG_DEBUG_FS
 int intel_crtc_set_crc_source(struct drm_crtc *crtc, const char *source_name,
                              size_t *values_cnt);
@@ -2167,5 +2169,4 @@ static inline void intel_crtc_enable_pipe_crc(struct intel_crtc *crtc)
 {
 }
 #endif
-extern const struct file_operations i915_display_crc_ctl_fops;
 #endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
deleted file mode 100644 (file)
index 3b7acb5..0000000
+++ /dev/null
@@ -1,1866 +0,0 @@
-/*
- * Copyright © 2013 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.
- *
- * Author: Jani Nikula <jani.nikula@intel.com>
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
-#include <drm/i915_drm.h>
-#include <drm/drm_mipi_dsi.h>
-#include <linux/slab.h>
-#include <linux/gpio/consumer.h>
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-
-/* return pixels in terms of txbyteclkhs */
-static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
-                      u16 burst_mode_ratio)
-{
-       return DIV_ROUND_UP(DIV_ROUND_UP(pixels * bpp * burst_mode_ratio,
-                                        8 * 100), lane_count);
-}
-
-/* return pixels equvalent to txbyteclkhs */
-static u16 pixels_from_txbyteclkhs(u16 clk_hs, int bpp, int lane_count,
-                       u16 burst_mode_ratio)
-{
-       return DIV_ROUND_UP((clk_hs * lane_count * 8 * 100),
-                                               (bpp * burst_mode_ratio));
-}
-
-enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt)
-{
-       /* It just so happens the VBT matches register contents. */
-       switch (fmt) {
-       case VID_MODE_FORMAT_RGB888:
-               return MIPI_DSI_FMT_RGB888;
-       case VID_MODE_FORMAT_RGB666:
-               return MIPI_DSI_FMT_RGB666;
-       case VID_MODE_FORMAT_RGB666_PACKED:
-               return MIPI_DSI_FMT_RGB666_PACKED;
-       case VID_MODE_FORMAT_RGB565:
-               return MIPI_DSI_FMT_RGB565;
-       default:
-               MISSING_CASE(fmt);
-               return MIPI_DSI_FMT_RGB666;
-       }
-}
-
-void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
-{
-       struct drm_encoder *encoder = &intel_dsi->base.base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 mask;
-
-       mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
-               LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
-
-       if (intel_wait_for_register(dev_priv,
-                                   MIPI_GEN_FIFO_STAT(port), mask, mask,
-                                   100))
-               DRM_ERROR("DPI FIFOs are not empty\n");
-}
-
-static void write_data(struct drm_i915_private *dev_priv,
-                      i915_reg_t reg,
-                      const u8 *data, u32 len)
-{
-       u32 i, j;
-
-       for (i = 0; i < len; i += 4) {
-               u32 val = 0;
-
-               for (j = 0; j < min_t(u32, len - i, 4); j++)
-                       val |= *data++ << 8 * j;
-
-               I915_WRITE(reg, val);
-       }
-}
-
-static void read_data(struct drm_i915_private *dev_priv,
-                     i915_reg_t reg,
-                     u8 *data, u32 len)
-{
-       u32 i, j;
-
-       for (i = 0; i < len; i += 4) {
-               u32 val = I915_READ(reg);
-
-               for (j = 0; j < min_t(u32, len - i, 4); j++)
-                       *data++ = val >> 8 * j;
-       }
-}
-
-static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host,
-                                      const struct mipi_dsi_msg *msg)
-{
-       struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
-       struct drm_device *dev = intel_dsi_host->intel_dsi->base.base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       enum port port = intel_dsi_host->port;
-       struct mipi_dsi_packet packet;
-       ssize_t ret;
-       const u8 *header, *data;
-       i915_reg_t data_reg, ctrl_reg;
-       u32 data_mask, ctrl_mask;
-
-       ret = mipi_dsi_create_packet(&packet, msg);
-       if (ret < 0)
-               return ret;
-
-       header = packet.header;
-       data = packet.payload;
-
-       if (msg->flags & MIPI_DSI_MSG_USE_LPM) {
-               data_reg = MIPI_LP_GEN_DATA(port);
-               data_mask = LP_DATA_FIFO_FULL;
-               ctrl_reg = MIPI_LP_GEN_CTRL(port);
-               ctrl_mask = LP_CTRL_FIFO_FULL;
-       } else {
-               data_reg = MIPI_HS_GEN_DATA(port);
-               data_mask = HS_DATA_FIFO_FULL;
-               ctrl_reg = MIPI_HS_GEN_CTRL(port);
-               ctrl_mask = HS_CTRL_FIFO_FULL;
-       }
-
-       /* note: this is never true for reads */
-       if (packet.payload_length) {
-               if (intel_wait_for_register(dev_priv,
-                                           MIPI_GEN_FIFO_STAT(port),
-                                           data_mask, 0,
-                                           50))
-                       DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
-
-               write_data(dev_priv, data_reg, packet.payload,
-                          packet.payload_length);
-       }
-
-       if (msg->rx_len) {
-               I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
-       }
-
-       if (intel_wait_for_register(dev_priv,
-                                   MIPI_GEN_FIFO_STAT(port),
-                                   ctrl_mask, 0,
-                                   50)) {
-               DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
-       }
-
-       I915_WRITE(ctrl_reg, header[2] << 16 | header[1] << 8 | header[0]);
-
-       /* ->rx_len is set only for reads */
-       if (msg->rx_len) {
-               data_mask = GEN_READ_DATA_AVAIL;
-               if (intel_wait_for_register(dev_priv,
-                                           MIPI_INTR_STAT(port),
-                                           data_mask, data_mask,
-                                           50))
-                       DRM_ERROR("Timeout waiting for read data.\n");
-
-               read_data(dev_priv, data_reg, msg->rx_buf, msg->rx_len);
-       }
-
-       /* XXX: fix for reads and writes */
-       return 4 + packet.payload_length;
-}
-
-static int intel_dsi_host_attach(struct mipi_dsi_host *host,
-                                struct mipi_dsi_device *dsi)
-{
-       return 0;
-}
-
-static int intel_dsi_host_detach(struct mipi_dsi_host *host,
-                                struct mipi_dsi_device *dsi)
-{
-       return 0;
-}
-
-static const struct mipi_dsi_host_ops intel_dsi_host_ops = {
-       .attach = intel_dsi_host_attach,
-       .detach = intel_dsi_host_detach,
-       .transfer = intel_dsi_host_transfer,
-};
-
-static struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
-                                                 enum port port)
-{
-       struct intel_dsi_host *host;
-       struct mipi_dsi_device *device;
-
-       host = kzalloc(sizeof(*host), GFP_KERNEL);
-       if (!host)
-               return NULL;
-
-       host->base.ops = &intel_dsi_host_ops;
-       host->intel_dsi = intel_dsi;
-       host->port = port;
-
-       /*
-        * We should call mipi_dsi_host_register(&host->base) here, but we don't
-        * have a host->dev, and we don't have OF stuff either. So just use the
-        * dsi framework as a library and hope for the best. Create the dsi
-        * devices by ourselves here too. Need to be careful though, because we
-        * don't initialize any of the driver model devices here.
-        */
-       device = kzalloc(sizeof(*device), GFP_KERNEL);
-       if (!device) {
-               kfree(host);
-               return NULL;
-       }
-
-       device->host = &host->base;
-       host->device = device;
-
-       return host;
-}
-
-/*
- * send a video mode command
- *
- * XXX: commands with data in MIPI_DPI_DATA?
- */
-static int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs,
-                       enum port port)
-{
-       struct drm_encoder *encoder = &intel_dsi->base.base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 mask;
-
-       /* XXX: pipe, hs */
-       if (hs)
-               cmd &= ~DPI_LP_MODE;
-       else
-               cmd |= DPI_LP_MODE;
-
-       /* clear bit */
-       I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT);
-
-       /* XXX: old code skips write if control unchanged */
-       if (cmd == I915_READ(MIPI_DPI_CONTROL(port)))
-               DRM_DEBUG_KMS("Same special packet %02x twice in a row.\n", cmd);
-
-       I915_WRITE(MIPI_DPI_CONTROL(port), cmd);
-
-       mask = SPL_PKT_SENT_INTERRUPT;
-       if (intel_wait_for_register(dev_priv,
-                                   MIPI_INTR_STAT(port), mask, mask,
-                                   100))
-               DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
-
-       return 0;
-}
-
-static void band_gap_reset(struct drm_i915_private *dev_priv)
-{
-       mutex_lock(&dev_priv->sb_lock);
-
-       vlv_flisdsi_write(dev_priv, 0x08, 0x0001);
-       vlv_flisdsi_write(dev_priv, 0x0F, 0x0005);
-       vlv_flisdsi_write(dev_priv, 0x0F, 0x0025);
-       udelay(150);
-       vlv_flisdsi_write(dev_priv, 0x0F, 0x0000);
-       vlv_flisdsi_write(dev_priv, 0x08, 0x0000);
-
-       mutex_unlock(&dev_priv->sb_lock);
-}
-
-static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
-{
-       return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
-}
-
-static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
-{
-       return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE;
-}
-
-static bool intel_dsi_compute_config(struct intel_encoder *encoder,
-                                    struct intel_crtc_state *pipe_config,
-                                    struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
-                                                  base);
-       struct intel_connector *intel_connector = intel_dsi->attached_connector;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       int ret;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (fixed_mode) {
-               intel_fixed_panel_mode(fixed_mode, adjusted_mode);
-
-               if (HAS_GMCH_DISPLAY(dev_priv))
-                       intel_gmch_panel_fitting(crtc, pipe_config,
-                                                conn_state->scaling_mode);
-               else
-                       intel_pch_panel_fitting(crtc, pipe_config,
-                                               conn_state->scaling_mode);
-       }
-
-       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return false;
-
-       /* DSI uses short packets for sync events, so clear mode flags for DSI */
-       adjusted_mode->flags = 0;
-
-       if (IS_GEN9_LP(dev_priv)) {
-               /* Enable Frame time stamp based scanline reporting */
-               adjusted_mode->private_flags |=
-                       I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP;
-
-               /* Dual link goes to DSI transcoder A. */
-               if (intel_dsi->ports == BIT(PORT_C))
-                       pipe_config->cpu_transcoder = TRANSCODER_DSI_C;
-               else
-                       pipe_config->cpu_transcoder = TRANSCODER_DSI_A;
-       }
-
-       ret = intel_compute_dsi_pll(encoder, pipe_config);
-       if (ret)
-               return false;
-
-       pipe_config->clock_set = true;
-
-       return true;
-}
-
-static bool glk_dsi_enable_io(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-       bool cold_boot = false;
-
-       /* Set the MIPI mode
-        * If MIPI_Mode is off, then writing to LP_Wake bit is not reflecting.
-        * Power ON MIPI IO first and then write into IO reset and LP wake bits
-        */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(MIPI_CTRL(port));
-               I915_WRITE(MIPI_CTRL(port), tmp | GLK_MIPIIO_ENABLE);
-       }
-
-       /* Put the IO into reset */
-       tmp = I915_READ(MIPI_CTRL(PORT_A));
-       tmp &= ~GLK_MIPIIO_RESET_RELEASED;
-       I915_WRITE(MIPI_CTRL(PORT_A), tmp);
-
-       /* Program LP Wake */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(MIPI_CTRL(port));
-               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY))
-                       tmp &= ~GLK_LP_WAKE;
-               else
-                       tmp |= GLK_LP_WAKE;
-               I915_WRITE(MIPI_CTRL(port), tmp);
-       }
-
-       /* Wait for Pwr ACK */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                               MIPI_CTRL(port), GLK_MIPIIO_PORT_POWERED,
-                               GLK_MIPIIO_PORT_POWERED, 20))
-                       DRM_ERROR("MIPIO port is powergated\n");
-       }
-
-       /* Check for cold boot scenario */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               cold_boot |= !(I915_READ(MIPI_DEVICE_READY(port)) &
-                                                       DEVICE_READY);
-       }
-
-       return cold_boot;
-}
-
-static void glk_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       /* Wait for MIPI PHY status bit to set */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                               MIPI_CTRL(port), GLK_PHY_STATUS_PORT_READY,
-                               GLK_PHY_STATUS_PORT_READY, 20))
-                       DRM_ERROR("PHY is not ON\n");
-       }
-
-       /* Get IO out of reset */
-       val = I915_READ(MIPI_CTRL(PORT_A));
-       I915_WRITE(MIPI_CTRL(PORT_A), val | GLK_MIPIIO_RESET_RELEASED);
-
-       /* Get IO out of Low power state*/
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY)) {
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= DEVICE_READY;
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-                       usleep_range(10, 15);
-               } else {
-                       /* Enter ULPS */
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= (ULPS_STATE_ENTER | DEVICE_READY);
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-
-                       /* Wait for ULPS active */
-                       if (intel_wait_for_register(dev_priv,
-                               MIPI_CTRL(port), GLK_ULPS_NOT_ACTIVE, 0, 20))
-                               DRM_ERROR("ULPS not active\n");
-
-                       /* Exit ULPS */
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= (ULPS_STATE_EXIT | DEVICE_READY);
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-
-                       /* Enter Normal Mode */
-                       val = I915_READ(MIPI_DEVICE_READY(port));
-                       val &= ~ULPS_STATE_MASK;
-                       val |= (ULPS_STATE_NORMAL_OPERATION | DEVICE_READY);
-                       I915_WRITE(MIPI_DEVICE_READY(port), val);
-
-                       val = I915_READ(MIPI_CTRL(port));
-                       val &= ~GLK_LP_WAKE;
-                       I915_WRITE(MIPI_CTRL(port), val);
-               }
-       }
-
-       /* Wait for Stop state */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                               MIPI_CTRL(port), GLK_DATA_LANE_STOP_STATE,
-                               GLK_DATA_LANE_STOP_STATE, 20))
-                       DRM_ERROR("Date lane not in STOP state\n");
-       }
-
-       /* Wait for AFE LATCH */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                               BXT_MIPI_PORT_CTRL(port), AFE_LATCHOUT,
-                               AFE_LATCHOUT, 20))
-                       DRM_ERROR("D-PHY not entering LP-11 state\n");
-       }
-}
-
-static void bxt_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* Enable MIPI PHY transparent latch */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val = I915_READ(BXT_MIPI_PORT_CTRL(port));
-               I915_WRITE(BXT_MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD);
-               usleep_range(2000, 2500);
-       }
-
-       /* Clear ULPS and set device ready */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val = I915_READ(MIPI_DEVICE_READY(port));
-               val &= ~ULPS_STATE_MASK;
-               I915_WRITE(MIPI_DEVICE_READY(port), val);
-               usleep_range(2000, 2500);
-               val |= DEVICE_READY;
-               I915_WRITE(MIPI_DEVICE_READY(port), val);
-       }
-}
-
-static void vlv_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       mutex_lock(&dev_priv->sb_lock);
-       /* program rcomp for compliance, reduce from 50 ohms to 45 ohms
-        * needed everytime after power gate */
-       vlv_flisdsi_write(dev_priv, 0x04, 0x0004);
-       mutex_unlock(&dev_priv->sb_lock);
-
-       /* bandgap reset is needed after everytime we do power gate */
-       band_gap_reset(dev_priv);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-
-               I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER);
-               usleep_range(2500, 3000);
-
-               /* Enable MIPI PHY transparent latch
-                * Common bit for both MIPI Port A & MIPI Port C
-                * No similar bit in MIPI Port C reg
-                */
-               val = I915_READ(MIPI_PORT_CTRL(PORT_A));
-               I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD);
-               usleep_range(1000, 1500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT);
-               usleep_range(2500, 3000);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY);
-               usleep_range(2500, 3000);
-       }
-}
-
-static void intel_dsi_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-               vlv_dsi_device_ready(encoder);
-       else if (IS_BROXTON(dev_priv))
-               bxt_dsi_device_ready(encoder);
-       else if (IS_GEMINILAKE(dev_priv))
-               glk_dsi_device_ready(encoder);
-}
-
-static void glk_dsi_enter_low_power_mode(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       /* Enter ULPS */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               val = I915_READ(MIPI_DEVICE_READY(port));
-               val &= ~ULPS_STATE_MASK;
-               val |= (ULPS_STATE_ENTER | DEVICE_READY);
-               I915_WRITE(MIPI_DEVICE_READY(port), val);
-       }
-
-       /* Wait for MIPI PHY status bit to unset */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                                           MIPI_CTRL(port),
-                                           GLK_PHY_STATUS_PORT_READY, 0, 20))
-                       DRM_ERROR("PHY is not turning OFF\n");
-       }
-
-       /* Wait for Pwr ACK bit to unset */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                                           MIPI_CTRL(port),
-                                           GLK_MIPIIO_PORT_POWERED, 0, 20))
-                       DRM_ERROR("MIPI IO Port is not powergated\n");
-       }
-}
-
-static void glk_dsi_disable_mipi_io(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 tmp;
-
-       /* Put the IO into reset */
-       tmp = I915_READ(MIPI_CTRL(PORT_A));
-       tmp &= ~GLK_MIPIIO_RESET_RELEASED;
-       I915_WRITE(MIPI_CTRL(PORT_A), tmp);
-
-       /* Wait for MIPI PHY status bit to unset */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (intel_wait_for_register(dev_priv,
-                                           MIPI_CTRL(port),
-                                           GLK_PHY_STATUS_PORT_READY, 0, 20))
-                       DRM_ERROR("PHY is not turning OFF\n");
-       }
-
-       /* Clear MIPI mode */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               tmp = I915_READ(MIPI_CTRL(port));
-               tmp &= ~GLK_MIPIIO_ENABLE;
-               I915_WRITE(MIPI_CTRL(port), tmp);
-       }
-}
-
-static void glk_dsi_clear_device_ready(struct intel_encoder *encoder)
-{
-       glk_dsi_enter_low_power_mode(encoder);
-       glk_dsi_disable_mipi_io(encoder);
-}
-
-static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-       for_each_dsi_port(port, intel_dsi->ports) {
-               /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */
-               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A);
-               u32 val;
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
-                                                       ULPS_STATE_ENTER);
-               usleep_range(2000, 2500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
-                                                       ULPS_STATE_EXIT);
-               usleep_range(2000, 2500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
-                                                       ULPS_STATE_ENTER);
-               usleep_range(2000, 2500);
-
-               /*
-                * On VLV/CHV, wait till Clock lanes are in LP-00 state for MIPI
-                * Port A only. MIPI Port C has no similar bit for checking.
-                */
-               if ((IS_GEN9_LP(dev_priv) || port == PORT_A) &&
-                   intel_wait_for_register(dev_priv,
-                                           port_ctrl, AFE_LATCHOUT, 0,
-                                           30))
-                       DRM_ERROR("DSI LP not going Low\n");
-
-               /* Disable MIPI PHY transparent latch */
-               val = I915_READ(port_ctrl);
-               I915_WRITE(port_ctrl, val & ~LP_OUTPUT_HOLD);
-               usleep_range(1000, 1500);
-
-               I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
-               usleep_range(2000, 2500);
-       }
-}
-
-static void intel_dsi_port_enable(struct intel_encoder *encoder,
-                                 const struct intel_crtc_state *crtc_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
-               u32 temp;
-               if (IS_GEN9_LP(dev_priv)) {
-                       for_each_dsi_port(port, intel_dsi->ports) {
-                               temp = I915_READ(MIPI_CTRL(port));
-                               temp &= ~BXT_PIXEL_OVERLAP_CNT_MASK |
-                                       intel_dsi->pixel_overlap <<
-                                       BXT_PIXEL_OVERLAP_CNT_SHIFT;
-                               I915_WRITE(MIPI_CTRL(port), temp);
-                       }
-               } else {
-                       temp = I915_READ(VLV_CHICKEN_3);
-                       temp &= ~PIXEL_OVERLAP_CNT_MASK |
-                                       intel_dsi->pixel_overlap <<
-                                       PIXEL_OVERLAP_CNT_SHIFT;
-                       I915_WRITE(VLV_CHICKEN_3, temp);
-               }
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
-               u32 temp;
-
-               temp = I915_READ(port_ctrl);
-
-               temp &= ~LANE_CONFIGURATION_MASK;
-               temp &= ~DUAL_LINK_MODE_MASK;
-
-               if (intel_dsi->ports == (BIT(PORT_A) | BIT(PORT_C))) {
-                       temp |= (intel_dsi->dual_link - 1)
-                                               << DUAL_LINK_MODE_SHIFT;
-                       if (IS_BROXTON(dev_priv))
-                               temp |= LANE_CONFIGURATION_DUAL_LINK_A;
-                       else
-                               temp |= crtc->pipe ?
-                                       LANE_CONFIGURATION_DUAL_LINK_B :
-                                       LANE_CONFIGURATION_DUAL_LINK_A;
-               }
-               /* assert ip_tg_enable signal */
-               I915_WRITE(port_ctrl, temp | DPI_ENABLE);
-               POSTING_READ(port_ctrl);
-       }
-}
-
-static void intel_dsi_port_disable(struct intel_encoder *encoder)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               i915_reg_t port_ctrl = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
-               u32 temp;
-
-               /* de-assert ip_tg_enable signal */
-               temp = I915_READ(port_ctrl);
-               I915_WRITE(port_ctrl, temp & ~DPI_ENABLE);
-               POSTING_READ(port_ctrl);
-       }
-}
-
-static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
-                             const struct intel_crtc_state *pipe_config);
-static void intel_dsi_unprepare(struct intel_encoder *encoder);
-
-static void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec)
-{
-       struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
-
-       /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */
-       if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3)
-               return;
-
-       msleep(msec);
-}
-
-/*
- * Panel enable/disable sequences from the VBT spec.
- *
- * Note the spec has AssertReset / DeassertReset swapped from their
- * usual naming. We use the normal names to avoid confusion (so below
- * they are swapped compared to the spec).
- *
- * Steps starting with MIPI refer to VBT sequences, note that for v2
- * VBTs several steps which have a VBT in v2 are expected to be handled
- * directly by the driver, by directly driving gpios for example.
- *
- * v2 video mode seq         v3 video mode seq         command mode seq
- * - power on                - MIPIPanelPowerOn        - power on
- * - wait t1+t2                                        - wait t1+t2
- * - MIPIDeassertResetPin    - MIPIDeassertResetPin    - MIPIDeassertResetPin
- * - io lines to lp-11       - io lines to lp-11       - io lines to lp-11
- * - MIPISendInitialDcsCmds  - MIPISendInitialDcsCmds  - MIPISendInitialDcsCmds
- *                                                     - MIPITearOn
- *                                                     - MIPIDisplayOn
- * - turn on DPI             - turn on DPI             - set pipe to dsr mode
- * - MIPIDisplayOn           - MIPIDisplayOn
- * - wait t5                                           - wait t5
- * - backlight on            - MIPIBacklightOn         - backlight on
- * ...                       ...                       ... issue mem cmds ...
- * - backlight off           - MIPIBacklightOff        - backlight off
- * - wait t6                                           - wait t6
- * - MIPIDisplayOff
- * - turn off DPI            - turn off DPI            - disable pipe dsr mode
- *                                                     - MIPITearOff
- *                           - MIPIDisplayOff          - MIPIDisplayOff
- * - io lines to lp-00       - io lines to lp-00       - io lines to lp-00
- * - MIPIAssertResetPin      - MIPIAssertResetPin      - MIPIAssertResetPin
- * - wait t3                                           - wait t3
- * - power off               - MIPIPanelPowerOff       - power off
- * - wait t4                                           - wait t4
- */
-
-static void intel_dsi_pre_enable(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config,
-                                const struct drm_connector_state *conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct drm_crtc *crtc = pipe_config->base.crtc;
-       struct drm_i915_private *dev_priv = to_i915(crtc->dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       enum port port;
-       u32 val;
-       bool glk_cold_boot = false;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
-
-       /*
-        * The BIOS may leave the PLL in a wonky state where it doesn't
-        * lock. It needs to be fully powered down to fix it.
-        */
-       intel_disable_dsi_pll(encoder);
-       intel_enable_dsi_pll(encoder, pipe_config);
-
-       if (IS_BROXTON(dev_priv)) {
-               /* Add MIPI IO reset programming for modeset */
-               val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
-               I915_WRITE(BXT_P_CR_GT_DISP_PWRON,
-                                       val | MIPIO_RST_CTRL);
-
-               /* Power up DSI regulator */
-               I915_WRITE(BXT_P_DSI_REGULATOR_CFG, STAP_SELECT);
-               I915_WRITE(BXT_P_DSI_REGULATOR_TX_CTRL, 0);
-       }
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               u32 val;
-
-               /* Disable DPOunit clock gating, can stall pipe */
-               val = I915_READ(DSPCLK_GATE_D);
-               val |= DPOUNIT_CLOCK_GATE_DISABLE;
-               I915_WRITE(DSPCLK_GATE_D, val);
-       }
-
-       if (!IS_GEMINILAKE(dev_priv))
-               intel_dsi_prepare(encoder, pipe_config);
-
-       /* Power on, try both CRC pmic gpio and VBT */
-       if (intel_dsi->gpio_panel)
-               gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_ON);
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay);
-
-       /* Deassert reset */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET);
-
-       if (IS_GEMINILAKE(dev_priv)) {
-               glk_cold_boot = glk_dsi_enable_io(encoder);
-
-               /* Prepare port in cold boot(s3/s4) scenario */
-               if (glk_cold_boot)
-                       intel_dsi_prepare(encoder, pipe_config);
-       }
-
-       /* Put device in ready state (LP-11) */
-       intel_dsi_device_ready(encoder);
-
-       /* Prepare port in normal boot scenario */
-       if (IS_GEMINILAKE(dev_priv) && !glk_cold_boot)
-               intel_dsi_prepare(encoder, pipe_config);
-
-       /* Send initialization commands in LP mode */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP);
-
-       /* Enable port in pre-enable phase itself because as per hw team
-        * recommendation, port should be enabled befor plane & pipe */
-       if (is_cmd_mode(intel_dsi)) {
-               for_each_dsi_port(port, intel_dsi->ports)
-                       I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_TEAR_ON);
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
-       } else {
-               msleep(20); /* XXX */
-               for_each_dsi_port(port, intel_dsi->ports)
-                       dpi_send_cmd(intel_dsi, TURN_ON, false, port);
-               intel_dsi_msleep(intel_dsi, 100);
-
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON);
-
-               intel_dsi_port_enable(encoder, pipe_config);
-       }
-
-       intel_panel_enable_backlight(pipe_config, conn_state);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON);
-}
-
-/*
- * DSI port enable has to be done before pipe and plane enable, so we do it in
- * the pre_enable hook.
- */
-static void intel_dsi_enable_nop(struct intel_encoder *encoder,
-                                const struct intel_crtc_state *pipe_config,
-                                const struct drm_connector_state *conn_state)
-{
-       DRM_DEBUG_KMS("\n");
-}
-
-/*
- * DSI port disable has to be done after pipe and plane disable, so we do it in
- * the post_disable hook.
- */
-static void intel_dsi_disable(struct intel_encoder *encoder,
-                             const struct intel_crtc_state *old_crtc_state,
-                             const struct drm_connector_state *old_conn_state)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_OFF);
-       intel_panel_disable_backlight(old_conn_state);
-
-       /*
-        * According to the spec we should send SHUTDOWN before
-        * MIPI_SEQ_DISPLAY_OFF only for v3+ VBTs, but field testing
-        * has shown that the v3 sequence works for v2 VBTs too
-        */
-       if (is_vid_mode(intel_dsi)) {
-               /* Send Shutdown command to the panel in LP mode */
-               for_each_dsi_port(port, intel_dsi->ports)
-                       dpi_send_cmd(intel_dsi, SHUTDOWN, false, port);
-               msleep(10);
-       }
-}
-
-static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv) ||
-           IS_BROXTON(dev_priv))
-               vlv_dsi_clear_device_ready(encoder);
-       else if (IS_GEMINILAKE(dev_priv))
-               glk_dsi_clear_device_ready(encoder);
-}
-
-static void intel_dsi_post_disable(struct intel_encoder *encoder,
-                                  const struct intel_crtc_state *pipe_config,
-                                  const struct drm_connector_state *conn_state)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (is_vid_mode(intel_dsi)) {
-               for_each_dsi_port(port, intel_dsi->ports)
-                       wait_for_dsi_fifo_empty(intel_dsi, port);
-
-               intel_dsi_port_disable(encoder);
-               usleep_range(2000, 5000);
-       }
-
-       intel_dsi_unprepare(encoder);
-
-       /*
-        * if disable packets are sent before sending shutdown packet then in
-        * some next enable sequence send turn on packet error is observed
-        */
-       if (is_cmd_mode(intel_dsi))
-               intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_TEAR_OFF);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_OFF);
-
-       /* Transition to LP-00 */
-       intel_dsi_clear_device_ready(encoder);
-
-       if (IS_BROXTON(dev_priv)) {
-               /* Power down DSI regulator to save power */
-               I915_WRITE(BXT_P_DSI_REGULATOR_CFG, STAP_SELECT);
-               I915_WRITE(BXT_P_DSI_REGULATOR_TX_CTRL, HS_IO_CTRL_SELECT);
-
-               /* Add MIPI IO reset programming for modeset */
-               val = I915_READ(BXT_P_CR_GT_DISP_PWRON);
-               I915_WRITE(BXT_P_CR_GT_DISP_PWRON,
-                               val & ~MIPIO_RST_CTRL);
-       }
-
-       intel_disable_dsi_pll(encoder);
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               u32 val;
-
-               val = I915_READ(DSPCLK_GATE_D);
-               val &= ~DPOUNIT_CLOCK_GATE_DISABLE;
-               I915_WRITE(DSPCLK_GATE_D, val);
-       }
-
-       /* Assert reset */
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_ASSERT_RESET);
-
-       /* Power off, try both CRC pmic gpio and VBT */
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_off_delay);
-       intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_POWER_OFF);
-       if (intel_dsi->gpio_panel)
-               gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0);
-
-       /*
-        * FIXME As we do with eDP, just make a note of the time here
-        * and perform the wait before the next panel power on.
-        */
-       intel_dsi_msleep(intel_dsi, intel_dsi->panel_pwr_cycle_delay);
-}
-
-static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
-                                  enum pipe *pipe)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       bool active = false;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (!intel_display_power_get_if_enabled(dev_priv,
-                                               encoder->power_domain))
-               return false;
-
-       /*
-        * On Broxton the PLL needs to be enabled with a valid divider
-        * configuration, otherwise accessing DSI registers will hang the
-        * machine. See BSpec North Display Engine registers/MIPI[BXT].
-        */
-       if (IS_GEN9_LP(dev_priv) && !intel_dsi_pll_is_enabled(dev_priv))
-               goto out_put_power;
-
-       /* XXX: this only works for one DSI output */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               i915_reg_t ctrl_reg = IS_GEN9_LP(dev_priv) ?
-                       BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port);
-               bool enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
-
-               /*
-                * Due to some hardware limitations on VLV/CHV, the DPI enable
-                * bit in port C control register does not get set. As a
-                * workaround, check pipe B conf instead.
-                */
-               if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-                   port == PORT_C)
-                       enabled = I915_READ(PIPECONF(PIPE_B)) & PIPECONF_ENABLE;
-
-               /* Try command mode if video mode not enabled */
-               if (!enabled) {
-                       u32 tmp = I915_READ(MIPI_DSI_FUNC_PRG(port));
-                       enabled = tmp & CMD_MODE_DATA_WIDTH_MASK;
-               }
-
-               if (!enabled)
-                       continue;
-
-               if (!(I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY))
-                       continue;
-
-               if (IS_GEN9_LP(dev_priv)) {
-                       u32 tmp = I915_READ(MIPI_CTRL(port));
-                       tmp &= BXT_PIPE_SELECT_MASK;
-                       tmp >>= BXT_PIPE_SELECT_SHIFT;
-
-                       if (WARN_ON(tmp > PIPE_C))
-                               continue;
-
-                       *pipe = tmp;
-               } else {
-                       *pipe = port == PORT_A ? PIPE_A : PIPE_B;
-               }
-
-               active = true;
-               break;
-       }
-
-out_put_power:
-       intel_display_power_put(dev_priv, encoder->power_domain);
-
-       return active;
-}
-
-static void bxt_dsi_get_pipe_config(struct intel_encoder *encoder,
-                                   struct intel_crtc_state *pipe_config)
-{
-       struct drm_device *dev = encoder->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_display_mode *adjusted_mode =
-                                       &pipe_config->base.adjusted_mode;
-       struct drm_display_mode *adjusted_mode_sw;
-       struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       unsigned int lane_count = intel_dsi->lane_count;
-       unsigned int bpp, fmt;
-       enum port port;
-       u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
-       u16 hfp_sw, hsync_sw, hbp_sw;
-       u16 crtc_htotal_sw, crtc_hsync_start_sw, crtc_hsync_end_sw,
-                               crtc_hblank_start_sw, crtc_hblank_end_sw;
-
-       /* FIXME: hw readout should not depend on SW state */
-       adjusted_mode_sw = &crtc->config->base.adjusted_mode;
-
-       /*
-        * Atleast one port is active as encoder->get_config called only if
-        * encoder->get_hw_state() returns true.
-        */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (I915_READ(BXT_MIPI_PORT_CTRL(port)) & DPI_ENABLE)
-                       break;
-       }
-
-       fmt = I915_READ(MIPI_DSI_FUNC_PRG(port)) & VID_MODE_FORMAT_MASK;
-       pipe_config->pipe_bpp =
-                       mipi_dsi_pixel_format_to_bpp(
-                               pixel_format_from_register_bits(fmt));
-       bpp = pipe_config->pipe_bpp;
-
-       /* Enable Frame time stamo based scanline reporting */
-       adjusted_mode->private_flags |=
-                       I915_MODE_FLAG_GET_SCANLINE_FROM_TIMESTAMP;
-
-       /* In terms of pixels */
-       adjusted_mode->crtc_hdisplay =
-                               I915_READ(BXT_MIPI_TRANS_HACTIVE(port));
-       adjusted_mode->crtc_vdisplay =
-                               I915_READ(BXT_MIPI_TRANS_VACTIVE(port));
-       adjusted_mode->crtc_vtotal =
-                               I915_READ(BXT_MIPI_TRANS_VTOTAL(port));
-
-       hactive = adjusted_mode->crtc_hdisplay;
-       hfp = I915_READ(MIPI_HFP_COUNT(port));
-
-       /*
-        * Meaningful for video mode non-burst sync pulse mode only,
-        * can be zero for non-burst sync events and burst modes
-        */
-       hsync = I915_READ(MIPI_HSYNC_PADDING_COUNT(port));
-       hbp = I915_READ(MIPI_HBP_COUNT(port));
-
-       /* harizontal values are in terms of high speed byte clock */
-       hfp = pixels_from_txbyteclkhs(hfp, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hsync = pixels_from_txbyteclkhs(hsync, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hbp = pixels_from_txbyteclkhs(hbp, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-
-       if (intel_dsi->dual_link) {
-               hfp *= 2;
-               hsync *= 2;
-               hbp *= 2;
-       }
-
-       /* vertical values are in terms of lines */
-       vfp = I915_READ(MIPI_VFP_COUNT(port));
-       vsync = I915_READ(MIPI_VSYNC_PADDING_COUNT(port));
-       vbp = I915_READ(MIPI_VBP_COUNT(port));
-
-       adjusted_mode->crtc_htotal = hactive + hfp + hsync + hbp;
-       adjusted_mode->crtc_hsync_start = hfp + adjusted_mode->crtc_hdisplay;
-       adjusted_mode->crtc_hsync_end = hsync + adjusted_mode->crtc_hsync_start;
-       adjusted_mode->crtc_hblank_start = adjusted_mode->crtc_hdisplay;
-       adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal;
-
-       adjusted_mode->crtc_vsync_start = vfp + adjusted_mode->crtc_vdisplay;
-       adjusted_mode->crtc_vsync_end = vsync + adjusted_mode->crtc_vsync_start;
-       adjusted_mode->crtc_vblank_start = adjusted_mode->crtc_vdisplay;
-       adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal;
-
-       /*
-        * In BXT DSI there is no regs programmed with few horizontal timings
-        * in Pixels but txbyteclkhs.. So retrieval process adds some
-        * ROUND_UP ERRORS in the process of PIXELS<==>txbyteclkhs.
-        * Actually here for the given adjusted_mode, we are calculating the
-        * value programmed to the port and then back to the horizontal timing
-        * param in pixels. This is the expected value, including roundup errors
-        * And if that is same as retrieved value from port, then
-        * (HW state) adjusted_mode's horizontal timings are corrected to
-        * match with SW state to nullify the errors.
-        */
-       /* Calculating the value programmed to the Port register */
-       hfp_sw = adjusted_mode_sw->crtc_hsync_start -
-                                       adjusted_mode_sw->crtc_hdisplay;
-       hsync_sw = adjusted_mode_sw->crtc_hsync_end -
-                                       adjusted_mode_sw->crtc_hsync_start;
-       hbp_sw = adjusted_mode_sw->crtc_htotal -
-                                       adjusted_mode_sw->crtc_hsync_end;
-
-       if (intel_dsi->dual_link) {
-               hfp_sw /= 2;
-               hsync_sw /= 2;
-               hbp_sw /= 2;
-       }
-
-       hfp_sw = txbyteclkhs(hfp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hsync_sw = txbyteclkhs(hsync_sw, bpp, lane_count,
-                           intel_dsi->burst_mode_ratio);
-       hbp_sw = txbyteclkhs(hbp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-
-       /* Reverse calculating the adjusted mode parameters from port reg vals*/
-       hfp_sw = pixels_from_txbyteclkhs(hfp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hsync_sw = pixels_from_txbyteclkhs(hsync_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-       hbp_sw = pixels_from_txbyteclkhs(hbp_sw, bpp, lane_count,
-                                               intel_dsi->burst_mode_ratio);
-
-       if (intel_dsi->dual_link) {
-               hfp_sw *= 2;
-               hsync_sw *= 2;
-               hbp_sw *= 2;
-       }
-
-       crtc_htotal_sw = adjusted_mode_sw->crtc_hdisplay + hfp_sw +
-                                                       hsync_sw + hbp_sw;
-       crtc_hsync_start_sw = hfp_sw + adjusted_mode_sw->crtc_hdisplay;
-       crtc_hsync_end_sw = hsync_sw + crtc_hsync_start_sw;
-       crtc_hblank_start_sw = adjusted_mode_sw->crtc_hdisplay;
-       crtc_hblank_end_sw = crtc_htotal_sw;
-
-       if (adjusted_mode->crtc_htotal == crtc_htotal_sw)
-               adjusted_mode->crtc_htotal = adjusted_mode_sw->crtc_htotal;
-
-       if (adjusted_mode->crtc_hsync_start == crtc_hsync_start_sw)
-               adjusted_mode->crtc_hsync_start =
-                                       adjusted_mode_sw->crtc_hsync_start;
-
-       if (adjusted_mode->crtc_hsync_end == crtc_hsync_end_sw)
-               adjusted_mode->crtc_hsync_end =
-                                       adjusted_mode_sw->crtc_hsync_end;
-
-       if (adjusted_mode->crtc_hblank_start == crtc_hblank_start_sw)
-               adjusted_mode->crtc_hblank_start =
-                                       adjusted_mode_sw->crtc_hblank_start;
-
-       if (adjusted_mode->crtc_hblank_end == crtc_hblank_end_sw)
-               adjusted_mode->crtc_hblank_end =
-                                       adjusted_mode_sw->crtc_hblank_end;
-}
-
-static void intel_dsi_get_config(struct intel_encoder *encoder,
-                                struct intel_crtc_state *pipe_config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 pclk;
-       DRM_DEBUG_KMS("\n");
-
-       pipe_config->output_types |= BIT(INTEL_OUTPUT_DSI);
-
-       if (IS_GEN9_LP(dev_priv))
-               bxt_dsi_get_pipe_config(encoder, pipe_config);
-
-       pclk = intel_dsi_get_pclk(encoder, pipe_config->pipe_bpp,
-                                 pipe_config);
-       if (!pclk)
-               return;
-
-       pipe_config->base.adjusted_mode.crtc_clock = pclk;
-       pipe_config->port_clock = pclk;
-}
-
-static enum drm_mode_status
-intel_dsi_mode_valid(struct drm_connector *connector,
-                    struct drm_display_mode *mode)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       const struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
-       int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
-
-       if (fixed_mode) {
-               if (mode->hdisplay > fixed_mode->hdisplay)
-                       return MODE_PANEL;
-               if (mode->vdisplay > fixed_mode->vdisplay)
-                       return MODE_PANEL;
-               if (fixed_mode->clock > max_dotclk)
-                       return MODE_CLOCK_HIGH;
-       }
-
-       return MODE_OK;
-}
-
-/* return txclkesc cycles in terms of divider and duration in us */
-static u16 txclkesc(u32 divider, unsigned int us)
-{
-       switch (divider) {
-       case ESCAPE_CLOCK_DIVIDER_1:
-       default:
-               return 20 * us;
-       case ESCAPE_CLOCK_DIVIDER_2:
-               return 10 * us;
-       case ESCAPE_CLOCK_DIVIDER_4:
-               return 5 * us;
-       }
-}
-
-static void set_dsi_timings(struct drm_encoder *encoder,
-                           const struct drm_display_mode *adjusted_mode)
-{
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-       enum port port;
-       unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-       unsigned int lane_count = intel_dsi->lane_count;
-
-       u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
-
-       hactive = adjusted_mode->crtc_hdisplay;
-       hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay;
-       hsync = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
-       hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end;
-
-       if (intel_dsi->dual_link) {
-               hactive /= 2;
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-                       hactive += intel_dsi->pixel_overlap;
-               hfp /= 2;
-               hsync /= 2;
-               hbp /= 2;
-       }
-
-       vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay;
-       vsync = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
-       vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end;
-
-       /* horizontal values are in terms of high speed byte clock */
-       hactive = txbyteclkhs(hactive, bpp, lane_count,
-                             intel_dsi->burst_mode_ratio);
-       hfp = txbyteclkhs(hfp, bpp, lane_count, intel_dsi->burst_mode_ratio);
-       hsync = txbyteclkhs(hsync, bpp, lane_count,
-                           intel_dsi->burst_mode_ratio);
-       hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (IS_GEN9_LP(dev_priv)) {
-                       /*
-                        * Program hdisplay and vdisplay on MIPI transcoder.
-                        * This is different from calculated hactive and
-                        * vactive, as they are calculated per channel basis,
-                        * whereas these values should be based on resolution.
-                        */
-                       I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port),
-                                  adjusted_mode->crtc_hdisplay);
-                       I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port),
-                                  adjusted_mode->crtc_vdisplay);
-                       I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port),
-                                  adjusted_mode->crtc_vtotal);
-               }
-
-               I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
-               I915_WRITE(MIPI_HFP_COUNT(port), hfp);
-
-               /* meaningful for video mode non-burst sync pulse mode only,
-                * can be zero for non-burst sync events and burst modes */
-               I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync);
-               I915_WRITE(MIPI_HBP_COUNT(port), hbp);
-
-               /* vertical values are in terms of lines */
-               I915_WRITE(MIPI_VFP_COUNT(port), vfp);
-               I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync);
-               I915_WRITE(MIPI_VBP_COUNT(port), vbp);
-       }
-}
-
-static u32 pixel_format_to_reg(enum mipi_dsi_pixel_format fmt)
-{
-       switch (fmt) {
-       case MIPI_DSI_FMT_RGB888:
-               return VID_MODE_FORMAT_RGB888;
-       case MIPI_DSI_FMT_RGB666:
-               return VID_MODE_FORMAT_RGB666;
-       case MIPI_DSI_FMT_RGB666_PACKED:
-               return VID_MODE_FORMAT_RGB666_PACKED;
-       case MIPI_DSI_FMT_RGB565:
-               return VID_MODE_FORMAT_RGB565;
-       default:
-               MISSING_CASE(fmt);
-               return VID_MODE_FORMAT_RGB666;
-       }
-}
-
-static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
-                             const struct intel_crtc_state *pipe_config)
-{
-       struct drm_encoder *encoder = &intel_encoder->base;
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-       const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       enum port port;
-       unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
-       u32 val, tmp;
-       u16 mode_hdisplay;
-
-       DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
-
-       mode_hdisplay = adjusted_mode->crtc_hdisplay;
-
-       if (intel_dsi->dual_link) {
-               mode_hdisplay /= 2;
-               if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
-                       mode_hdisplay += intel_dsi->pixel_overlap;
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-                       /*
-                        * escape clock divider, 20MHz, shared for A and C.
-                        * device ready must be off when doing this! txclkesc?
-                        */
-                       tmp = I915_READ(MIPI_CTRL(PORT_A));
-                       tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
-                       I915_WRITE(MIPI_CTRL(PORT_A), tmp |
-                                       ESCAPE_CLOCK_DIVIDER_1);
-
-                       /* read request priority is per pipe */
-                       tmp = I915_READ(MIPI_CTRL(port));
-                       tmp &= ~READ_REQUEST_PRIORITY_MASK;
-                       I915_WRITE(MIPI_CTRL(port), tmp |
-                                       READ_REQUEST_PRIORITY_HIGH);
-               } else if (IS_GEN9_LP(dev_priv)) {
-                       enum pipe pipe = intel_crtc->pipe;
-
-                       tmp = I915_READ(MIPI_CTRL(port));
-                       tmp &= ~BXT_PIPE_SELECT_MASK;
-
-                       tmp |= BXT_PIPE_SELECT(pipe);
-                       I915_WRITE(MIPI_CTRL(port), tmp);
-               }
-
-               /* XXX: why here, why like this? handling in irq handler?! */
-               I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
-               I915_WRITE(MIPI_INTR_EN(port), 0xffffffff);
-
-               I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
-
-               I915_WRITE(MIPI_DPI_RESOLUTION(port),
-                       adjusted_mode->crtc_vdisplay << VERTICAL_ADDRESS_SHIFT |
-                       mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
-       }
-
-       set_dsi_timings(encoder, adjusted_mode);
-
-       val = intel_dsi->lane_count << DATA_LANES_PRG_REG_SHIFT;
-       if (is_cmd_mode(intel_dsi)) {
-               val |= intel_dsi->channel << CMD_MODE_CHANNEL_NUMBER_SHIFT;
-               val |= CMD_MODE_DATA_WIDTH_8_BIT; /* XXX */
-       } else {
-               val |= intel_dsi->channel << VID_MODE_CHANNEL_NUMBER_SHIFT;
-               val |= pixel_format_to_reg(intel_dsi->pixel_format);
-       }
-
-       tmp = 0;
-       if (intel_dsi->eotp_pkt == 0)
-               tmp |= EOT_DISABLE;
-       if (intel_dsi->clock_stop)
-               tmp |= CLOCKSTOP;
-
-       if (IS_GEN9_LP(dev_priv)) {
-               tmp |= BXT_DPHY_DEFEATURE_EN;
-               if (!is_cmd_mode(intel_dsi))
-                       tmp |= BXT_DEFEATURE_DPI_FIFO_CTR;
-       }
-
-       for_each_dsi_port(port, intel_dsi->ports) {
-               I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
-
-               /* timeouts for recovery. one frame IIUC. if counter expires,
-                * EOT and stop state. */
-
-               /*
-                * In burst mode, value greater than one DPI line Time in byte
-                * clock (txbyteclkhs) To timeout this timer 1+ of the above
-                * said value is recommended.
-                *
-                * In non-burst mode, Value greater than one DPI frame time in
-                * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
-                * said value is recommended.
-                *
-                * In DBI only mode, value greater than one DBI frame time in
-                * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
-                * said value is recommended.
-                */
-
-               if (is_vid_mode(intel_dsi) &&
-                       intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
-                       I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
-                               txbyteclkhs(adjusted_mode->crtc_htotal, bpp,
-                                           intel_dsi->lane_count,
-                                           intel_dsi->burst_mode_ratio) + 1);
-               } else {
-                       I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
-                               txbyteclkhs(adjusted_mode->crtc_vtotal *
-                                           adjusted_mode->crtc_htotal,
-                                           bpp, intel_dsi->lane_count,
-                                           intel_dsi->burst_mode_ratio) + 1);
-               }
-               I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
-               I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
-                                               intel_dsi->turn_arnd_val);
-               I915_WRITE(MIPI_DEVICE_RESET_TIMER(port),
-                                               intel_dsi->rst_timer_val);
-
-               /* dphy stuff */
-
-               /* in terms of low power clock */
-               I915_WRITE(MIPI_INIT_COUNT(port),
-                               txclkesc(intel_dsi->escape_clk_div, 100));
-
-               if (IS_GEN9_LP(dev_priv) && (!intel_dsi->dual_link)) {
-                       /*
-                        * BXT spec says write MIPI_INIT_COUNT for
-                        * both the ports, even if only one is
-                        * getting used. So write the other port
-                        * if not in dual link mode.
-                        */
-                       I915_WRITE(MIPI_INIT_COUNT(port ==
-                                               PORT_A ? PORT_C : PORT_A),
-                                       intel_dsi->init_count);
-               }
-
-               /* recovery disables */
-               I915_WRITE(MIPI_EOT_DISABLE(port), tmp);
-
-               /* in terms of low power clock */
-               I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
-
-               /* in terms of txbyteclkhs. actual high to low switch +
-                * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
-                *
-                * XXX: write MIPI_STOP_STATE_STALL?
-                */
-               I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port),
-                                               intel_dsi->hs_to_lp_count);
-
-               /* XXX: low power clock equivalence in terms of byte clock.
-                * the number of byte clocks occupied in one low power clock.
-                * based on txbyteclkhs and txclkesc.
-                * txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL
-                * ) / 105.???
-                */
-               I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk);
-
-               if (IS_GEMINILAKE(dev_priv)) {
-                       I915_WRITE(MIPI_TLPX_TIME_COUNT(port),
-                                       intel_dsi->lp_byte_clk);
-                       /* Shadow of DPHY reg */
-                       I915_WRITE(MIPI_CLK_LANE_TIMING(port),
-                                       intel_dsi->dphy_reg);
-               }
-
-               /* the bw essential for transmitting 16 long packets containing
-                * 252 bytes meant for dcs write memory command is programmed in
-                * this register in terms of byte clocks. based on dsi transfer
-                * rate and the number of lanes configured the time taken to
-                * transmit 16 long packets in a dsi stream varies. */
-               I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer);
-
-               I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port),
-               intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
-               intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
-
-               if (is_vid_mode(intel_dsi))
-                       /* Some panels might have resolution which is not a
-                        * multiple of 64 like 1366 x 768. Enable RANDOM
-                        * resolution support for such panels by default */
-                       I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port),
-                               intel_dsi->video_frmt_cfg_bits |
-                               intel_dsi->video_mode_format |
-                               IP_TG_CONFIG |
-                               RANDOM_DPI_DISPLAY_RESOLUTION);
-       }
-}
-
-static void intel_dsi_unprepare(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       if (!IS_GEMINILAKE(dev_priv)) {
-               for_each_dsi_port(port, intel_dsi->ports) {
-                       /* Panel commands can be sent when clock is in LP11 */
-                       I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
-
-                       intel_dsi_reset_clocks(encoder, port);
-                       I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
-
-                       val = I915_READ(MIPI_DSI_FUNC_PRG(port));
-                       val &= ~VID_MODE_FORMAT_MASK;
-                       I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
-
-                       I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
-               }
-       }
-}
-
-static int intel_dsi_get_modes(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-       struct drm_display_mode *mode;
-
-       DRM_DEBUG_KMS("\n");
-
-       if (!intel_connector->panel.fixed_mode) {
-               DRM_DEBUG_KMS("no fixed mode\n");
-               return 0;
-       }
-
-       mode = drm_mode_duplicate(connector->dev,
-                                 intel_connector->panel.fixed_mode);
-       if (!mode) {
-               DRM_DEBUG_KMS("drm_mode_duplicate failed\n");
-               return 0;
-       }
-
-       drm_mode_probed_add(connector, mode);
-       return 1;
-}
-
-static void intel_dsi_connector_destroy(struct drm_connector *connector)
-{
-       struct intel_connector *intel_connector = to_intel_connector(connector);
-
-       DRM_DEBUG_KMS("\n");
-       intel_panel_fini(&intel_connector->panel);
-       drm_connector_cleanup(connector);
-       kfree(connector);
-}
-
-static void intel_dsi_encoder_destroy(struct drm_encoder *encoder)
-{
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
-
-       /* dispose of the gpios */
-       if (intel_dsi->gpio_panel)
-               gpiod_put(intel_dsi->gpio_panel);
-
-       intel_encoder_destroy(encoder);
-}
-
-static const struct drm_encoder_funcs intel_dsi_funcs = {
-       .destroy = intel_dsi_encoder_destroy,
-};
-
-static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = {
-       .get_modes = intel_dsi_get_modes,
-       .mode_valid = intel_dsi_mode_valid,
-       .atomic_check = intel_digital_connector_atomic_check,
-};
-
-static const struct drm_connector_funcs intel_dsi_connector_funcs = {
-       .late_register = intel_connector_register,
-       .early_unregister = intel_connector_unregister,
-       .destroy = intel_dsi_connector_destroy,
-       .fill_modes = drm_helper_probe_single_connector_modes,
-       .atomic_get_property = intel_digital_connector_atomic_get_property,
-       .atomic_set_property = intel_digital_connector_atomic_set_property,
-       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-       .atomic_duplicate_state = intel_digital_connector_duplicate_state,
-};
-
-static int intel_dsi_get_panel_orientation(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-       int orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
-       enum i9xx_plane_id i9xx_plane;
-       u32 val;
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               if (connector->encoder->crtc_mask == BIT(PIPE_B))
-                       i9xx_plane = PLANE_B;
-               else
-                       i9xx_plane = PLANE_A;
-
-               val = I915_READ(DSPCNTR(i9xx_plane));
-               if (val & DISPPLANE_ROTATE_180)
-                       orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
-       }
-
-       return orientation;
-}
-
-static void intel_dsi_add_properties(struct intel_connector *connector)
-{
-       struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
-
-       if (connector->panel.fixed_mode) {
-               u32 allowed_scalers;
-
-               allowed_scalers = BIT(DRM_MODE_SCALE_ASPECT) | BIT(DRM_MODE_SCALE_FULLSCREEN);
-               if (!HAS_GMCH_DISPLAY(dev_priv))
-                       allowed_scalers |= BIT(DRM_MODE_SCALE_CENTER);
-
-               drm_connector_attach_scaling_mode_property(&connector->base,
-                                                               allowed_scalers);
-
-               connector->base.state->scaling_mode = DRM_MODE_SCALE_ASPECT;
-
-               connector->base.display_info.panel_orientation =
-                       intel_dsi_get_panel_orientation(connector);
-               drm_connector_init_panel_orientation_property(
-                               &connector->base,
-                               connector->panel.fixed_mode->hdisplay,
-                               connector->panel.fixed_mode->vdisplay);
-       }
-}
-
-void intel_dsi_init(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = &dev_priv->drm;
-       struct intel_dsi *intel_dsi;
-       struct intel_encoder *intel_encoder;
-       struct drm_encoder *encoder;
-       struct intel_connector *intel_connector;
-       struct drm_connector *connector;
-       struct drm_display_mode *scan, *fixed_mode = NULL;
-       enum port port;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* There is no detection method for MIPI so rely on VBT */
-       if (!intel_bios_is_dsi_present(dev_priv, &port))
-               return;
-
-       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-               dev_priv->mipi_mmio_base = VLV_MIPI_BASE;
-       } else if (IS_GEN9_LP(dev_priv)) {
-               dev_priv->mipi_mmio_base = BXT_MIPI_BASE;
-       } else {
-               DRM_ERROR("Unsupported Mipi device to reg base");
-               return;
-       }
-
-       intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
-       if (!intel_dsi)
-               return;
-
-       intel_connector = intel_connector_alloc();
-       if (!intel_connector) {
-               kfree(intel_dsi);
-               return;
-       }
-
-       intel_encoder = &intel_dsi->base;
-       encoder = &intel_encoder->base;
-       intel_dsi->attached_connector = intel_connector;
-
-       connector = &intel_connector->base;
-
-       drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI,
-                        "DSI %c", port_name(port));
-
-       intel_encoder->compute_config = intel_dsi_compute_config;
-       intel_encoder->pre_enable = intel_dsi_pre_enable;
-       intel_encoder->enable = intel_dsi_enable_nop;
-       intel_encoder->disable = intel_dsi_disable;
-       intel_encoder->post_disable = intel_dsi_post_disable;
-       intel_encoder->get_hw_state = intel_dsi_get_hw_state;
-       intel_encoder->get_config = intel_dsi_get_config;
-
-       intel_connector->get_hw_state = intel_connector_get_hw_state;
-
-       intel_encoder->port = port;
-
-       /*
-        * On BYT/CHV, pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI
-        * port C. BXT isn't limited like this.
-        */
-       if (IS_GEN9_LP(dev_priv))
-               intel_encoder->crtc_mask = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C);
-       else if (port == PORT_A)
-               intel_encoder->crtc_mask = BIT(PIPE_A);
-       else
-               intel_encoder->crtc_mask = BIT(PIPE_B);
-
-       if (dev_priv->vbt.dsi.config->dual_link)
-               intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C);
-       else
-               intel_dsi->ports = BIT(port);
-
-       intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports;
-       intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports;
-
-       /* Create a DSI host (and a device) for each port. */
-       for_each_dsi_port(port, intel_dsi->ports) {
-               struct intel_dsi_host *host;
-
-               host = intel_dsi_host_init(intel_dsi, port);
-               if (!host)
-                       goto err;
-
-               intel_dsi->dsi_hosts[port] = host;
-       }
-
-       if (!intel_dsi_vbt_init(intel_dsi, MIPI_DSI_GENERIC_PANEL_ID)) {
-               DRM_DEBUG_KMS("no device found\n");
-               goto err;
-       }
-
-       /*
-        * In case of BYT with CRC PMIC, we need to use GPIO for
-        * Panel control.
-        */
-       if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
-           (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC)) {
-               intel_dsi->gpio_panel =
-                       gpiod_get(dev->dev, "panel", GPIOD_OUT_HIGH);
-
-               if (IS_ERR(intel_dsi->gpio_panel)) {
-                       DRM_ERROR("Failed to own gpio for panel control\n");
-                       intel_dsi->gpio_panel = NULL;
-               }
-       }
-
-       intel_encoder->type = INTEL_OUTPUT_DSI;
-       intel_encoder->power_domain = POWER_DOMAIN_PORT_DSI;
-       intel_encoder->cloneable = 0;
-       drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
-                          DRM_MODE_CONNECTOR_DSI);
-
-       drm_connector_helper_add(connector, &intel_dsi_connector_helper_funcs);
-
-       connector->display_info.subpixel_order = SubPixelHorizontalRGB; /*XXX*/
-       connector->interlace_allowed = false;
-       connector->doublescan_allowed = false;
-
-       intel_connector_attach_encoder(intel_connector, intel_encoder);
-
-       mutex_lock(&dev->mode_config.mutex);
-       intel_dsi_vbt_get_modes(intel_dsi);
-       list_for_each_entry(scan, &connector->probed_modes, head) {
-               if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
-                       fixed_mode = drm_mode_duplicate(dev, scan);
-                       break;
-               }
-       }
-       mutex_unlock(&dev->mode_config.mutex);
-
-       if (!fixed_mode) {
-               DRM_DEBUG_KMS("no fixed mode\n");
-               goto err;
-       }
-
-       connector->display_info.width_mm = fixed_mode->width_mm;
-       connector->display_info.height_mm = fixed_mode->height_mm;
-
-       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
-       intel_panel_setup_backlight(connector, INVALID_PIPE);
-
-       intel_dsi_add_properties(intel_connector);
-
-       return;
-
-err:
-       drm_encoder_cleanup(&intel_encoder->base);
-       kfree(intel_dsi);
-       kfree(intel_connector);
-}
index 7afeb9580f41f6eb22f547616dca505314957bb6..ad7c1cb329836510d7263988a258a8be7f6e9623 100644 (file)
@@ -129,21 +129,29 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
        return container_of(encoder, struct intel_dsi, base.base);
 }
 
-/* intel_dsi.c */
-void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
+/* vlv_dsi.c */
+void vlv_dsi_wait_for_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
 enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt);
 
-/* intel_dsi_pll.c */
-bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
-int intel_compute_dsi_pll(struct intel_encoder *encoder,
-                         struct intel_crtc_state *config);
-void intel_enable_dsi_pll(struct intel_encoder *encoder,
-                         const struct intel_crtc_state *config);
-void intel_disable_dsi_pll(struct intel_encoder *encoder);
-u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
-                      struct intel_crtc_state *config);
-void intel_dsi_reset_clocks(struct intel_encoder *encoder,
-                           enum port port);
+/* vlv_dsi_pll.c */
+int vlv_dsi_pll_compute(struct intel_encoder *encoder,
+                       struct intel_crtc_state *config);
+void vlv_dsi_pll_enable(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *config);
+void vlv_dsi_pll_disable(struct intel_encoder *encoder);
+u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
+                    struct intel_crtc_state *config);
+void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port);
+
+bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
+int bxt_dsi_pll_compute(struct intel_encoder *encoder,
+                       struct intel_crtc_state *config);
+void bxt_dsi_pll_enable(struct intel_encoder *encoder,
+                       const struct intel_crtc_state *config);
+void bxt_dsi_pll_disable(struct intel_encoder *encoder);
+u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
+                    struct intel_crtc_state *config);
+void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port);
 
 /* intel_dsi_vbt.c */
 bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id);
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
deleted file mode 100644 (file)
index 2ff2ee7..0000000
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Copyright © 2013 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.
- *
- * Authors:
- *     Shobhit Kumar <shobhit.kumar@intel.com>
- *     Yogesh Mohan Marimuthu <yogesh.mohan.marimuthu@intel.com>
- */
-
-#include <linux/kernel.h>
-#include "intel_drv.h"
-#include "i915_drv.h"
-#include "intel_dsi.h"
-
-static const u16 lfsr_converts[] = {
-       426, 469, 234, 373, 442, 221, 110, 311, 411,            /* 62 - 70 */
-       461, 486, 243, 377, 188, 350, 175, 343, 427, 213,       /* 71 - 80 */
-       106, 53, 282, 397, 454, 227, 113, 56, 284, 142,         /* 81 - 90 */
-       71, 35, 273, 136, 324, 418, 465, 488, 500, 506          /* 91 - 100 */
-};
-
-/* Get DSI clock from pixel clock */
-static u32 dsi_clk_from_pclk(u32 pclk, enum mipi_dsi_pixel_format fmt,
-                            int lane_count)
-{
-       u32 dsi_clk_khz;
-       u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt);
-
-       /* DSI data rate = pixel clock * bits per pixel / lane count
-          pixel clock is converted from KHz to Hz */
-       dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count);
-
-       return dsi_clk_khz;
-}
-
-static int dsi_calc_mnp(struct drm_i915_private *dev_priv,
-                       struct intel_crtc_state *config,
-                       int target_dsi_clk)
-{
-       unsigned int m_min, m_max, p_min = 2, p_max = 6;
-       unsigned int m, n, p;
-       unsigned int calc_m, calc_p;
-       int delta, ref_clk;
-
-       /* target_dsi_clk is expected in kHz */
-       if (target_dsi_clk < 300000 || target_dsi_clk > 1150000) {
-               DRM_ERROR("DSI CLK Out of Range\n");
-               return -ECHRNG;
-       }
-
-       if (IS_CHERRYVIEW(dev_priv)) {
-               ref_clk = 100000;
-               n = 4;
-               m_min = 70;
-               m_max = 96;
-       } else {
-               ref_clk = 25000;
-               n = 1;
-               m_min = 62;
-               m_max = 92;
-       }
-
-       calc_p = p_min;
-       calc_m = m_min;
-       delta = abs(target_dsi_clk - (m_min * ref_clk) / (p_min * n));
-
-       for (m = m_min; m <= m_max && delta; m++) {
-               for (p = p_min; p <= p_max && delta; p++) {
-                       /*
-                        * Find the optimal m and p divisors with minimal delta
-                        * +/- the required clock
-                        */
-                       int calc_dsi_clk = (m * ref_clk) / (p * n);
-                       int d = abs(target_dsi_clk - calc_dsi_clk);
-                       if (d < delta) {
-                               delta = d;
-                               calc_m = m;
-                               calc_p = p;
-                       }
-               }
-       }
-
-       /* register has log2(N1), this works fine for powers of two */
-       config->dsi_pll.ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + calc_p - 2);
-       config->dsi_pll.div =
-               (ffs(n) - 1) << DSI_PLL_N1_DIV_SHIFT |
-               (u32)lfsr_converts[calc_m - 62] << DSI_PLL_M1_DIV_SHIFT;
-
-       return 0;
-}
-
-/*
- * XXX: The muxing and gating is hard coded for now. Need to add support for
- * sharing PLLs with two DSI outputs.
- */
-static int vlv_compute_dsi_pll(struct intel_encoder *encoder,
-                              struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       int ret;
-       u32 dsi_clk;
-
-       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
-                                   intel_dsi->lane_count);
-
-       ret = dsi_calc_mnp(dev_priv, config, dsi_clk);
-       if (ret) {
-               DRM_DEBUG_KMS("dsi_calc_mnp failed\n");
-               return ret;
-       }
-
-       if (intel_dsi->ports & (1 << PORT_A))
-               config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
-
-       if (intel_dsi->ports & (1 << PORT_C))
-               config->dsi_pll.ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
-
-       config->dsi_pll.ctrl |= DSI_PLL_VCO_EN;
-
-       DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
-                     config->dsi_pll.div, config->dsi_pll.ctrl);
-
-       return 0;
-}
-
-static void vlv_enable_dsi_pll(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       DRM_DEBUG_KMS("\n");
-
-       mutex_lock(&dev_priv->sb_lock);
-
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0);
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, config->dsi_pll.div);
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL,
-                     config->dsi_pll.ctrl & ~DSI_PLL_VCO_EN);
-
-       /* wait at least 0.5 us after ungating before enabling VCO,
-        * allow hrtimer subsystem optimization by relaxing timing
-        */
-       usleep_range(10, 50);
-
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, config->dsi_pll.ctrl);
-
-       if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
-                                               DSI_PLL_LOCK, 20)) {
-
-               mutex_unlock(&dev_priv->sb_lock);
-               DRM_ERROR("DSI PLL lock failed\n");
-               return;
-       }
-       mutex_unlock(&dev_priv->sb_lock);
-
-       DRM_DEBUG_KMS("DSI PLL locked\n");
-}
-
-static void vlv_disable_dsi_pll(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 tmp;
-
-       DRM_DEBUG_KMS("\n");
-
-       mutex_lock(&dev_priv->sb_lock);
-
-       tmp = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
-       tmp &= ~DSI_PLL_VCO_EN;
-       tmp |= DSI_PLL_LDO_GATE;
-       vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
-
-       mutex_unlock(&dev_priv->sb_lock);
-}
-
-static bool bxt_dsi_pll_is_enabled(struct drm_i915_private *dev_priv)
-{
-       bool enabled;
-       u32 val;
-       u32 mask;
-
-       mask = BXT_DSI_PLL_DO_ENABLE | BXT_DSI_PLL_LOCKED;
-       val = I915_READ(BXT_DSI_PLL_ENABLE);
-       enabled = (val & mask) == mask;
-
-       if (!enabled)
-               return false;
-
-       /*
-        * Dividers must be programmed with valid values. As per BSEPC, for
-        * GEMINLAKE only PORT A divider values are checked while for BXT
-        * both divider values are validated. Check this here for
-        * paranoia, since BIOS is known to misconfigure PLLs in this way at
-        * times, and since accessing DSI registers with invalid dividers
-        * causes a system hang.
-        */
-       val = I915_READ(BXT_DSI_PLL_CTL);
-       if (IS_GEMINILAKE(dev_priv)) {
-               if (!(val & BXT_DSIA_16X_MASK)) {
-                       DRM_DEBUG_DRIVER("Invalid PLL divider (%08x)\n", val);
-                       enabled = false;
-               }
-       } else {
-               if (!(val & BXT_DSIA_16X_MASK) || !(val & BXT_DSIC_16X_MASK)) {
-                       DRM_DEBUG_DRIVER("Invalid PLL divider (%08x)\n", val);
-                       enabled = false;
-               }
-       }
-
-       return enabled;
-}
-
-static void bxt_disable_dsi_pll(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       val = I915_READ(BXT_DSI_PLL_ENABLE);
-       val &= ~BXT_DSI_PLL_DO_ENABLE;
-       I915_WRITE(BXT_DSI_PLL_ENABLE, val);
-
-       /*
-        * PLL lock should deassert within 200us.
-        * Wait up to 1ms before timing out.
-        */
-       if (intel_wait_for_register(dev_priv,
-                                   BXT_DSI_PLL_ENABLE,
-                                   BXT_DSI_PLL_LOCKED,
-                                   0,
-                                   1))
-               DRM_ERROR("Timeout waiting for PLL lock deassertion\n");
-}
-
-static void assert_bpp_mismatch(enum mipi_dsi_pixel_format fmt, int pipe_bpp)
-{
-       int bpp = mipi_dsi_pixel_format_to_bpp(fmt);
-
-       WARN(bpp != pipe_bpp,
-            "bpp match assertion failure (expected %d, current %d)\n",
-            bpp, pipe_bpp);
-}
-
-static u32 vlv_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
-                           struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u32 dsi_clock, pclk;
-       u32 pll_ctl, pll_div;
-       u32 m = 0, p = 0, n;
-       int refclk = IS_CHERRYVIEW(dev_priv) ? 100000 : 25000;
-       int i;
-
-       DRM_DEBUG_KMS("\n");
-
-       mutex_lock(&dev_priv->sb_lock);
-       pll_ctl = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL);
-       pll_div = vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER);
-       mutex_unlock(&dev_priv->sb_lock);
-
-       config->dsi_pll.ctrl = pll_ctl & ~DSI_PLL_LOCK;
-       config->dsi_pll.div = pll_div;
-
-       /* mask out other bits and extract the P1 divisor */
-       pll_ctl &= DSI_PLL_P1_POST_DIV_MASK;
-       pll_ctl = pll_ctl >> (DSI_PLL_P1_POST_DIV_SHIFT - 2);
-
-       /* N1 divisor */
-       n = (pll_div & DSI_PLL_N1_DIV_MASK) >> DSI_PLL_N1_DIV_SHIFT;
-       n = 1 << n; /* register has log2(N1) */
-
-       /* mask out the other bits and extract the M1 divisor */
-       pll_div &= DSI_PLL_M1_DIV_MASK;
-       pll_div = pll_div >> DSI_PLL_M1_DIV_SHIFT;
-
-       while (pll_ctl) {
-               pll_ctl = pll_ctl >> 1;
-               p++;
-       }
-       p--;
-
-       if (!p) {
-               DRM_ERROR("wrong P1 divisor\n");
-               return 0;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(lfsr_converts); i++) {
-               if (lfsr_converts[i] == pll_div)
-                       break;
-       }
-
-       if (i == ARRAY_SIZE(lfsr_converts)) {
-               DRM_ERROR("wrong m_seed programmed\n");
-               return 0;
-       }
-
-       m = i + 62;
-
-       dsi_clock = (m * refclk) / (p * n);
-
-       /* pixel_format and pipe_bpp should agree */
-       assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp);
-
-       pclk = DIV_ROUND_CLOSEST(dsi_clock * intel_dsi->lane_count, pipe_bpp);
-
-       return pclk;
-}
-
-static u32 bxt_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
-                           struct intel_crtc_state *config)
-{
-       u32 pclk;
-       u32 dsi_clk;
-       u32 dsi_ratio;
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-
-       /* Divide by zero */
-       if (!pipe_bpp) {
-               DRM_ERROR("Invalid BPP(0)\n");
-               return 0;
-       }
-
-       config->dsi_pll.ctrl = I915_READ(BXT_DSI_PLL_CTL);
-
-       dsi_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
-
-       dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2;
-
-       /* pixel_format and pipe_bpp should agree */
-       assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp);
-
-       pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, pipe_bpp);
-
-       DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk);
-       return pclk;
-}
-
-u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
-                      struct intel_crtc_state *config)
-{
-       if (IS_GEN9_LP(to_i915(encoder->base.dev)))
-               return bxt_dsi_get_pclk(encoder, pipe_bpp, config);
-       else
-               return vlv_dsi_get_pclk(encoder, pipe_bpp, config);
-}
-
-static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
-{
-       u32 temp;
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-
-       temp = I915_READ(MIPI_CTRL(port));
-       temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
-       I915_WRITE(MIPI_CTRL(port), temp |
-                       intel_dsi->escape_clk_div <<
-                       ESCAPE_CLOCK_DIVIDER_SHIFT);
-}
-
-static void glk_dsi_program_esc_clock(struct drm_device *dev,
-                                  const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 dsi_rate = 0;
-       u32 pll_ratio = 0;
-       u32 ddr_clk = 0;
-       u32 div1_value = 0;
-       u32 div2_value = 0;
-       u32 txesc1_div = 0;
-       u32 txesc2_div = 0;
-
-       pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
-
-       dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
-
-       ddr_clk = dsi_rate / 2;
-
-       /* Variable divider value */
-       div1_value = DIV_ROUND_CLOSEST(ddr_clk, 20000);
-
-       /* Calculate TXESC1 divider */
-       if (div1_value <= 10)
-               txesc1_div = div1_value;
-       else if ((div1_value > 10) && (div1_value <= 20))
-               txesc1_div = DIV_ROUND_UP(div1_value, 2);
-       else if ((div1_value > 20) && (div1_value <= 30))
-               txesc1_div = DIV_ROUND_UP(div1_value, 4);
-       else if ((div1_value > 30) && (div1_value <= 40))
-               txesc1_div = DIV_ROUND_UP(div1_value, 6);
-       else if ((div1_value > 40) && (div1_value <= 50))
-               txesc1_div = DIV_ROUND_UP(div1_value, 8);
-       else
-               txesc1_div = 10;
-
-       /* Calculate TXESC2 divider */
-       div2_value = DIV_ROUND_UP(div1_value, txesc1_div);
-
-       if (div2_value < 10)
-               txesc2_div = div2_value;
-       else
-               txesc2_div = 10;
-
-       I915_WRITE(MIPIO_TXESC_CLK_DIV1, txesc1_div & GLK_TX_ESC_CLK_DIV1_MASK);
-       I915_WRITE(MIPIO_TXESC_CLK_DIV2, txesc2_div & GLK_TX_ESC_CLK_DIV2_MASK);
-}
-
-/* Program BXT Mipi clocks and dividers */
-static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port,
-                                  const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       u32 tmp;
-       u32 dsi_rate = 0;
-       u32 pll_ratio = 0;
-       u32 rx_div;
-       u32 tx_div;
-       u32 rx_div_upper;
-       u32 rx_div_lower;
-       u32 mipi_8by3_divider;
-
-       /* Clear old configurations */
-       tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
-       tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
-       tmp &= ~(BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port));
-       tmp &= ~(BXT_MIPI_8X_BY3_DIVIDER_MASK(port));
-       tmp &= ~(BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port));
-
-       /* Get the current DSI rate(actual) */
-       pll_ratio = config->dsi_pll.ctrl & BXT_DSI_PLL_RATIO_MASK;
-       dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
-
-       /*
-        * tx clock should be <= 20MHz and the div value must be
-        * subtracted by 1 as per bspec
-        */
-       tx_div = DIV_ROUND_UP(dsi_rate, 20000) - 1;
-       /*
-        * rx clock should be <= 150MHz and the div value must be
-        * subtracted by 1 as per bspec
-        */
-       rx_div = DIV_ROUND_UP(dsi_rate, 150000) - 1;
-
-       /*
-        * rx divider value needs to be updated in the
-        * two differnt bit fields in the register hence splitting the
-        * rx divider value accordingly
-        */
-       rx_div_lower = rx_div & RX_DIVIDER_BIT_1_2;
-       rx_div_upper = (rx_div & RX_DIVIDER_BIT_3_4) >> 2;
-
-       mipi_8by3_divider = 0x2;
-
-       tmp |= BXT_MIPI_8X_BY3_DIVIDER(port, mipi_8by3_divider);
-       tmp |= BXT_MIPI_TX_ESCLK_DIVIDER(port, tx_div);
-       tmp |= BXT_MIPI_RX_ESCLK_LOWER_DIVIDER(port, rx_div_lower);
-       tmp |= BXT_MIPI_RX_ESCLK_UPPER_DIVIDER(port, rx_div_upper);
-
-       I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
-}
-
-static int gen9lp_compute_dsi_pll(struct intel_encoder *encoder,
-                              struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       u8 dsi_ratio, dsi_ratio_min, dsi_ratio_max;
-       u32 dsi_clk;
-
-       dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
-                                   intel_dsi->lane_count);
-
-       /*
-        * From clock diagram, to get PLL ratio divider, divide double of DSI
-        * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to
-        * round 'up' the result
-        */
-       dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ);
-
-       if (IS_BROXTON(dev_priv)) {
-               dsi_ratio_min = BXT_DSI_PLL_RATIO_MIN;
-               dsi_ratio_max = BXT_DSI_PLL_RATIO_MAX;
-       } else {
-               dsi_ratio_min = GLK_DSI_PLL_RATIO_MIN;
-               dsi_ratio_max = GLK_DSI_PLL_RATIO_MAX;
-       }
-
-       if (dsi_ratio < dsi_ratio_min || dsi_ratio > dsi_ratio_max) {
-               DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n");
-               return -ECHRNG;
-       } else
-               DRM_DEBUG_KMS("DSI PLL calculation is Done!!\n");
-
-       /*
-        * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x
-        * Spec says both have to be programmed, even if one is not getting
-        * used. Configure MIPI_CLOCK_CTL dividers in modeset
-        */
-       config->dsi_pll.ctrl = dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2;
-
-       /* As per recommendation from hardware team,
-        * Prog PVD ratio =1 if dsi ratio <= 50
-        */
-       if (IS_BROXTON(dev_priv) && dsi_ratio <= 50)
-               config->dsi_pll.ctrl |= BXT_DSI_PLL_PVD_RATIO_1;
-
-       return 0;
-}
-
-static void gen9lp_enable_dsi_pll(struct intel_encoder *encoder,
-                              const struct intel_crtc_state *config)
-{
-       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
-       enum port port;
-       u32 val;
-
-       DRM_DEBUG_KMS("\n");
-
-       /* Configure PLL vales */
-       I915_WRITE(BXT_DSI_PLL_CTL, config->dsi_pll.ctrl);
-       POSTING_READ(BXT_DSI_PLL_CTL);
-
-