summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/i915/Kconfig6
-rw-r--r--drivers/gpu/drm/i915/Kconfig.debug12
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c5
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h101
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c45
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h11
-rw-r--r--drivers/gpu/drm/i915/i915_gem_userptr.c7
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c31
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c17
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h105
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c10
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c4
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c4
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c40
-rw-r--r--drivers/gpu/drm/i915/intel_csr.c40
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c1200
-rw-r--r--drivers/gpu/drm/i915/intel_display.c1181
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c147
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c4
-rw-r--r--drivers/gpu/drm/i915/intel_dpll_mgr.c1774
-rw-r--r--drivers/gpu/drm/i915/intel_dpll_mgr.h164
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h132
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_pll.c56
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c3
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c216
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c10
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c50
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c253
-rw-r--r--drivers/gpu/drm/i915/intel_psr.c6
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h5
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c143
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c4
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c27
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c12
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c56
39 files changed, 3312 insertions, 2576 deletions
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 20a5d0455e19..29a32b11953b 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -56,3 +56,9 @@ config DRM_I915_USERPTR
selected to enabled full userptr support.
If in doubt, say "Y".
+
+menu "drm/i915 Debugging"
+depends on DRM_I915
+depends on EXPERT
+source drivers/gpu/drm/i915/Kconfig.debug
+endmenu
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
new file mode 100644
index 000000000000..649a562ddf17
--- /dev/null
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -0,0 +1,12 @@
+config DRM_I915_DEBUG
+ bool "Enable additional driver debugging"
+ depends on DRM_I915
+ default n
+ help
+ Choose this option to turn on extra driver debugging that may affect
+ performance but will catch some internal issues.
+
+ Recommended for driver developers only.
+
+ If in doubt, say "N".
+
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0851de07bd13..5558a0312558 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -56,6 +56,7 @@ i915-y += intel_audio.o \
intel_atomic_plane.o \
intel_bios.o \
intel_display.o \
+ intel_dpll_mgr.o \
intel_fbc.o \
intel_fifo_underrun.o \
intel_frontbuffer.o \
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index a0f1bd711b53..15aacd0ee66f 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1367,8 +1367,6 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
seq_printf(m, "\tACTHD = 0x%08llx [current 0x%08llx]\n",
(long long)ring->hangcheck.acthd,
(long long)acthd[i]);
- seq_printf(m, "\tmax ACTHD = 0x%08llx\n",
- (long long)ring->hangcheck.max_acthd);
seq_printf(m, "\tscore = %d\n", ring->hangcheck.score);
seq_printf(m, "\taction = %d\n", ring->hangcheck.action);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 1c6d227aae7c..4aa3db61a535 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -853,6 +853,10 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
else if (INTEL_INFO(dev)->gen >= 9)
gen9_sseu_info_init(dev);
+ /* Snooping is broken on BXT A stepping. */
+ info->has_snoop = !info->has_llc;
+ info->has_snoop &= !IS_BXT_REVID(dev, 0, BXT_REVID_A1);
+
DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
@@ -1010,6 +1014,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
mutex_init(&dev_priv->sb_lock);
mutex_init(&dev_priv->modeset_restore_lock);
mutex_init(&dev_priv->av_mutex);
+ mutex_init(&dev_priv->wm.wm_mutex);
ret = i915_workqueues_init(dev_priv);
if (ret < 0)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 10480939159c..80b14f1ba302 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -53,13 +53,14 @@
#include <linux/kref.h>
#include <linux/pm_qos.h>
#include "intel_guc.h"
+#include "intel_dpll_mgr.h"
/* General customization:
*/
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20160229"
+#define DRIVER_DATE "20160314"
#undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */
@@ -340,81 +341,6 @@ struct drm_i915_file_private {
unsigned int bsd_ring;
};
-enum intel_dpll_id {
- DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */
- /* real shared dpll ids must be >= 0 */
- DPLL_ID_PCH_PLL_A = 0,
- DPLL_ID_PCH_PLL_B = 1,
- /* hsw/bdw */
- DPLL_ID_WRPLL1 = 0,
- DPLL_ID_WRPLL2 = 1,
- DPLL_ID_SPLL = 2,
-
- /* skl */
- DPLL_ID_SKL_DPLL1 = 0,
- DPLL_ID_SKL_DPLL2 = 1,
- DPLL_ID_SKL_DPLL3 = 2,
-};
-#define I915_NUM_PLLS 3
-
-struct intel_dpll_hw_state {
- /* i9xx, pch plls */
- uint32_t dpll;
- uint32_t dpll_md;
- uint32_t fp0;
- uint32_t fp1;
-
- /* hsw, bdw */
- uint32_t wrpll;
- uint32_t spll;
-
- /* skl */
- /*
- * DPLL_CTRL1 has 6 bits for each each this DPLL. We store those in
- * lower part of ctrl1 and they get shifted into position when writing
- * the register. This allows us to easily compare the state to share
- * the DPLL.
- */
- uint32_t ctrl1;
- /* HDMI only, 0 when used for DP */
- uint32_t cfgcr1, cfgcr2;
-
- /* bxt */
- uint32_t ebb0, ebb4, pll0, pll1, pll2, pll3, pll6, pll8, pll9, pll10,
- pcsdw12;
-};
-
-struct intel_shared_dpll_config {
- unsigned crtc_mask; /* mask of CRTCs sharing this PLL */
- struct intel_dpll_hw_state hw_state;
-};
-
-struct intel_shared_dpll {
- struct intel_shared_dpll_config config;
-
- int active; /* count of number of active CRTCs (i.e. DPMS on) */
- bool on; /* is the PLL actually active? Disabled during modeset */
- const char *name;
- /* should match the index in the dev_priv->shared_dplls array */
- enum intel_dpll_id id;
- /* The mode_set hook is optional and should be used together with the
- * intel_prepare_shared_dpll function. */
- void (*mode_set)(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll);
- void (*enable)(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll);
- void (*disable)(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll);
- bool (*get_hw_state)(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state);
-};
-
-#define SKL_DPLL0 0
-#define SKL_DPLL1 1
-#define SKL_DPLL2 2
-#define SKL_DPLL3 3
-
/* Used by dp and fdi links */
struct intel_link_m_n {
uint32_t tu;
@@ -561,6 +487,8 @@ struct drm_i915_error_state {
u32 *pages[0];
} *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
+ struct drm_i915_error_object *wa_ctx;
+
struct drm_i915_error_request {
long jiffies;
u32 seqno;
@@ -629,9 +557,12 @@ struct drm_i915_display_funcs {
int target, int refclk,
struct dpll *match_clock,
struct dpll *best_clock);
- int (*compute_pipe_wm)(struct intel_crtc *crtc,
- struct drm_atomic_state *state);
- void (*program_watermarks)(struct intel_crtc_state *cstate);
+ int (*compute_pipe_wm)(struct intel_crtc_state *cstate);
+ int (*compute_intermediate_wm)(struct drm_device *dev,
+ struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *newstate);
+ void (*initial_watermarks)(struct intel_crtc_state *cstate);
+ void (*optimize_watermarks)(struct intel_crtc_state *cstate);
void (*update_wm)(struct drm_crtc *crtc);
int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
@@ -750,6 +681,7 @@ struct intel_csr {
i915_reg_t mmioaddr[8];
uint32_t mmiodata[8];
uint32_t dc_state;
+ uint32_t allowed_dc_mask;
};
#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
@@ -779,6 +711,7 @@ struct intel_csr {
func(overlay_needs_physical) sep \
func(supports_tv) sep \
func(has_llc) sep \
+ func(has_snoop) sep \
func(has_ddi) sep \
func(has_fpga_dbg)
@@ -1829,6 +1762,7 @@ struct drm_i915_private {
unsigned int skl_boot_cdclk;
unsigned int cdclk_freq, max_cdclk_freq, atomic_cdclk_freq;
unsigned int max_dotclk_freq;
+ unsigned int rawclk_freq;
unsigned int hpll_freq;
unsigned int czclk_freq;
@@ -1876,6 +1810,7 @@ struct drm_i915_private {
/* dpll and cdclk state is protected by connection_mutex */
int num_shared_dpll;
struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
+ const struct intel_dpll_mgr *dpll_mgr;
unsigned int active_crtcs;
unsigned int min_pixclk[I915_MAX_PIPES];
@@ -1980,6 +1915,13 @@ struct drm_i915_private {
};
uint8_t max_level;
+
+ /*
+ * Should be held around atomic WM register writing; also
+ * protects * intel_crtc->wm.active and
+ * cstate->wm.need_postvbl_update.
+ */
+ struct mutex wm_mutex;
} wm;
struct i915_runtime_pm pm;
@@ -2616,6 +2558,7 @@ struct drm_i915_cmd_table {
#define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING)
#define HAS_VEBOX(dev) (INTEL_INFO(dev)->ring_mask & VEBOX_RING)
#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc)
+#define HAS_SNOOP(dev) (INTEL_INFO(dev)->has_snoop)
#define HAS_WT(dev) ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && \
__I915__(dev)->ellc_size)
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 3d31d3ac589e..b854af2c4141 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3949,7 +3949,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
* cacheline, whereas normally such cachelines would get
* invalidated.
*/
- if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
+ if (!HAS_LLC(dev) && !HAS_SNOOP(dev))
return -ENODEV;
level = I915_CACHE_LLC;
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 49e4f26b79d8..7b8de85c5f76 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -3377,11 +3377,6 @@ rotate_pages(const dma_addr_t *in, unsigned int offset,
unsigned int column, row;
unsigned int src_idx;
- if (!sg) {
- st->nents = 0;
- sg = st->sgl;
- }
-
for (column = 0; column < width; column++) {
src_idx = stride * (height - 1) + column;
for (row = 0; row < height; row++) {
@@ -3405,7 +3400,7 @@ static struct sg_table *
intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
struct drm_i915_gem_object *obj)
{
- unsigned int size_pages = rot_info->size >> PAGE_SHIFT;
+ unsigned int size_pages = rot_info->plane[0].width * rot_info->plane[0].height;
unsigned int size_pages_uv;
struct sg_page_iter sg_iter;
unsigned long i;
@@ -3423,7 +3418,7 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
/* Account for UV plane with NV12. */
if (rot_info->pixel_format == DRM_FORMAT_NV12)
- size_pages_uv = rot_info->size_uv >> PAGE_SHIFT;
+ size_pages_uv = rot_info->plane[1].width * rot_info->plane[1].height;
else
size_pages_uv = 0;
@@ -3443,11 +3438,14 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
i++;
}
+ st->nents = 0;
+ sg = st->sgl;
+
/* Rotate the pages. */
sg = rotate_pages(page_addr_list, 0,
- rot_info->width_pages, rot_info->height_pages,
- rot_info->width_pages,
- st, NULL);
+ rot_info->plane[0].width, rot_info->plane[0].height,
+ rot_info->plane[0].width,
+ st, sg);
/* Append the UV plane if NV12. */
if (rot_info->pixel_format == DRM_FORMAT_NV12) {
@@ -3459,18 +3457,15 @@ intel_rotate_fb_obj_pages(struct intel_rotation_info *rot_info,
rot_info->uv_start_page = uv_start_page;
- rotate_pages(page_addr_list, uv_start_page,
- rot_info->width_pages_uv,
- rot_info->height_pages_uv,
- rot_info->width_pages_uv,
- st, sg);
+ sg = rotate_pages(page_addr_list, rot_info->uv_start_page,
+ rot_info->plane[1].width, rot_info->plane[1].height,
+ rot_info->plane[1].width,
+ st, sg);
}
- DRM_DEBUG_KMS(
- "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0)).\n",
- obj->base.size, rot_info->pitch, rot_info->height,
- rot_info->pixel_format, rot_info->width_pages,
- rot_info->height_pages, size_pages + size_pages_uv,
+ DRM_DEBUG_KMS("Created rotated page mapping for object size %zu (%ux%u tiles, %u pages (%u plane 0)).\n",
+ obj->base.size, rot_info->plane[0].width,
+ rot_info->plane[0].height, size_pages + size_pages_uv,
size_pages);
drm_free_large(page_addr_list);
@@ -3482,11 +3477,9 @@ err_sg_alloc:
err_st_alloc:
drm_free_large(page_addr_list);
- DRM_DEBUG_KMS(
- "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages (%u plane 0))\n",
- obj->base.size, ret, rot_info->pitch, rot_info->height,
- rot_info->pixel_format, rot_info->width_pages,
- rot_info->height_pages, size_pages + size_pages_uv,
+ DRM_DEBUG_KMS("Failed to create rotated mapping for object size %zu! (%d) (%ux%u tiles, %u pages (%u plane 0))\n",
+ obj->base.size, ret, rot_info->plane[0].width,
+ rot_info->plane[0].height, size_pages + size_pages_uv,
size_pages);
return ERR_PTR(ret);
}
@@ -3634,7 +3627,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj,
if (view->type == I915_GGTT_VIEW_NORMAL) {
return obj->base.size;
} else if (view->type == I915_GGTT_VIEW_ROTATED) {
- return view->params.rotated.size;
+ return intel_rotation_info_size(&view->params.rotated) << PAGE_SHIFT;
} else if (view->type == I915_GGTT_VIEW_PARTIAL) {
return view->params.partial.size << PAGE_SHIFT;
} else {
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 8774f1ba46e7..dc208c05cd2c 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -135,16 +135,13 @@ enum i915_ggtt_view_type {
};
struct intel_rotation_info {
- unsigned int height;
- unsigned int pitch;
unsigned int uv_offset;
uint32_t pixel_format;
- uint64_t fb_modifier;
- unsigned int width_pages, height_pages;
- uint64_t size;
- unsigned int width_pages_uv, height_pages_uv;
- uint64_t size_uv;
unsigned int uv_start_page;
+ struct {
+ /* tiles */
+ unsigned int width, height;
+ } plane[2];
};
struct i915_ggtt_view {
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index 4b09c840d493..54088a4d6498 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -758,6 +758,13 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file
int ret;
u32 handle;
+ if (!HAS_LLC(dev) && !HAS_SNOOP(dev)) {
+ /* We cannot support coherent userptr objects on hw without
+ * LLC and broken snooping.
+ */
+ return -ENODEV;
+ }
+
if (args->flags & ~(I915_USERPTR_READ_ONLY |
I915_USERPTR_UNSYNCHRONIZED))
return -EINVAL;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 831895b8cb75..13b5f3aed01c 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -230,8 +230,6 @@ static const char *hangcheck_action_to_str(enum intel_ring_hangcheck_action a)
return "wait";
case HANGCHECK_ACTIVE:
return "active";
- case HANGCHECK_ACTIVE_LOOP:
- return "active (loop)";
case HANGCHECK_KICK:
return "kick";
case HANGCHECK_HUNG:
@@ -493,6 +491,28 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
}
}
+ obj = error->ring[i].wa_ctx;
+ if (obj) {
+ u64 wa_ctx_offset = obj->gtt_offset;
+ u32 *wa_ctx_page = &obj->pages[0][0];
+ struct intel_engine_cs *ring = &dev_priv->ring[RCS];
+ u32 wa_ctx_size = (ring->wa_ctx.indirect_ctx.size +
+ ring->wa_ctx.per_ctx.size);
+
+ err_printf(m, "%s --- WA ctx batch buffer = 0x%08llx\n",
+ dev_priv->ring[i].name, wa_ctx_offset);
+ offset = 0;
+ for (elt = 0; elt < wa_ctx_size; elt += 4) {
+ err_printf(m, "[%04x] %08x %08x %08x %08x\n",
+ offset,
+ wa_ctx_page[elt + 0],
+ wa_ctx_page[elt + 1],
+ wa_ctx_page[elt + 2],
+ wa_ctx_page[elt + 3]);
+ offset += 16;
+ }
+ }
+
if ((obj = error->ring[i].ctx)) {
err_printf(m, "%s --- HW Context = 0x%08x\n",
dev_priv->ring[i].name,
@@ -585,6 +605,7 @@ static void i915_error_state_free(struct kref *error_ref)
i915_error_object_free(error->ring[i].hws_page);
i915_error_object_free(error->ring[i].ctx);
kfree(error->ring[i].requests);
+ i915_error_object_free(error->ring[i].wa_ctx);
}
i915_error_object_free(error->semaphore_obj);
@@ -1067,6 +1088,12 @@ static void i915_gem_record_rings(struct drm_device *dev,
error->ring[i].hws_page =
i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
+ if (ring->wa_ctx.obj) {
+ error->ring[i].wa_ctx =
+ i915_error_ggtt_object_create(dev_priv,
+ ring->wa_ctx.obj);
+ }
+
i915_gem_record_active_context(ring, error, &error->ring[i]);
count = 0;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d1a46ef5ab3f..53e5104964b3 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -3001,12 +3001,7 @@ head_stuck(struct intel_engine_cs *ring, u64 acthd)
memset(ring->hangcheck.instdone, 0,
sizeof(ring->hangcheck.instdone));
- if (acthd > ring->hangcheck.max_acthd) {
- ring->hangcheck.max_acthd = acthd;
- return HANGCHECK_ACTIVE;
- }
-
- return HANGCHECK_ACTIVE_LOOP;
+ return HANGCHECK_ACTIVE;
}
if (!subunits_stuck(ring))
@@ -3083,6 +3078,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
#define BUSY 1
#define KICK 5
#define HUNG 20
+#define ACTIVE_DECAY 15
if (!i915.enable_hangcheck)
return;
@@ -3151,9 +3147,8 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
switch (ring->hangcheck.action) {
case HANGCHECK_IDLE:
case HANGCHECK_WAIT:
- case HANGCHECK_ACTIVE:
break;
- case HANGCHECK_ACTIVE_LOOP:
+ case HANGCHECK_ACTIVE:
ring->hangcheck.score += BUSY;
break;
case HANGCHECK_KICK:
@@ -3172,10 +3167,12 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
* attempts across multiple batches.
*/
if (ring->hangcheck.score > 0)
- ring->hangcheck.score--;
+ ring->hangcheck.score -= ACTIVE_DECAY;
+ if (ring->hangcheck.score < 0)
+ ring->hangcheck.score = 0;
/* Clear head and subunit states on seqno movement */
- ring->hangcheck.acthd = ring->hangcheck.max_acthd = 0;
+ ring->hangcheck.acthd = 0;
memset(ring->hangcheck.instdone, 0,
sizeof(ring->hangcheck.instdone));
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f76cbf3e5d1e..7dfc4007f3fa 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -786,6 +786,7 @@ enum skl_disp_power_wells {
#define DSI_PLL_M1_DIV_MASK (0x1ff << 0)
#define CCK_CZ_CLOCK_CONTROL 0x62
#define CCK_DISPLAY_CLOCK_CONTROL 0x6b
+#define CCK_DISPLAY_REF_CLOCK_CONTROL 0x6c
#define CCK_TRUNK_FORCE_ON (1 << 17)
#define CCK_TRUNK_FORCE_OFF (1 << 16)
#define CCK_FREQUENCY_STATUS (0x1f << 8)
@@ -7362,9 +7363,11 @@ enum skl_disp_power_wells {
/* SBI offsets */
#define SBI_SSCDIVINTPHASE 0x0200
#define SBI_SSCDIVINTPHASE6 0x0600
-#define SBI_SSCDIVINTPHASE_DIVSEL_MASK ((0x7f)<<1)
+#define SBI_SSCDIVINTPHASE_DIVSEL_SHIFT 1
+#define SBI_SSCDIVINTPHASE_DIVSEL_MASK (0x7f<<1)
#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1)
-#define SBI_SSCDIVINTPHASE_INCVAL_MASK ((0x7f)<<8)
+#define SBI_SSCDIVINTPHASE_INCVAL_SHIFT 8
+#define SBI_SSCDIVINTPHASE_INCVAL_MASK (0x7f<<8)
#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8)
#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15)
#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0)
@@ -7374,6 +7377,8 @@ enum skl_disp_power_wells {
#define SBI_SSCCTL_PATHALT (1<<3)
#define SBI_SSCCTL_DISABLE (1<<0)
#define SBI_SSCAUXDIV6 0x0610
+#define SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT 4
+#define SBI_SSCAUXDIV_FINALDIV2SEL_MASK (1<<4)
#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4)
#define SBI_DBUFF0 0x2a00
#define SBI_GEN0 0x1f00
@@ -7665,58 +7670,62 @@ enum skl_disp_power_wells {
#define BXT_MIPI_DIV_SHIFT(port) \
_MIPI_PORT(port, BXT_MIPI1_DIV_SHIFT, \
BXT_MIPI2_DIV_SHIFT)
-/* Var clock divider to generate TX source. Result must be < 39.5 M */
-#define BXT_MIPI1_ESCLK_VAR_DIV_MASK (0x3F << 26)
-#define BXT_MIPI2_ESCLK_VAR_DIV_MASK (0x3F << 10)
-#define BXT_MIPI_ESCLK_VAR_DIV_MASK(port) \
- _MIPI_PORT(port, BXT_MIPI1_ESCLK_VAR_DIV_MASK, \
- BXT_MIPI2_ESCLK_VAR_DIV_MASK)
-
-#define BXT_MIPI_ESCLK_VAR_DIV(port, val) \
- (val << BXT_MIPI_DIV_SHIFT(port))
+
/* TX control divider to select actual TX clock output from (8x/var) */
-#define BXT_MIPI1_TX_ESCLK_SHIFT 21
-#define BXT_MIPI2_TX_ESCLK_SHIFT 5
+#define BXT_MIPI1_TX_ESCLK_SHIFT 26
+#define BXT_MIPI2_TX_ESCLK_SHIFT 10
#define BXT_MIPI_TX_ESCLK_SHIFT(port) \
_MIPI_PORT(port, BXT_MIPI1_TX_ESCLK_SHIFT, \
BXT_MIPI2_TX_ESCLK_SHIFT)
-#define BXT_MIPI1_TX_ESCLK_FIXDIV_MASK (3 << 21)
-#define BXT_MIPI2_TX_ESCLK_FIXDIV_MASK (3 << 5)
+#define BXT_MIPI1_TX_ESCLK_FIXDIV_MASK (0x3F << 26)
+#define BXT_MIPI2_TX_ESCLK_FIXDIV_MASK (0x3F << 10)
#define BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port) \
_MIPI_PORT(port, BXT_MIPI1_TX_ESCLK_FIXDIV_MASK, \
- BXT_MIPI2_TX_ESCLK_FIXDIV_MASK)
-#define BXT_MIPI_TX_ESCLK_8XDIV_BY2(port) \
- (0x0 << BXT_MIPI_TX_ESCLK_SHIFT(port))
-#define BXT_MIPI_TX_ESCLK_8XDIV_BY4(port) \
- (0x1 << BXT_MIPI_TX_ESCLK_SHIFT(port))
-#define BXT_MIPI_TX_ESCLK_8XDIV_BY8(port) \
- (0x2 << BXT_MIPI_TX_ESCLK_SHIFT(port))
-/* RX control divider to select actual RX clock output from 8x*/
-#define BXT_MIPI1_RX_ESCLK_SHIFT 19
-#define BXT_MIPI2_RX_ESCLK_SHIFT 3
-#define BXT_MIPI_RX_ESCLK_SHIFT(port) \
- _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_SHIFT, \
- BXT_MIPI2_RX_ESCLK_SHIFT)
-#define BXT_MIPI1_RX_ESCLK_FIXDIV_MASK (3 << 19)
-#define BXT_MIPI2_RX_ESCLK_FIXDIV_MASK (3 << 3)
-#define BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port) \
- (3 << BXT_MIPI_RX_ESCLK_SHIFT(port))
-#define BXT_MIPI_RX_ESCLK_8X_BY2(port) \
- (1 << BXT_MIPI_RX_ESCLK_SHIFT(port))
-#define BXT_MIPI_RX_ESCLK_8X_BY3(port) \
- (2 << BXT_MIPI_RX_ESCLK_SHIFT(port))
-#define BXT_MIPI_RX_ESCLK_8X_BY4(port) \
- (3 << BXT_MIPI_RX_ESCLK_SHIFT(port))
-/* BXT-A WA: Always prog DPHY dividers to 00 */
-#define BXT_MIPI1_DPHY_DIV_SHIFT 16
-#define BXT_MIPI2_DPHY_DIV_SHIFT 0
-#define BXT_MIPI_DPHY_DIV_SHIFT(port) \
- _MIPI_PORT(port, BXT_MIPI1_DPHY_DIV_SHIFT, \
- BXT_MIPI2_DPHY_DIV_SHIFT)
-#define BXT_MIPI_1_DPHY_DIVIDER_MASK (3 << 16)
-#define BXT_MIPI_2_DPHY_DIVIDER_MASK (3 << 0)
-#define BXT_MIPI_DPHY_DIVIDER_MASK(port) \
- (3 << BXT_MIPI_DPHY_DIV_SHIFT(port))
+ BXT_MIPI2_TX_ESCLK_FIXDIV_MASK)
+#define BXT_MIPI_TX_ESCLK_DIVIDER(port, val) \
+ ((val & 0x3F) << BXT_MIPI_TX_ESCLK_SHIFT(port))
+/* RX upper control divider to select actual RX clock output from 8x */
+#define BXT_MIPI1_RX_ESCLK_UPPER_SHIFT 21
+#define BXT_MIPI2_RX_ESCLK_UPPER_SHIFT 5
+#define BXT_MIPI_RX_ESCLK_UPPER_SHIFT(port) \
+ _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_UPPER_SHIFT, \
+ BXT_MIPI2_RX_ESCLK_UPPER_SHIFT)
+#define BXT_MIPI1_RX_ESCLK_UPPER_FIXDIV_MASK (3 << 21)
+#define BXT_MIPI2_RX_ESCLK_UPPER_FIXDIV_MASK (3 << 5)
+#define BXT_MIPI_RX_ESCLK_UPPER_FIXDIV_MASK(port) \
+ _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_UPPER_FIXDIV_MASK, \
+ BXT_MIPI2_RX_ESCLK_UPPER_FIXDIV_MASK)
+#define BXT_MIPI_RX_ESCLK_UPPER_DIVIDER(port, val) \
+ ((val & 3) << BXT_MIPI_RX_ESCLK_UPPER_SHIFT(port))
+/* 8/3X divider to select the actual 8/3X clock output from 8x */
+#define BXT_MIPI1_8X_BY3_SHIFT 19
+#define BXT_MIPI2_8X_BY3_SHIFT 3
+#define BXT_MIPI_8X_BY3_SHIFT(port) \
+ _MIPI_PORT(port, BXT_MIPI1_8X_BY3_SHIFT, \
+ BXT_MIPI2_8X_BY3_SHIFT)
+#define BXT_MIPI1_8X_BY3_DIVIDER_MASK (3 << 19)
+#define BXT_MIPI2_8X_BY3_DIVIDER_MASK (3 << 3)
+#define BXT_MIPI_8X_BY3_DIVIDER_MASK(port) \
+ _MIPI_PORT(port, BXT_MIPI1_8X_BY3_DIVIDER_MASK, \
+ BXT_MIPI2_8X_BY3_DIVIDER_MASK)
+#define BXT_MIPI_8X_BY3_DIVIDER(port, val) \
+ ((val & 3) << BXT_MIPI_8X_BY3_SHIFT(port))
+/* RX lower control divider to select actual RX clock output from 8x */
+#define BXT_MIPI1_RX_ESCLK_LOWER_SHIFT 16
+#define BXT_MIPI2_RX_ESCLK_LOWER_SHIFT 0
+#define BXT_MIPI_RX_ESCLK_LOWER_SHIFT(port) \
+ _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_LOWER_SHIFT, \
+ BXT_MIPI2_RX_ESCLK_LOWER_SHIFT)
+#define BXT_MIPI1_RX_ESCLK_LOWER_FIXDIV_MASK (3 << 16)
+#define BXT_MIPI2_RX_ESCLK_LOWER_FIXDIV_MASK (3 << 0)
+#define BXT_MIPI_RX_ESCLK_LOWER_FIXDIV_MASK(port) \
+ _MIPI_PORT(port, BXT_MIPI1_RX_ESCLK_LOWER_FIXDIV_MASK, \
+ BXT_MIPI2_RX_ESCLK_LOWER_FIXDIV_MASK)
+#define BXT_MIPI_RX_ESCLK_LOWER_DIVIDER(port, val) \
+ ((val & 3) << BXT_MIPI_RX_ESCLK_LOWER_SHIFT(port))
+
+#define RX_DIVIDER_BIT_1_2 0x3
+#define RX_DIVIDER_BIT_3_4 0xC
/* BXT MIPI mode configure */
#define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index c6188dddb341..2d576b7ff299 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -370,6 +370,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+ intel_runtime_pm_get(dev_priv);
+
mutex_lock(&dev_priv->rps.hw_lock);
val = intel_freq_opcode(dev_priv, val);
@@ -378,6 +380,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
val > dev_priv->rps.max_freq ||
val < dev_priv->rps.min_freq_softlimit) {
mutex_unlock(&dev_priv->rps.hw_lock);
+ intel_runtime_pm_put(dev_priv);
return -EINVAL;
}
@@ -398,6 +401,8 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
mutex_unlock(&dev_priv->rps.hw_lock);
+ intel_runtime_pm_put(dev_priv);
+
return count;
}
@@ -433,6 +438,8 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+ intel_runtime_pm_get(dev_priv);
+
mutex_lock(&dev_priv->rps.hw_lock);
val = intel_freq_opcode(dev_priv, val);
@@ -441,6 +448,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
val > dev_priv->rps.max_freq ||
val > dev_priv->rps.max_freq_softlimit) {
mutex_unlock(&dev_priv->rps.hw_lock);
+ intel_runtime_pm_put(dev_priv);
return -EINVAL;
}
@@ -457,6 +465,8 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
mutex_unlock(&dev_priv->rps.hw_lock);
+ intel_runtime_pm_put(dev_priv);
+
return count;
}
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 8e579a8505ac..79448f1c8b8d 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -96,8 +96,10 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
crtc_state->update_pipe = false;
crtc_state->disable_lp_wm = false;
crtc_state->disable_cxsr = false;
- crtc_state->wm_changed = false;
+ crtc_state->update_wm_pre = false;
+ crtc_state->update_wm_post = false;
crtc_state->fb_changed = false;
+ crtc_state->wm.need_postvbl_update = false;
return &crtc_state->base;
}
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index e0b851a0004a..7de7721f65bc 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -195,12 +195,10 @@ static void intel_plane_atomic_update(struct drm_plane *plane,
struct intel_plane_state *intel_state =
to_intel_plane_state(plane->state);
struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
- struct drm_crtc_state *crtc_state =
- drm_atomic_get_existing_crtc_state(old_state->state, crtc);
if (intel_state->visible)
intel_plane->update_plane(plane,
- to_intel_crtc_state(crtc_state),
+ to_intel_crtc_state(crtc->state),
intel_state);
else
intel_plane->disable_plane(plane, crtc);
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 505fc5cf26f8..a2a31fd01d1d 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -120,22 +120,16 @@ static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
static void intel_crt_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->base.dev;
- int dotclock;
-
pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
- dotclock = pipe_config->port_clock;
-
- if (HAS_PCH_SPLIT(dev))
- ironlake_check_encoder_dotclock(pipe_config, dotclock);
-
- pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
}
static void hsw_crt_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+
intel_ddi_get_config(encoder, pipe_config);
pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
@@ -143,6 +137,8 @@ static void hsw_crt_get_config(struct intel_encoder *encoder,
DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_NVSYNC);
pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
+
+ pipe_config->base.adjusted_mode.crtc_clock = lpt_get_iclkip(dev_priv);
}
/* Note: The caller is required to filter out dpms modes not supported by the
@@ -222,18 +218,26 @@ intel_crt_mode_valid(struct drm_connector *connector,
{
struct drm_device *dev = connector->dev;
int max_dotclk = to_i915(dev)->max_dotclk_freq;
+ int max_clock;
- int max_clock = 0;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
if (mode->clock < 25000)
return MODE_CLOCK_LOW;
- if (IS_GEN2(dev))
- max_clock = 350000;
- else
+ if (HAS_PCH_LPT(dev))
+ max_clock = 180000;
+ else if (IS_VALLEYVIEW(dev))
+ /*
+ * 270 MHz due to current DPLL limits,
+ * DAC limit supposedly 355 MHz.
+ */
+ max_clock = 270000;
+ else if (IS_GEN3(dev) || IS_GEN4(dev))
max_clock = 400000;
+ else
+ max_clock = 350000;
if (mode->clock > max_clock)
return MODE_CLOCK_HIGH;
@@ -261,15 +265,9 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
pipe_config->pipe_bpp = 24;
/* FDI must always be 2.7 GHz */
- if (HAS_DDI(dev)) {
- pipe_config->ddi_pll_sel = PORT_CLK_SEL_SPLL;
+ if (HAS_DDI(dev))
pipe_config->port_clock = 135000 * 2;
- pipe_config->dpll_hw_state.wrpll = 0;
- pipe_config->dpll_hw_state.spll =
- SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
- }
-
return true;
}
@@ -652,6 +650,8 @@ intel_crt_detect(struct drm_connector *connector, bool force)
else if (INTEL_INFO(dev)->gen < 4)
status = intel_crt_load_detect(crt,
to_intel_crtc(connector->state->crtc)->pipe);
+ else if (i915.load_detect_test)
+ status = connector_status_disconnected;
else
status = connector_status_unknown;
intel_release_load_detect_pipe(connector, &tmp, &ctx);
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index 902054efb902..d417d9ab49b5 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -212,6 +212,24 @@ static const struct stepping_info *intel_get_stepping_info(struct drm_device *de
return NULL;
}
+static void gen9_set_dc_state_debugmask(struct drm_i915_private *dev_priv)
+{
+ uint32_t val, mask;
+
+ mask = DC_STATE_DEBUG_MASK_MEMORY_UP;
+
+ if (IS_BROXTON(dev_priv))
+ mask |= DC_STATE_DEBUG_MASK_CORES;
+
+ /* The below bit doesn't need to be cleared ever afterwards */
+ val = I915_READ(DC_STATE_DEBUG);
+ if ((val & mask) != mask) {
+ val |= mask;
+ I915_WRITE(DC_STATE_DEBUG, val);
+ POSTING_READ(DC_STATE_DEBUG);
+ }
+}
+
/**
* intel_csr_load_program() - write the firmware from memory to register.
* @dev_priv: i915 drm device.
@@ -220,19 +238,19 @@ static const struct stepping_info *intel_get_stepping_info(struct drm_device *de
* Everytime display comes back from low power state this function is called to
* copy the firmware from internal memory to registers.
*/
-bool intel_csr_load_program(struct drm_i915_private *dev_priv)
+void intel_csr_load_program(struct drm_i915_private *dev_priv)
{
u32 *payload = dev_priv->csr.dmc_payload;
uint32_t i, fw_size;
if (!IS_GEN9(dev_priv)) {
DRM_ERROR("No CSR support available for this platform\n");
- return false;
+ return;
}
if (!dev_priv->csr.dmc_payload) {
DRM_ERROR("Tried to program CSR with empty payload\n");
- return false;
+ return;
}
fw_size = dev_priv->csr.dmc_fw_size;
@@ -246,7 +264,7 @@ bool intel_csr_load_program(struct drm_i915_private *dev_priv)
dev_priv->csr.dc_state = 0;
- return true;
+ gen9_set_dc_state_debugmask(dev_priv);
}
static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
@@ -388,18 +406,12 @@ static void csr_load_work_fn(struct work_struct *work)
ret = request_firmware(&fw, dev_priv->csr.fw_path,
&dev_priv->dev->pdev->dev);
- if (!fw)
- goto out;
+ if (fw)
+ dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw);
- dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw);
- if (!dev_priv->csr.dmc_payload)
- goto out;
-
- /* load csr program during system boot, as needed for DC states */
- intel_csr_load_program(dev_priv);
-
-out:
if (dev_priv->csr.dmc_payload) {
+ intel_csr_load_program(dev_priv);
+
intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
DRM_INFO("Finished loading %s (v%u.%u)\n",
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 62de9f4bce09..91654ffc3a42 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -724,160 +724,6 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
}
#define LC_FREQ 2700
-#define LC_FREQ_2K U64_C(LC_FREQ * 2000)
-
-#define P_MIN 2
-#define P_MAX 64
-#define P_INC 2
-
-/* Constraints for PLL good behavior */
-#define REF_MIN 48
-#define REF_MAX 400
-#define VCO_MIN 2400
-#define VCO_MAX 4800
-
-#define abs_diff(a, b) ({ \
- typeof(a) __a = (a); \
- typeof(b) __b = (b); \
- (void) (&__a == &__b); \
- __a > __b ? (__a - __b) : (__b - __a); })
-
-struct hsw_wrpll_rnp {
- unsigned p, n2, r2;
-};
-
-static unsigned hsw_wrpll_get_budget_for_freq(int clock)
-{
- unsigned budget;
-
- switch (clock) {
- case 25175000:
- case 25200000:
- case 27000000:
- case 27027000:
- case 37762500:
- case 37800000:
- case 40500000:
- case 40541000:
- case 54000000:
- case 54054000:
- case 59341000:
- case 59400000:
- case 72000000:
- case 74176000:
- case 74250000:
- case 81000000:
- case 81081000:
- case 89012000:
- case 89100000:
- case 108000000:
- case 108108000:
- case 111264000:
- case 111375000:
- case 148352000:
- case 148500000:
- case 162000000:
- case 162162000:
- case 222525000:
- case 222750000:
- case 296703000:
- case 297000000:
- budget = 0;
- break;
- case 233500000:
- case 245250000:
- case 247750000:
- case 253250000:
- case 298000000:
- budget = 1500;
- break;
- case 169128000:
- case 169500000:
- case 179500000:
- case 202000000:
- budget = 2000;
- break;
- case 256250000:
- case 262500000:
- case 270000000:
- case 272500000:
- case 273750000:
- case 280750000:
- case 281250000:
- case 286000000:
- case 291750000:
- budget = 4000;
- break;
- case 267250000:
- case 268500000:
- budget = 5000;
- break;
- default:
- budget = 1000;
- break;
- }
-
- return budget;
-}
-
-static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
- unsigned r2, unsigned n2, unsigned p,
- struct hsw_wrpll_rnp *best)
-{
- uint64_t a, b, c, d, diff, diff_best;
-
- /* No best (r,n,p) yet */
- if (best->p == 0) {
- best->p = p;
- best->n2 = n2;
- best->r2 = r2;
- return;
- }
-
- /*
- * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
- * freq2k.
- *
- * delta = 1e6 *
- * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
- * freq2k;
- *
- * and we would like delta <= budget.
- *
- * If the discrepancy is above the PPM-based budget, always prefer to
- * improve upon the previous solution. However, if you're within the
- * budget, try to maximize Ref * VCO, that is N / (P * R^2).
- */
- a = freq2k * budget * p * r2;
- b = freq2k * budget * best->p * best->r2;
- diff = abs_diff(freq2k * p * r2, LC_FREQ_2K * n2);
- diff_best = abs_diff(freq2k * best->p * best->r2,
- LC_FREQ_2K * best->n2);
- c = 1000000 * diff;
- d = 1000000 * diff_best;
-
- if (a < c && b < d) {
- /* If both are above the budget, pick the closer */
- if (best->p * best->r2 * diff < p * r2 * diff_best) {
- best->p = p;
- best->n2 = n2;
- best->r2 = r2;
- }
- } else if (a >= c && b < d) {
- /* If A is below the threshold but B is above it? Update. */
- best->p = p;
- best->n2 = n2;
- best->r2 = r2;
- } else if (a >= c && b >= d) {
- /* Both are below the limit, so pick the higher n2/(r2*r2) */
- if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
- best->p = p;
- best->n2 = n2;
- best->r2 = r2;
- }
- }
- /* Otherwise a < c && b >= d, do nothing */
-}
static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
i915_reg_t reg)
@@ -1139,363 +985,20 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
bxt_ddi_clock_get(encoder, pipe_config);
}
-static void
-hsw_ddi_calculate_wrpll(int clock /* in Hz */,
- unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
-{
- uint64_t freq2k;
- unsigned p, n2, r2;
- struct hsw_wrpll_rnp best = { 0, 0, 0 };
- unsigned budget;
-
- freq2k = clock / 100;
-
- budget = hsw_wrpll_get_budget_for_freq(clock);
-
- /* Special case handling for 540 pixel clock: bypass WR PLL entirely
- * and directly pass the LC PLL to it. */
- if (freq2k == 5400000) {
- *n2_out = 2;
- *p_out = 1;
- *r2_out = 2;
- return;
- }
-
- /*
- * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
- * the WR PLL.
- *
- * We want R so that REF_MIN <= Ref <= REF_MAX.
- * Injecting R2 = 2 * R gives:
- * REF_MAX * r2 > LC_FREQ * 2 and
- * REF_MIN * r2 < LC_FREQ * 2
- *
- * Which means the desired boundaries for r2 are:
- * LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
- *
- */
- for (r2 = LC_FREQ * 2 / REF_MAX + 1;
- r2 <= LC_FREQ * 2 / REF_MIN;
- r2++) {
-
- /*
- * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
- *
- * Once again we want VCO_MIN <= VCO <= VCO_MAX.
- * Injecting R2 = 2 * R and N2 = 2 * N, we get:
- * VCO_MAX * r2 > n2 * LC_FREQ and
- * VCO_MIN * r2 < n2 * LC_FREQ)
- *
- * Which means the desired boundaries for n2 are:
- * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
- */
- for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
- n2 <= VCO_MAX * r2 / LC_FREQ;
- n2++) {
-
- for (p = P_MIN; p <= P_MAX; p += P_INC)
- hsw_wrpll_update_rnp(freq2k, budget,
- r2, n2, p, &best);
- }
- }
-
- *n2_out = best.n2;
- *p_out = best.p;
- *r2_out = best.r2;
-}
-
static bool
hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder)
{
- int clock = crtc_state->port_clock;
-
- if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
- struct intel_shared_dpll *pll;
- uint32_t val;
- unsigned p, n2, r2;
-
- hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
-
- val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
- WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
- WRPLL_DIVIDER_POST(p);
-
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
- crtc_state->dpll_hw_state.wrpll = val;
-
- pll = intel_get_shared_dpll(intel_crtc, crtc_state);
- if (pll == NULL) {
- DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
- pipe_name(intel_crtc->pipe));
- return false;
- }
-
- crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
- } else if (crtc_state->ddi_pll_sel == PORT_CLK_SEL_SPLL) {
- struct drm_atomic_state *state = crtc_state->base.state;
- struct intel_shared_dpll_config *spll =
- &intel_atomic_get_shared_dpll_state(state)[DPLL_ID_SPLL];
-
- if (spll->crtc_mask &&
- WARN_ON(spll->hw_state.spll != crtc_state->dpll_hw_state.spll))
- return false;
-
- crtc_state->shared_dpll = DPLL_ID_SPLL;
- spll->hw_state.spll = crtc_state->dpll_hw_state.spll;
- spll->crtc_mask |= 1 << intel_crtc->pipe;
- }
-
- return true;
-}
-
-struct skl_wrpll_context {
- uint64_t min_deviation; /* current minimal deviation */
- uint64_t central_freq; /* chosen central freq */
- uint64_t dco_freq; /* chosen dco freq */
- unsigned int p; /* chosen divider */
-};
-
-static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
-{
- memset(ctx, 0, sizeof(*ctx));
-
- ctx->min_deviation = U64_MAX;
-}
-
-/* DCO freq must be within +1%/-6% of the DCO central freq */
-#define SKL_DCO_MAX_PDEVIATION 100
-#define SKL_DCO_MAX_NDEVIATION 600
-
-static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
- uint64_t central_freq,
- uint64_t dco_freq,
- unsigned int divider)
-{
- uint64_t deviation;
-
- deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
- central_freq);
-
- /* positive deviation */
- if (dco_freq >= central_freq) {
- if (deviation < SKL_DCO_MAX_PDEVIATION &&
- deviation < ctx->min_deviation) {
- ctx->min_deviation = deviation;
- ctx->central_freq = central_freq;
- ctx->dco_freq = dco_freq;
- ctx->p = divider;
- }
- /* negative deviation */
- } else if (deviation < SKL_DCO_MAX_NDEVIATION &&
- deviation < ctx->min_deviation) {
- ctx->min_deviation = deviation;
- ctx->central_freq = central_freq;
- ctx->dco_freq = dco_freq;
- ctx->p = divider;
- }
-}
-
-static void skl_wrpll_get_multipliers(unsigned int p,
- unsigned int *p0 /* out */,
- unsigned int *p1 /* out */,
- unsigned int *p2 /* out */)
-{
- /* even dividers */
- if (p % 2 == 0) {
- unsigned int half = p / 2;
-
- if (half == 1 || half == 2 || half == 3 || half == 5) {
- *p0 = 2;
- *p1 = 1;
- *p2 = half;
- } else if (half % 2 == 0) {
- *p0 = 2;
- *p1 = half / 2;
- *p2 = 2;
- } else if (half % 3 == 0) {
- *p0 = 3;
- *p1 = half / 3;
- *p2 = 2;
- } else if (half % 7 == 0) {
- *p0 = 7;
- *p1 = half / 7;
- *p2 = 2;
- }
- } else if (p == 3 || p == 9) { /* 3, 5, 7, 9, 15, 21, 35 */
- *p0 = 3;
- *p1 = 1;
- *p2 = p / 3;
- } else if (p == 5 || p == 7) {
- *p0 = p;
- *p1 = 1;
- *p2 = 1;
- } else if (p == 15) {
- *p0 = 3;
- *p1 = 1;
- *p2 = 5;
- } else if (p == 21) {
- *p0 = 7;
- *p1 = 1;
- *p2 = 3;
- } else if (p == 35) {
- *p0 = 7;
- *p1 = 1;
- *p2 = 5;
- }
-}
-
-struct skl_wrpll_params {
- uint32_t dco_fraction;
- uint32_t dco_integer;
- uint32_t qdiv_ratio;
- uint32_t qdiv_mode;
- uint32_t kdiv;
- uint32_t pdiv;
- uint32_t central_freq;
-};
-
-static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
- uint64_t afe_clock,
- uint64_t central_freq,
- uint32_t p0, uint32_t p1, uint32_t p2)
-{
- uint64_t dco_freq;
-
- switch (central_freq) {
- case 9600000000ULL:
- params->central_freq = 0;
- break;
- case 9000000000ULL:
- params->central_freq = 1;
- break;
- case 8400000000ULL:
- params->central_freq = 3;
- }
-
- switch (p0) {
- case 1:
- params->pdiv = 0;
- break;
- case 2:
- params->pdiv = 1;
- break;
- case 3:
- params->pdiv = 2;
- break;
- case 7:
- params->pdiv = 4;
- break;
- default:
- WARN(1, "Incorrect PDiv\n");
- }
-
- switch (p2) {
- case 5:
- params->kdiv = 0;
- break;
- case 2:
- params->kdiv = 1;
- break;
- case 3:
- params->kdiv = 2;
- break;
- case 1:
- params->kdiv = 3;
- break;
- default:
- WARN(1, "Incorrect KDiv\n");
- }
-
- params->qdiv_ratio = p1;
- params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
-
- dco_freq = p0 * p1 * p2 * afe_clock;
-
- /*
- * Intermediate values are in Hz.
- * Divide by MHz to match bsepc
- */
- params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
- params->dco_fraction =
- div_u64((div_u64(dco_freq, 24) -
- params->dco_integer * MHz(1)) * 0x8000, MHz(1));
-}
-
-static bool
-skl_ddi_calculate_wrpll(int clock /* in Hz */,
- struct skl_wrpll_params *wrpll_params)
-{
- uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
- uint64_t dco_central_freq[3] = {8400000000ULL,
- 9000000000ULL,
- 9600000000ULL};
- static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20,
- 24, 28, 30, 32, 36, 40, 42, 44,
- 48, 52, 54, 56, 60, 64, 66, 68,
- 70, 72, 76, 78, 80, 84, 88, 90,
- 92, 96, 98 };
- static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
- static const struct {
- const int *list;
- int n_dividers;
- } dividers[] = {
- { even_dividers, ARRAY_SIZE(even_dividers) },
- { odd_dividers, ARRAY_SIZE(odd_dividers) },
- };
- struct skl_wrpll_context ctx;
- unsigned int dco, d, i;
- unsigned int p0, p1, p2;
-
- skl_wrpll_context_init(&ctx);
-
- for (d = 0; d < ARRAY_SIZE(dividers); d++) {
- for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
- for (i = 0; i < dividers[d].n_dividers; i++) {
- unsigned int p = dividers[d].list[i];
- uint64_t dco_freq = p * afe_clock;
-
- skl_wrpll_try_divider(&ctx,
- dco_central_freq[dco],
- dco_freq,
- p);
- /*
- * Skip the remaining dividers if we're sure to
- * have found the definitive divider, we can't
- * improve a 0 deviation.
- */
- if (ctx.min_deviation == 0)
- goto skip_remaining_dividers;
- }
- }
-
-skip_remaining_dividers:
- /*
- * If a solution is found with an even divider, prefer
- * this one.
- */
- if (d == 0 && ctx.p)
- break;
- }
-
- if (!ctx.p) {
- DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
- return false;
- }
+ struct intel_shared_dpll *pll;
- /*
- * gcc incorrectly analyses that these can be used without being
- * initialized. To be fair, it's hard to guess.
- */
- p0 = p1 = p2 = 0;
- skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
- skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
- p0, p1, p2);
+ pll = intel_get_shared_dpll(intel_crtc, crtc_state,
+ intel_encoder);
+ if (!pll)
+ DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+ pipe_name(intel_crtc->pipe));
- return true;
+ return pll;
}
static bool
@@ -1504,218 +1007,23 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_encoder *intel_encoder)
{
struct intel_shared_dpll *pll;
- uint32_t ctrl1, cfgcr1, cfgcr2;
- int clock = crtc_state->port_clock;
-
- /*
- * See comment in intel_dpll_hw_state to understand why we always use 0
- * as the DPLL id in this function.
- */
-
- ctrl1 = DPLL_CTRL1_OVERRIDE(0);
-
- if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
- struct skl_wrpll_params wrpll_params = { 0, };
-
- ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
-
- if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
- return false;
-
- cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
- DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
- wrpll_params.dco_integer;
-
- cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
- DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
- DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
- DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
- wrpll_params.central_freq;
- } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
- intel_encoder->type == INTEL_OUTPUT_DP_MST) {
- switch (crtc_state->port_clock / 2) {
- case 81000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
- break;
- case 135000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
- break;
- case 270000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
- break;
- }
-
- cfgcr1 = cfgcr2 = 0;
- } else if (intel_encoder->type == INTEL_OUTPUT_EDP) {
- return true;
- } else
- return false;
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
- crtc_state->dpll_hw_state.ctrl1 = ctrl1;
- crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
- crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
-
- pll = intel_get_shared_dpll(intel_crtc, crtc_state);
+ pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder);
if (pll == NULL) {
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(intel_crtc->pipe));
return false;
}
- /* shared DPLL id 0 is DPLL 1 */
- crtc_state->ddi_pll_sel = pll->id + 1;
-
return true;
}
-/* bxt clock parameters */
-struct bxt_clk_div {
- int clock;
- uint32_t p1;
- uint32_t p2;
- uint32_t m2_int;
- uint32_t m2_frac;
- bool m2_frac_en;
- uint32_t n;
-};
-
-/* pre-calculated values for DP linkrates */
-static const struct bxt_clk_div bxt_dp_clk_val[] = {
- {162000, 4, 2, 32, 1677722, 1, 1},
- {270000, 4, 1, 27, 0, 0, 1},
- {540000, 2, 1, 27, 0, 0, 1},
- {216000, 3, 2, 32, 1677722, 1, 1},
- {243000, 4, 1, 24, 1258291, 1, 1},
- {324000, 4, 1, 32, 1677722, 1, 1},
- {432000, 3, 1, 32, 1677722, 1, 1}
-};
-
static bool
bxt_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder)
{
- struct intel_shared_dpll *pll;
- struct bxt_clk_div clk_div = {0};
- int vco = 0;
- uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
- uint32_t lanestagger;
- int clock = crtc_state->port_clock;
-
- if (intel_encoder->type == INTEL_OUTPUT_HDMI) {
- intel_clock_t best_clock;
-
- /* Calculate HDMI div */
- /*
- * FIXME: tie the following calculation into
- * i9xx_crtc_compute_clock
- */
- if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
- DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
- clock, pipe_name(intel_crtc->pipe));
- return false;
- }
-
- clk_div.p1 = best_clock.p1;
- clk_div.p2 = best_clock.p2;
- WARN_ON(best_clock.m1 != 2);
- clk_div.n = best_clock.n;
- clk_div.m2_int = best_clock.m2 >> 22;
- clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
- clk_div.m2_frac_en = clk_div.m2_frac != 0;
-
- vco = best_clock.vco;
- } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
- intel_encoder->type == INTEL_OUTPUT_EDP) {
- int i;
-
- clk_div = bxt_dp_clk_val[0];
- for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
- if (bxt_dp_clk_val[i].clock == clock) {
- clk_div = bxt_dp_clk_val[i];
- break;
- }
- }
- vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
- }
-
- if (vco >= 6200000 && vco <= 6700000) {
- prop_coef = 4;
- int_coef = 9;
- gain_ctl = 3;
- targ_cnt = 8;
- } else if ((vco > 5400000 && vco < 6200000) ||
- (vco >= 4800000 && vco < 5400000)) {
- prop_coef = 5;
- int_coef = 11;
- gain_ctl = 3;
- targ_cnt = 9;
- } else if (vco == 5400000) {
- prop_coef = 3;
- int_coef = 8;
- gain_ctl = 1;
- targ_cnt = 9;
- } else {
- DRM_ERROR("Invalid VCO\n");
- return false;
- }
-
- memset(&crtc_state->dpll_hw_state, 0,
- sizeof(crtc_state->dpll_hw_state));
-
- if (clock > 270000)
- lanestagger = 0x18;
- else if (clock > 135000)
- lanestagger = 0x0d;
- else if (clock > 67000)
- lanestagger = 0x07;
- else if (clock > 33000)
- lanestagger = 0x04;
- else
- lanestagger = 0x02;
-
- crtc_state->dpll_hw_state.ebb0 =
- PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
- crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
- crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
- crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
-
- if (clk_div.m2_frac_en)
- crtc_state->dpll_hw_state.pll3 =
- PORT_PLL_M2_FRAC_ENABLE;
-
- crtc_state->dpll_hw_state.pll6 =
- prop_coef | PORT_PLL_INT_COEFF(int_coef);
- crtc_state->dpll_hw_state.pll6 |=
- PORT_PLL_GAIN_CTL(gain_ctl);
-
- crtc_state->dpll_hw_state.pll8 = targ_cnt;
-
- crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
-
- crtc_state->dpll_hw_state.pll10 =
- PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
- | PORT_PLL_DCO_AMP_OVR_EN_H;
-
- crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
-
- crtc_state->dpll_hw_state.pcsdw12 =
- LANESTAGGER_STRAP_OVRD | lanestagger;
-
- pll = intel_get_shared_dpll(intel_crtc, crtc_state);
- if (pll == NULL) {
- DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
- pipe_name(intel_crtc->pipe));
- return false;
- }
-
- /* shared DPLL id 0 is DPLL A */
- crtc_state->ddi_pll_sel = pll->id;
-
- return true;
+ return !!intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder);
}
/*
@@ -2259,24 +1567,6 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
uint32_t dpll = pipe_config->ddi_pll_sel;
uint32_t val;
- /*
- * DPLL0 is used for eDP and is the only "private" DPLL (as
- * opposed to shared) on SKL
- */
- if (encoder->type == INTEL_OUTPUT_EDP) {
- WARN_ON(dpll != SKL_DPLL0);
-
- val = I915_READ(DPLL_CTRL1);
-
- val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
- DPLL_CTRL1_SSC(dpll) |
- DPLL_CTRL1_LINK_RATE_MASK(dpll));
- val |= pipe_config->dpll_hw_state.ctrl1 << (dpll * 6);
-
- I915_WRITE(DPLL_CTRL1, val);
- POSTING_READ(DPLL_CTRL1);
- }
-
/* DDI -> PLL mapping */
val = I915_READ(DPLL_CTRL2);
@@ -2430,235 +1720,6 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
}
}
-static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
- POSTING_READ(WRPLL_CTL(pll->id));
- udelay(20);
-}
-
-static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
- POSTING_READ(SPLL_CTL);
- udelay(20);
-}
-
-static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- uint32_t val;
-
- val = I915_READ(WRPLL_CTL(pll->id));
- I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
- POSTING_READ(WRPLL_CTL(pll->id));
-}
-
-static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- uint32_t val;
-
- val = I915_READ(SPLL_CTL);
- I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
- POSTING_READ(SPLL_CTL);
-}
-
-static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state)
-{
- uint32_t val;
-
- if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
- return false;
-
- val = I915_READ(WRPLL_CTL(pll->id));
- hw_state->wrpll = val;
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
- return val & WRPLL_PLL_ENABLE;
-}
-
-static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state)
-{
- uint32_t val;
-
- if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
- return false;
-
- val = I915_READ(SPLL_CTL);
- hw_state->spll = val;
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
- return val & SPLL_PLL_ENABLE;
-}
-
-
-static const char * const hsw_ddi_pll_names[] = {
- "WRPLL 1",
- "WRPLL 2",
- "SPLL"
-};
-
-static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
-{
- int i;
-
- dev_priv->num_shared_dpll = 3;
-
- for (i = 0; i < 2; i++) {
- dev_priv->shared_dplls[i].id = i;
- dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
- dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
- dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
- dev_priv->shared_dplls[i].get_hw_state =
- hsw_ddi_wrpll_get_hw_state;
- }
-
- /* SPLL is special, but needs to be initialized anyway.. */
- dev_priv->shared_dplls[i].id = i;
- dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
- dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
- dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
- dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
-
-}
-
-static const char * const skl_ddi_pll_names[] = {
- "DPLL 1",
- "DPLL 2",
- "DPLL 3",
-};
-
-struct skl_dpll_regs {
- i915_reg_t ctl, cfgcr1, cfgcr2;
-};
-
-/* this array is indexed by the *shared* pll id */
-static const struct skl_dpll_regs skl_dpll_regs[3] = {
- {
- /* DPLL 1 */
- .ctl = LCPLL2_CTL,
- .cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
- .cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
- },
- {
- /* DPLL 2 */
- .ctl = WRPLL_CTL(0),
- .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
- .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
- },
- {
- /* DPLL 3 */
- .ctl = WRPLL_CTL(1),
- .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
- .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
- },
-};
-
-static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- uint32_t val;
- unsigned int dpll;
- const struct skl_dpll_regs *regs = skl_dpll_regs;
-
- /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
- dpll = pll->id + 1;
-
- val = I915_READ(DPLL_CTRL1);
-
- val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) |
- DPLL_CTRL1_LINK_RATE_MASK(dpll));
- val |= pll->config.hw_state.ctrl1 << (dpll * 6);
-
- I915_WRITE(DPLL_CTRL1, val);
- POSTING_READ(DPLL_CTRL1);
-
- I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
- I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
- POSTING_READ(regs[pll->id].cfgcr1);
- POSTING_READ(regs[pll->id].cfgcr2);
-
- /* the enable bit is always bit 31 */
- I915_WRITE(regs[pll->id].ctl,
- I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
-
- if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5))
- DRM_ERROR("DPLL %d not locked\n", dpll);
-}
-
-static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- const struct skl_dpll_regs *regs = skl_dpll_regs;
-
- /* the enable bit is always bit 31 */
- I915_WRITE(regs[pll->id].ctl,
- I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
- POSTING_READ(regs[pll->id].ctl);
-}
-
-static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state)
-{
- uint32_t val;
- unsigned int dpll;
- const struct skl_dpll_regs *regs = skl_dpll_regs;
- bool ret;
-
- if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
- return false;
-
- ret = false;
-
- /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
- dpll = pll->id + 1;
-
- val = I915_READ(regs[pll->id].ctl);
- if (!(val & LCPLL_PLL_ENABLE))
- goto out;
-
- val = I915_READ(DPLL_CTRL1);
- hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
-
- /* avoid reading back stale values if HDMI mode is not enabled */
- if (val & DPLL_CTRL1_HDMI_MODE(dpll)) {
- hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
- hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
- }
- ret = true;
-
-out:
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
- return ret;
-}
-
-static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
-{
- int i;
-
- dev_priv->num_shared_dpll = 3;
-
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
- dev_priv->shared_dplls[i].id = i;
- dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i];
- dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable;
- dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable;
- dev_priv->shared_dplls[i].get_hw_state =
- skl_ddi_pll_get_hw_state;
- }
-}
-
static void broxton_phy_init(struct drm_i915_private *dev_priv,
enum dpio_phy phy)
{
@@ -2783,249 +1844,6 @@ void broxton_ddi_phy_uninit(struct drm_device *dev)
I915_WRITE(BXT_P_CR_GT_DISP_PWRON, 0);
}
-static const char * const bxt_ddi_pll_names[] = {
- "PORT PLL A",
- "PORT PLL B",
- "PORT PLL C",
-};
-
-static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- uint32_t temp;
- enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
-
- temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
- temp &= ~PORT_PLL_REF_SEL;
- /* Non-SSC reference */
- I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
-
- /* Disable 10 bit clock */
- temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
- temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
- I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
-
- /* Write P1 & P2 */
- temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
- temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
- temp |= pll->config.hw_state.ebb0;
- I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
-
- /* Write M2 integer */
- temp = I915_READ(BXT_PORT_PLL(port, 0));
- temp &= ~PORT_PLL_M2_MASK;
- temp |= pll->config.hw_state.pll0;
- I915_WRITE(BXT_PORT_PLL(port, 0), temp);
-
- /* Write N */
- temp = I915_READ(BXT_PORT_PLL(port, 1));
- temp &= ~PORT_PLL_N_MASK;
- temp |= pll->config.hw_state.pll1;
- I915_WRITE(BXT_PORT_PLL(port, 1), temp);
-
- /* Write M2 fraction */
- temp = I915_READ(BXT_PORT_PLL(port, 2));
- temp &= ~PORT_PLL_M2_FRAC_MASK;
- temp |= pll->config.hw_state.pll2;
- I915_WRITE(BXT_PORT_PLL(port, 2), temp);
-
- /* Write M2 fraction enable */
- temp = I915_READ(BXT_PORT_PLL(port, 3));
- temp &= ~PORT_PLL_M2_FRAC_ENABLE;
- temp |= pll->config.hw_state.pll3;
- I915_WRITE(BXT_PORT_PLL(port, 3), temp);
-
- /* Write coeff */
- temp = I915_READ(BXT_PORT_PLL(port, 6));
- temp &= ~PORT_PLL_PROP_COEFF_MASK;
- temp &= ~PORT_PLL_INT_COEFF_MASK;
- temp &= ~PORT_PLL_GAIN_CTL_MASK;
- temp |= pll->config.hw_state.pll6;
- I915_WRITE(BXT_PORT_PLL(port, 6), temp);
-
- /* Write calibration val */
- temp = I915_READ(BXT_PORT_PLL(port, 8));
- temp &= ~PORT_PLL_TARGET_CNT_MASK;
- temp |= pll->config.hw_state.pll8;
- I915_WRITE(BXT_PORT_PLL(port, 8), temp);
-
- temp = I915_READ(BXT_PORT_PLL(port, 9));
- temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
- temp |= pll->config.hw_state.pll9;
- I915_WRITE(BXT_PORT_PLL(port, 9), temp);
-
- temp = I915_READ(BXT_PORT_PLL(port, 10));
- temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
- temp &= ~PORT_PLL_DCO_AMP_MASK;
- temp |= pll->config.hw_state.pll10;
- I915_WRITE(BXT_PORT_PLL(port, 10), temp);
-
- /* Recalibrate with new settings */
- temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
- temp |= PORT_PLL_RECALIBRATE;
- I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
- temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
- temp |= pll->config.hw_state.ebb4;
- I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
-
- /* Enable PLL */
- temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
- temp |= PORT_PLL_ENABLE;
- I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
- POSTING_READ(BXT_PORT_PLL_ENABLE(port));
-
- if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
- PORT_PLL_LOCK), 200))
- DRM_ERROR("PLL %d not locked\n", port);
-
- /*
- * While we write to the group register to program all lanes at once we
- * can read only lane registers and we pick lanes 0/1 for that.
- */
- temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
- temp &= ~LANE_STAGGER_MASK;
- temp &= ~LANESTAGGER_STRAP_OVRD;
- temp |= pll->config.hw_state.pcsdw12;
- I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
-}
-
-static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
- uint32_t temp;
-
- temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
- temp &= ~PORT_PLL_ENABLE;
- I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
- POSTING_READ(BXT_PORT_PLL_ENABLE(port));
-}
-
-static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state)
-{
- enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
- uint32_t val;
- bool ret;
-
- if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
- return false;
-
- ret = false;
-
- val = I915_READ(BXT_PORT_PLL_ENABLE(port));
- if (!(val & PORT_PLL_ENABLE))
- goto out;
-
- hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
- hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
-
- hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
- hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
-
- hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
- hw_state->pll0 &= PORT_PLL_M2_MASK;
-
- hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
- hw_state->pll1 &= PORT_PLL_N_MASK;
-
- hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
- hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
-
- hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
- hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
-
- hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
- hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
- PORT_PLL_INT_COEFF_MASK |
- PORT_PLL_GAIN_CTL_MASK;
-
- hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
- hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
-
- hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
- hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
-
- hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
- hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
- PORT_PLL_DCO_AMP_MASK;
-
- /*
- * While we write to the group register to program all lanes at once we
- * can read only lane registers. We configure all lanes the same way, so
- * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
- */
- hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
- if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
- DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
- hw_state->pcsdw12,
- I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
- hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
-
- ret = true;
-
-out:
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
- return ret;
-}
-
-static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
-{
- int i;
-
- dev_priv->num_shared_dpll = 3;
-
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
- dev_priv->shared_dplls[i].id = i;
- dev_priv->shared_dplls[i].name = bxt_ddi_pll_names[i];
- dev_priv->shared_dplls[i].disable = bxt_ddi_pll_disable;
- dev_priv->shared_dplls[i].enable = bxt_ddi_pll_enable;
- dev_priv->shared_dplls[i].get_hw_state =
- bxt_ddi_pll_get_hw_state;
- }
-}
-
-void intel_ddi_pll_init(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t val = I915_READ(LCPLL_CTL);
-
- if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
- skl_shared_dplls_init(dev_priv);
- else if (IS_BROXTON(dev))
- bxt_shared_dplls_init(dev_priv);
- else
- hsw_shared_dplls_init(dev_priv);
-
- if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
- int cdclk_freq;
-
- cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
- dev_priv->skl_boot_cdclk = cdclk_freq;
- if (skl_sanitize_cdclk(dev_priv))
- DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
- if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
- DRM_ERROR("LCPLL1 is disabled\n");
- } else if (IS_BROXTON(dev)) {
- broxton_init_cdclk(dev);
- broxton_ddi_phy_init(dev);
- } else {
- /*
- * The LCPLL register should be turned on by the BIOS. For now
- * let's just check its state and print errors in case
- * something is wrong. Don't even try to turn it on.
- */
-
- if (val & LCPLL_CD_SOURCE_FCLK)
- DRM_ERROR("CDCLK source is not LCPLL\n");
-
- if (val & LCPLL_PLL_DISABLE)
- DRM_ERROR("LCPLL is disabled\n");
- }
-}
-
void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8b7b8b64b008..ce55f0b683c6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -116,7 +116,7 @@ static void skylake_pfit_enable(struct intel_crtc *crtc);
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
static void ironlake_pfit_enable(struct intel_crtc *crtc);
static void intel_modeset_setup_hw_state(struct drm_device *dev);
-static void intel_pre_disable_primary(struct drm_crtc *crtc);
+static void intel_pre_disable_primary_noatomic(struct drm_crtc *crtc);
typedef struct {
int min, max;
@@ -169,49 +169,62 @@ static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1);
}
-int
-intel_pch_rawclk(struct drm_device *dev)
+static int
+intel_pch_rawclk(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- WARN_ON(!HAS_PCH_SPLIT(dev));
+ return (I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK) * 1000;
+}
- return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK;
+static int
+intel_vlv_hrawclk(struct drm_i915_private *dev_priv)
+{
+ return vlv_get_cck_clock_hpll(dev_priv, "hrawclk",
+ CCK_DISPLAY_REF_CLOCK_CONTROL);
}
-/* hrawclock is 1/4 the FSB frequency */
-int intel_hrawclk(struct drm_device *dev)
+static int
+intel_g4x_hrawclk(struct drm_i915_private *dev_priv)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t clkcfg;
- /* There is no CLKCFG reg in Valleyview. VLV hrawclk is 200 MHz */
- if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
- return 200;
-
+ /* hrawclock is 1/4 the FSB frequency */
clkcfg = I915_READ(CLKCFG);
switch (clkcfg & CLKCFG_FSB_MASK) {
case CLKCFG_FSB_400:
- return 100;
+ return 100000;
case CLKCFG_FSB_533:
- return 133;
+ return 133333;
case CLKCFG_FSB_667:
- return 166;
+ return 166667;
case CLKCFG_FSB_800:
- return 200;
+ return 200000;
case CLKCFG_FSB_1067:
- return 266;
+ return 266667;
case CLKCFG_FSB_1333:
- return 333;
+ return 333333;
/* these two are just a guess; one of them might be right */
case CLKCFG_FSB_1600:
case CLKCFG_FSB_1600_ALT:
- return 400;
+ return 400000;
default:
- return 133;
+ return 133333;
}
}
+static void intel_update_rawclk(struct drm_i915_private *dev_priv)
+{
+ if (HAS_PCH_SPLIT(dev_priv))
+ dev_priv->rawclk_freq = intel_pch_rawclk(dev_priv);
+ else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+ dev_priv->rawclk_freq = intel_vlv_hrawclk(dev_priv);
+ else if (IS_G4X(dev_priv) || IS_PINEVIEW(dev_priv))
+ dev_priv->rawclk_freq = intel_g4x_hrawclk(dev_priv);
+ else
+ return; /* no rawclk on other platforms, or no need to know it */
+
+ DRM_DEBUG_DRIVER("rawclk rate: %d kHz\n", dev_priv->rawclk_freq);
+}
+
static void intel_update_czclk(struct drm_i915_private *dev_priv)
{
if (!(IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)))
@@ -224,13 +237,15 @@ static void intel_update_czclk(struct drm_i915_private *dev_priv)
}
static inline u32 /* units of 100MHz */
-intel_fdi_link_freq(struct drm_device *dev)
+intel_fdi_link_freq(struct drm_i915_private *dev_priv,
+ const struct intel_crtc_state *pipe_config)
{
- if (IS_GEN5(dev)) {
- struct drm_i915_private *dev_priv = dev->dev_private;
- return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
- } else
- return 27;
+ if (HAS_DDI(dev_priv))
+ return pipe_config->port_clock; /* SPLL */
+ else if (IS_GEN5(dev_priv))
+ return ((I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2) * 10000;
+ else
+ return 270000;
}
static const intel_limit_t intel_limits_i8xx_dac = {
@@ -1182,34 +1197,6 @@ static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
#define assert_dsi_pll_enabled(d) assert_dsi_pll(d, true)
#define assert_dsi_pll_disabled(d) assert_dsi_pll(d, false)
-struct intel_shared_dpll *
-intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
-{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
-
- if (crtc->config->shared_dpll < 0)
- return NULL;
-
- return &dev_priv->shared_dplls[crtc->config->shared_dpll];
-}
-
-/* For ILK+ */
-void assert_shared_dpll(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- bool state)
-{
- bool cur_state;
- struct intel_dpll_hw_state hw_state;
-
- if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
- return;
-
- cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
- I915_STATE_WARN(cur_state != state,
- "%s assertion failure (expected %s, current %s)\n",
- pll->name, onoff(state), onoff(cur_state));
-}
-
static void assert_fdi_tx(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
@@ -1446,21 +1433,8 @@ static void assert_vblank_disabled(struct drm_crtc *crtc)
drm_crtc_vblank_put(crtc);
}
-static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
-{
- u32 val;
- bool enabled;
-
- I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
-
- val = I915_READ(PCH_DREF_CONTROL);
- enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
- DREF_SUPERSPREAD_SOURCE_MASK));
- I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
-}
-
-static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
{
u32 val;
bool enabled;
@@ -1856,100 +1830,6 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
port_name(dport->port), I915_READ(dpll_reg) & port_mask, expected_mask);
}
-static void intel_prepare_shared_dpll(struct intel_crtc *crtc)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
- if (WARN_ON(pll == NULL))
- return;
-
- WARN_ON(!pll->config.crtc_mask);
- if (pll->active == 0) {
- DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
- WARN_ON(pll->on);
- assert_shared_dpll_disabled(dev_priv, pll);
-
- pll->mode_set(dev_priv, pll);
- }
-}
-
-/**
- * intel_enable_shared_dpll - enable PCH PLL
- * @dev_priv: i915 private structure
- * @pipe: pipe PLL to enable
- *
- * The PCH PLL needs to be enabled before the PCH transcoder, since it
- * drives the transcoder clock.
- */
-static void intel_enable_shared_dpll(struct intel_crtc *crtc)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
- if (WARN_ON(pll == NULL))
- return;
-
- if (WARN_ON(pll->config.crtc_mask == 0))
- return;
-
- DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n",
- pll->name, pll->active, pll->on,
- crtc->base.base.id);
-
- if (pll->active++) {
- WARN_ON(!pll->on);
- assert_shared_dpll_enabled(dev_priv, pll);
- return;
- }
- WARN_ON(pll->on);
-
- intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
-
- DRM_DEBUG_KMS("enabling %s\n", pll->name);
- pll->enable(dev_priv, pll);
- pll->on = true;
-}
-
-static void intel_disable_shared_dpll(struct intel_crtc *crtc)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
-
- /* PCH only available on ILK+ */
- if (INTEL_INFO(dev)->gen < 5)
- return;
-
- if (pll == NULL)
- return;
-
- if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base)))))
- return;
-
- DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n",
- pll->name, pll->active, pll->on,
- crtc->base.base.id);
-
- if (WARN_ON(pll->active == 0)) {
- assert_shared_dpll_disabled(dev_priv, pll);
- return;
- }
-
- assert_shared_dpll_enabled(dev_priv, pll);
- WARN_ON(!pll->on);
- if (--pll->active)
- return;
-
- DRM_DEBUG_KMS("disabling %s\n", pll->name);
- pll->disable(dev_priv, pll);
- pll->on = false;
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-}
-
static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
@@ -1963,8 +1843,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
BUG_ON(!HAS_PCH_SPLIT(dev));
/* Make sure PCH DPLL is enabled */
- assert_shared_dpll_enabled(dev_priv,
- intel_crtc_to_shared_dpll(intel_crtc));
+ assert_shared_dpll_enabled(dev_priv, intel_crtc->config->shared_dpll);
/* FDI must be feeding us bits for PCH ports */
assert_fdi_tx_enabled(dev_priv, pipe);
@@ -2225,8 +2104,8 @@ static unsigned int intel_tile_size(const struct drm_i915_private *dev_priv)
return IS_GEN2(dev_priv) ? 2048 : 4096;
}
-static unsigned int intel_tile_width(const struct drm_i915_private *dev_priv,
- uint64_t fb_modifier, unsigned int cpp)
+static unsigned int intel_tile_width_bytes(const struct drm_i915_private *dev_priv,
+ uint64_t fb_modifier, unsigned int cpp)
{
switch (fb_modifier) {
case DRM_FORMAT_MOD_NONE:
@@ -2269,7 +2148,21 @@ unsigned int intel_tile_height(const struct drm_i915_private *dev_priv,
return 1;
else
return intel_tile_size(dev_priv) /
- intel_tile_width(dev_priv, fb_modifier, cpp);
+ intel_tile_width_bytes(dev_priv, fb_modifier, cpp);
+}
+
+/* Return the tile dimensions in pixel units */
+static void intel_tile_dims(const struct drm_i915_private *dev_priv,
+ unsigned int *tile_width,
+ unsigned int *tile_height,
+ uint64_t fb_modifier,
+ unsigned int cpp)
+{
+ unsigned int tile_width_bytes =
+ intel_tile_width_bytes(dev_priv, fb_modifier, cpp);
+
+ *tile_width = tile_width_bytes / cpp;
+ *tile_height = intel_tile_size(dev_priv) / tile_width_bytes;
}
unsigned int
@@ -2282,48 +2175,54 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height,
return ALIGN(height, tile_height);
}
-static void
-intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
- const struct drm_plane_state *plane_state)
+unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info)
{
- struct drm_i915_private *dev_priv = to_i915(fb->dev);
- struct intel_rotation_info *info = &view->params.rotated;
- unsigned int tile_size, tile_width, tile_height, cpp;
-
- *view = i915_ggtt_view_normal;
+ unsigned int size = 0;
+ int i;
- if (!plane_state)
- return;
+ for (i = 0 ; i < ARRAY_SIZE(rot_info->plane); i++)
+ size += rot_info->plane[i].width * rot_info->plane[i].height;
- if (!intel_rotation_90_or_270(plane_state->rotation))
- return;
+ return size;
+}
- *view = i915_ggtt_view_rotated;
+static void
+intel_fill_fb_ggtt_view(struct i915_ggtt_view *view,
+ const struct drm_framebuffer *fb,
+ unsigned int rotation)
+{
+ if (intel_rotation_90_or_270(rotation)) {
+ *view = i915_ggtt_view_rotated;
+ view->params.rotated = to_intel_framebuffer(fb)->rot_info;
+ } else {
+ *view = i915_ggtt_view_normal;
+ }
+}
- info->height = fb->height;
- info->pixel_format = fb->pixel_format;
- info->pitch = fb->pitches[0];
- info->uv_offset = fb->offsets[1];
- info->fb_modifier = fb->modifier[0];
+static void
+intel_fill_fb_info(struct drm_i915_private *dev_priv,
+ struct drm_framebuffer *fb)
+{
+ struct intel_rotation_info *info = &to_intel_framebuffer(fb)->rot_info;
+ unsigned int tile_size, tile_width, tile_height, cpp;
tile_size = intel_tile_size(dev_priv);
cpp = drm_format_plane_cpp(fb->pixel_format, 0);
- tile_width = intel_tile_width(dev_priv, fb->modifier[0], cpp);
- tile_height = tile_size / tile_width;
+ intel_tile_dims(dev_priv, &tile_width, &tile_height,
+ fb->modifier[0], cpp);
- info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_width);
- info->height_pages = DIV_ROUND_UP(fb->height, tile_height);
- info->size = info->width_pages * info->height_pages * tile_size;
+ info->plane[0].width = DIV_ROUND_UP(fb->pitches[0], tile_width * cpp);
+ info->plane[0].height = DIV_ROUND_UP(fb->height, tile_height);
if (info->pixel_format == DRM_FORMAT_NV12) {
cpp = drm_format_plane_cpp(fb->pixel_format, 1);
- tile_width = intel_tile_width(dev_priv, fb->modifier[1], cpp);
- tile_height = tile_size / tile_width;
+ intel_tile_dims(dev_priv, &tile_width, &tile_height,
+ fb->modifier[1], cpp);
- info->width_pages_uv = DIV_ROUND_UP(fb->pitches[1], tile_width);
- info->height_pages_uv = DIV_ROUND_UP(fb->height / 2, tile_height);
- info->size_uv = info->width_pages_uv * info->height_pages_uv * tile_size;
+ info->uv_offset = fb->offsets[1];
+ info->plane[1].width = DIV_ROUND_UP(fb->pitches[1], tile_width * cpp);
+ info->plane[1].height = DIV_ROUND_UP(fb->height / 2, tile_height);
}
}
@@ -2360,9 +2259,8 @@ static unsigned int intel_surf_alignment(const struct drm_i915_private *dev_priv
}
int
-intel_pin_and_fence_fb_obj(struct drm_plane *plane,
- struct drm_framebuffer *fb,
- const struct drm_plane_state *plane_state)
+intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
+ unsigned int rotation)
{
struct drm_device *dev = fb->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2375,7 +2273,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
- intel_fill_fb_ggtt_view(&view, fb, plane_state);
+ intel_fill_fb_ggtt_view(&view, fb, rotation);
/* Note that the w/a also requires 64 PTE of padding following the
* bo. We currently fill all unused PTE with the shadow page and so
@@ -2433,15 +2331,14 @@ err_pm:
return ret;
}
-static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
- const struct drm_plane_state *plane_state)
+static void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
{
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct i915_ggtt_view view;
WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
- intel_fill_fb_ggtt_view(&view, fb, plane_state);
+ intel_fill_fb_ggtt_view(&view, fb, rotation);
if (view.type == I915_GGTT_VIEW_NORMAL)
i915_gem_object_unpin_fence(obj);
@@ -2449,38 +2346,93 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
i915_gem_object_unpin_from_display_plane(obj, &view);
}
-/* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
- * is assumed to be a power-of-two. */
-u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv,
- int *x, int *y,
- uint64_t fb_modifier,
- unsigned int cpp,
- unsigned int pitch)
+/*
+ * Adjust the tile offset by moving the difference into
+ * the x/y offsets.
+ *
+ * Input tile dimensions and pitch must already be
+ * rotated to match x and y, and in pixel units.
+ */
+static u32 intel_adjust_tile_offset(int *x, int *y,
+ unsigned int tile_width,
+ unsigned int tile_height,
+ unsigned int tile_size,
+ unsigned int pitch_tiles,
+ u32 old_offset,
+ u32 new_offset)
{
+ unsigned int tiles;
+
+ WARN_ON(old_offset & (tile_size - 1));
+ WARN_ON(new_offset & (tile_size - 1));
+ WARN_ON(new_offset > old_offset);
+
+ tiles = (old_offset - new_offset) / tile_size;
+
+ *y += tiles / pitch_tiles * tile_height;
+ *x += tiles % pitch_tiles * tile_width;
+
+ return new_offset;
+}
+
+/*
+ * Computes the linear offset to the base tile and adjusts
+ * x, y. bytes per pixel is assumed to be a power-of-two.
+ *
+ * In the 90/270 rotated case, x and y are assumed
+ * to be already rotated to match the rotated GTT view, and
+ * pitch is the tile_height aligned framebuffer height.
+ */
+u32 intel_compute_tile_offset(int *x, int *y,
+ const struct drm_framebuffer *fb, int plane,
+ unsigned int pitch,
+ unsigned int rotation)
+{
+ const struct drm_i915_private *dev_priv = to_i915(fb->dev);
+ uint64_t fb_modifier = fb->modifier[plane];
+ unsigned int cpp = drm_format_plane_cpp(fb->pixel_format, plane);
+ u32 offset, offset_aligned, alignment;
+
+ alignment = intel_surf_alignment(dev_priv, fb_modifier);
+ if (alignment)
+ alignment--;
+
if (fb_modifier != DRM_FORMAT_MOD_NONE) {
unsigned int tile_size, tile_width, tile_height;
- unsigned int tile_rows, tiles;
+ unsigned int tile_rows, tiles, pitch_tiles;
tile_size = intel_tile_size(dev_priv);
- tile_width = intel_tile_width(dev_priv, fb_modifier, cpp);
- tile_height = tile_size / tile_width;
+ intel_tile_dims(dev_priv, &tile_width, &tile_height,
+ fb_modifier, cpp);
+
+ if (intel_rotation_90_or_270(rotation)) {
+ pitch_tiles = pitch / tile_height;
+ swap(tile_width, tile_height);
+ } else {
+ pitch_tiles = pitch / (tile_width * cpp);
+ }
tile_rows = *y / tile_height;
*y %= tile_height;
- tiles = *x / (tile_width/cpp);
- *x %= tile_width/cpp;
+ tiles = *x / tile_width;
+ *x %= tile_width;
- return tile_rows * pitch * tile_height + tiles * tile_size;
- } else {
- unsigned int alignment = intel_linear_alignment(dev_priv) - 1;
- unsigned int offset;
+ offset = (tile_rows * pitch_tiles + tiles) * tile_size;
+ offset_aligned = offset & ~alignment;
+ intel_adjust_tile_offset(x, y, tile_width, tile_height,
+ tile_size, pitch_tiles,
+ offset, offset_aligned);
+ } else {
offset = *y * pitch + *x * cpp;
+ offset_aligned = offset & ~alignment;
+
*y = (offset & alignment) / pitch;
*x = ((offset & alignment) - *y * pitch) / cpp;
- return offset & ~alignment;
}
+
+ return offset_aligned;
}
static int i9xx_format_to_fourcc(int format)
@@ -2667,7 +2619,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
*/
to_intel_plane_state(plane_state)->visible = false;
crtc_state->plane_mask &= ~(1 << drm_plane_index(primary));
- intel_pre_disable_primary(&intel_crtc->base);
+ intel_pre_disable_primary_noatomic(&intel_crtc->base);
intel_plane->disable_plane(primary, &intel_crtc->base);
return;
@@ -2716,6 +2668,7 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
u32 linear_offset;
u32 dspcntr;
i915_reg_t reg = DSPCNTR(plane);
+ unsigned int rotation = plane_state->base.rotation;
int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
int x = plane_state->src.x1 >> 16;
int y = plane_state->src.y1 >> 16;
@@ -2780,15 +2733,14 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
if (INTEL_INFO(dev)->gen >= 4) {
intel_crtc->dspaddr_offset =
- intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0], cpp,
- fb->pitches[0]);
+ intel_compute_tile_offset(&x, &y, fb, 0,
+ fb->pitches[0], rotation);
linear_offset -= intel_crtc->dspaddr_offset;
} else {
intel_crtc->dspaddr_offset = linear_offset;
}
- if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+ if (rotation == BIT(DRM_ROTATE_180)) {
dspcntr |= DISPPLANE_ROTATE_180;
x += (crtc_state->pipe_src_w - 1);
@@ -2846,6 +2798,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
u32 linear_offset;
u32 dspcntr;
i915_reg_t reg = DSPCNTR(plane);
+ unsigned int rotation = plane_state->base.rotation;
int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
int x = plane_state->src.x1 >> 16;
int y = plane_state->src.y1 >> 16;
@@ -2887,11 +2840,10 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
linear_offset = y * fb->pitches[0] + x * cpp;
intel_crtc->dspaddr_offset =
- intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0], cpp,
- fb->pitches[0]);
+ intel_compute_tile_offset(&x, &y, fb, 0,
+ fb->pitches[0], rotation);
linear_offset -= intel_crtc->dspaddr_offset;
- if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+ if (rotation == BIT(DRM_ROTATE_180)) {
dspcntr |= DISPPLANE_ROTATE_180;
if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
@@ -2931,7 +2883,7 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
} else {
int cpp = drm_format_plane_cpp(pixel_format, 0);
- return intel_tile_width(dev_priv, fb_modifier, cpp);
+ return intel_tile_width_bytes(dev_priv, fb_modifier, cpp);
}
}
@@ -2944,7 +2896,7 @@ u32 intel_plane_obj_offset(struct intel_plane *intel_plane,
u64 offset;
intel_fill_fb_ggtt_view(&view, intel_plane->base.state->fb,
- intel_plane->base.state);
+ intel_plane->base.state->rotation);
vma = i915_gem_obj_to_ggtt_view(obj, &view);
if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
@@ -3955,37 +3907,35 @@ static void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
/* Program iCLKIP clock to the desired frequency */
static void lpt_program_iclkip(struct drm_crtc *crtc)
{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(crtc->dev);
int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
u32 divsel, phaseinc, auxdiv, phasedir = 0;
u32 temp;
lpt_disable_iclkip(dev_priv);
- /* 20MHz is a corner case which is out of range for the 7-bit divisor */
- if (clock == 20000) {
- auxdiv = 1;
- divsel = 0x41;
- phaseinc = 0x20;
- } else {
- /* The iCLK virtual clock root frequency is in MHz,
- * but the adjusted_mode->crtc_clock in in KHz. To get the
- * divisors, it is necessary to divide one by another, so we
- * convert the virtual clock precision to KHz here for higher
- * precision.
- */
+ /* The iCLK virtual clock root frequency is in MHz,
+ * but the adjusted_mode->crtc_clock in in KHz. To get the
+ * divisors, it is necessary to divide one by another, so we
+ * convert the virtual clock precision to KHz here for higher
+ * precision.
+ */
+ for (auxdiv = 0; auxdiv < 2; auxdiv++) {
u32 iclk_virtual_root_freq = 172800 * 1000;
u32 iclk_pi_range = 64;
- u32 desired_divisor, msb_divisor_value, pi_value;
+ u32 desired_divisor;
- desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq, clock);
- msb_divisor_value = desired_divisor / iclk_pi_range;
- pi_value = desired_divisor % iclk_pi_range;
+ desired_divisor = DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
+ clock << auxdiv);
+ divsel = (desired_divisor / iclk_pi_range) - 2;
+ phaseinc = desired_divisor % iclk_pi_range;
- auxdiv = 0;
- divsel = msb_divisor_value - 2;
- phaseinc = pi_value;
+ /*
+ * Near 20MHz is a corner case which is
+ * out of range for the 7-bit divisor
+ */
+ if (divsel <= 0x7f)
+ break;
}
/* This should not happen with any sane values */
@@ -4032,6 +3982,43 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
}
+int lpt_get_iclkip(struct drm_i915_private *dev_priv)
+{
+ u32 divsel, phaseinc, auxdiv;
+ u32 iclk_virtual_root_freq = 172800 * 1000;
+ u32 iclk_pi_range = 64;
+ u32 desired_divisor;
+ u32 temp;
+
+ if ((I915_READ(PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
+ return 0;
+
+ mutex_lock(&dev_priv->sb_lock);
+
+ temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
+ if (temp & SBI_SSCCTL_DISABLE) {
+ mutex_unlock(&dev_priv->sb_lock);
+ return 0;
+ }
+
+ temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
+ divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
+ SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
+ phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
+ SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
+
+ temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
+ auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
+ SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
+
+ mutex_unlock(&dev_priv->sb_lock);
+
+ desired_divisor = (divsel + 2) * iclk_pi_range + phaseinc;
+
+ return DIV_ROUND_CLOSEST(iclk_virtual_root_freq,
+ desired_divisor << auxdiv);
+}
+
static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
enum pipe pch_transcoder)
{
@@ -4159,7 +4146,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
temp = I915_READ(PCH_DPLL_SEL);
temp |= TRANS_DPLL_ENABLE(pipe);
sel = TRANS_DPLLB_SEL(pipe);
- if (intel_crtc->config->shared_dpll == DPLL_ID_PCH_PLL_B)
+ if (intel_crtc->config->shared_dpll ==
+ intel_get_shared_dpll_by_id(dev_priv, DPLL_ID_PCH_PLL_B))
temp |= sel;
else
temp &= ~sel;
@@ -4238,113 +4226,6 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
}
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
- struct intel_crtc_state *crtc_state)
-{
- struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- struct intel_shared_dpll *pll;
- struct intel_shared_dpll_config *shared_dpll;
- enum intel_dpll_id i;
- int max = dev_priv->num_shared_dpll;
-
- shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
-
- if (HAS_PCH_IBX(dev_priv->dev)) {
- /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
- i = (enum intel_dpll_id) crtc->pipe;
- pll = &dev_priv->shared_dplls[i];
-
- DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
- crtc->base.base.id, pll->name);
-
- WARN_ON(shared_dpll[i].crtc_mask);
-
- goto found;
- }
-
- if (IS_BROXTON(dev_priv->dev)) {
- /* PLL is attached to port in bxt */
- struct intel_encoder *encoder;
- struct intel_digital_port *intel_dig_port;
-
- encoder = intel_ddi_get_crtc_new_encoder(crtc_state);
- if (WARN_ON(!encoder))
- return NULL;
-
- intel_dig_port = enc_to_dig_port(&encoder->base);
- /* 1:1 mapping between ports and PLLs */
- i = (enum intel_dpll_id)intel_dig_port->port;
- pll = &dev_priv->shared_dplls[i];
- DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
- crtc->base.base.id, pll->name);
- WARN_ON(shared_dpll[i].crtc_mask);
-
- goto found;
- } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
- /* Do not consider SPLL */
- max = 2;
-
- for (i = 0; i < max; i++) {
- pll = &dev_priv->shared_dplls[i];
-
- /* Only want to check enabled timings first */
- if (shared_dpll[i].crtc_mask == 0)
- continue;
-
- if (memcmp(&crtc_state->dpll_hw_state,
- &shared_dpll[i].hw_state,
- sizeof(crtc_state->dpll_hw_state)) == 0) {
- DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
- crtc->base.base.id, pll->name,
- shared_dpll[i].crtc_mask,
- pll->active);
- goto found;
- }
- }
-
- /* Ok no matching timings, maybe there's a free one? */
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
- pll = &dev_priv->shared_dplls[i];
- if (shared_dpll[i].crtc_mask == 0) {
- DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
- crtc->base.base.id, pll->name);
- goto found;
- }
- }
-
- return NULL;
-
-found:
- if (shared_dpll[i].crtc_mask == 0)
- shared_dpll[i].hw_state =
- crtc_state->dpll_hw_state;
-
- crtc_state->shared_dpll = i;
- DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
- pipe_name(crtc->pipe));
-
- shared_dpll[i].crtc_mask |= 1 << crtc->pipe;
-
- return pll;
-}
-
-static void intel_shared_dpll_commit(struct drm_atomic_state *state)
-{
- struct drm_i915_private *dev_priv = to_i915(state->dev);
- struct intel_shared_dpll_config *shared_dpll;
- struct intel_shared_dpll *pll;
- enum intel_dpll_id i;
-
- if (!to_intel_atomic_state(state)->dpll_set)
- return;
-
- shared_dpll = to_intel_atomic_state(state)->shared_dpll;
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
- pll = &dev_priv->shared_dplls[i];
- pll->config = shared_dpll[i];
- }
-}
-
static void cpt_verify_modeset(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4734,16 +4615,7 @@ intel_post_enable_primary(struct drm_crtc *crtc)
intel_check_pch_fifo_underruns(dev_priv);
}
-/**
- * intel_pre_disable_primary - Perform operations before disabling primary plane
- * @crtc: the CRTC whose primary plane is to be disabled
- *
- * Performs potentially sleeping operations that must be done before the
- * primary plane is disabled, such as updating FBC and IPS. Note that this may
- * be called due to an explicit primary plane update, or due to an implicit
- * disable that is caused when a sprite plane completely hides the primary
- * plane.
- */
+/* FIXME move all this to pre_plane_update() with proper state tracking */
static void
intel_pre_disable_primary(struct drm_crtc *crtc)
{
@@ -4762,6 +4634,26 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
/*
+ * FIXME IPS should be fine as long as one plane is
+ * enabled, but in practice it seems to have problems
+ * when going from primary only to sprite only and vice
+ * versa.
+ */
+ hsw_disable_ips(intel_crtc);
+}
+
+/* FIXME get rid of this and use pre_plane_update */
+static void
+intel_pre_disable_primary_noatomic(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+
+ intel_pre_disable_primary(crtc);
+
+ /*
* Vblank time updates from the shadow to live plane control register
* are blocked if the memory self-refresh mode is active at that
* moment. So to make sure the plane gets truly disabled, disable
@@ -4775,14 +4667,6 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
dev_priv->wm.vlv.cxsr = false;
intel_wait_for_vblank(dev, pipe);
}
-
- /*
- * FIXME IPS should be fine as long as one plane is
- * enabled, but in practice it seems to have problems
- * when going from primary only to sprite only and vice
- * versa.
- */
- hsw_disable_ips(intel_crtc);
}
static void intel_post_plane_update(struct intel_crtc *crtc)
@@ -4796,7 +4680,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc)
crtc->wm.cxsr_allowed = true;
- if (pipe_config->wm_changed && pipe_config->base.active)
+ if (pipe_config->update_wm_post && pipe_config->base.active)
intel_update_watermarks(&crtc->base);
if (atomic->update_fbc)
@@ -4839,11 +4723,58 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
if (pipe_config->disable_cxsr) {
crtc->wm.cxsr_allowed = false;
- if (old_crtc_state->base.active)
+ /*
+ * Vblank time updates from the shadow to live plane control register
+ * are blocked if the memory self-refresh mode is active at that
+ * moment. So to make sure the plane gets truly disabled, disable
+ * first the self-refresh mode. The self-refresh enable bit in turn
+ * will be checked/applied by the HW only at the next frame start
+ * event which is after the vblank start event, so we need to have a
+ * wait-for-vblank between disabling the plane and the pipe.
+ */
+ if (old_crtc_state->base.active) {
intel_set_memory_cxsr(dev_priv, false);
+ dev_priv->wm.vlv.cxsr = false;
+ intel_wait_for_vblank(dev, crtc->pipe);
+ }
}
- if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed)
+ /*
+ * IVB workaround: must disable low power watermarks for at least
+ * one frame before enabling scaling. LP watermarks can be re-enabled
+ * when scaling is disabled.
+ *
+ * WaCxSRDisabledForSpriteScaling:ivb
+ */
+ if (pipe_config->disable_lp_wm) {
+ ilk_disable_lp_wm(dev);
+ intel_wait_for_vblank(dev, crtc->pipe);
+ }
+
+ /*
+ * If we're doing a modeset, we're done. No need to do any pre-vblank
+ * watermark programming here.
+ */
+ if (needs_modeset(&pipe_config->base))
+ return;
+
+ /*
+ * For platforms that support atomic watermarks, program the
+ * 'intermediate' watermarks immediately. On pre-gen9 platforms, these
+ * will be the intermediate values that are safe for both pre- and
+ * post- vblank; when vblank happens, the 'active' values will be set
+ * to the final 'target' values and we'll do this again to get the
+ * optimal watermarks. For gen9+ platforms, the values we program here
+ * will be the final target values which will get automatically latched
+ * at vblank time; no further programming will be necessary.
+ *
+ * If a platform hasn't been transitioned to atomic watermarks yet,
+ * we'll continue to update watermarks the old way, if flags tell
+ * us to.
+ */
+ if (dev_priv->display.initial_watermarks != NULL)
+ dev_priv->display.initial_watermarks(pipe_config);
+ else if (pipe_config->update_wm_pre)
intel_update_watermarks(&crtc->base);
}
@@ -4922,7 +4853,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
*/
intel_crtc_load_lut(crtc);
- intel_update_watermarks(crtc);
+ if (dev_priv->display.initial_watermarks != NULL)
+ dev_priv->display.initial_watermarks(intel_crtc->config);
intel_enable_pipe(intel_crtc);
if (intel_crtc->config->has_pch_encoder)
@@ -4966,7 +4898,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
false);
- if (intel_crtc_to_shared_dpll(intel_crtc))
+ if (intel_crtc->config->shared_dpll)
intel_enable_shared_dpll(intel_crtc);
if (intel_crtc->config->has_dp_encoder)
@@ -5021,7 +4953,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
if (!intel_crtc->config->has_dsi_encoder)
intel_ddi_enable_transcoder_func(crtc);
- intel_update_watermarks(crtc);
+ if (dev_priv->display.initial_watermarks != NULL)
+ dev_priv->display.initial_watermarks(pipe_config);
+ else
+ intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
if (intel_crtc->config->has_pch_encoder)
@@ -6210,6 +6145,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
intel_crtc_load_lut(crtc);
+ intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
assert_vblank_disabled(crtc);
@@ -6337,6 +6273,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
{
+ struct intel_encoder *encoder;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
enum intel_display_power_domain domain;
@@ -6348,14 +6285,27 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
if (to_intel_plane_state(crtc->primary->state)->visible) {
WARN_ON(intel_crtc->unpin_work);
- intel_pre_disable_primary(crtc);
+ intel_pre_disable_primary_noatomic(crtc);
intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
to_intel_plane_state(crtc->primary->state)->visible = false;
}
dev_priv->display.crtc_disable(crtc);
+
+ DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was enabled, now disabled\n",
+ crtc->base.id);
+
+ WARN_ON(drm_atomic_set_mode_for_crtc(crtc->state, NULL) < 0);
+ crtc->state->active = false;
intel_crtc->active = false;
+ crtc->enabled = false;
+ crtc->state->connector_mask = 0;
+ crtc->state->encoder_mask = 0;
+
+ for_each_encoder_on_crtc(crtc->dev, crtc, encoder)
+ encoder->base.crtc = NULL;
+
intel_fbc_disable(intel_crtc);
intel_update_watermarks(crtc);
intel_disable_shared_dpll(intel_crtc);
@@ -6568,7 +6518,7 @@ retry:
* Hence the bw of each lane in terms of the mode signal
* is:
*/
- link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+ link_bw = intel_fdi_link_freq(to_i915(dev), pipe_config);
fdi_dotclock = adjusted_mode->crtc_clock;
@@ -6580,8 +6530,7 @@ retry:
intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
link_bw, &pipe_config->fdi_m_n);
- ret = ironlake_check_fdi_lanes(intel_crtc->base.dev,
- intel_crtc->pipe, pipe_config);
+ ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
pipe_config->pipe_bpp -= 2*3;
DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n",
@@ -8133,7 +8082,7 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
return false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
- pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+ pipe_config->shared_dpll = NULL;
ret = false;
@@ -9024,7 +8973,7 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
else
crtc_state->dpll_hw_state.fp1 = fp;
- pll = intel_get_shared_dpll(crtc, crtc_state);
+ pll = intel_get_shared_dpll(crtc, crtc_state, NULL);
if (pll == NULL) {
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(crtc->pipe));
@@ -9337,7 +9286,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
return false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
- pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+ pipe_config->shared_dpll = NULL;
ret = false;
tmp = I915_READ(PIPECONF(crtc->pipe));
@@ -9366,6 +9315,7 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
struct intel_shared_dpll *pll;
+ enum intel_dpll_id pll_id;
pipe_config->has_pch_encoder = true;
@@ -9376,20 +9326,21 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
ironlake_get_fdi_m_n_config(crtc, pipe_config);
if (HAS_PCH_IBX(dev_priv->dev)) {
- pipe_config->shared_dpll =
- (enum intel_dpll_id) crtc->pipe;
+ pll_id = (enum intel_dpll_id) crtc->pipe;
} else {
tmp = I915_READ(PCH_DPLL_SEL);
if (tmp & TRANS_DPLLB_SEL(crtc->pipe))
- pipe_config->shared_dpll = DPLL_ID_PCH_PLL_B;
+ pll_id = DPLL_ID_PCH_PLL_B;
else
- pipe_config->shared_dpll = DPLL_ID_PCH_PLL_A;
+ pll_id= DPLL_ID_PCH_PLL_A;
}
- pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
+ pipe_config->shared_dpll =
+ intel_get_shared_dpll_by_id(dev_priv, pll_id);
+ pll = pipe_config->shared_dpll;
- WARN_ON(!pll->get_hw_state(dev_priv, pll,
- &pipe_config->dpll_hw_state));
+ WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state));
tmp = pipe_config->dpll_hw_state.dpll;
pipe_config->pixel_multiplier =
@@ -9709,8 +9660,8 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
val |= LCPLL_CD_SOURCE_FCLK;
I915_WRITE(LCPLL_CTL, val);
- if (wait_for_atomic_us(I915_READ(LCPLL_CTL) &
- LCPLL_CD_SOURCE_FCLK_DONE, 1))
+ if (wait_for_us(I915_READ(LCPLL_CTL) &
+ LCPLL_CD_SOURCE_FCLK_DONE, 1))
DRM_ERROR("Switching to FCLK failed\n");
val = I915_READ(LCPLL_CTL);
@@ -9744,8 +9695,8 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk)
val &= ~LCPLL_CD_SOURCE_FCLK;
I915_WRITE(LCPLL_CTL, val);
- if (wait_for_atomic_us((I915_READ(LCPLL_CTL) &
- LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
+ if (wait_for_us((I915_READ(LCPLL_CTL) &
+ LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1))
DRM_ERROR("Switching back to LCPLL failed\n");
mutex_lock(&dev_priv->rps.hw_lock);
@@ -9822,72 +9773,95 @@ static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_state *pipe_config)
{
+ enum intel_dpll_id id;
+
switch (port) {
case PORT_A:
pipe_config->ddi_pll_sel = SKL_DPLL0;
- pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+ id = DPLL_ID_SKL_DPLL1;
break;
case PORT_B:
pipe_config->ddi_pll_sel = SKL_DPLL1;
- pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+ id = DPLL_ID_SKL_DPLL2;
break;
case PORT_C:
pipe_config->ddi_pll_sel = SKL_DPLL2;
- pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+ id = DPLL_ID_SKL_DPLL3;
break;
default:
DRM_ERROR("Incorrect port type\n");
+ return;
}
+
+ pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
}
static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_state *pipe_config)
{
- u32 temp, dpll_ctl1;
+ enum intel_dpll_id id;
+ u32 temp;
temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
switch (pipe_config->ddi_pll_sel) {
case SKL_DPLL0:
- /*
- * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part
- * of the shared DPLL framework and thus needs to be read out
- * separately
- */
- dpll_ctl1 = I915_READ(DPLL_CTRL1);
- pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f;
+ id = DPLL_ID_SKL_DPLL0;
break;
case SKL_DPLL1:
- pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
+ id = DPLL_ID_SKL_DPLL1;
break;
case SKL_DPLL2:
- pipe_config->shared_dpll = DPLL_ID_SKL_DPLL2;
+ id = DPLL_ID_SKL_DPLL2;
break;
case SKL_DPLL3:
- pipe_config->shared_dpll = DPLL_ID_SKL_DPLL3;
+ id = DPLL_ID_SKL_DPLL3;
break;
+ default:
+ MISSING_CASE(pipe_config->ddi_pll_sel);
+ return;
}
+
+ pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
}
static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
struct intel_crtc_state *pipe_config)
{
+ enum intel_dpll_id id;
+
pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
switch (pipe_config->ddi_pll_sel) {
case PORT_CLK_SEL_WRPLL1:
- pipe_config->shared_dpll = DPLL_ID_WRPLL1;
+ id = DPLL_ID_WRPLL1;
break;
case PORT_CLK_SEL_WRPLL2:
- pipe_config->shared_dpll = DPLL_ID_WRPLL2;
+ id = DPLL_ID_WRPLL2;
break;
case PORT_CLK_SEL_SPLL:
- pipe_config->shared_dpll = DPLL_ID_SPLL;
+ id = DPLL_ID_SPLL;
+ break;
+ case PORT_CLK_SEL_LCPLL_810:
+ id = DPLL_ID_LCPLL_810;
break;
+ case PORT_CLK_SEL_LCPLL_1350:
+ id = DPLL_ID_LCPLL_1350;
+ break;
+ case PORT_CLK_SEL_LCPLL_2700:
+ id = DPLL_ID_LCPLL_2700;
+ break;
+ default:
+ MISSING_CASE(pipe_config->ddi_pll_sel);
+ /* fall through */
+ case PORT_CLK_SEL_NONE:
+ return;
}
+
+ pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
}
static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
@@ -9910,11 +9884,10 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
else
haswell_get_ddi_pll(dev_priv, port, pipe_config);
- if (pipe_config->shared_dpll >= 0) {
- pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
-
- WARN_ON(!pll->get_hw_state(dev_priv, pll,
- &pipe_config->dpll_hw_state));
+ pll = pipe_config->shared_dpll;
+ if (pll) {
+ WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state));
}
/*
@@ -9952,7 +9925,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
ret = false;
pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
- pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+ pipe_config->shared_dpll = NULL;
tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
if (tmp & TRANS_DDI_FUNC_ENABLE) {
@@ -10542,7 +10515,8 @@ found:
goto fail;
}
- if (drm_atomic_commit(state)) {
+ ret = drm_atomic_commit(state);
+ if (ret) {
DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
goto fail;
}
@@ -10718,19 +10692,18 @@ int intel_dotclock_calculate(int link_freq,
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
/* read out port_clock from the DPLL */
i9xx_crtc_clock_get(crtc, pipe_config);
/*
- * This value does not include pixel_multiplier.
- * We will check that port_clock and adjusted_mode.crtc_clock
- * agree once we know their relationship in the encoder's
- * get_config() function.
+ * In case there is an active pipe without active ports,
+ * we may need some idea for the dotclock anyway.
+ * Calculate one based on the FDI configuration.
*/
pipe_config->base.adjusted_mode.crtc_clock =
- intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000,
+ intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config),
&pipe_config->fdi_m_n);
}
@@ -10849,7 +10822,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
struct drm_plane *primary = crtc->base.primary;
mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(work->old_fb, primary->state);
+ intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
drm_gem_object_unreference(&work->pending_flip_obj->base);
if (work->flip_queued_req)
@@ -11621,8 +11594,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
goto cleanup_pending;
}
- ret = intel_pin_and_fence_fb_obj(crtc->primary, fb,
- crtc->primary->state);
+ ret = intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
if (ret)
goto cleanup_pending;
@@ -11672,7 +11644,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
return 0;
cleanup_unpin:
- intel_unpin_fb_obj(fb, crtc->primary->state);
+ intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
cleanup_pending:
if (!IS_ERR_OR_NULL(request))
i915_gem_request_cancel(request);
@@ -11785,6 +11757,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_plane *plane = plane_state->plane;
struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_plane_state *old_plane_state =
to_intel_plane_state(plane->state);
int idx = intel_crtc->base.base.id, ret;
@@ -11833,16 +11806,29 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
plane->base.id, was_visible, visible,
turn_off, turn_on, mode_changed);
- if (turn_on || turn_off) {
- pipe_config->wm_changed = true;
+ if (turn_on) {
+ pipe_config->update_wm_pre = true;
+
+ /* must disable cxsr around plane enable/disable */
+ if (plane->type != DRM_PLANE_TYPE_CURSOR)
+ pipe_config->disable_cxsr = true;
+ } else if (turn_off) {
+ pipe_config->update_wm_post = true;
/* must disable cxsr around plane enable/disable */
if (plane->type != DRM_PLANE_TYPE_CURSOR)
pipe_config->disable_cxsr = true;
} else if (intel_wm_need_update(plane, plane_state)) {
- pipe_config->wm_changed = true;
+ /* FIXME bollocks */
+ pipe_config->update_wm_pre = true;
+ pipe_config->update_wm_post = true;
}
+ /* Pre-gen9 platforms need two-step watermark updates */
+ if ((pipe_config->update_wm_pre || pipe_config->update_wm_post) &&
+ INTEL_INFO(dev)->gen < 9 && dev_priv->display.optimize_watermarks)
+ to_intel_crtc_state(crtc_state)->wm.need_postvbl_update = true;
+
if (visible || was_visible)
intel_crtc->atomic.fb_bits |=
to_intel_plane(plane)->frontbuffer_bit;
@@ -11940,11 +11926,11 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
}
if (mode_changed && !crtc_state->active)
- pipe_config->wm_changed = true;
+ pipe_config->update_wm_post = true;
if (mode_changed && crtc_state->enable &&
dev_priv->display.crtc_compute_clock &&
- !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) {
+ !WARN_ON(pipe_config->shared_dpll)) {
ret = dev_priv->display.crtc_compute_clock(intel_crtc,
pipe_config);
if (ret)
@@ -11953,9 +11939,30 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
ret = 0;
if (dev_priv->display.compute_pipe_wm) {
- ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
- if (ret)
+ ret = dev_priv->display.compute_pipe_wm(pipe_config);
+ if (ret) {
+ DRM_DEBUG_KMS("Target pipe watermarks are invalid\n");
return ret;
+ }
+ }
+
+ if (dev_priv->display.compute_intermediate_wm &&
+ !to_intel_atomic_state(state)->skip_intermediate_wm) {
+ if (WARN_ON(!dev_priv->display.compute_pipe_wm))
+ return 0;
+
+ /*
+ * Calculate 'intermediate' watermarks that satisfy both the
+ * old state and the new state. We can program these
+ * immediately.
+ */
+ ret = dev_priv->display.compute_intermediate_wm(crtc->dev,
+ intel_crtc,
+ pipe_config);
+ if (ret) {
+ DRM_DEBUG_KMS("No valid intermediate pipe watermarks are possible\n");
+ return ret;
+ }
}
if (INTEL_INFO(dev)->gen >= 9) {
@@ -12165,7 +12172,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->dpll_hw_state.cfgcr1,
pipe_config->dpll_hw_state.cfgcr2);
} else if (HAS_DDI(dev)) {
- DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
+ DRM_DEBUG_KMS("ddi_pll_sel: 0x%x; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
pipe_config->ddi_pll_sel,
pipe_config->dpll_hw_state.wrpll,
pipe_config->dpll_hw_state.spll);
@@ -12268,7 +12275,7 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
struct drm_crtc_state tmp_state;
struct intel_crtc_scaler_state scaler_state;
struct intel_dpll_hw_state dpll_hw_state;
- enum intel_dpll_id shared_dpll;
+ struct intel_shared_dpll *shared_dpll;
uint32_t ddi_pll_sel;
bool force_thru;
@@ -12538,6 +12545,15 @@ intel_pipe_config_compare(struct drm_device *dev,
ret = false; \
}
+#define PIPE_CONF_CHECK_P(name) \
+ if (current_config->name != pipe_config->name) { \
+ INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \
+ "(expected %p, found %p)\n", \
+ current_config->name, \
+ pipe_config->name); \
+ ret = false; \
+ }
+
#define PIPE_CONF_CHECK_M_N(name) \
if (!intel_compare_link_m_n(&current_config->name, \
&pipe_config->name,\
@@ -12705,7 +12721,7 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_X(ddi_pll_sel);
- PIPE_CONF_CHECK_I(shared_dpll);
+ PIPE_CONF_CHECK_P(shared_dpll);
PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
@@ -12724,6 +12740,7 @@ intel_pipe_config_compare(struct drm_device *dev,
#undef PIPE_CONF_CHECK_X
#undef PIPE_CONF_CHECK_I
+#undef PIPE_CONF_CHECK_P
#undef PIPE_CONF_CHECK_I_ALT
#undef PIPE_CONF_CHECK_FLAGS
#undef PIPE_CONF_CHECK_CLOCK_FUZZY
@@ -12733,6 +12750,24 @@ intel_pipe_config_compare(struct drm_device *dev,
return ret;
}
+static void intel_pipe_config_sanity_check(struct drm_i915_private *dev_priv,
+ const struct intel_crtc_state *pipe_config)
+{
+ if (pipe_config->has_pch_encoder) {
+ int fdi_dotclock = intel_dotclock_calculate(intel_fdi_link_freq(dev_priv, pipe_config),
+ &pipe_config->fdi_m_n);
+ int dotclock = pipe_config->base.adjusted_mode.crtc_clock;
+
+ /*
+ * FDI already provided one idea for the dotclock.
+ * Yell if the encoder disagrees.
+ */
+ WARN(!intel_fuzzy_clock_check(fdi_dotclock, dotclock),
+ "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
+ fdi_dotclock, dotclock);
+ }
+}
+
static void check_wm_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -12906,6 +12941,8 @@ check_crtc_state(struct drm_device *dev, struct drm_atomic_state *old_state)
if (!crtc->state->active)
continue;
+ intel_pipe_config_sanity_check(dev_priv, pipe_config);
+
sw_config = to_intel_crtc_state(crtc->state);
if (!intel_pipe_config_compare(dev, sw_config,
pipe_config, false)) {
@@ -12927,7 +12964,8 @@ check_shared_dpll_state(struct drm_device *dev)
int i;
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
- struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+ struct intel_shared_dpll *pll =
+ intel_get_shared_dpll_by_id(dev_priv, i);
int enabled_crtcs = 0, active_crtcs = 0;
bool active;
@@ -12935,23 +12973,26 @@ check_shared_dpll_state(struct drm_device *dev)
DRM_DEBUG_KMS("%s\n", pll->name);
- active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
+ active = pll->funcs.get_hw_state(dev_priv, pll, &dpll_hw_state);
I915_STATE_WARN(pll->active > hweight32(pll->config.crtc_mask),
"more active pll users than references: %i vs %i\n",
pll->active, hweight32(pll->config.crtc_mask));
I915_STATE_WARN(pll->active && !pll->on,
"pll in active use but not on in sw tracking\n");
- I915_STATE_WARN(pll->on && !pll->active,
- "pll in on but not on in use in sw tracking\n");
- I915_STATE_WARN(pll->on != active,
- "pll on state mismatch (expected %i, found %i)\n",
- pll->on, active);
+
+ if (!(pll->flags & INTEL_DPLL_ALWAYS_ON)) {
+ I915_STATE_WARN(pll->on && !pll->active,
+ "pll in on but not on in use in sw tracking\n");
+ I915_STATE_WARN(pll->on != active,
+ "pll on state mismatch (expected %i, found %i)\n",
+ pll->on, active);
+ }
for_each_intel_crtc(dev, crtc) {
- if (crtc->base.state->enable && intel_crtc_to_shared_dpll(crtc) == pll)
+ if (crtc->base.state->enable && crtc->config->shared_dpll == pll)
enabled_crtcs++;
- if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
+ if (crtc->active && crtc->config->shared_dpll == pll)
active_crtcs++;
}
I915_STATE_WARN(pll->active != active_crtcs,
@@ -12978,18 +13019,6 @@ intel_modeset_check_state(struct drm_device *dev,
check_shared_dpll_state(dev);
}
-void ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
- int dotclock)
-{
- /*
- * FDI already provided one idea for the dotclock.
- * Yell if the encoder disagrees.
- */
- WARN(!intel_fuzzy_clock_check(pipe_config->base.adjusted_mode.crtc_clock, dotclock),
- "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
- pipe_config->base.adjusted_mode.crtc_clock, dotclock);
-}
-
static void update_scanline_offset(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
@@ -13042,20 +13071,21 @@ static void intel_modeset_clear_plls(struct drm_atomic_state *state)
for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int old_dpll = to_intel_crtc_state(crtc->state)->shared_dpll;
+ struct intel_shared_dpll *old_dpll =
+ to_intel_crtc_state(crtc->state)->shared_dpll;
if (!needs_modeset(crtc_state))
continue;
- to_intel_crtc_state(crtc_state)->shared_dpll = DPLL_ID_PRIVATE;
+ to_intel_crtc_state(crtc_state)->shared_dpll = NULL;
- if (old_dpll == DPLL_ID_PRIVATE)
+ if (!old_dpll)
continue;
if (!shared_dpll)
shared_dpll = intel_atomic_get_shared_dpll_state(state);
- shared_dpll[old_dpll].crtc_mask &= ~(1 << intel_crtc->pipe);
+ intel_shared_dpll_config_put(shared_dpll, old_dpll, intel_crtc);
}
}
@@ -13450,12 +13480,12 @@ static bool needs_vblank_wait(struct intel_crtc_state *crtc_state)
return true;
/* wm changes, need vblank before final wm's */
- if (crtc_state->wm_changed)
+ if (crtc_state->update_wm_post)
return true;
/*
* cxsr is re-enabled after vblank.
- * This is already handled by crtc_state->wm_changed,
+ * This is already handled by crtc_state->update_wm_post,
* but added for clarity.
*/
if (crtc_state->disable_cxsr)
@@ -13486,8 +13516,9 @@ static int intel_atomic_commit(struct drm_device *dev,
{
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc_state *crtc_state;
+ struct drm_crtc_state *old_crtc_state;
struct drm_crtc *crtc;
+ struct intel_crtc_state *intel_cstate;
int ret = 0, i;
bool hw_check = intel_state->modeset;
unsigned long put_domains[I915_MAX_PIPES] = {};
@@ -13511,7 +13542,7 @@ static int intel_atomic_commit(struct drm_device *dev,
intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET);
}
- for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
if (needs_modeset(crtc->state) ||
@@ -13526,10 +13557,10 @@ static int intel_atomic_commit(struct drm_device *dev,
if (!needs_modeset(crtc->state))
continue;
- intel_pre_plane_update(to_intel_crtc_state(crtc_state));
+ intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
- if (crtc_state->active) {
- intel_crtc_disable_planes(crtc, crtc_state->plane_mask);
+ if (old_crtc_state->active) {
+ intel_crtc_disable_planes(crtc, old_crtc_state->plane_mask);
dev_priv->display.crtc_disable(crtc);
intel_crtc->active = false;
intel_fbc_disable(intel_crtc);
@@ -13562,7 +13593,7 @@ static int intel_atomic_commit(struct drm_device *dev,
}
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
- for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
bool modeset = needs_modeset(crtc->state);
struct intel_crtc_state *pipe_config =
@@ -13575,14 +13606,14 @@ static int intel_atomic_commit(struct drm_device *dev,
}
if (!modeset)
- intel_pre_plane_update(to_intel_crtc_state(crtc_state));
+ intel_pre_plane_update(to_intel_crtc_state(old_crtc_state));
if (crtc->state->active && intel_crtc->atomic.update_fbc)
intel_fbc_enable(intel_crtc);
if (crtc->state->active &&
(crtc->state->planes_changed || update_pipe))
- drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+ drm_atomic_helper_commit_planes_on_crtc(old_crtc_state);
if (pipe_config->base.active && needs_vblank_wait(pipe_config))
crtc_vblank_mask |= 1 << i;
@@ -13593,7 +13624,7 @@ static int intel_atomic_commit(struct drm_device *dev,
if (!state->legacy_cursor_update)
intel_atomic_wait_for_vblanks(dev, dev_priv, crtc_vblank_mask);
- for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
intel_post_plane_update(to_intel_crtc(crtc));
if (put_domains[i])
@@ -13603,6 +13634,20 @@ static int intel_atomic_commit(struct drm_device *dev,
if (intel_state->modeset)
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
+ /*
+ * Now that the vblank has passed, we can go ahead and program the
+ * optimal watermarks on platforms that need two-step watermark
+ * programming.
+ *
+ * TODO: Move this (and other cleanup) to an async worker eventually.
+ */
+ for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
+ intel_cstate = to_intel_crtc_state(crtc->state);
+
+ if (dev_priv->display.optimize_watermarks)
+ dev_priv->display.optimize_watermarks(intel_cstate);
+ }
+
mutex_lock(&dev->struct_mutex);
drm_atomic_helper_cleanup_planes(dev, state);
mutex_unlock(&dev->struct_mutex);
@@ -13677,108 +13722,6 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.atomic_destroy_state = intel_crtc_destroy_state,
};
-static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state)
-{
- uint32_t val;
-
- if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
- return false;
-
- val = I915_READ(PCH_DPLL(pll->id));
- hw_state->dpll = val;
- hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
- hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
-
- intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
-
- return val & DPLL_VCO_ENABLE;
-}
-
-static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0);
- I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
-}
-
-static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- /* PCH refclock must be enabled first */
- ibx_assert_pch_refclk_enabled(dev_priv);
-
- I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
-
- /* Wait for the clocks to stabilize. */
- POSTING_READ(PCH_DPLL(pll->id));
- udelay(150);
-
- /* The pixel multiplier can only be updated once the
- * DPLL is enabled and the clocks are stable.
- *
- * So write it again.
- */
- I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
- POSTING_READ(PCH_DPLL(pll->id));
- udelay(200);
-}
-
-static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll)
-{
- struct drm_device *dev = dev_priv->dev;
- struct intel_crtc *crtc;
-
- /* Make sure no transcoder isn't still depending on us. */
- for_each_intel_crtc(dev, crtc) {
- if (intel_crtc_to_shared_dpll(crtc) == pll)
- assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
- }
-
- I915_WRITE(PCH_DPLL(pll->id), 0);
- POSTING_READ(PCH_DPLL(pll->id));
- udelay(200);
-}
-
-static char *ibx_pch_dpll_names[] = {
- "PCH DPLL A",
- "PCH DPLL B",
-};
-
-static void ibx_pch_dpll_init(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int i;
-
- dev_priv->num_shared_dpll = 2;
-
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
- dev_priv->shared_dplls[i].id = i;
- dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
- dev_priv->shared_dplls[i].mode_set = ibx_pch_dpll_mode_set;
- dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
- dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
- dev_priv->shared_dplls[i].get_hw_state =
- ibx_pch_dpll_get_hw_state;
- }
-}
-
-static void intel_shared_dpll_init(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (HAS_DDI(dev))
- intel_ddi_pll_init(dev);
- else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
- ibx_pch_dpll_init(dev);
- else
- dev_priv->num_shared_dpll = 0;
-
- BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
-}
-
/**
* intel_prepare_plane_fb - Prepare fb for usage on plane
* @plane: drm plane to prepare for
@@ -13852,7 +13795,7 @@ intel_prepare_plane_fb(struct drm_plane *plane,
if (ret)
DRM_DEBUG_KMS("failed to attach phys object\n");
} else {
- ret = intel_pin_and_fence_fb_obj(plane, fb, new_state);
+ ret = intel_pin_and_fence_fb_obj(fb, new_state->rotation);
}
if (ret == 0) {
@@ -13896,7 +13839,7 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
!INTEL_INFO(dev)->cursor_needs_physical))
- intel_unpin_fb_obj(old_state->fb, old_state);
+ intel_unpin_fb_obj(old_state->fb, old_state->rotation);
/* prepare_fb aborted? */
if ((old_obj && (old_obj->frontbuffer_bits & intel_plane->frontbuffer_bit)) ||
@@ -13904,7 +13847,6 @@ intel_cleanup_plane_fb(struct drm_plane *plane,
i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit);
i915_gem_request_assign(&old_intel_state->wait_req, NULL);
-
}
int
@@ -14836,6 +14778,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
intel_fb->obj = obj;
+ intel_fill_fb_info(dev_priv, &intel_fb->base);
+
ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
if (ret) {
DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -15273,7 +15217,7 @@ static void sanitize_watermarks(struct drm_device *dev)
int i;
/* Only supported on platforms that use atomic watermark design */
- if (!dev_priv->display.program_watermarks)
+ if (!dev_priv->display.optimize_watermarks)
return;
/*
@@ -15294,6 +15238,13 @@ retry:
if (WARN_ON(IS_ERR(state)))
goto fail;
+ /*
+ * Hardware readout is the only time we don't want to calculate
+ * intermediate watermarks (since we don't trust the current
+ * watermarks).
+ */
+ to_intel_atomic_state(state)->skip_intermediate_wm = true;
+
ret = intel_atomic_check(dev, state);
if (ret) {
/*
@@ -15316,7 +15267,8 @@ retry:
for_each_crtc_in_state(state, crtc, cstate, i) {
struct intel_crtc_state *cs = to_intel_crtc_state(cstate);
- dev_priv->display.program_watermarks(cs);
+ cs->wm.need_postvbl_update = true;
+ dev_priv->display.optimize_watermarks(cs);
}
drm_atomic_state_free(state);
@@ -15411,6 +15363,7 @@ void intel_modeset_init(struct drm_device *dev)
}
intel_update_czclk(dev_priv);
+ intel_update_rawclk(dev_priv);
intel_update_cdclk(dev);
intel_shared_dpll_init(dev);
@@ -15574,38 +15527,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
/* Adjust the state of the output pipe according to whether we
* have active connectors/encoders. */
- if (!intel_crtc_has_encoders(crtc))
+ if (crtc->active && !intel_crtc_has_encoders(crtc))
intel_crtc_disable_noatomic(&crtc->base);
- if (crtc->active != crtc->base.state->active) {
- struct intel_encoder *encoder;
-
- /* This can happen either due to bugs in the get_hw_state
- * functions or because of calls to intel_crtc_disable_noatomic,
- * or because the pipe is force-enabled due to the
- * pipe A quirk. */
- DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n",
- crtc->base.base.id,
- crtc->base.state->enable ? "enabled" : "disabled",
- crtc->active ? "enabled" : "disabled");
-
- WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0);
- crtc->base.state->active = crtc->active;
- crtc->base.enabled = crtc->active;
- crtc->base.state->connector_mask = 0;
- crtc->base.state->encoder_mask = 0;
-
- /* Because we only establish the connector -> encoder ->
- * crtc links if something is active, this means the
- * crtc is now deactivated. Break the links. connector
- * -> encoder links are only establish when things are
- * actually up, hence no need to break them. */
- WARN_ON(crtc->active);
-
- for_each_encoder_on_crtc(dev, &crtc->base, encoder)
- encoder->base.crtc = NULL;
- }
-
if (crtc->active || HAS_GMCH_DISPLAY(dev)) {
/*
* We start out with underrun reporting disabled to avoid races.
@@ -15774,12 +15698,12 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
- pll->on = pll->get_hw_state(dev_priv, pll,
- &pll->config.hw_state);
+ pll->on = pll->funcs.get_hw_state(dev_priv, pll,
+ &pll->config.hw_state);
pll->active = 0;
pll->config.crtc_mask = 0;
for_each_intel_crtc(dev, crtc) {
- if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) {
+ if (crtc->active && crtc->config->shared_dpll == pll) {
pll->active++;
pll->config.crtc_mask |= 1 << crtc->pipe;
}
@@ -15871,6 +15795,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
update_scanline_offset(crtc);
}
+
+ intel_pipe_config_sanity_check(dev_priv, crtc->config);
}
}
@@ -15910,7 +15836,7 @@ intel_modeset_setup_hw_state(struct drm_device *dev)
DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name);
- pll->disable(dev_priv, pll);
+ pll->funcs.disable(dev_priv, pll);
pll->on = false;
}
@@ -16019,9 +15945,8 @@ void intel_modeset_gem_init(struct drm_device *dev)
continue;
mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(c->primary,
- c->primary->fb,
- c->primary->state);
+ ret = intel_pin_and_fence_fb_obj(c->primary->fb,
+ c->primary->state->rotation);
mutex_unlock(&dev->struct_mutex);
if (ret) {
DRM_ERROR("failed to pin boot fb on pipe %d\n",
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index f069a82deb57..0e326e776e8f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -671,60 +671,55 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
return status;
}
-static uint32_t i9xx_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+static uint32_t g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
+
+ if (index)
+ return 0;
/*
* The clock divider is based off the hrawclk, and would like to run at
- * 2MHz. So, take the hrawclk value and divide by 2 and use that
+ * 2MHz. So, take the hrawclk value and divide by 2000 and use that
*/
- return index ? 0 : DIV_ROUND_CLOSEST(intel_hrawclk(dev), 2);
+ return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
}
static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- struct drm_device *dev = intel_dig_port->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
if (index)
return 0;
- if (intel_dig_port->port == PORT_A) {
+ /*
+ * The clock divider is based off the cdclk or PCH rawclk, and would
+ * like to run at 2MHz. So, take the cdclk or PCH rawclk value and
+ * divide by 2000 and use that
+ */
+ if (intel_dig_port->port == PORT_A)
return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000);
-
- } else {
- return DIV_ROUND_CLOSEST(intel_pch_rawclk(dev), 2);
- }
+ else
+ return DIV_ROUND_CLOSEST(dev_priv->rawclk_freq, 2000);
}
static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- struct drm_device *dev = intel_dig_port->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev);
- if (intel_dig_port->port == PORT_A) {
- if (index)
- return 0;
- return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000);
- } else if (HAS_PCH_LPT_H(dev_priv)) {
+ if (intel_dig_port->port != PORT_A && HAS_PCH_LPT_H(dev_priv)) {
/* Workaround for non-ULT HSW */
switch (index) {
case 0: return 63;
case 1: return 72;
default: return 0;
}
- } else {
- return index ? 0 : DIV_ROUND_CLOSEST(intel_pch_rawclk(dev), 2);
}
-}
-static uint32_t vlv_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
-{
- return index ? 0 : 100;
+ return ilk_get_aux_clock_divider(intel_dp, index);
}
static uint32_t skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
@@ -737,10 +732,10 @@ static uint32_t skl_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
return index ? 0 : 1;
}
-static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
- bool has_aux_irq,
- int send_bytes,
- uint32_t aux_clock_divider)
+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)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -1229,71 +1224,6 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
intel_connector_unregister(intel_connector);
}
-static void
-skl_edp_set_pll_config(struct intel_crtc_state *pipe_config)
-{
- u32 ctrl1;
-
- memset(&pipe_config->dpll_hw_state, 0,
- sizeof(pipe_config->dpll_hw_state));
-
- pipe_config->ddi_pll_sel = SKL_DPLL0;
- pipe_config->dpll_hw_state.cfgcr1 = 0;
- pipe_config->dpll_hw_state.cfgcr2 = 0;
-
- ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0);
- switch (pipe_config->port_clock / 2) {
- case 81000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810,
- SKL_DPLL0);
- break;
- case 135000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350,
- SKL_DPLL0);
- break;
- case 270000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700,
- SKL_DPLL0);
- break;
- case 162000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620,
- SKL_DPLL0);
- break;
- /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which
- results in CDCLK change. Need to handle the change of CDCLK by
- disabling pipes and re-enabling them */
- case 108000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080,
- SKL_DPLL0);
- break;
- case 216000:
- ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160,
- SKL_DPLL0);
- break;
-
- }
- pipe_config->dpll_hw_state.ctrl1 = ctrl1;
-}
-
-void
-hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config)
-{
- memset(&pipe_config->dpll_hw_state, 0,
- sizeof(pipe_config->dpll_hw_state));
-
- switch (pipe_config->port_clock / 2) {
- case 81000:
- pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810;
- break;
- case 135000:
- pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350;
- break;
- case 270000:
- pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700;
- break;
- }
-}
-
static int
intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
{
@@ -1651,13 +1581,7 @@ found:
&pipe_config->dp_m2_n2);
}
- if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) && is_edp(intel_dp))
- skl_edp_set_pll_config(pipe_config);
- else if (IS_BROXTON(dev))
- /* handled in ddi */;
- else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
- hsw_dp_set_ddi_pll_sel(pipe_config);
- else
+ if (!HAS_DDI(dev))
intel_dp_set_clock(encoder, pipe_config);
return true;
@@ -1779,11 +1703,11 @@ static void wait_panel_status(struct intel_dp *intel_dp,
I915_READ(pp_stat_reg),
I915_READ(pp_ctrl_reg));
- if (_wait_for((I915_READ(pp_stat_reg) & mask) == value, 5000, 10)) {
+ if (_wait_for((I915_READ(pp_stat_reg) & mask) == value,
+ 5 * USEC_PER_SEC, 10 * USEC_PER_MSEC))
DRM_ERROR("Panel status timeout: status %08x control %08x\n",
I915_READ(pp_stat_reg),
I915_READ(pp_ctrl_reg));
- }
DRM_DEBUG_KMS("Wait complete\n");
}
@@ -2409,7 +2333,6 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- int dotclock;
tmp = I915_READ(intel_dp->output_reg);
@@ -2459,13 +2382,9 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
pipe_config->port_clock = 270000;
}
- dotclock = intel_dotclock_calculate(pipe_config->port_clock,
- &pipe_config->dp_m_n);
-
- if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A)
- ironlake_check_encoder_dotclock(pipe_config, dotclock);
-
- pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock =
+ intel_dotclock_calculate(pipe_config->port_clock,
+ &pipe_config->dp_m_n);
if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp &&
pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) {
@@ -5259,7 +5178,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_on, pp_off, pp_div, port_sel = 0;
- int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev);
+ int div = dev_priv->rawclk_freq / 1000;
i915_reg_t pp_on_reg, pp_off_reg, pp_div_reg, pp_ctrl_reg;
enum port port = dp_to_dig_port(intel_dp)->port;
const struct edp_power_seq *seq = &intel_dp->pps_delays;
@@ -5852,19 +5771,17 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
/* intel_dp vfuncs */
if (INTEL_INFO(dev)->gen >= 9)
intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider;
- else if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
- intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider;
else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
else if (HAS_PCH_SPLIT(dev))
intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
else
- intel_dp->get_aux_clock_divider = i9xx_get_aux_clock_divider;
+ intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider;
if (INTEL_INFO(dev)->gen >= 9)
intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl;
else
- intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
+ intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl;
if (HAS_DDI(dev))
intel_dp->prepare_link_retrain = intel_ddi_prepare_link_retrain;
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index a2bd698fe2f7..8d1b7033aaba 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -33,7 +33,6 @@
static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
- struct drm_device *dev = encoder->base.dev;
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
struct intel_digital_port *intel_dig_port = intel_mst->primary;
struct intel_dp *intel_dp = &intel_dig_port->dp;
@@ -92,9 +91,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
pipe_config->dp_m_n.tu = slots;
- if (IS_HASWELL(dev) || IS_BROADWELL(dev))
- hsw_dp_set_ddi_pll_sel(pipe_config);
-
return true;
}
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
new file mode 100644
index 000000000000..4b636c47e8e3
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -0,0 +1,1774 @@
+/*
+ * Copyright © 2006-2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "intel_drv.h"
+
+struct intel_shared_dpll *
+intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
+ enum intel_dpll_id id)
+{
+ return &dev_priv->shared_dplls[id];
+}
+
+enum intel_dpll_id
+intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ if (WARN_ON(pll < dev_priv->shared_dplls||
+ pll > &dev_priv->shared_dplls[dev_priv->num_shared_dpll]))
+ return -1;
+
+ return (enum intel_dpll_id) (pll - dev_priv->shared_dplls);
+}
+
+void
+intel_shared_dpll_config_get(struct intel_shared_dpll_config *config,
+ struct intel_shared_dpll *pll,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum intel_dpll_id id = intel_get_shared_dpll_id(dev_priv, pll);
+
+ config[id].crtc_mask |= 1 << crtc->pipe;
+}
+
+void
+intel_shared_dpll_config_put(struct intel_shared_dpll_config *config,
+ struct intel_shared_dpll *pll,
+ struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ enum intel_dpll_id id = intel_get_shared_dpll_id(dev_priv, pll);
+
+ config[id].crtc_mask &= ~(1 << crtc->pipe);
+}
+
+/* For ILK+ */
+void assert_shared_dpll(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ bool state)
+{
+ bool cur_state;
+ struct intel_dpll_hw_state hw_state;
+
+ if (WARN(!pll, "asserting DPLL %s with no DPLL\n", onoff(state)))
+ return;
+
+ cur_state = pll->funcs.get_hw_state(dev_priv, pll, &hw_state);
+ I915_STATE_WARN(cur_state != state,
+ "%s assertion failure (expected %s, current %s)\n",
+ pll->name, onoff(state), onoff(cur_state));
+}
+
+void intel_prepare_shared_dpll(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_shared_dpll *pll = crtc->config->shared_dpll;
+
+ if (WARN_ON(pll == NULL))
+ return;
+
+ WARN_ON(!pll->config.crtc_mask);
+ if (pll->active == 0) {
+ DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
+ WARN_ON(pll->on);
+ assert_shared_dpll_disabled(dev_priv, pll);
+
+ pll->funcs.mode_set(dev_priv, pll);
+ }
+}
+
+/**
+ * intel_enable_shared_dpll - enable PCH PLL
+ * @dev_priv: i915 private structure
+ * @pipe: pipe PLL to enable
+ *
+ * The PCH PLL needs to be enabled before the PCH transcoder, since it
+ * drives the transcoder clock.
+ */
+void intel_enable_shared_dpll(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_shared_dpll *pll = crtc->config->shared_dpll;
+
+ if (WARN_ON(pll == NULL))
+ return;
+
+ if (WARN_ON(pll->config.crtc_mask == 0))
+ return;
+
+ DRM_DEBUG_KMS("enable %s (active %d, on? %d) for crtc %d\n",
+ pll->name, pll->active, pll->on,
+ crtc->base.base.id);
+
+ if (pll->active++) {
+ WARN_ON(!pll->on);
+ assert_shared_dpll_enabled(dev_priv, pll);
+ return;
+ }
+ WARN_ON(pll->on);
+
+ intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS);
+
+ DRM_DEBUG_KMS("enabling %s\n", pll->name);
+ pll->funcs.enable(dev_priv, pll);
+ pll->on = true;
+}
+
+void intel_disable_shared_dpll(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_shared_dpll *pll = crtc->config->shared_dpll;
+
+ /* PCH only available on ILK+ */
+ if (INTEL_INFO(dev)->gen < 5)
+ return;
+
+ if (pll == NULL)
+ return;
+
+ if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base)))))
+ return;
+
+ DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n",
+ pll->name, pll->active, pll->on,
+ crtc->base.base.id);
+
+ if (WARN_ON(pll->active == 0)) {
+ assert_shared_dpll_disabled(dev_priv, pll);
+ return;
+ }
+
+ assert_shared_dpll_enabled(dev_priv, pll);
+ WARN_ON(!pll->on);
+ if (--pll->active)
+ return;
+
+ DRM_DEBUG_KMS("disabling %s\n", pll->name);
+ pll->funcs.disable(dev_priv, pll);
+ pll->on = false;
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+}
+
+static struct intel_shared_dpll *
+intel_find_shared_dpll(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
+ enum intel_dpll_id range_min,
+ enum intel_dpll_id range_max)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_shared_dpll *pll;
+ struct intel_shared_dpll_config *shared_dpll;
+ enum intel_dpll_id i;
+
+ shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
+
+ for (i = range_min; i <= range_max; i++) {
+ pll = &dev_priv->shared_dplls[i];
+
+ /* Only want to check enabled timings first */
+ if (shared_dpll[i].crtc_mask == 0)
+ continue;
+
+ if (memcmp(&crtc_state->dpll_hw_state,
+ &shared_dpll[i].hw_state,
+ sizeof(crtc_state->dpll_hw_state)) == 0) {
+ DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
+ crtc->base.base.id, pll->name,
+ shared_dpll[i].crtc_mask,
+ pll->active);
+ return pll;
+ }
+ }
+
+ /* Ok no matching timings, maybe there's a free one? */
+ for (i = range_min; i <= range_max; i++) {
+ pll = &dev_priv->shared_dplls[i];
+ if (shared_dpll[i].crtc_mask == 0) {
+ DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
+ crtc->base.base.id, pll->name);
+ return pll;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+intel_reference_shared_dpll(struct intel_shared_dpll *pll,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_shared_dpll_config *shared_dpll;
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+ enum intel_dpll_id i = pll->id;
+
+ shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
+
+ if (shared_dpll[i].crtc_mask == 0)
+ shared_dpll[i].hw_state =
+ crtc_state->dpll_hw_state;
+
+ crtc_state->shared_dpll = pll;
+ DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
+ pipe_name(crtc->pipe));
+
+ intel_shared_dpll_config_get(shared_dpll, pll, crtc);
+}
+
+void intel_shared_dpll_commit(struct drm_atomic_state *state)
+{
+ struct drm_i915_private *dev_priv = to_i915(state->dev);
+ struct intel_shared_dpll_config *shared_dpll;
+ struct intel_shared_dpll *pll;
+ enum intel_dpll_id i;
+
+ if (!to_intel_atomic_state(state)->dpll_set)
+ return;
+
+ shared_dpll = to_intel_atomic_state(state)->shared_dpll;
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ pll = &dev_priv->shared_dplls[i];
+ pll->config = shared_dpll[i];
+ }
+}
+
+static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ val = I915_READ(PCH_DPLL(pll->id));
+ hw_state->dpll = val;
+ hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
+ hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return val & DPLL_VCO_ENABLE;
+}
+
+static void ibx_pch_dpll_mode_set(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ I915_WRITE(PCH_FP0(pll->id), pll->config.hw_state.fp0);
+ I915_WRITE(PCH_FP1(pll->id), pll->config.hw_state.fp1);
+}
+
+static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
+{
+ u32 val;
+ bool enabled;
+
+ I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
+
+ val = I915_READ(PCH_DREF_CONTROL);
+ enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
+ DREF_SUPERSPREAD_SOURCE_MASK));
+ I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
+}
+
+static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ /* PCH refclock must be enabled first */
+ ibx_assert_pch_refclk_enabled(dev_priv);
+
+ I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
+
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(PCH_DPLL(pll->id));
+ udelay(150);
+
+ /* The pixel multiplier can only be updated once the
+ * DPLL is enabled and the clocks are stable.
+ *
+ * So write it again.
+ */
+ I915_WRITE(PCH_DPLL(pll->id), pll->config.hw_state.dpll);
+ POSTING_READ(PCH_DPLL(pll->id));
+ udelay(200);
+}
+
+static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ struct drm_device *dev = dev_priv->dev;
+ struct intel_crtc *crtc;
+
+ /* Make sure no transcoder isn't still depending on us. */
+ for_each_intel_crtc(dev, crtc) {
+ if (crtc->config->shared_dpll == pll)
+ assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
+ }
+
+ I915_WRITE(PCH_DPLL(pll->id), 0);
+ POSTING_READ(PCH_DPLL(pll->id));
+ udelay(200);
+}
+
+static struct intel_shared_dpll *
+ibx_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_shared_dpll *pll;
+ enum intel_dpll_id i;
+
+ if (HAS_PCH_IBX(dev_priv)) {
+ /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
+ i = (enum intel_dpll_id) crtc->pipe;
+ pll = &dev_priv->shared_dplls[i];
+
+ DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
+ crtc->base.base.id, pll->name);
+ } else {
+ pll = intel_find_shared_dpll(crtc, crtc_state,
+ DPLL_ID_PCH_PLL_A,
+ DPLL_ID_PCH_PLL_B);
+ }
+
+ /* reference the pll */
+ intel_reference_shared_dpll(pll, crtc_state);
+
+ return pll;
+}
+
+static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = {
+ .mode_set = ibx_pch_dpll_mode_set,
+ .enable = ibx_pch_dpll_enable,
+ .disable = ibx_pch_dpll_disable,
+ .get_hw_state = ibx_pch_dpll_get_hw_state,
+};
+
+static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
+ POSTING_READ(WRPLL_CTL(pll->id));
+ udelay(20);
+}
+
+static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
+ POSTING_READ(SPLL_CTL);
+ udelay(20);
+}
+
+static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ uint32_t val;
+
+ val = I915_READ(WRPLL_CTL(pll->id));
+ I915_WRITE(WRPLL_CTL(pll->id), val & ~WRPLL_PLL_ENABLE);
+ POSTING_READ(WRPLL_CTL(pll->id));
+}
+
+static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ uint32_t val;
+
+ val = I915_READ(SPLL_CTL);
+ I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
+ POSTING_READ(SPLL_CTL);
+}
+
+static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ val = I915_READ(WRPLL_CTL(pll->id));
+ hw_state->wrpll = val;
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return val & WRPLL_PLL_ENABLE;
+}
+
+static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ val = I915_READ(SPLL_CTL);
+ hw_state->spll = val;
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return val & SPLL_PLL_ENABLE;
+}
+
+static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
+{
+ switch (pll->id) {
+ case DPLL_ID_WRPLL1:
+ return PORT_CLK_SEL_WRPLL1;
+ case DPLL_ID_WRPLL2:
+ return PORT_CLK_SEL_WRPLL2;
+ case DPLL_ID_SPLL:
+ return PORT_CLK_SEL_SPLL;
+ case DPLL_ID_LCPLL_810:
+ return PORT_CLK_SEL_LCPLL_810;
+ case DPLL_ID_LCPLL_1350:
+ return PORT_CLK_SEL_LCPLL_1350;
+ case DPLL_ID_LCPLL_2700:
+ return PORT_CLK_SEL_LCPLL_2700;
+ default:
+ return PORT_CLK_SEL_NONE;
+ }
+}
+
+#define LC_FREQ 2700
+#define LC_FREQ_2K U64_C(LC_FREQ * 2000)
+
+#define P_MIN 2
+#define P_MAX 64
+#define P_INC 2
+
+/* Constraints for PLL good behavior */
+#define REF_MIN 48
+#define REF_MAX 400
+#define VCO_MIN 2400
+#define VCO_MAX 4800
+
+struct hsw_wrpll_rnp {
+ unsigned p, n2, r2;
+};
+
+static unsigned hsw_wrpll_get_budget_for_freq(int clock)
+{
+ unsigned budget;
+
+ switch (clock) {
+ case 25175000:
+ case 25200000:
+ case 27000000:
+ case 27027000:
+ case 37762500:
+ case 37800000:
+ case 40500000:
+ case 40541000:
+ case 54000000:
+ case 54054000:
+ case 59341000:
+ case 59400000:
+ case 72000000:
+ case 74176000:
+ case 74250000:
+ case 81000000:
+ case 81081000:
+ case 89012000:
+ case 89100000:
+ case 108000000:
+ case 108108000:
+ case 111264000:
+ case 111375000:
+ case 148352000:
+ case 148500000:
+ case 162000000:
+ case 162162000:
+ case 222525000:
+ case 222750000:
+ case 296703000:
+ case 297000000:
+ budget = 0;
+ break;
+ case 233500000:
+ case 245250000:
+ case 247750000:
+ case 253250000:
+ case 298000000:
+ budget = 1500;
+ break;
+ case 169128000:
+ case 169500000:
+ case 179500000:
+ case 202000000:
+ budget = 2000;
+ break;
+ case 256250000:
+ case 262500000:
+ case 270000000:
+ case 272500000:
+ case 273750000:
+ case 280750000:
+ case 281250000:
+ case 286000000:
+ case 291750000:
+ budget = 4000;
+ break;
+ case 267250000:
+ case 268500000:
+ budget = 5000;
+ break;
+ default:
+ budget = 1000;
+ break;
+ }
+
+ return budget;
+}
+
+static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget,
+ unsigned r2, unsigned n2, unsigned p,
+ struct hsw_wrpll_rnp *best)
+{
+ uint64_t a, b, c, d, diff, diff_best;
+
+ /* No best (r,n,p) yet */
+ if (best->p == 0) {
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ return;
+ }
+
+ /*
+ * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
+ * freq2k.
+ *
+ * delta = 1e6 *
+ * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
+ * freq2k;
+ *
+ * and we would like delta <= budget.
+ *
+ * If the discrepancy is above the PPM-based budget, always prefer to
+ * improve upon the previous solution. However, if you're within the
+ * budget, try to maximize Ref * VCO, that is N / (P * R^2).
+ */
+ a = freq2k * budget * p * r2;
+ b = freq2k * budget * best->p * best->r2;
+ diff = abs_diff(freq2k * p * r2, LC_FREQ_2K * n2);
+ diff_best = abs_diff(freq2k * best->p * best->r2,
+ LC_FREQ_2K * best->n2);
+ c = 1000000 * diff;
+ d = 1000000 * diff_best;
+
+ if (a < c && b < d) {
+ /* If both are above the budget, pick the closer */
+ if (best->p * best->r2 * diff < p * r2 * diff_best) {
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ }
+ } else if (a >= c && b < d) {
+ /* If A is below the threshold but B is above it? Update. */
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ } else if (a >= c && b >= d) {
+ /* Both are below the limit, so pick the higher n2/(r2*r2) */
+ if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ }
+ }
+ /* Otherwise a < c && b >= d, do nothing */
+}
+
+static void
+hsw_ddi_calculate_wrpll(int clock /* in Hz */,
+ unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
+{
+ uint64_t freq2k;
+ unsigned p, n2, r2;
+ struct hsw_wrpll_rnp best = { 0, 0, 0 };
+ unsigned budget;
+
+ freq2k = clock / 100;
+
+ budget = hsw_wrpll_get_budget_for_freq(clock);
+
+ /* Special case handling for 540 pixel clock: bypass WR PLL entirely
+ * and directly pass the LC PLL to it. */
+ if (freq2k == 5400000) {
+ *n2_out = 2;
+ *p_out = 1;
+ *r2_out = 2;
+ return;
+ }
+
+ /*
+ * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
+ * the WR PLL.
+ *
+ * We want R so that REF_MIN <= Ref <= REF_MAX.
+ * Injecting R2 = 2 * R gives:
+ * REF_MAX * r2 > LC_FREQ * 2 and
+ * REF_MIN * r2 < LC_FREQ * 2
+ *
+ * Which means the desired boundaries for r2 are:
+ * LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
+ *
+ */
+ for (r2 = LC_FREQ * 2 / REF_MAX + 1;
+ r2 <= LC_FREQ * 2 / REF_MIN;
+ r2++) {
+
+ /*
+ * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
+ *
+ * Once again we want VCO_MIN <= VCO <= VCO_MAX.
+ * Injecting R2 = 2 * R and N2 = 2 * N, we get:
+ * VCO_MAX * r2 > n2 * LC_FREQ and
+ * VCO_MIN * r2 < n2 * LC_FREQ)
+ *
+ * Which means the desired boundaries for n2 are:
+ * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
+ */
+ for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
+ n2 <= VCO_MAX * r2 / LC_FREQ;
+ n2++) {
+
+ for (p = P_MIN; p <= P_MAX; p += P_INC)
+ hsw_wrpll_update_rnp(freq2k, budget,
+ r2, n2, p, &best);
+ }
+ }
+
+ *n2_out = best.n2;
+ *p_out = best.p;
+ *r2_out = best.r2;
+}
+
+static struct intel_shared_dpll *
+hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_shared_dpll *pll;
+ int clock = crtc_state->port_clock;
+
+ memset(&crtc_state->dpll_hw_state, 0,
+ sizeof(crtc_state->dpll_hw_state));
+
+ if (encoder->type == INTEL_OUTPUT_HDMI) {
+ uint32_t val;
+ unsigned p, n2, r2;
+
+ hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
+
+ val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
+ WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
+ WRPLL_DIVIDER_POST(p);
+
+ crtc_state->dpll_hw_state.wrpll = val;
+
+ pll = intel_find_shared_dpll(crtc, crtc_state,
+ DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
+
+ } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+ encoder->type == INTEL_OUTPUT_DP_MST ||
+ encoder->type == INTEL_OUTPUT_EDP) {
+ enum intel_dpll_id pll_id;
+
+ switch (clock / 2) {
+ case 81000:
+ pll_id = DPLL_ID_LCPLL_810;
+ break;
+ case 135000:
+ pll_id = DPLL_ID_LCPLL_1350;
+ break;
+ case 270000:
+ pll_id = DPLL_ID_LCPLL_2700;
+ break;
+ default:
+ DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
+ return NULL;
+ }
+
+ pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+
+ } else if (encoder->type == INTEL_OUTPUT_ANALOG) {
+ if (WARN_ON(crtc_state->port_clock / 2 != 135000))
+ return NULL;
+
+ crtc_state->dpll_hw_state.spll =
+ SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
+
+ pll = intel_find_shared_dpll(crtc, crtc_state,
+ DPLL_ID_SPLL, DPLL_ID_SPLL);
+ } else {
+ return NULL;
+ }
+
+ if (!pll)
+ return NULL;
+
+ crtc_state->ddi_pll_sel = hsw_pll_to_ddi_pll_sel(pll);
+
+ intel_reference_shared_dpll(pll, crtc_state);
+
+ return pll;
+}
+
+
+static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
+ .enable = hsw_ddi_wrpll_enable,
+ .disable = hsw_ddi_wrpll_disable,
+ .get_hw_state = hsw_ddi_wrpll_get_hw_state,
+};
+
+static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
+ .enable = hsw_ddi_spll_enable,
+ .disable = hsw_ddi_spll_disable,
+ .get_hw_state = hsw_ddi_spll_get_hw_state,
+};
+
+static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+}
+
+static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+}
+
+static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ return true;
+}
+
+static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
+ .enable = hsw_ddi_lcpll_enable,
+ .disable = hsw_ddi_lcpll_disable,
+ .get_hw_state = hsw_ddi_lcpll_get_hw_state,
+};
+
+struct skl_dpll_regs {
+ i915_reg_t ctl, cfgcr1, cfgcr2;
+};
+
+/* this array is indexed by the *shared* pll id */
+static const struct skl_dpll_regs skl_dpll_regs[4] = {
+ {
+ /* DPLL 0 */
+ .ctl = LCPLL1_CTL,
+ /* DPLL 0 doesn't support HDMI mode */
+ },
+ {
+ /* DPLL 1 */
+ .ctl = LCPLL2_CTL,
+ .cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
+ .cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
+ },
+ {
+ /* DPLL 2 */
+ .ctl = WRPLL_CTL(0),
+ .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
+ .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
+ },
+ {
+ /* DPLL 3 */
+ .ctl = WRPLL_CTL(1),
+ .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
+ .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
+ },
+};
+
+static void skl_ddi_pll_write_ctrl1(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ uint32_t val;
+
+ val = I915_READ(DPLL_CTRL1);
+
+ val &= ~(DPLL_CTRL1_HDMI_MODE(pll->id) | DPLL_CTRL1_SSC(pll->id) |
+ DPLL_CTRL1_LINK_RATE_MASK(pll->id));
+ val |= pll->config.hw_state.ctrl1 << (pll->id * 6);
+
+ I915_WRITE(DPLL_CTRL1, val);
+ POSTING_READ(DPLL_CTRL1);
+}
+
+static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ const struct skl_dpll_regs *regs = skl_dpll_regs;
+
+ skl_ddi_pll_write_ctrl1(dev_priv, pll);
+
+ I915_WRITE(regs[pll->id].cfgcr1, pll->config.hw_state.cfgcr1);
+ I915_WRITE(regs[pll->id].cfgcr2, pll->config.hw_state.cfgcr2);
+ POSTING_READ(regs[pll->id].cfgcr1);
+ POSTING_READ(regs[pll->id].cfgcr2);
+
+ /* the enable bit is always bit 31 */
+ I915_WRITE(regs[pll->id].ctl,
+ I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE);
+
+ if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(pll->id), 5))
+ DRM_ERROR("DPLL %d not locked\n", pll->id);
+}
+
+static void skl_ddi_dpll0_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ skl_ddi_pll_write_ctrl1(dev_priv, pll);
+}
+
+static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ const struct skl_dpll_regs *regs = skl_dpll_regs;
+
+ /* the enable bit is always bit 31 */
+ I915_WRITE(regs[pll->id].ctl,
+ I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE);
+ POSTING_READ(regs[pll->id].ctl);
+}
+
+static void skl_ddi_dpll0_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+}
+
+static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+ const struct skl_dpll_regs *regs = skl_dpll_regs;
+ bool ret;
+
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ ret = false;
+
+ val = I915_READ(regs[pll->id].ctl);
+ if (!(val & LCPLL_PLL_ENABLE))
+ goto out;
+
+ val = I915_READ(DPLL_CTRL1);
+ hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
+
+ /* avoid reading back stale values if HDMI mode is not enabled */
+ if (val & DPLL_CTRL1_HDMI_MODE(pll->id)) {
+ hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
+ hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
+ }
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return ret;
+}
+
+static bool skl_ddi_dpll0_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+ const struct skl_dpll_regs *regs = skl_dpll_regs;
+ bool ret;
+
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ ret = false;
+
+ /* DPLL0 is always enabled since it drives CDCLK */
+ val = I915_READ(regs[pll->id].ctl);
+ if (WARN_ON(!(val & LCPLL_PLL_ENABLE)))
+ goto out;
+
+ val = I915_READ(DPLL_CTRL1);
+ hw_state->ctrl1 = (val >> (pll->id * 6)) & 0x3f;
+
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return ret;
+}
+
+struct skl_wrpll_context {
+ uint64_t min_deviation; /* current minimal deviation */
+ uint64_t central_freq; /* chosen central freq */
+ uint64_t dco_freq; /* chosen dco freq */
+ unsigned int p; /* chosen divider */
+};
+
+static void skl_wrpll_context_init(struct skl_wrpll_context *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->min_deviation = U64_MAX;
+}
+
+/* DCO freq must be within +1%/-6% of the DCO central freq */
+#define SKL_DCO_MAX_PDEVIATION 100
+#define SKL_DCO_MAX_NDEVIATION 600
+
+static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx,
+ uint64_t central_freq,
+ uint64_t dco_freq,
+ unsigned int divider)
+{
+ uint64_t deviation;
+
+ deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq),
+ central_freq);
+
+ /* positive deviation */
+ if (dco_freq >= central_freq) {
+ if (deviation < SKL_DCO_MAX_PDEVIATION &&
+ deviation < ctx->min_deviation) {
+ ctx->min_deviation = deviation;
+ ctx->central_freq = central_freq;
+ ctx->dco_freq = dco_freq;
+ ctx->p = divider;
+ }
+ /* negative deviation */
+ } else if (deviation < SKL_DCO_MAX_NDEVIATION &&
+ deviation < ctx->min_deviation) {
+ ctx->min_deviation = deviation;
+ ctx->central_freq = central_freq;
+ ctx->dco_freq = dco_freq;
+ ctx->p = divider;
+ }
+}
+
+static void skl_wrpll_get_multipliers(unsigned int p,
+ unsigned int *p0 /* out */,
+ unsigned int *p1 /* out */,
+ unsigned int *p2 /* out */)
+{
+ /* even dividers */
+ if (p % 2 == 0) {
+ unsigned int half = p / 2;
+
+ if (half == 1 || half == 2 || half == 3 || half == 5) {
+ *p0 = 2;
+ *p1 = 1;
+ *p2 = half;
+ } else if (half % 2 == 0) {
+ *p0 = 2;
+ *p1 = half / 2;
+ *p2 = 2;
+ } else if (half % 3 == 0) {
+ *p0 = 3;
+ *p1 = half / 3;
+ *p2 = 2;
+ } else if (half % 7 == 0) {
+ *p0 = 7;
+ *p1 = half / 7;
+ *p2 = 2;
+ }
+ } else if (p == 3 || p == 9) { /* 3, 5, 7, 9, 15, 21, 35 */
+ *p0 = 3;
+ *p1 = 1;
+ *p2 = p / 3;
+ } else if (p == 5 || p == 7) {
+ *p0 = p;
+ *p1 = 1;
+ *p2 = 1;
+ } else if (p == 15) {
+ *p0 = 3;
+ *p1 = 1;
+ *p2 = 5;
+ } else if (p == 21) {
+ *p0 = 7;
+ *p1 = 1;
+ *p2 = 3;
+ } else if (p == 35) {
+ *p0 = 7;
+ *p1 = 1;
+ *p2 = 5;
+ }
+}
+
+struct skl_wrpll_params {
+ uint32_t dco_fraction;
+ uint32_t dco_integer;
+ uint32_t qdiv_ratio;
+ uint32_t qdiv_mode;
+ uint32_t kdiv;
+ uint32_t pdiv;
+ uint32_t central_freq;
+};
+
+static void skl_wrpll_params_populate(struct skl_wrpll_params *params,
+ uint64_t afe_clock,
+ uint64_t central_freq,
+ uint32_t p0, uint32_t p1, uint32_t p2)
+{
+ uint64_t dco_freq;
+
+ switch (central_freq) {
+ case 9600000000ULL:
+ params->central_freq = 0;
+ break;
+ case 9000000000ULL:
+ params->central_freq = 1;
+ break;
+ case 8400000000ULL:
+ params->central_freq = 3;
+ }
+
+ switch (p0) {
+ case 1:
+ params->pdiv = 0;
+ break;
+ case 2:
+ params->pdiv = 1;
+ break;
+ case 3:
+ params->pdiv = 2;
+ break;
+ case 7:
+ params->pdiv = 4;
+ break;
+ default:
+ WARN(1, "Incorrect PDiv\n");
+ }
+
+ switch (p2) {
+ case 5:
+ params->kdiv = 0;
+ break;
+ case 2:
+ params->kdiv = 1;
+ break;
+ case 3:
+ params->kdiv = 2;
+ break;
+ case 1:
+ params->kdiv = 3;
+ break;
+ default:
+ WARN(1, "Incorrect KDiv\n");
+ }
+
+ params->qdiv_ratio = p1;
+ params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1;
+
+ dco_freq = p0 * p1 * p2 * afe_clock;
+
+ /*
+ * Intermediate values are in Hz.
+ * Divide by MHz to match bsepc
+ */
+ params->dco_integer = div_u64(dco_freq, 24 * MHz(1));
+ params->dco_fraction =
+ div_u64((div_u64(dco_freq, 24) -
+ params->dco_integer * MHz(1)) * 0x8000, MHz(1));
+}
+
+static bool
+skl_ddi_calculate_wrpll(int clock /* in Hz */,
+ struct skl_wrpll_params *wrpll_params)
+{
+ uint64_t afe_clock = clock * 5; /* AFE Clock is 5x Pixel clock */
+ uint64_t dco_central_freq[3] = {8400000000ULL,
+ 9000000000ULL,
+ 9600000000ULL};
+ static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20,
+ 24, 28, 30, 32, 36, 40, 42, 44,
+ 48, 52, 54, 56, 60, 64, 66, 68,
+ 70, 72, 76, 78, 80, 84, 88, 90,
+ 92, 96, 98 };
+ static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 };
+ static const struct {
+ const int *list;
+ int n_dividers;
+ } dividers[] = {
+ { even_dividers, ARRAY_SIZE(even_dividers) },
+ { odd_dividers, ARRAY_SIZE(odd_dividers) },
+ };
+ struct skl_wrpll_context ctx;
+ unsigned int dco, d, i;
+ unsigned int p0, p1, p2;
+
+ skl_wrpll_context_init(&ctx);
+
+ for (d = 0; d < ARRAY_SIZE(dividers); d++) {
+ for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) {
+ for (i = 0; i < dividers[d].n_dividers; i++) {
+ unsigned int p = dividers[d].list[i];
+ uint64_t dco_freq = p * afe_clock;
+
+ skl_wrpll_try_divider(&ctx,
+ dco_central_freq[dco],
+ dco_freq,
+ p);
+ /*
+ * Skip the remaining dividers if we're sure to
+ * have found the definitive divider, we can't
+ * improve a 0 deviation.
+ */
+ if (ctx.min_deviation == 0)
+ goto skip_remaining_dividers;
+ }
+ }
+
+skip_remaining_dividers:
+ /*
+ * If a solution is found with an even divider, prefer
+ * this one.
+ */
+ if (d == 0 && ctx.p)
+ break;
+ }
+
+ if (!ctx.p) {
+ DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock);
+ return false;
+ }
+
+ /*
+ * gcc incorrectly analyses that these can be used without being
+ * initialized. To be fair, it's hard to guess.
+ */
+ p0 = p1 = p2 = 0;
+ skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2);
+ skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq,
+ p0, p1, p2);
+
+ return true;
+}
+
+static struct intel_shared_dpll *
+skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ struct intel_shared_dpll *pll;
+ uint32_t ctrl1, cfgcr1, cfgcr2;
+ int clock = crtc_state->port_clock;
+
+ /*
+ * See comment in intel_dpll_hw_state to understand why we always use 0
+ * as the DPLL id in this function.
+ */
+
+ ctrl1 = DPLL_CTRL1_OVERRIDE(0);
+
+ if (encoder->type == INTEL_OUTPUT_HDMI) {
+ struct skl_wrpll_params wrpll_params = { 0, };
+
+ ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
+
+ if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
+ return false;
+
+ cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
+ DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
+ wrpll_params.dco_integer;
+
+ cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
+ DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
+ DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
+ DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
+ wrpll_params.central_freq;
+ } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+ encoder->type == INTEL_OUTPUT_DP_MST ||
+ encoder->type == INTEL_OUTPUT_EDP) {
+ switch (crtc_state->port_clock / 2) {
+ case 81000:
+ ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
+ break;
+ case 135000:
+ ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
+ break;
+ case 270000:
+ ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
+ break;
+ /* eDP 1.4 rates */
+ case 162000:
+ ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
+ break;
+ /* TBD: For DP link rates 2.16 GHz and 4.32 GHz, VCO is 8640 which
+ results in CDCLK change. Need to handle the change of CDCLK by
+ disabling pipes and re-enabling them */
+ case 108000:
+ ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
+ break;
+ case 216000:
+ ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
+ break;
+ }
+
+ cfgcr1 = cfgcr2 = 0;
+ } else {
+ return NULL;
+ }
+
+ memset(&crtc_state->dpll_hw_state, 0,
+ sizeof(crtc_state->dpll_hw_state));
+
+ crtc_state->dpll_hw_state.ctrl1 = ctrl1;
+ crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+ crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
+
+ if (encoder->type == INTEL_OUTPUT_EDP)
+ pll = intel_find_shared_dpll(crtc, crtc_state,
+ DPLL_ID_SKL_DPLL0,
+ DPLL_ID_SKL_DPLL0);
+ else
+ pll = intel_find_shared_dpll(crtc, crtc_state,
+ DPLL_ID_SKL_DPLL1,
+ DPLL_ID_SKL_DPLL3);
+ if (!pll)
+ return NULL;
+
+ crtc_state->ddi_pll_sel = pll->id;
+
+ intel_reference_shared_dpll(pll, crtc_state);
+
+ return pll;
+}
+
+static const struct intel_shared_dpll_funcs skl_ddi_pll_funcs = {
+ .enable = skl_ddi_pll_enable,
+ .disable = skl_ddi_pll_disable,
+ .get_hw_state = skl_ddi_pll_get_hw_state,
+};
+
+static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = {
+ .enable = skl_ddi_dpll0_enable,
+ .disable = skl_ddi_dpll0_disable,
+ .get_hw_state = skl_ddi_dpll0_get_hw_state,
+};
+
+static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ uint32_t temp;
+ enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
+
+ temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
+ temp &= ~PORT_PLL_REF_SEL;
+ /* Non-SSC reference */
+ I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
+
+ /* Disable 10 bit clock */
+ temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
+ temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
+ I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
+
+ /* Write P1 & P2 */
+ temp = I915_READ(BXT_PORT_PLL_EBB_0(port));
+ temp &= ~(PORT_PLL_P1_MASK | PORT_PLL_P2_MASK);
+ temp |= pll->config.hw_state.ebb0;
+ I915_WRITE(BXT_PORT_PLL_EBB_0(port), temp);
+
+ /* Write M2 integer */
+ temp = I915_READ(BXT_PORT_PLL(port, 0));
+ temp &= ~PORT_PLL_M2_MASK;
+ temp |= pll->config.hw_state.pll0;
+ I915_WRITE(BXT_PORT_PLL(port, 0), temp);
+
+ /* Write N */
+ temp = I915_READ(BXT_PORT_PLL(port, 1));
+ temp &= ~PORT_PLL_N_MASK;
+ temp |= pll->config.hw_state.pll1;
+ I915_WRITE(BXT_PORT_PLL(port, 1), temp);
+
+ /* Write M2 fraction */
+ temp = I915_READ(BXT_PORT_PLL(port, 2));
+ temp &= ~PORT_PLL_M2_FRAC_MASK;
+ temp |= pll->config.hw_state.pll2;
+ I915_WRITE(BXT_PORT_PLL(port, 2), temp);
+
+ /* Write M2 fraction enable */
+ temp = I915_READ(BXT_PORT_PLL(port, 3));
+ temp &= ~PORT_PLL_M2_FRAC_ENABLE;
+ temp |= pll->config.hw_state.pll3;
+ I915_WRITE(BXT_PORT_PLL(port, 3), temp);
+
+ /* Write coeff */
+ temp = I915_READ(BXT_PORT_PLL(port, 6));
+ temp &= ~PORT_PLL_PROP_COEFF_MASK;
+ temp &= ~PORT_PLL_INT_COEFF_MASK;
+ temp &= ~PORT_PLL_GAIN_CTL_MASK;
+ temp |= pll->config.hw_state.pll6;
+ I915_WRITE(BXT_PORT_PLL(port, 6), temp);
+
+ /* Write calibration val */
+ temp = I915_READ(BXT_PORT_PLL(port, 8));
+ temp &= ~PORT_PLL_TARGET_CNT_MASK;
+ temp |= pll->config.hw_state.pll8;
+ I915_WRITE(BXT_PORT_PLL(port, 8), temp);
+
+ temp = I915_READ(BXT_PORT_PLL(port, 9));
+ temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK;
+ temp |= pll->config.hw_state.pll9;
+ I915_WRITE(BXT_PORT_PLL(port, 9), temp);
+
+ temp = I915_READ(BXT_PORT_PLL(port, 10));
+ temp &= ~PORT_PLL_DCO_AMP_OVR_EN_H;
+ temp &= ~PORT_PLL_DCO_AMP_MASK;
+ temp |= pll->config.hw_state.pll10;
+ I915_WRITE(BXT_PORT_PLL(port, 10), temp);
+
+ /* Recalibrate with new settings */
+ temp = I915_READ(BXT_PORT_PLL_EBB_4(port));
+ temp |= PORT_PLL_RECALIBRATE;
+ I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
+ temp &= ~PORT_PLL_10BIT_CLK_ENABLE;
+ temp |= pll->config.hw_state.ebb4;
+ I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp);
+
+ /* Enable PLL */
+ temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
+ temp |= PORT_PLL_ENABLE;
+ I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
+ POSTING_READ(BXT_PORT_PLL_ENABLE(port));
+
+ if (wait_for_atomic_us((I915_READ(BXT_PORT_PLL_ENABLE(port)) &
+ PORT_PLL_LOCK), 200))
+ DRM_ERROR("PLL %d not locked\n", port);
+
+ /*
+ * While we write to the group register to program all lanes at once we
+ * can read only lane registers and we pick lanes 0/1 for that.
+ */
+ temp = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
+ temp &= ~LANE_STAGGER_MASK;
+ temp &= ~LANESTAGGER_STRAP_OVRD;
+ temp |= pll->config.hw_state.pcsdw12;
+ I915_WRITE(BXT_PORT_PCS_DW12_GRP(port), temp);
+}
+
+static void bxt_ddi_pll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
+ uint32_t temp;
+
+ temp = I915_READ(BXT_PORT_PLL_ENABLE(port));
+ temp &= ~PORT_PLL_ENABLE;
+ I915_WRITE(BXT_PORT_PLL_ENABLE(port), temp);
+ POSTING_READ(BXT_PORT_PLL_ENABLE(port));
+}
+
+static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
+ uint32_t val;
+ bool ret;
+
+ if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ ret = false;
+
+ val = I915_READ(BXT_PORT_PLL_ENABLE(port));
+ if (!(val & PORT_PLL_ENABLE))
+ goto out;
+
+ hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
+ hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
+
+ hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port));
+ hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE;
+
+ hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0));
+ hw_state->pll0 &= PORT_PLL_M2_MASK;
+
+ hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1));
+ hw_state->pll1 &= PORT_PLL_N_MASK;
+
+ hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2));
+ hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK;
+
+ hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3));
+ hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE;
+
+ hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6));
+ hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK |
+ PORT_PLL_INT_COEFF_MASK |
+ PORT_PLL_GAIN_CTL_MASK;
+
+ hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8));
+ hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK;
+
+ hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9));
+ hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK;
+
+ hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10));
+ hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H |
+ PORT_PLL_DCO_AMP_MASK;
+
+ /*
+ * While we write to the group register to program all lanes at once we
+ * can read only lane registers. We configure all lanes the same way, so
+ * here just read out lanes 0/1 and output a note if lanes 2/3 differ.
+ */
+ hw_state->pcsdw12 = I915_READ(BXT_PORT_PCS_DW12_LN01(port));
+ if (I915_READ(BXT_PORT_PCS_DW12_LN23(port)) != hw_state->pcsdw12)
+ DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n",
+ hw_state->pcsdw12,
+ I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
+ hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;
+
+ ret = true;
+
+out:
+ intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+ return ret;
+}
+
+/* bxt clock parameters */
+struct bxt_clk_div {
+ int clock;
+ uint32_t p1;
+ uint32_t p2;
+ uint32_t m2_int;
+ uint32_t m2_frac;
+ bool m2_frac_en;
+ uint32_t n;
+};
+
+/* pre-calculated values for DP linkrates */
+static const struct bxt_clk_div bxt_dp_clk_val[] = {
+ {162000, 4, 2, 32, 1677722, 1, 1},
+ {270000, 4, 1, 27, 0, 0, 1},
+ {540000, 2, 1, 27, 0, 0, 1},
+ {216000, 3, 2, 32, 1677722, 1, 1},
+ {243000, 4, 1, 24, 1258291, 1, 1},
+ {324000, 4, 1, 32, 1677722, 1, 1},
+ {432000, 3, 1, 32, 1677722, 1, 1}
+};
+
+static struct intel_shared_dpll *
+bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_shared_dpll *pll;
+ enum intel_dpll_id i;
+ struct intel_digital_port *intel_dig_port;
+ struct bxt_clk_div clk_div = {0};
+ int vco = 0;
+ uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
+ uint32_t lanestagger;
+ int clock = crtc_state->port_clock;
+
+ if (encoder->type == INTEL_OUTPUT_HDMI) {
+ intel_clock_t best_clock;
+
+ /* Calculate HDMI div */
+ /*
+ * FIXME: tie the following calculation into
+ * i9xx_crtc_compute_clock
+ */
+ if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
+ DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
+ clock, pipe_name(crtc->pipe));
+ return NULL;
+ }
+
+ clk_div.p1 = best_clock.p1;
+ clk_div.p2 = best_clock.p2;
+ WARN_ON(best_clock.m1 != 2);
+ clk_div.n = best_clock.n;
+ clk_div.m2_int = best_clock.m2 >> 22;
+ clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
+ clk_div.m2_frac_en = clk_div.m2_frac != 0;
+
+ vco = best_clock.vco;
+ } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+ encoder->type == INTEL_OUTPUT_EDP) {
+ int i;
+
+ clk_div = bxt_dp_clk_val[0];
+ for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
+ if (bxt_dp_clk_val[i].clock == clock) {
+ clk_div = bxt_dp_clk_val[i];
+ break;
+ }
+ }
+ vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
+ }
+
+ if (vco >= 6200000 && vco <= 6700000) {
+ prop_coef = 4;
+ int_coef = 9;
+ gain_ctl = 3;
+ targ_cnt = 8;
+ } else if ((vco > 5400000 && vco < 6200000) ||
+ (vco >= 4800000 && vco < 5400000)) {
+ prop_coef = 5;
+ int_coef = 11;
+ gain_ctl = 3;
+ targ_cnt = 9;
+ } else if (vco == 5400000) {
+ prop_coef = 3;
+ int_coef = 8;
+ gain_ctl = 1;
+ targ_cnt = 9;
+ } else {
+ DRM_ERROR("Invalid VCO\n");
+ return NULL;
+ }
+
+ memset(&crtc_state->dpll_hw_state, 0,
+ sizeof(crtc_state->dpll_hw_state));
+
+ if (clock > 270000)
+ lanestagger = 0x18;
+ else if (clock > 135000)
+ lanestagger = 0x0d;
+ else if (clock > 67000)
+ lanestagger = 0x07;
+ else if (clock > 33000)
+ lanestagger = 0x04;
+ else
+ lanestagger = 0x02;
+
+ crtc_state->dpll_hw_state.ebb0 =
+ PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
+ crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
+ crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
+ crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
+
+ if (clk_div.m2_frac_en)
+ crtc_state->dpll_hw_state.pll3 =
+ PORT_PLL_M2_FRAC_ENABLE;
+
+ crtc_state->dpll_hw_state.pll6 =
+ prop_coef | PORT_PLL_INT_COEFF(int_coef);
+ crtc_state->dpll_hw_state.pll6 |=
+ PORT_PLL_GAIN_CTL(gain_ctl);
+
+ crtc_state->dpll_hw_state.pll8 = targ_cnt;
+
+ crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
+
+ crtc_state->dpll_hw_state.pll10 =
+ PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
+ | PORT_PLL_DCO_AMP_OVR_EN_H;
+
+ crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
+
+ crtc_state->dpll_hw_state.pcsdw12 =
+ LANESTAGGER_STRAP_OVRD | lanestagger;
+
+ intel_dig_port = enc_to_dig_port(&encoder->base);
+
+ /* 1:1 mapping between ports and PLLs */
+ i = (enum intel_dpll_id) intel_dig_port->port;
+ pll = intel_get_shared_dpll_by_id(dev_priv, i);
+
+ DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
+ crtc->base.base.id, pll->name);
+
+ intel_reference_shared_dpll(pll, crtc_state);
+
+ /* shared DPLL id 0 is DPLL A */
+ crtc_state->ddi_pll_sel = pll->id;
+
+ return pll;
+}
+
+static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = {
+ .enable = bxt_ddi_pll_enable,
+ .disable = bxt_ddi_pll_disable,
+ .get_hw_state = bxt_ddi_pll_get_hw_state,
+};
+
+static void intel_ddi_pll_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t val = I915_READ(LCPLL_CTL);
+
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
+ int cdclk_freq;
+
+ cdclk_freq = dev_priv->display.get_display_clock_speed(dev);
+ dev_priv->skl_boot_cdclk = cdclk_freq;
+ if (skl_sanitize_cdclk(dev_priv))
+ DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n");
+ if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE))
+ DRM_ERROR("LCPLL1 is disabled\n");
+ } else if (IS_BROXTON(dev)) {
+ broxton_init_cdclk(dev);
+ broxton_ddi_phy_init(dev);
+ } else {
+ /*
+ * The LCPLL register should be turned on by the BIOS. For now
+ * let's just check its state and print errors in case
+ * something is wrong. Don't even try to turn it on.
+ */
+
+ if (val & LCPLL_CD_SOURCE_FCLK)
+ DRM_ERROR("CDCLK source is not LCPLL\n");
+
+ if (val & LCPLL_PLL_DISABLE)
+ DRM_ERROR("LCPLL is disabled\n");
+ }
+}
+
+struct dpll_info {
+ const char *name;
+ const int id;
+ const struct intel_shared_dpll_funcs *funcs;
+ uint32_t flags;
+};
+
+struct intel_dpll_mgr {
+ const struct dpll_info *dpll_info;
+
+ struct intel_shared_dpll *(*get_dpll)(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder);
+};
+
+static const struct dpll_info pch_plls[] = {
+ { "PCH DPLL A", DPLL_ID_PCH_PLL_A, &ibx_pch_dpll_funcs, 0 },
+ { "PCH DPLL B", DPLL_ID_PCH_PLL_B, &ibx_pch_dpll_funcs, 0 },
+ { NULL, -1, NULL, 0 },
+};
+
+static const struct intel_dpll_mgr pch_pll_mgr = {
+ .dpll_info = pch_plls,
+ .get_dpll = ibx_get_dpll,
+};
+
+static const struct dpll_info hsw_plls[] = {
+ { "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs, 0 },
+ { "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs, 0 },
+ { "SPLL", DPLL_ID_SPLL, &hsw_ddi_spll_funcs, 0 },
+ { "LCPLL 810", DPLL_ID_LCPLL_810, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
+ { "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
+ { "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs, INTEL_DPLL_ALWAYS_ON },
+ { NULL, -1, NULL, },
+};
+
+static const struct intel_dpll_mgr hsw_pll_mgr = {
+ .dpll_info = hsw_plls,
+ .get_dpll = hsw_get_dpll,
+};
+
+static const struct dpll_info skl_plls[] = {
+ { "DPLL 0", DPLL_ID_SKL_DPLL0, &skl_ddi_dpll0_funcs, INTEL_DPLL_ALWAYS_ON },
+ { "DPPL 1", DPLL_ID_SKL_DPLL1, &skl_ddi_pll_funcs, 0 },
+ { "DPPL 2", DPLL_ID_SKL_DPLL2, &skl_ddi_pll_funcs, 0 },
+ { "DPPL 3", DPLL_ID_SKL_DPLL3, &skl_ddi_pll_funcs, 0 },
+ { NULL, -1, NULL, },
+};
+
+static const struct intel_dpll_mgr skl_pll_mgr = {
+ .dpll_info = skl_plls,
+ .get_dpll = skl_get_dpll,
+};
+
+static const struct dpll_info bxt_plls[] = {
+ { "PORT PLL A", 0, &bxt_ddi_pll_funcs, 0 },
+ { "PORT PLL B", 1, &bxt_ddi_pll_funcs, 0 },
+ { "PORT PLL C", 2, &bxt_ddi_pll_funcs, 0 },
+ { NULL, -1, NULL, },
+};
+
+static const struct intel_dpll_mgr bxt_pll_mgr = {
+ .dpll_info = bxt_plls,
+ .get_dpll = bxt_get_dpll,
+};
+
+void intel_shared_dpll_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const struct intel_dpll_mgr *dpll_mgr = NULL;
+ const struct dpll_info *dpll_info;
+ int i;
+
+ if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
+ dpll_mgr = &skl_pll_mgr;
+ else if IS_BROXTON(dev)
+ dpll_mgr = &bxt_pll_mgr;
+ else if (HAS_DDI(dev))
+ dpll_mgr = &hsw_pll_mgr;
+ else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+ dpll_mgr = &pch_pll_mgr;
+
+ if (!dpll_mgr) {
+ dev_priv->num_shared_dpll = 0;
+ return;
+ }
+
+ dpll_info = dpll_mgr->dpll_info;
+
+ for (i = 0; dpll_info[i].id >= 0; i++) {
+ WARN_ON(i != dpll_info[i].id);
+
+ dev_priv->shared_dplls[i].id = dpll_info[i].id;
+ dev_priv->shared_dplls[i].name = dpll_info[i].name;
+ dev_priv->shared_dplls[i].funcs = *dpll_info[i].funcs;
+ dev_priv->shared_dplls[i].flags = dpll_info[i].flags;
+ }
+
+ dev_priv->dpll_mgr = dpll_mgr;
+ dev_priv->num_shared_dpll = i;
+
+ BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
+
+ /* FIXME: Move this to a more suitable place */
+ if (HAS_DDI(dev))
+ intel_ddi_pll_init(dev);
+}
+
+struct intel_shared_dpll *
+intel_get_shared_dpll(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ const struct intel_dpll_mgr *dpll_mgr = dev_priv->dpll_mgr;
+
+ if (WARN_ON(!dpll_mgr))
+ return NULL;
+
+ return dpll_mgr->get_dpll(crtc, crtc_state, encoder);
+}
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
new file mode 100644
index 000000000000..1d341472f8b0
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright © 2012-2016 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.
+ *
+ */
+
+#ifndef _INTEL_DPLL_MGR_H_
+#define _INTEL_DPLL_MGR_H_
+
+/*FIXME: Move this to a more appropriate place. */
+#define abs_diff(a, b) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ (void) (&__a == &__b); \
+ __a > __b ? (__a - __b) : (__b - __a); })
+
+struct drm_i915_private;
+struct intel_crtc;
+struct intel_crtc_state;
+struct intel_encoder;
+
+struct intel_shared_dpll;
+struct intel_dpll_mgr;
+
+enum intel_dpll_id {
+ DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */
+ /* real shared dpll ids must be >= 0 */
+ DPLL_ID_PCH_PLL_A = 0,
+ DPLL_ID_PCH_PLL_B = 1,
+ /* hsw/bdw */
+ DPLL_ID_WRPLL1 = 0,
+ DPLL_ID_WRPLL2 = 1,
+ DPLL_ID_SPLL = 2,
+ DPLL_ID_LCPLL_810 = 3,
+ DPLL_ID_LCPLL_1350 = 4,
+ DPLL_ID_LCPLL_2700 = 5,
+
+ /* skl */
+ DPLL_ID_SKL_DPLL0 = 0,
+ DPLL_ID_SKL_DPLL1 = 1,
+ DPLL_ID_SKL_DPLL2 = 2,
+ DPLL_ID_SKL_DPLL3 = 3,
+};
+#define I915_NUM_PLLS 6
+
+/** Inform the state checker that the DPLL is kept enabled even if not
+ * in use by any crtc.
+ */
+#define INTEL_DPLL_ALWAYS_ON (1 << 0)
+
+struct intel_dpll_hw_state {
+ /* i9xx, pch plls */
+ uint32_t dpll;
+ uint32_t dpll_md;
+ uint32_t fp0;
+ uint32_t fp1;
+
+ /* hsw, bdw */
+ uint32_t wrpll;
+ uint32_t spll;
+
+ /* skl */
+ /*
+ * DPLL_CTRL1 has 6 bits for each each this DPLL. We store those in
+ * lower part of ctrl1 and they get shifted into position when writing
+ * the register. This allows us to easily compare the state to share
+ * the DPLL.
+ */
+ uint32_t ctrl1;
+ /* HDMI only, 0 when used for DP */
+ uint32_t cfgcr1, cfgcr2;
+
+ /* bxt */
+ uint32_t ebb0, ebb4, pll0, pll1, pll2, pll3, pll6, pll8, pll9, pll10,
+ pcsdw12;
+};
+
+struct intel_shared_dpll_config {
+ unsigned crtc_mask; /* mask of CRTCs sharing this PLL */
+ struct intel_dpll_hw_state hw_state;
+};
+
+struct intel_shared_dpll_funcs {
+ /* The mode_set hook is optional and should be used together with the
+ * intel_prepare_shared_dpll function. */
+ void (*mode_set)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
+ void (*enable)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
+ void (*disable)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
+ bool (*get_hw_state)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
+};
+
+struct intel_shared_dpll {
+ struct intel_shared_dpll_config config;
+
+ int active; /* count of number of active CRTCs (i.e. DPMS on) */
+ bool on; /* is the PLL actually active? Disabled during modeset */
+ const char *name;
+ /* should match the index in the dev_priv->shared_dplls array */
+ enum intel_dpll_id id;
+
+ struct intel_shared_dpll_funcs funcs;
+
+ uint32_t flags;
+};
+
+#define SKL_DPLL0 0
+#define SKL_DPLL1 1
+#define SKL_DPLL2 2
+#define SKL_DPLL3 3
+
+/* shared dpll functions */
+struct intel_shared_dpll *
+intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
+ enum intel_dpll_id id);
+enum intel_dpll_id
+intel_get_shared_dpll_id(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
+void
+intel_shared_dpll_config_get(struct intel_shared_dpll_config *config,
+ struct intel_shared_dpll *pll,
+ struct intel_crtc *crtc);
+void
+intel_shared_dpll_config_put(struct intel_shared_dpll_config *config,
+ struct intel_shared_dpll *pll,
+ struct intel_crtc *crtc);
+void assert_shared_dpll(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ bool state);
+#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
+#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
+struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
+ struct intel_crtc_state *state,
+ struct intel_encoder *encoder);
+void intel_prepare_shared_dpll(struct intel_crtc *crtc);
+void intel_enable_shared_dpll(struct intel_crtc *crtc);
+void intel_disable_shared_dpll(struct intel_crtc *crtc);
+void intel_shared_dpll_commit(struct drm_atomic_state *state);
+void intel_shared_dpll_init(struct drm_device *dev);
+
+
+#endif /* _INTEL_DPLL_MGR_H_ */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 4c027d69fac9..02b3d22862a1 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -44,9 +44,13 @@
* contexts. Note that it's important that we check the condition again after
* having timed out, since the timeout could be due to preemption or similar and
* we've never had a chance to check the condition before the timeout.
+ *
+ * TODO: When modesetting has fully transitioned to atomic, the below
+ * drm_can_sleep() can be removed and in_atomic()/!in_atomic() asserts
+ * added.
*/
-#define _wait_for(COND, MS, W) ({ \
- unsigned long timeout__ = jiffies + msecs_to_jiffies(MS) + 1; \
+#define _wait_for(COND, US, W) ({ \
+ unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1; \
int ret__ = 0; \
while (!(COND)) { \
if (time_after(jiffies, timeout__)) { \
@@ -55,7 +59,7 @@
break; \
} \
if ((W) && drm_can_sleep()) { \
- usleep_range((W)*1000, (W)*2000); \
+ usleep_range((W), (W)*2); \
} else { \
cpu_relax(); \
} \
@@ -63,10 +67,40 @@
ret__; \
})
-#define wait_for(COND, MS) _wait_for(COND, MS, 1)
-#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
-#define wait_for_atomic_us(COND, US) _wait_for((COND), \
- DIV_ROUND_UP((US), 1000), 0)
+#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 1000)
+#define wait_for_us(COND, US) _wait_for((COND), (US), 1)
+
+/* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */
+#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT)
+# define _WAIT_FOR_ATOMIC_CHECK WARN_ON_ONCE(!in_atomic())
+#else
+# define _WAIT_FOR_ATOMIC_CHECK do { } while (0)
+#endif
+
+#define _wait_for_atomic(COND, US) ({ \
+ unsigned long end__; \
+ int ret__ = 0; \
+ _WAIT_FOR_ATOMIC_CHECK; \
+ BUILD_BUG_ON((US) > 50000); \
+ end__ = (local_clock() >> 10) + (US) + 1; \
+ while (!(COND)) { \
+ if (time_after((unsigned long)(local_clock() >> 10), end__)) { \
+ /* Unlike the regular wait_for(), this atomic variant \
+ * cannot be preempted (and we'll just ignore the issue\
+ * of irq interruptions) and so we know that no time \
+ * has passed since the last check of COND and can \
+ * immediately report the timeout. \
+ */ \
+ ret__ = -ETIMEDOUT; \
+ break; \
+ } \
+ cpu_relax(); \
+ } \
+ ret__; \
+})
+
+#define wait_for_atomic(COND, MS) _wait_for_atomic((COND), (MS) * 1000)
+#define wait_for_atomic_us(COND, US) _wait_for_atomic((COND), (US))
#define KHz(x) (1000 * (x))
#define MHz(x) KHz(1000 * (x))
@@ -118,6 +152,7 @@ enum intel_output_type {
struct intel_framebuffer {
struct drm_framebuffer base;
struct drm_i915_gem_object *obj;
+ struct intel_rotation_info rot_info;
};
struct intel_fbdev {
@@ -260,6 +295,12 @@ struct intel_atomic_state {
struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
struct intel_wm_config wm_config;
+
+ /*
+ * Current watermarks can't be trusted during hardware readout, so
+ * don't bother calculating intermediate watermarks.
+ */
+ bool skip_intermediate_wm;
};
struct intel_plane_state {
@@ -349,6 +390,7 @@ struct intel_crtc_scaler_state {
struct intel_pipe_wm {
struct intel_wm_level wm[5];
+ struct intel_wm_level raw_wm[5];
uint32_t linetime;
bool fbc_wm_enabled;
bool pipe_enabled;
@@ -378,7 +420,7 @@ struct intel_crtc_state {
bool update_pipe; /* can a fast modeset be performed? */
bool disable_cxsr;
- bool wm_changed; /* watermarks are updated */
+ bool update_wm_pre, update_wm_post; /* watermarks are updated */
bool fb_changed; /* fb on any of the planes is changed */
/* Pipe source size (ie. panel fitter input size)
@@ -441,8 +483,8 @@ struct intel_crtc_state {
* haswell. */
struct dpll dpll;
- /* Selected dpll when shared or DPLL_ID_PRIVATE. */
- enum intel_dpll_id shared_dpll;
+ /* Selected dpll when shared or NULL. */
+ struct intel_shared_dpll *shared_dpll;
/*
* - PORT_CLK_SEL for DDI ports on HSW/BDW.
@@ -510,13 +552,29 @@ struct intel_crtc_state {
struct {
/*
- * optimal watermarks, programmed post-vblank when this state
- * is committed
+ * Optimal watermarks, programmed post-vblank when this state
+ * is committed.
*/
union {
struct intel_pipe_wm ilk;
struct skl_pipe_wm skl;
} optimal;
+
+ /*
+ * Intermediate watermarks; these can be programmed immediately
+ * since they satisfy both the current configuration we're
+ * switching away from and the new configuration we're switching
+ * to.
+ */
+ struct intel_pipe_wm intermediate;
+
+ /*
+ * Platforms with two-step watermark programming will need to
+ * update watermark programming post-vblank to switch from the
+ * safe intermediate watermarks to the optimal final
+ * watermarks.
+ */
+ bool need_postvbl_update;
} wm;
};
@@ -600,6 +658,7 @@ struct intel_crtc {
struct intel_pipe_wm ilk;
struct skl_pipe_wm skl;
} active;
+
/* allow CxSR on this pipe */
bool cxsr_allowed;
} wm;
@@ -1007,7 +1066,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc);
void intel_ddi_init(struct drm_device *dev, enum port port);
enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder);
bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe);
-void intel_ddi_pll_init(struct drm_device *dev);
void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc);
void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder);
@@ -1059,9 +1117,8 @@ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
/* intel_display.c */
extern const struct drm_plane_funcs intel_plane_funcs;
+unsigned int intel_rotation_info_size(const struct intel_rotation_info *rot_info);
bool intel_has_pending_fb_unpin(struct drm_device *dev);
-int intel_pch_rawclk(struct drm_device *dev);
-int intel_hrawclk(struct drm_device *dev);
void intel_mark_busy(struct drm_device *dev);
void intel_mark_idle(struct drm_device *dev);
void intel_crtc_restore_mode(struct drm_crtc *crtc);
@@ -1106,9 +1163,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
void intel_release_load_detect_pipe(struct drm_connector *connector,
struct intel_load_detect_pipe *old,
struct drm_modeset_acquire_ctx *ctx);
-int intel_pin_and_fence_fb_obj(struct drm_plane *plane,
- struct drm_framebuffer *fb,
- const struct drm_plane_state *plane_state);
+int intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb,
+ unsigned int rotation);
struct drm_framebuffer *
__intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
@@ -1144,19 +1200,13 @@ intel_rotation_90_or_270(unsigned int rotation)
void intel_create_rotation_property(struct drm_device *dev,
struct intel_plane *plane);
-/* shared dpll functions */
-struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
-void assert_shared_dpll(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- bool state);
-#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
-#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
- struct intel_crtc_state *state);
+void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+ enum pipe pipe);
int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
const struct dpll *dpll);
void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe);
+int lpt_get_iclkip(struct drm_i915_private *dev_priv);
/* modesetting asserts */
void assert_panel_unlocked(struct drm_i915_private *dev_priv,
@@ -1172,11 +1222,10 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state);
#define assert_pipe_enabled(d, p) assert_pipe(d, p, true)
#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
-u32 intel_compute_tile_offset(struct drm_i915_private *dev_priv,
- int *x, int *y,
- uint64_t fb_modifier,
- unsigned int cpp,
- unsigned int pitch);
+u32 intel_compute_tile_offset(int *x, int *y,
+ const struct drm_framebuffer *fb, int plane,
+ unsigned int pitch,
+ unsigned int rotation);
void intel_prepare_reset(struct drm_device *dev);
void intel_finish_reset(struct drm_device *dev);
void hsw_enable_pc8(struct drm_i915_private *dev_priv);
@@ -1196,9 +1245,6 @@ void intel_dp_get_m_n(struct intel_crtc *crtc,
struct intel_crtc_state *pipe_config);
void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n);
int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
-void
-ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
- int dotclock);
bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock,
intel_clock_t *best_clock);
int chv_calc_dpll_params(int refclk, intel_clock_t *pll_clock);
@@ -1226,7 +1272,7 @@ u32 skl_plane_ctl_rotation(unsigned int rotation);
/* intel_csr.c */
void intel_csr_ucode_init(struct drm_i915_private *);
-bool intel_csr_load_program(struct drm_i915_private *);
+void intel_csr_load_program(struct drm_i915_private *);
void intel_csr_ucode_fini(struct drm_i915_private *);
/* intel_dp.c */
@@ -1266,7 +1312,6 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
struct intel_digital_port *port);
-void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
void
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
@@ -1565,6 +1610,7 @@ void skl_wm_get_hw_state(struct drm_device *dev);
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
struct skl_ddb_allocation *ddb /* out */);
uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
+bool ilk_disable_lp_wm(struct drm_device *dev);
int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6);
/* intel_sdvo.c */
@@ -1606,6 +1652,18 @@ intel_atomic_get_crtc_state(struct drm_atomic_state *state,
return to_intel_crtc_state(crtc_state);
}
+
+static inline struct intel_plane_state *
+intel_atomic_get_existing_plane_state(struct drm_atomic_state *state,
+ struct intel_plane *plane)
+{
+ struct drm_plane_state *plane_state;
+
+ plane_state = drm_atomic_get_existing_plane_state(state, &plane->base);
+
+ return to_intel_plane_state(plane_state);
+}
+
int intel_atomic_setup_scalers(struct drm_device *dev,
struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state);
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index 70883c54cb0a..2451c84949bd 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -362,35 +362,57 @@ static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
/* Program BXT Mipi clocks and dividers */
static void bxt_dsi_program_clocks(struct drm_device *dev, enum port port)
{
- u32 tmp;
- u32 divider;
- u32 dsi_rate;
- u32 pll_ratio;
struct drm_i915_private *dev_priv = dev->dev_private;
+ 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_FIXDIV_MASK(port));
- tmp &= ~(BXT_MIPI_ESCLK_VAR_DIV_MASK(port));
- tmp &= ~(BXT_MIPI_DPHY_DIVIDER_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 = I915_READ(BXT_DSI_PLL_CTL) &
BXT_DSI_PLL_RATIO_MASK;
dsi_rate = (BXT_REF_CLOCK_KHZ * pll_ratio) / 2;
- /* Max possible output of clock is 39.5 MHz, program value -1 */
- divider = (dsi_rate / BXT_MAX_VAR_OUTPUT_KHZ) - 1;
- tmp |= BXT_MIPI_ESCLK_VAR_DIV(port, divider);
+ /*
+ * 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;
/*
- * Tx escape clock must be as close to 20MHz possible, but should
- * not exceed it. Hence select divide by 2
+ * rx divider value needs to be updated in the
+ * two differnt bit fields in the register hence splitting the
+ * rx divider value accordingly
*/
- tmp |= BXT_MIPI_TX_ESCLK_8XDIV_BY2(port);
+ rx_div_lower = rx_div & RX_DIVIDER_BIT_1_2;
+ rx_div_upper = (rx_div & RX_DIVIDER_BIT_3_4) >> 2;
+
+ /* As per bpsec program the 8/3X clock divider to the below value */
+ if (dev_priv->vbt.dsi.config->is_cmd_mode)
+ mipi_8by3_divider = 0x2;
+ else
+ mipi_8by3_divider = 0x3;
- tmp |= BXT_MIPI_RX_ESCLK_8X_BY3(port);
+ 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);
}
@@ -513,9 +535,9 @@ static void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
/* Clear old configurations */
tmp = I915_READ(BXT_MIPI_CLOCK_CTL);
tmp &= ~(BXT_MIPI_TX_ESCLK_FIXDIV_MASK(port));
- tmp &= ~(BXT_MIPI_RX_ESCLK_FIXDIV_MASK(port));
- tmp &= ~(BXT_MIPI_ESCLK_VAR_DIV_MASK(port));
- tmp &= ~(BXT_MIPI_DPHY_DIVIDER_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));
I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
}
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 97a91e631915..ae9cf6fcb870 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -220,7 +220,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
* This also validates that any existing fb inherited from the
* BIOS is suitable for own access.
*/
- ret = intel_pin_and_fence_fb_obj(NULL, &ifbdev->fb->base, NULL);
+ ret = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, BIT(DRM_ROTATE_0));
if (ret)
goto out_unlock;
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index a0d8daed2470..e2dab4828508 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -952,9 +952,6 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
if (pipe_config->pixel_multiplier)
dotclock /= pipe_config->pixel_multiplier;
- if (HAS_PCH_SPLIT(dev_priv->dev))
- ironlake_check_encoder_dotclock(pipe_config, dotclock);
-
pipe_config->base.adjusted_mode.crtc_clock = dotclock;
}
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 6a978ce80244..6fcbf6bb0479 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -270,6 +270,9 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *ring)
{
struct drm_device *dev = ring->dev;
+ if (IS_GEN8(dev) || IS_GEN9(dev))
+ ring->idle_lite_restore_wa = ~0;
+
ring->disable_lite_restore_wa = (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
IS_BXT_REVID(dev, 0, BXT_REVID_A1)) &&
(ring->id == VCS || ring->id == VCS2);
@@ -373,8 +376,6 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
rq0->elsp_submitted++;
/* You must always write both descriptors in the order below. */
- spin_lock(&dev_priv->uncore.lock);
- intel_uncore_forcewake_get__locked(dev_priv, FORCEWAKE_ALL);
I915_WRITE_FW(RING_ELSP(ring), upper_32_bits(desc[1]));
I915_WRITE_FW(RING_ELSP(ring), lower_32_bits(desc[1]));
@@ -384,11 +385,18 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
/* ELSP is a wo register, use another nearby reg for posting */
POSTING_READ_FW(RING_EXECLIST_STATUS_LO(ring));
- intel_uncore_forcewake_put__locked(dev_priv, FORCEWAKE_ALL);
- spin_unlock(&dev_priv->uncore.lock);
}
-static int execlists_update_context(struct drm_i915_gem_request *rq)
+static void
+execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
+{
+ ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
+ ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
+ ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
+ ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
+}
+
+static void execlists_update_context(struct drm_i915_gem_request *rq)
{
struct intel_engine_cs *ring = rq->ring;
struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt;
@@ -396,19 +404,13 @@ static int execlists_update_context(struct drm_i915_gem_request *rq)
reg_state[CTX_RING_TAIL+1] = rq->tail;
- if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
- /* True 32b PPGTT with dynamic page allocation: update PDP
- * registers and point the unallocated PDPs to scratch page.
- * PML4 is allocated during ppgtt init, so this is not needed
- * in 48-bit mode.
- */
- ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
- ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
- ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
- ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
- }
-
- return 0;
+ /* True 32b PPGTT with dynamic page allocation: update PDP
+ * registers and point the unallocated PDPs to scratch page.
+ * PML4 is allocated during ppgtt init, so this is not needed
+ * in 48-bit mode.
+ */
+ if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev))
+ execlists_update_context_pdps(ppgtt, reg_state);
}
static void execlists_submit_requests(struct drm_i915_gem_request *rq0,
@@ -422,10 +424,10 @@ static void execlists_submit_requests(struct drm_i915_gem_request *rq0,
execlists_elsp_write(rq0, rq1);
}
-static void execlists_context_unqueue(struct intel_engine_cs *ring)
+static void execlists_context_unqueue__locked(struct intel_engine_cs *ring)
{
struct drm_i915_gem_request *req0 = NULL, *req1 = NULL;
- struct drm_i915_gem_request *cursor = NULL, *tmp = NULL;
+ struct drm_i915_gem_request *cursor, *tmp;
assert_spin_locked(&ring->execlist_lock);
@@ -435,9 +437,6 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
*/
WARN_ON(!intel_irqs_enabled(ring->dev->dev_private));
- if (list_empty(&ring->execlist_queue))
- return;
-
/* Try to read in pairs */
list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue,
execlist_link) {
@@ -452,37 +451,48 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
req0 = cursor;
} else {
req1 = cursor;
+ WARN_ON(req1->elsp_submitted);
break;
}
}
- if (IS_GEN8(ring->dev) || IS_GEN9(ring->dev)) {
+ if (unlikely(!req0))
+ return;
+
+ if (req0->elsp_submitted & ring->idle_lite_restore_wa) {
/*
- * WaIdleLiteRestore: make sure we never cause a lite
- * restore with HEAD==TAIL
+ * WaIdleLiteRestore: make sure we never cause a lite restore
+ * with HEAD==TAIL.
+ *
+ * Apply the wa NOOPS to prevent ring:HEAD == req:TAIL as we
+ * resubmit the request. See gen8_emit_request() for where we
+ * prepare the padding after the end of the request.
*/
- if (req0->elsp_submitted) {
- /*
- * Apply the wa NOOPS to prevent ring:HEAD == req:TAIL
- * as we resubmit the request. See gen8_emit_request()
- * for where we prepare the padding after the end of the
- * request.
- */
- struct intel_ringbuffer *ringbuf;
+ struct intel_ringbuffer *ringbuf;
- ringbuf = req0->ctx->engine[ring->id].ringbuf;
- req0->tail += 8;
- req0->tail &= ringbuf->size - 1;
- }
+ ringbuf = req0->ctx->engine[ring->id].ringbuf;
+ req0->tail += 8;
+ req0->tail &= ringbuf->size - 1;
}
- WARN_ON(req1 && req1->elsp_submitted);
-
execlists_submit_requests(req0, req1);
}
-static bool execlists_check_remove_request(struct intel_engine_cs *ring,
- u32 request_id)
+static void execlists_context_unqueue(struct intel_engine_cs *ring)
+{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+ spin_lock(&dev_priv->uncore.lock);
+ intel_uncore_forcewake_get__locked(dev_priv, FORCEWAKE_ALL);
+
+ execlists_context_unqueue__locked(ring);
+
+ intel_uncore_forcewake_put__locked(dev_priv, FORCEWAKE_ALL);
+ spin_unlock(&dev_priv->uncore.lock);
+}
+
+static unsigned int
+execlists_check_remove_request(struct intel_engine_cs *ring, u32 request_id)
{
struct drm_i915_gem_request *head_req;
@@ -492,33 +502,41 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
struct drm_i915_gem_request,
execlist_link);
- if (head_req != NULL) {
- if (intel_execlists_ctx_id(head_req->ctx, ring) == request_id) {
- WARN(head_req->elsp_submitted == 0,
- "Never submitted head request\n");
+ if (!head_req)
+ return 0;
- if (--head_req->elsp_submitted <= 0) {
- list_move_tail(&head_req->execlist_link,
- &ring->execlist_retired_req_list);
- return true;
- }
- }
- }
+ if (unlikely(intel_execlists_ctx_id(head_req->ctx, ring) != request_id))
+ return 0;
+
+ WARN(head_req->elsp_submitted == 0, "Never submitted head request\n");
+
+ if (--head_req->elsp_submitted > 0)
+ return 0;
+
+ list_move_tail(&head_req->execlist_link,
+ &ring->execlist_retired_req_list);
- return false;
+ return 1;
}
-static void get_context_status(struct intel_engine_cs *ring,
- u8 read_pointer,
- u32 *status, u32 *context_id)
+static u32
+get_context_status(struct intel_engine_cs *ring, unsigned int read_pointer,
+ u32 *context_id)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ u32 status;
- if (WARN_ON(read_pointer >= GEN8_CSB_ENTRIES))
- return;
+ read_pointer %= GEN8_CSB_ENTRIES;
+
+ status = I915_READ_FW(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer));
+
+ if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
+ return 0;
- *status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer));
- *context_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer));
+ *context_id = I915_READ_FW(RING_CONTEXT_STATUS_BUF_HI(ring,
+ read_pointer));
+
+ return status;
}
/**
@@ -532,30 +550,27 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
u32 status_pointer;
- u8 read_pointer;
- u8 write_pointer;
+ unsigned int read_pointer, write_pointer;
u32 status = 0;
u32 status_id;
- u32 submit_contexts = 0;
+ unsigned int submit_contexts = 0;
+
+ spin_lock(&ring->execlist_lock);
- status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
+ spin_lock(&dev_priv->uncore.lock);
+ intel_uncore_forcewake_get__locked(dev_priv, FORCEWAKE_ALL);
+
+ status_pointer = I915_READ_FW(RING_CONTEXT_STATUS_PTR(ring));
read_pointer = ring->next_context_status_buffer;
write_pointer = GEN8_CSB_WRITE_PTR(status_pointer);
if (read_pointer > write_pointer)
write_pointer += GEN8_CSB_ENTRIES;
- spin_lock(&ring->execlist_lock);
-
while (read_pointer < write_pointer) {
+ status = get_context_status(ring, ++read_pointer, &status_id);
- get_context_status(ring, ++read_pointer % GEN8_CSB_ENTRIES,
- &status, &status_id);
-
- if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
- continue;
-
- if (status & GEN8_CTX_STATUS_PREEMPTED) {
+ if (unlikely(status & GEN8_CTX_STATUS_PREEMPTED)) {
if (status & GEN8_CTX_STATUS_LITE_RESTORE) {
if (execlists_check_remove_request(ring, status_id))
WARN(1, "Lite Restored request removed from queue\n");
@@ -563,37 +578,36 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
WARN(1, "Preemption without Lite Restore\n");
}
- if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) ||
- (status & GEN8_CTX_STATUS_ELEMENT_SWITCH)) {
- if (execlists_check_remove_request(ring, status_id))
- submit_contexts++;
- }
+ if (status & (GEN8_CTX_STATUS_ACTIVE_IDLE |
+ GEN8_CTX_STATUS_ELEMENT_SWITCH))
+ submit_contexts +=
+ execlists_check_remove_request(ring, status_id);
}
- if (ring->disable_lite_restore_wa) {
- /* Prevent a ctx to preempt itself */
- if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) &&
- (submit_contexts != 0))
- execlists_context_unqueue(ring);
- } else if (submit_contexts != 0) {
- execlists_context_unqueue(ring);
+ if (submit_contexts) {
+ if (!ring->disable_lite_restore_wa ||
+ (status & GEN8_CTX_STATUS_ACTIVE_IDLE))
+ execlists_context_unqueue__locked(ring);
}
- spin_unlock(&ring->execlist_lock);
-
- if (unlikely(submit_contexts > 2))
- DRM_ERROR("More than two context complete events?\n");
-
ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES;
/* Update the read pointer to the old write pointer. Manual ringbuffer
* management ftw </sarcasm> */
- I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
- _MASKED_FIELD(GEN8_CSB_READ_PTR_MASK,
- ring->next_context_status_buffer << 8));
+ I915_WRITE_FW(RING_CONTEXT_STATUS_PTR(ring),
+ _MASKED_FIELD(GEN8_CSB_READ_PTR_MASK,
+ ring->next_context_status_buffer << 8));
+
+ intel_uncore_forcewake_put__locked(dev_priv, FORCEWAKE_ALL);
+ spin_unlock(&dev_priv->uncore.lock);
+
+ spin_unlock(&ring->execlist_lock);
+
+ if (unlikely(submit_contexts > 2))
+ DRM_ERROR("More than two context complete events?\n");
}
-static int execlists_context_queue(struct drm_i915_gem_request *request)
+static void execlists_context_queue(struct drm_i915_gem_request *request)
{
struct intel_engine_cs *ring = request->ring;
struct drm_i915_gem_request *cursor;
@@ -630,8 +644,6 @@ static int execlists_context_queue(struct drm_i915_gem_request *request)
execlists_context_unqueue(ring);
spin_unlock_irq(&ring->execlist_lock);
-
- return 0;
}
static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
@@ -1050,7 +1062,7 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
/* TODO: Is this correct with Execlists enabled? */
I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
- if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
+ if (wait_for((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
return;
}
@@ -1550,7 +1562,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
{
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u8 next_context_status_buffer_hw;
+ unsigned int next_context_status_buffer_hw;
lrc_setup_hardware_status_page(ring,
dev_priv->kernel_context->engine[ring->id].state);
@@ -2013,6 +2025,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
ring->status_page.obj = NULL;
}
+ ring->idle_lite_restore_wa = 0;
ring->disable_lite_restore_wa = false;
ring->ctx_desc_template = 0;
@@ -2439,10 +2452,7 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
* With dynamic page allocation, PDPs may not be allocated at
* this point. Point the unallocated PDPs to the scratch page
*/
- ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
- ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
- ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
- ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
+ execlists_update_context_pdps(ppgtt, reg_state);
}
if (ring->id == RCS) {
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 30a8403a8f4f..cbd1b0d547ee 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -109,7 +109,6 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
u32 tmp, flags = 0;
- int dotclock;
tmp = I915_READ(lvds_encoder->reg);
if (tmp & LVDS_HSYNC_POLARITY)
@@ -130,12 +129,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
}
- dotclock = pipe_config->port_clock;
-
- if (HAS_PCH_SPLIT(dev_priv->dev))
- ironlake_check_encoder_dotclock(pipe_config, dotclock);
-
- pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
}
static void intel_pre_enable_lvds(struct intel_encoder *encoder)
@@ -151,7 +145,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
if (HAS_PCH_SPLIT(dev)) {
assert_fdi_rx_pll_disabled(dev_priv, pipe);
assert_shared_dpll_disabled(dev_priv,
- intel_crtc_to_shared_dpll(crtc));
+ crtc->config->shared_dpll);
} else {
assert_pll_disabled(dev_priv, pipe);
}
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 21ee6477bf98..0fe059bc7d80 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -1240,7 +1240,7 @@ static void intel_backlight_device_unregister(struct intel_connector *connector)
*/
static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- return KHz(19200) / pwm_freq_hz;
+ return DIV_ROUND_CLOSEST(KHz(19200), pwm_freq_hz);
}
/*
@@ -1251,16 +1251,14 @@ static u32 bxt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
static u32 spt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- u32 mul, clock;
+ u32 mul;
if (I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY)
mul = 128;
else
mul = 16;
- clock = MHz(24);
-
- return clock / (pwm_freq_hz * mul);
+ return DIV_ROUND_CLOSEST(MHz(24), pwm_freq_hz * mul);
}
/*
@@ -1283,7 +1281,7 @@ static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
else
clock = MHz(24); /* LPT:LP */
- return clock / (pwm_freq_hz * mul);
+ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
}
/*
@@ -1292,10 +1290,9 @@ static u32 lpt_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_device *dev = connector->base.dev;
- int clock = MHz(intel_pch_rawclk(dev));
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- return clock / (pwm_freq_hz * 128);
+ return DIV_ROUND_CLOSEST(KHz(dev_priv->rawclk_freq), pwm_freq_hz * 128);
}
/*
@@ -1308,16 +1305,15 @@ static u32 pch_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 i9xx_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
int clock;
- if (IS_PINEVIEW(dev))
- clock = MHz(intel_hrawclk(dev));
+ if (IS_PINEVIEW(dev_priv))
+ clock = KHz(dev_priv->rawclk_freq);
else
- clock = 1000 * dev_priv->cdclk_freq;
+ clock = KHz(dev_priv->cdclk_freq);
- return clock / (pwm_freq_hz * 32);
+ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 32);
}
/*
@@ -1332,11 +1328,11 @@ static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
int clock;
if (IS_G4X(dev_priv))
- clock = MHz(intel_hrawclk(dev));
+ clock = KHz(dev_priv->rawclk_freq);
else
- clock = 1000 * dev_priv->cdclk_freq;
+ clock = KHz(dev_priv->cdclk_freq);
- return clock / (pwm_freq_hz * 128);
+ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * 128);
}
/*
@@ -1346,19 +1342,21 @@ static u32 i965_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
*/
static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int clock;
+ struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+ int mul, clock;
if ((I915_READ(CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
- if (IS_CHERRYVIEW(dev))
- return KHz(19200) / (pwm_freq_hz * 16);
+ if (IS_CHERRYVIEW(dev_priv))
+ clock = KHz(19200);
else
- return MHz(25) / (pwm_freq_hz * 16);
+ clock = MHz(25);
+ mul = 16;
} else {
- clock = intel_hrawclk(dev);
- return MHz(clock) / (pwm_freq_hz * 128);
+ clock = KHz(dev_priv->rawclk_freq);
+ mul = 128;
}
+
+ return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul);
}
static u32 get_backlight_max_vbt(struct intel_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 347d4df49a9b..d7aef17bf0f9 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -487,20 +487,6 @@ static const struct intel_watermark_params g4x_cursor_wm_info = {
.guard_size = 2,
.cacheline_size = G4X_FIFO_LINE_SIZE,
};
-static const struct intel_watermark_params valleyview_wm_info = {
- .fifo_size = VALLEYVIEW_FIFO_SIZE,
- .max_wm = VALLEYVIEW_MAX_WM,
- .default_wm = VALLEYVIEW_MAX_WM,
- .guard_size = 2,
- .cacheline_size = G4X_FIFO_LINE_SIZE,
-};
-static const struct intel_watermark_params valleyview_cursor_wm_info = {
- .fifo_size = I965_CURSOR_FIFO,
- .max_wm = VALLEYVIEW_CURSOR_MAX_WM,
- .default_wm = I965_CURSOR_DFT_WM,
- .guard_size = 2,
- .cacheline_size = G4X_FIFO_LINE_SIZE,
-};
static const struct intel_watermark_params i965_cursor_wm_info = {
.fifo_size = I965_CURSOR_FIFO,
.max_wm = I965_CURSOR_MAX_WM,
@@ -2010,11 +1996,18 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
cur_latency *= 5;
}
- result->pri_val = ilk_compute_pri_wm(cstate, pristate,
- pri_latency, level);
- result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency);
- result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency);
- result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val);
+ if (pristate) {
+ result->pri_val = ilk_compute_pri_wm(cstate, pristate,
+ pri_latency, level);
+ result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val);
+ }
+
+ if (sprstate)
+ result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency);
+
+ if (curstate)
+ result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency);
+
result->enable = true;
}
@@ -2278,100 +2271,171 @@ static void skl_setup_wm_latency(struct drm_device *dev)
intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
}
+static bool ilk_validate_pipe_wm(struct drm_device *dev,
+ struct intel_pipe_wm *pipe_wm)
+{
+ /* LP0 watermark maximums depend on this pipe alone */
+ const struct intel_wm_config config = {
+ .num_pipes_active = 1,
+ .sprites_enabled = pipe_wm->sprites_enabled,
+ .sprites_scaled = pipe_wm->sprites_scaled,
+ };
+ struct ilk_wm_maximums max;
+
+ /* LP0 watermarks always use 1/2 DDB partitioning */
+ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
+
+ /* At least LP0 must be valid */
+ if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) {
+ DRM_DEBUG_KMS("LP0 watermark invalid\n");
+ return false;
+ }
+
+ return true;
+}
+
/* Compute new watermarks for the pipe */
-static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
- struct drm_atomic_state *state)
+static int ilk_compute_pipe_wm(struct intel_crtc_state *cstate)
{
+ struct drm_atomic_state *state = cstate->base.state;
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
struct intel_pipe_wm *pipe_wm;
- struct drm_device *dev = intel_crtc->base.dev;
+ struct drm_device *dev = state->dev;
const struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc_state *cstate = NULL;
struct intel_plane *intel_plane;
- struct drm_plane_state *ps;
struct intel_plane_state *pristate = NULL;
struct intel_plane_state *sprstate = NULL;
struct intel_plane_state *curstate = NULL;
- int level, max_level = ilk_wm_max_level(dev);
- /* LP0 watermark maximums depend on this pipe alone */
- struct intel_wm_config config = {
- .num_pipes_active = 1,
- };
+ int level, max_level = ilk_wm_max_level(dev), usable_level;
struct ilk_wm_maximums max;
- cstate = intel_atomic_get_crtc_state(state, intel_crtc);
- if (IS_ERR(cstate))
- return PTR_ERR(cstate);
-
pipe_wm = &cstate->wm.optimal.ilk;
- memset(pipe_wm, 0, sizeof(*pipe_wm));
for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
- ps = drm_atomic_get_plane_state(state,
- &intel_plane->base);
- if (IS_ERR(ps))
- return PTR_ERR(ps);
+ struct intel_plane_state *ps;
+
+ ps = intel_atomic_get_existing_plane_state(state,
+ intel_plane);
+ if (!ps)
+ continue;
if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY)
- pristate = to_intel_plane_state(ps);
+ pristate = ps;
else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY)
- sprstate = to_intel_plane_state(ps);
+ sprstate = ps;
else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
- curstate = to_intel_plane_state(ps);
+ curstate = ps;
}
- config.sprites_enabled = sprstate->visible;
- config.sprites_scaled = sprstate->visible &&
- (drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 ||
- drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
-
pipe_wm->pipe_enabled = cstate->base.active;
- pipe_wm->sprites_enabled = config.sprites_enabled;
- pipe_wm->sprites_scaled = config.sprites_scaled;
+ if (sprstate) {
+ pipe_wm->sprites_enabled = sprstate->visible;
+ pipe_wm->sprites_scaled = sprstate->visible &&
+ (drm_rect_width(&sprstate->dst) != drm_rect_width(&sprstate->src) >> 16 ||
+ drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
+ }
+
+ usable_level = max_level;
/* ILK/SNB: LP2+ watermarks only w/o sprites */
- if (INTEL_INFO(dev)->gen <= 6 && sprstate->visible)
- max_level = 1;
+ if (INTEL_INFO(dev)->gen <= 6 && pipe_wm->sprites_enabled)
+ usable_level = 1;
/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
- if (config.sprites_scaled)
- max_level = 0;
+ if (pipe_wm->sprites_scaled)
+ usable_level = 0;
ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
- pristate, sprstate, curstate, &pipe_wm->wm[0]);
+ pristate, sprstate, curstate, &pipe_wm->raw_wm[0]);
+
+ memset(&pipe_wm->wm, 0, sizeof(pipe_wm->wm));
+ pipe_wm->wm[0] = pipe_wm->raw_wm[0];
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
pipe_wm->linetime = hsw_compute_linetime_wm(dev, cstate);
- /* LP0 watermarks always use 1/2 DDB partitioning */
- ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
-
- /* At least LP0 must be valid */
- if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
+ if (!ilk_validate_pipe_wm(dev, pipe_wm))
return -EINVAL;
ilk_compute_wm_reg_maximums(dev, 1, &max);
for (level = 1; level <= max_level; level++) {
- struct intel_wm_level wm = {};
+ struct intel_wm_level *wm = &pipe_wm->raw_wm[level];
ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate,
- pristate, sprstate, curstate, &wm);
+ pristate, sprstate, curstate, wm);
/*
* Disable any watermark level that exceeds the
* register maximums since such watermarks are
* always invalid.
*/
- if (!ilk_validate_wm_level(level, &max, &wm))
- break;
+ if (level > usable_level)
+ continue;
- pipe_wm->wm[level] = wm;
+ if (ilk_validate_wm_level(level, &max, wm))
+ pipe_wm->wm[level] = *wm;
+ else
+ usable_level = level;
}
return 0;
}
/*
+ * Build a set of 'intermediate' watermark values that satisfy both the old
+ * state and the new state. These can be programmed to the hardware
+ * immediately.
+ */
+static int ilk_compute_intermediate_wm(struct drm_device *dev,
+ struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *newstate)
+{
+ struct intel_pipe_wm *a = &newstate->wm.intermediate;
+ struct intel_pipe_wm *b = &intel_crtc->wm.active.ilk;
+ int level, max_level = ilk_wm_max_level(dev);
+
+ /*
+ * Start with the final, target watermarks, then combine with the
+ * currently active watermarks to get values that are safe both before
+ * and after the vblank.
+ */
+ *a = newstate->wm.optimal.ilk;
+ a->pipe_enabled |= b->pipe_enabled;
+ a->sprites_enabled |= b->sprites_enabled;
+ a->sprites_scaled |= b->sprites_scaled;
+
+ for (level = 0; level <= max_level; level++) {
+ struct intel_wm_level *a_wm = &a->wm[level];
+ const struct intel_wm_level *b_wm = &b->wm[level];
+
+ a_wm->enable &= b_wm->enable;
+ a_wm->pri_val = max(a_wm->pri_val, b_wm->pri_val);
+ a_wm->spr_val = max(a_wm->spr_val, b_wm->spr_val);
+ a_wm->cur_val = max(a_wm->cur_val, b_wm->cur_val);
+ a_wm->fbc_val = max(a_wm->fbc_val, b_wm->fbc_val);
+ }
+
+ /*
+ * We need to make sure that these merged watermark values are
+ * actually a valid configuration themselves. If they're not,
+ * there's no safe way to transition from the old state to
+ * the new state, so we need to fail the atomic transaction.
+ */
+ if (!ilk_validate_pipe_wm(dev, a))
+ return -EINVAL;
+
+ /*
+ * If our intermediate WM are identical to the final WM, then we can
+ * omit the post-vblank programming; only update if it's different.
+ */
+ if (memcmp(a, &newstate->wm.optimal.ilk, sizeof(*a)) == 0)
+ newstate->wm.need_postvbl_update = false;
+
+ return 0;
+}
+
+/*
* Merge the watermarks from all active pipes for a specific level.
*/
static void ilk_merge_wm_level(struct drm_device *dev,
@@ -2383,9 +2447,7 @@ static void ilk_merge_wm_level(struct drm_device *dev,
ret_wm->enable = true;
for_each_intel_crtc(dev, intel_crtc) {
- const struct intel_crtc_state *cstate =
- to_intel_crtc_state(intel_crtc->base.state);
- const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
+ const struct intel_pipe_wm *active = &intel_crtc->wm.active.ilk;
const struct intel_wm_level *wm = &active->wm[level];
if (!active->pipe_enabled)
@@ -2533,15 +2595,14 @@ static void ilk_compute_wm_results(struct drm_device *dev,
/* LP0 register values */
for_each_intel_crtc(dev, intel_crtc) {
- const struct intel_crtc_state *cstate =
- to_intel_crtc_state(intel_crtc->base.state);
enum pipe pipe = intel_crtc->pipe;
- const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0];
+ const struct intel_wm_level *r =
+ &intel_crtc->wm.active.ilk.wm[0];
if (WARN_ON(!r->enable))
continue;
- results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime;
+ results->wm_linetime[pipe] = intel_crtc->wm.active.ilk.linetime;
results->wm_pipe[pipe] =
(r->pri_val << WM0_PIPE_PLANE_SHIFT) |
@@ -2748,7 +2809,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
dev_priv->wm.hw = *results;
}
-static bool ilk_disable_lp_wm(struct drm_device *dev)
+bool ilk_disable_lp_wm(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3643,11 +3704,9 @@ static void ilk_compute_wm_config(struct drm_device *dev,
}
}
-static void ilk_program_watermarks(struct intel_crtc_state *cstate)
+static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
{
- struct drm_crtc *crtc = cstate->base.crtc;
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_device *dev = dev_priv->dev;
struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
struct ilk_wm_maximums max;
struct intel_wm_config config = {};
@@ -3678,28 +3737,28 @@ static void ilk_program_watermarks(struct intel_crtc_state *cstate)
ilk_write_wm_values(dev_priv, &results);
}
-static void ilk_update_wm(struct drm_crtc *crtc)
+static void ilk_initial_watermarks(struct intel_crtc_state *cstate)
{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
-
- WARN_ON(cstate->base.active != intel_crtc->active);
+ struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
- /*
- * IVB workaround: must disable low power watermarks for at least
- * one frame before enabling scaling. LP watermarks can be re-enabled
- * when scaling is disabled.
- *
- * WaCxSRDisabledForSpriteScaling:ivb
- */
- if (cstate->disable_lp_wm) {
- ilk_disable_lp_wm(crtc->dev);
- intel_wait_for_vblank(crtc->dev, intel_crtc->pipe);
- }
+ mutex_lock(&dev_priv->wm.wm_mutex);
+ intel_crtc->wm.active.ilk = cstate->wm.intermediate;
+ ilk_program_watermarks(dev_priv);
+ mutex_unlock(&dev_priv->wm.wm_mutex);
+}
- intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
+static void ilk_optimize_watermarks(struct intel_crtc_state *cstate)
+{
+ struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
+ struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
- ilk_program_watermarks(cstate);
+ mutex_lock(&dev_priv->wm.wm_mutex);
+ if (cstate->wm.need_postvbl_update) {
+ intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
+ ilk_program_watermarks(dev_priv);
+ }
+ mutex_unlock(&dev_priv->wm.wm_mutex);
}
static void skl_pipe_wm_active_state(uint32_t val,
@@ -7076,9 +7135,13 @@ void intel_init_pm(struct drm_device *dev)
dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
(!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
- dev_priv->display.update_wm = ilk_update_wm;
dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
- dev_priv->display.program_watermarks = ilk_program_watermarks;
+ dev_priv->display.compute_intermediate_wm =
+ ilk_compute_intermediate_wm;
+ dev_priv->display.initial_watermarks =
+ ilk_initial_watermarks;
+ dev_priv->display.optimize_watermarks =
+ ilk_optimize_watermarks;
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 0b42ada338c8..38e95185d9c6 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -507,7 +507,8 @@ static void hsw_psr_disable(struct intel_dp *intel_dp)
/* Wait till PSR is idle */
if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) &
- EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10))
+ EDP_PSR_STATUS_STATE_MASK) == 0,
+ 2 * USEC_PER_SEC, 10 * USEC_PER_MSEC))
DRM_ERROR("Timed out waiting for PSR Idle State\n");
dev_priv->psr.active = false;
@@ -780,8 +781,7 @@ void intel_psr_init(struct drm_device *dev)
/* Per platform default */
if (i915.enable_psr == -1) {
- if (IS_HASWELL(dev) || IS_BROADWELL(dev) ||
- IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
+ if (IS_HASWELL(dev) || IS_BROADWELL(dev))
i915.enable_psr = 1;
else
i915.enable_psr = 0;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 566b0ae10ce0..4b1439deb7fe 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -79,7 +79,6 @@ enum intel_ring_hangcheck_action {
HANGCHECK_IDLE = 0,
HANGCHECK_WAIT,
HANGCHECK_ACTIVE,
- HANGCHECK_ACTIVE_LOOP,
HANGCHECK_KICK,
HANGCHECK_HUNG,
};
@@ -88,7 +87,6 @@ enum intel_ring_hangcheck_action {
struct intel_ring_hangcheck {
u64 acthd;
- u64 max_acthd;
u32 seqno;
int score;
enum intel_ring_hangcheck_action action;
@@ -271,7 +269,8 @@ struct intel_engine_cs {
spinlock_t execlist_lock;
struct list_head execlist_queue;
struct list_head execlist_retired_req_list;
- u8 next_context_status_buffer;
+ unsigned int next_context_status_buffer;
+ unsigned int idle_lite_restore_wa;
bool disable_lite_restore_wa;
u32 ctx_desc_template;
u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 6e54d978d9d4..2e88a5e06884 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -421,6 +421,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \
BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \
+ BIT(POWER_DOMAIN_PORT_DSI) | \
BIT(POWER_DOMAIN_AUX_A) | \
BIT(POWER_DOMAIN_PLLS) | \
BIT(POWER_DOMAIN_INIT))
@@ -458,8 +459,6 @@ static void assert_can_enable_dc9(struct drm_i915_private *dev_priv)
static void assert_can_disable_dc9(struct drm_i915_private *dev_priv)
{
WARN(intel_irqs_enabled(dev_priv), "Interrupts not disabled yet.\n");
- WARN(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_DC9),
- "DC9 already programmed to be disabled.\n");
WARN(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5,
"DC5 still not disabled.\n");
@@ -472,24 +471,6 @@ static void assert_can_disable_dc9(struct drm_i915_private *dev_priv)
*/
}
-static void gen9_set_dc_state_debugmask(struct drm_i915_private *dev_priv)
-{
- uint32_t val, mask;
-
- mask = DC_STATE_DEBUG_MASK_MEMORY_UP;
-
- if (IS_BROXTON(dev_priv))
- mask |= DC_STATE_DEBUG_MASK_CORES;
-
- /* The below bit doesn't need to be cleared ever afterwards */
- val = I915_READ(DC_STATE_DEBUG);
- if ((val & mask) != mask) {
- val |= mask;
- I915_WRITE(DC_STATE_DEBUG, val);
- POSTING_READ(DC_STATE_DEBUG);
- }
-}
-
static void gen9_write_dc_state(struct drm_i915_private *dev_priv,
u32 state)
{
@@ -538,12 +519,8 @@ static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state)
else
mask |= DC_STATE_EN_UPTO_DC6;
- WARN_ON_ONCE(state & ~mask);
-
- if (i915.enable_dc == 0)
- state = DC_STATE_DISABLE;
- else if (i915.enable_dc == 1 && state > DC_STATE_EN_UPTO_DC5)
- state = DC_STATE_EN_UPTO_DC5;
+ if (WARN_ON_ONCE(state & ~dev_priv->csr.allowed_dc_mask))
+ state &= dev_priv->csr.allowed_dc_mask;
val = I915_READ(DC_STATE_EN);
DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n",
@@ -606,18 +583,6 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
assert_csr_loaded(dev_priv);
}
-static void assert_can_disable_dc5(struct drm_i915_private *dev_priv)
-{
- /*
- * During initialization, the firmware may not be loaded yet.
- * We still want to make sure that the DC enabling flag is cleared.
- */
- if (dev_priv->power_domains.initializing)
- return;
-
- assert_rpm_wakelock_held(dev_priv);
-}
-
static void gen9_enable_dc5(struct drm_i915_private *dev_priv)
{
assert_can_enable_dc5(dev_priv);
@@ -642,30 +607,6 @@ static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
assert_csr_loaded(dev_priv);
}
-static void assert_can_disable_dc6(struct drm_i915_private *dev_priv)
-{
- /*
- * During initialization, the firmware may not be loaded yet.
- * We still want to make sure that the DC enabling flag is cleared.
- */
- if (dev_priv->power_domains.initializing)
- return;
-
- WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
- "DC6 already programmed to be disabled.\n");
-}
-
-static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv)
-{
- assert_can_disable_dc5(dev_priv);
-
- if ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
- i915.enable_dc != 0 && i915.enable_dc != 1)
- assert_can_disable_dc6(dev_priv);
-
- gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
-}
-
void skl_enable_dc6(struct drm_i915_private *dev_priv)
{
assert_can_enable_dc6(dev_priv);
@@ -678,8 +619,6 @@ void skl_enable_dc6(struct drm_i915_private *dev_priv)
void skl_disable_dc6(struct drm_i915_private *dev_priv)
{
- assert_can_disable_dc6(dev_priv);
-
DRM_DEBUG_KMS("Disabling DC6\n");
gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
@@ -833,32 +772,25 @@ static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv,
static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- gen9_disable_dc5_dc6(dev_priv);
+ gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
}
static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- if ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
- i915.enable_dc != 0 && i915.enable_dc != 1)
+ if (dev_priv->csr.allowed_dc_mask & DC_STATE_EN_UPTO_DC6)
skl_enable_dc6(dev_priv);
- else
+ else if (dev_priv->csr.allowed_dc_mask & DC_STATE_EN_UPTO_DC5)
gen9_enable_dc5(dev_priv);
}
static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
- if (power_well->count > 0) {
- gen9_set_dc_state(dev_priv, DC_STATE_DISABLE);
- } else {
- if ((IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
- i915.enable_dc != 0 &&
- i915.enable_dc != 1)
- gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6);
- else
- gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5);
- }
+ if (power_well->count > 0)
+ gen9_dc_off_power_well_enable(dev_priv, power_well);
+ else
+ gen9_dc_off_power_well_disable(dev_priv, power_well);
}
static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
@@ -2023,6 +1955,55 @@ sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv,
return 1;
}
+static uint32_t get_allowed_dc_mask(const struct drm_i915_private *dev_priv,
+ int enable_dc)
+{
+ uint32_t mask;
+ int requested_dc;
+ int max_dc;
+
+ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+ max_dc = 2;
+ mask = 0;
+ } else if (IS_BROXTON(dev_priv)) {
+ max_dc = 1;
+ /*
+ * DC9 has a separate HW flow from the rest of the DC states,
+ * not depending on the DMC firmware. It's needed by system
+ * suspend/resume, so allow it unconditionally.
+ */
+ mask = DC_STATE_EN_DC9;
+ } else {
+ max_dc = 0;
+ mask = 0;
+ }
+
+ if (!i915.disable_power_well)
+ max_dc = 0;
+
+ if (enable_dc >= 0 && enable_dc <= max_dc) {
+ requested_dc = enable_dc;
+ } else if (enable_dc == -1) {
+ requested_dc = max_dc;
+ } else if (enable_dc > max_dc && enable_dc <= 2) {
+ DRM_DEBUG_KMS("Adjusting requested max DC state (%d->%d)\n",
+ enable_dc, max_dc);
+ requested_dc = max_dc;
+ } else {
+ DRM_ERROR("Unexpected value for enable_dc (%d)\n", enable_dc);
+ requested_dc = max_dc;
+ }
+
+ if (requested_dc > 1)
+ mask |= DC_STATE_EN_UPTO_DC6;
+ if (requested_dc > 0)
+ mask |= DC_STATE_EN_UPTO_DC5;
+
+ DRM_DEBUG_KMS("Allowed DC state mask %02x\n", mask);
+
+ return mask;
+}
+
#define set_power_wells(power_domains, __power_wells) ({ \
(power_domains)->power_wells = (__power_wells); \
(power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
@@ -2041,6 +2022,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
i915.disable_power_well = sanitize_disable_power_well_option(dev_priv,
i915.disable_power_well);
+ dev_priv->csr.allowed_dc_mask = get_allowed_dc_mask(dev_priv,
+ i915.enable_dc);
BUILD_BUG_ON(POWER_DOMAIN_NUM > 31);
@@ -2141,8 +2124,8 @@ static void skl_display_core_init(struct drm_i915_private *dev_priv,
skl_init_cdclk(dev_priv);
- if (dev_priv->csr.dmc_payload && intel_csr_load_program(dev_priv))
- gen9_set_dc_state_debugmask(dev_priv);
+ if (dev_priv->csr.dmc_payload)
+ intel_csr_load_program(dev_priv);
}
static void skl_display_core_uninit(struct drm_i915_private *dev_priv)
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 4ecc076c4041..fae64bc93c1b 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1398,12 +1398,10 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
}
dotclock = pipe_config->port_clock;
+
if (pipe_config->pixel_multiplier)
dotclock /= pipe_config->pixel_multiplier;
- if (HAS_PCH_SPLIT(dev))
- ironlake_check_encoder_dotclock(pipe_config, dotclock);
-
pipe_config->base.adjusted_mode.crtc_clock = dotclock;
/* Cross check the port pixel multiplier with the sdvo encoder state. */
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index a2582c455b36..8821533561b1 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -193,7 +193,7 @@ skl_update_plane(struct drm_plane *drm_plane,
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
u32 surf_addr;
u32 tile_height, plane_offset, plane_size;
- unsigned int rotation;
+ unsigned int rotation = plane_state->base.rotation;
int x_offset, y_offset;
int crtc_x = plane_state->dst.x1;
int crtc_y = plane_state->dst.y1;
@@ -213,7 +213,6 @@ skl_update_plane(struct drm_plane *drm_plane,
plane_ctl |= skl_plane_ctl_format(fb->pixel_format);
plane_ctl |= skl_plane_ctl_tiling(fb->modifier[0]);
- rotation = plane_state->base.rotation;
plane_ctl |= skl_plane_ctl_rotation(rotation);
stride_div = intel_fb_stride_alignment(dev_priv, fb->modifier[0],
@@ -351,6 +350,7 @@ vlv_update_plane(struct drm_plane *dplane,
int plane = intel_plane->plane;
u32 sprctl;
u32 sprsurf_offset, linear_offset;
+ unsigned int rotation = dplane->state->rotation;
int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
int crtc_x = plane_state->dst.x1;
@@ -423,12 +423,11 @@ vlv_update_plane(struct drm_plane *dplane,
crtc_h--;
linear_offset = y * fb->pitches[0] + x * cpp;
- sprsurf_offset = intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0], cpp,
- fb->pitches[0]);
+ sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
+ fb->pitches[0], rotation);
linear_offset -= sprsurf_offset;
- if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+ if (rotation == BIT(DRM_ROTATE_180)) {
sprctl |= SP_ROTATE_180;
x += src_w;
@@ -493,6 +492,7 @@ ivb_update_plane(struct drm_plane *plane,
enum pipe pipe = intel_plane->pipe;
u32 sprctl, sprscale = 0;
u32 sprsurf_offset, linear_offset;
+ unsigned int rotation = plane_state->base.rotation;
int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
int crtc_x = plane_state->dst.x1;
@@ -556,12 +556,11 @@ ivb_update_plane(struct drm_plane *plane,
sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
linear_offset = y * fb->pitches[0] + x * cpp;
- sprsurf_offset = intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0], cpp,
- fb->pitches[0]);
+ sprsurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
+ fb->pitches[0], rotation);
linear_offset -= sprsurf_offset;
- if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+ if (rotation == BIT(DRM_ROTATE_180)) {
sprctl |= SPRITE_ROTATE_180;
/* HSW and BDW does this automagically in hardware */
@@ -634,6 +633,7 @@ ilk_update_plane(struct drm_plane *plane,
int pipe = intel_plane->pipe;
u32 dvscntr, dvsscale;
u32 dvssurf_offset, linear_offset;
+ unsigned int rotation = plane_state->base.rotation;
int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
int crtc_x = plane_state->dst.x1;
@@ -693,12 +693,11 @@ ilk_update_plane(struct drm_plane *plane,
dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
linear_offset = y * fb->pitches[0] + x * cpp;
- dvssurf_offset = intel_compute_tile_offset(dev_priv, &x, &y,
- fb->modifier[0], cpp,
- fb->pitches[0]);
+ dvssurf_offset = intel_compute_tile_offset(&x, &y, fb, 0,
+ fb->pitches[0], rotation);
linear_offset -= dvssurf_offset;
- if (plane_state->base.rotation == BIT(DRM_ROTATE_180)) {
+ if (rotation == BIT(DRM_ROTATE_180)) {
dvscntr |= DVS_ROTATE_180;
x += src_w;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 6745bad5bff0..d5570c859009 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -326,24 +326,12 @@ static const struct color_conversion sdtv_csc_yprpb = {
.rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
};
-static const struct color_conversion sdtv_csc_rgb = {
- .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
- .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
- .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
-};
-
static const struct color_conversion hdtv_csc_yprpb = {
.ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
.ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
.rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
};
-static const struct color_conversion hdtv_csc_rgb = {
- .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
- .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
- .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
-};
-
static const struct video_levels component_levels = {
.blank = 279, .black = 279, .burst = 0,
};
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 436d8f2b8682..d31447f6fa32 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -1531,13 +1531,40 @@ static int gen6_do_reset(struct drm_device *dev)
return ret;
}
-static int wait_for_register(struct drm_i915_private *dev_priv,
- i915_reg_t reg,
- const u32 mask,
- const u32 value,
- const unsigned long timeout_ms)
+static int wait_for_register_fw(struct drm_i915_private *dev_priv,
+ i915_reg_t reg,
+ const u32 mask,
+ const u32 value,
+ const unsigned long timeout_ms)
{
- return wait_for((I915_READ(reg) & mask) == value, timeout_ms);
+ return wait_for((I915_READ_FW(reg) & mask) == value, timeout_ms);
+}
+
+static int gen8_request_engine_reset(struct intel_engine_cs *engine)
+{
+ int ret;
+ struct drm_i915_private *dev_priv = engine->dev->dev_private;
+
+ I915_WRITE_FW(RING_RESET_CTL(engine->mmio_base),
+ _MASKED_BIT_ENABLE(RESET_CTL_REQUEST_RESET));
+
+ ret = wait_for_register_fw(dev_priv,
+ RING_RESET_CTL(engine->mmio_base),
+ RESET_CTL_READY_TO_RESET,
+ RESET_CTL_READY_TO_RESET,
+ 700);
+ if (ret)
+ DRM_ERROR("%s: reset request timeout\n", engine->name);
+
+ return ret;
+}
+
+static void gen8_unrequest_engine_reset(struct intel_engine_cs *engine)
+{
+ struct drm_i915_private *dev_priv = engine->dev->dev_private;
+
+ I915_WRITE_FW(RING_RESET_CTL(engine->mmio_base),
+ _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET));
}
static int gen8_do_reset(struct drm_device *dev)
@@ -1546,26 +1573,15 @@ static int gen8_do_reset(struct drm_device *dev)
struct intel_engine_cs *engine;
int i;
- for_each_ring(engine, dev_priv, i) {
- I915_WRITE(RING_RESET_CTL(engine->mmio_base),
- _MASKED_BIT_ENABLE(RESET_CTL_REQUEST_RESET));
-
- if (wait_for_register(dev_priv,
- RING_RESET_CTL(engine->mmio_base),
- RESET_CTL_READY_TO_RESET,
- RESET_CTL_READY_TO_RESET,
- 700)) {
- DRM_ERROR("%s: reset request timeout\n", engine->name);
+ for_each_ring(engine, dev_priv, i)
+ if (gen8_request_engine_reset(engine))
goto not_ready;
- }
- }
return gen6_do_reset(dev);
not_ready:
for_each_ring(engine, dev_priv, i)
- I915_WRITE(RING_RESET_CTL(engine->mmio_base),
- _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET));
+ gen8_unrequest_engine_reset(engine);
return -EIO;
}