aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/Makefile4
-rw-r--r--drivers/gpu/drm/i915/dvo.h4
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7017.c4
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7xxx.c4
-rw-r--r--drivers/gpu/drm/i915/dvo_ivch.c12
-rw-r--r--drivers/gpu/drm/i915/dvo_ns2501.c4
-rw-r--r--drivers/gpu/drm/i915/dvo_sil164.c4
-rw-r--r--drivers/gpu/drm/i915/dvo_tfp410.c4
-rw-r--r--drivers/gpu/drm/i915/i915_cmd_parser.c17
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c264
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c245
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c83
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h149
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c272
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c31
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c45
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c167
-rw-r--r--drivers/gpu/drm/i915/i915_gem_fence.c47
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c878
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h77
-rw-r--r--drivers/gpu/drm/i915/i915_gem_shrinker.c19
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c181
-rw-r--r--drivers/gpu/drm/i915/i915_gem_userptr.c333
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c78
-rw-r--r--drivers/gpu/drm/i915/i915_guc_reg.h21
-rw-r--r--drivers/gpu/drm/i915/i915_guc_submission.c975
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c686
-rw-r--r--drivers/gpu/drm/i915/i915_params.c43
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h593
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c45
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c34
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h78
-rw-r--r--drivers/gpu/drm/i915/i915_vgpu.h34
-rw-r--r--drivers/gpu/drm/i915/intel_acpi.c3
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c13
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c6
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c47
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c43
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h3
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c15
-rw-r--r--drivers/gpu/drm/i915/intel_csr.c41
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c182
-rw-r--r--drivers/gpu/drm/i915/intel_display.c929
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c838
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c26
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h101
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c323
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.h7
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_pll.c243
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c64
-rw-r--r--drivers/gpu/drm/i915/intel_fbc.c264
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c23
-rw-r--r--drivers/gpu/drm/i915/intel_guc.h124
-rw-r--r--drivers/gpu/drm/i915/intel_guc_fwif.h31
-rw-r--r--drivers/gpu/drm/i915/intel_guc_loader.c608
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c306
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c54
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c427
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.h18
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c50
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c9
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c92
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c525
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c569
-rw-r--r--drivers/gpu/drm/i915/intel_psr.c18
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c262
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h15
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c492
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c51
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c59
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c14
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c49
72 files changed, 8703 insertions, 3676 deletions
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 998b4643109f..44d290ae1999 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -40,6 +40,10 @@ i915-y += i915_cmd_parser.o \
intel_ringbuffer.o \
intel_uncore.o
+# general-purpose microcontroller (GuC) support
+i915-y += intel_guc_loader.o \
+ i915_guc_submission.o
+
# autogenerated null render state
i915-y += intel_renderstate_gen6.o \
intel_renderstate_gen7.o \
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h
index 312163379db9..0e2c1b9648a7 100644
--- a/drivers/gpu/drm/i915/dvo.h
+++ b/drivers/gpu/drm/i915/dvo.h
@@ -94,8 +94,8 @@ struct intel_dvo_dev_ops {
* after this function is called.
*/
void (*mode_set)(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode);
/*
* Probe for a connected output, and return detect_status.
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
index 86b27d1d90c2..cbb22027a3ce 100644
--- a/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -255,8 +255,8 @@ static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
}
static void ch7017_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
uint8_t lvds_pll_feedback_div, lvds_pll_vco_control;
uint8_t outputs_enable, lvds_control_2, lvds_power_down;
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 80449f475960..4b4acc1a06fe 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -275,8 +275,8 @@ static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
}
static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
uint8_t tvco, tpcp, tpd, tlpf, idf;
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index 732ce8785945..ff9f1b077d83 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -394,8 +394,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo)
}
static void ivch_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
struct ivch_priv *priv = dvo->dev_priv;
uint16_t vr40 = 0;
@@ -414,16 +414,16 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
VR40_HORIZONTAL_INTERP_ENABLE);
- if (mode->hdisplay != adjusted_mode->hdisplay ||
- mode->vdisplay != adjusted_mode->vdisplay) {
+ if (mode->hdisplay != adjusted_mode->crtc_hdisplay ||
+ mode->vdisplay != adjusted_mode->crtc_vdisplay) {
uint16_t x_ratio, y_ratio;
vr01 |= VR01_PANEL_FIT_ENABLE;
vr40 |= VR40_CLOCK_GATING_ENABLE;
x_ratio = (((mode->hdisplay - 1) << 16) /
- (adjusted_mode->hdisplay - 1)) >> 2;
+ (adjusted_mode->crtc_hdisplay - 1)) >> 2;
y_ratio = (((mode->vdisplay - 1) << 16) /
- (adjusted_mode->vdisplay - 1)) >> 2;
+ (adjusted_mode->crtc_vdisplay - 1)) >> 2;
ivch_write(dvo, VR42, x_ratio);
ivch_write(dvo, VR41, y_ratio);
} else {
diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c
index 97ae8aa157e9..063859fff0f0 100644
--- a/drivers/gpu/drm/i915/dvo_ns2501.c
+++ b/drivers/gpu/drm/i915/dvo_ns2501.c
@@ -546,8 +546,8 @@ static enum drm_mode_status ns2501_mode_valid(struct intel_dvo_device *dvo,
}
static void ns2501_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
const struct ns2501_configuration *conf;
struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
index fa0114967076..26f13eb634f9 100644
--- a/drivers/gpu/drm/i915/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/dvo_sil164.c
@@ -190,8 +190,8 @@ static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
}
static void sil164_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
/* As long as the basics are set up, since we don't have clock
* dependencies in the mode setup, we can just leave the
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
index 7853719a0e81..6f1a0a6d4e22 100644
--- a/drivers/gpu/drm/i915/dvo_tfp410.c
+++ b/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -222,8 +222,8 @@ static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
}
static void tfp410_mode_set(struct intel_dvo_device *dvo,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
{
/* As long as the basics are set up, since we don't have clock dependencies
* in the mode setup, we can just leave the registers alone and everything
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index 237ff6884a22..db58c8d664c2 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -94,7 +94,7 @@
#define CMD(op, opm, f, lm, fl, ...) \
{ \
.flags = (fl) | ((f) ? CMD_DESC_FIXED : 0), \
- .cmd = { (op), (opm) }, \
+ .cmd = { (op), (opm) }, \
.length = { (lm) }, \
__VA_ARGS__ \
}
@@ -124,14 +124,14 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = {
CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ),
CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W,
.reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ),
- CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B,
+ CMD( MI_STORE_REGISTER_MEM, SMI, F, 3, W | B,
.reg = { .offset = 1, .mask = 0x007FFFFC },
.bits = {{
.offset = 0,
.mask = MI_GLOBAL_GTT,
.expected = 0,
}}, ),
- CMD( MI_LOAD_REGISTER_MEM(1), SMI, !F, 0xFF, W | B,
+ CMD( MI_LOAD_REGISTER_MEM, SMI, F, 3, W | B,
.reg = { .offset = 1, .mask = 0x007FFFFC },
.bits = {{
.offset = 0,
@@ -448,6 +448,9 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = {
REG32(GEN7_3DPRIM_INSTANCE_COUNT),
REG32(GEN7_3DPRIM_START_INSTANCE),
REG32(GEN7_3DPRIM_BASE_VERTEX),
+ REG32(GEN7_GPGPU_DISPATCHDIMX),
+ REG32(GEN7_GPGPU_DISPATCHDIMY),
+ REG32(GEN7_GPGPU_DISPATCHDIMZ),
REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)),
REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)),
REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)),
@@ -1021,7 +1024,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
* only MI_LOAD_REGISTER_IMM commands.
*/
if (reg_addr == OACONTROL) {
- if (desc->cmd.value == MI_LOAD_REGISTER_MEM(1)) {
+ if (desc->cmd.value == MI_LOAD_REGISTER_MEM) {
DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n");
return false;
}
@@ -1035,7 +1038,7 @@ static bool check_cmd(const struct intel_engine_cs *ring,
* allowed mask/value pair given in the whitelist entry.
*/
if (reg->mask) {
- if (desc->cmd.value == MI_LOAD_REGISTER_MEM(1)) {
+ if (desc->cmd.value == MI_LOAD_REGISTER_MEM) {
DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n",
reg_addr);
return false;
@@ -1213,6 +1216,8 @@ int i915_cmd_parser_get_version(void)
* 2. Allow access to the MI_PREDICATE_SRC0 and
* MI_PREDICATE_SRC1 registers.
* 3. Allow access to the GPGPU_THREADS_DISPATCHED register.
+ * 4. L3 atomic chicken bits of HSW_SCRATCH1 and HSW_ROW_CHICKEN3.
+ * 5. GPGPU dispatch compute indirect registers.
*/
- return 3;
+ return 5;
}
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index e3ec9049081f..a3b22bdacd44 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -46,11 +46,6 @@ enum {
PINNED_LIST,
};
-static const char *yesno(int v)
-{
- return v ? "yes" : "no";
-}
-
/* As the drm_debugfs_init() routines are called before dev->dev_private is
* allocated we need to hook into the minor for release. */
static int
@@ -258,7 +253,11 @@ static int obj_rank_by_stolen(void *priv,
struct drm_i915_gem_object *b =
container_of(B, struct drm_i915_gem_object, obj_exec_link);
- return a->stolen->start - b->stolen->start;
+ if (a->stolen->start < b->stolen->start)
+ return -1;
+ if (a->stolen->start > b->stolen->start)
+ return 1;
+ return 0;
}
static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
@@ -957,7 +956,6 @@ static int i915_gem_fence_regs_info(struct seq_file *m, void *data)
if (ret)
return ret;
- seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
for (i = 0; i < dev_priv->num_fence_regs; i++) {
struct drm_i915_gem_object *obj = dev_priv->fence_regs[i].obj;
@@ -1314,6 +1312,10 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
seq_puts(m, "no P-state info available\n");
}
+ seq_printf(m, "Current CD clock frequency: %d kHz\n", dev_priv->cdclk_freq);
+ seq_printf(m, "Max CD clock frequency: %d kHz\n", dev_priv->max_cdclk_freq);
+ seq_printf(m, "Max pixel clock frequency: %d kHz\n", dev_priv->max_dotclk_freq);
+
out:
intel_runtime_pm_put(dev_priv);
return ret;
@@ -1387,17 +1389,16 @@ static int ironlake_drpc_info(struct seq_file *m)
intel_runtime_pm_put(dev_priv);
mutex_unlock(&dev->struct_mutex);
- seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
- "yes" : "no");
+ seq_printf(m, "HD boost: %s\n", yesno(rgvmodectl & MEMMODE_BOOST_EN));
seq_printf(m, "Boost freq: %d\n",
(rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
MEMMODE_BOOST_FREQ_SHIFT);
seq_printf(m, "HW control enabled: %s\n",
- rgvmodectl & MEMMODE_HWIDLE_EN ? "yes" : "no");
+ yesno(rgvmodectl & MEMMODE_HWIDLE_EN));
seq_printf(m, "SW control enabled: %s\n",
- rgvmodectl & MEMMODE_SWMODE_EN ? "yes" : "no");
+ yesno(rgvmodectl & MEMMODE_SWMODE_EN));
seq_printf(m, "Gated voltage change: %s\n",
- rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
+ yesno(rgvmodectl & MEMMODE_RCLK_GATE));
seq_printf(m, "Starting frequency: P%d\n",
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
seq_printf(m, "Max P-state: P%d\n",
@@ -1406,7 +1407,7 @@ static int ironlake_drpc_info(struct seq_file *m)
seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f));
seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
seq_printf(m, "Render standby enabled: %s\n",
- (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes");
+ yesno(!(rstdbyctl & RCX_SW_EXIT)));
seq_puts(m, "Current RS state: ");
switch (rstdbyctl & RSX_STATUS_MASK) {
case RSX_STATUS_ON:
@@ -1849,7 +1850,7 @@ static int i915_opregion(struct seq_file *m, void *unused)
goto out;
if (opregion->header) {
- memcpy_fromio(data, opregion->header, OPREGION_SIZE);
+ memcpy(data, opregion->header, OPREGION_SIZE);
seq_write(m, data, OPREGION_SIZE);
}
@@ -1995,7 +1996,7 @@ static void i915_dump_lrc_obj(struct seq_file *m,
return;
}
- page = i915_gem_object_get_page(ctx_obj, 1);
+ page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
if (!WARN_ON(page == NULL)) {
reg_state = kmap_atomic(page);
@@ -2075,8 +2076,8 @@ static int i915_execlists(struct seq_file *m, void *data)
seq_printf(m, "%s\n", ring->name);
- status = I915_READ(RING_EXECLIST_STATUS(ring));
- ctx_id = I915_READ(RING_EXECLIST_STATUS(ring) + 4);
+ status = I915_READ(RING_EXECLIST_STATUS_LO(ring));
+ ctx_id = I915_READ(RING_EXECLIST_STATUS_HI(ring));
seq_printf(m, "\tExeclist status: 0x%08X, context: %u\n",
status, ctx_id);
@@ -2091,8 +2092,8 @@ static int i915_execlists(struct seq_file *m, void *data)
read_pointer, write_pointer);
for (i = 0; i < 6; i++) {
- status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i);
- ctx_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i + 4);
+ status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, i));
+ ctx_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, i));
seq_printf(m, "\tStatus buffer %d: 0x%08X, context: %u\n",
i, status, ctx_id);
@@ -2237,10 +2238,9 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
for_each_ring(ring, dev_priv, unused) {
seq_printf(m, "%s\n", ring->name);
for (i = 0; i < 4; i++) {
- u32 offset = 0x270 + i * 8;
- u64 pdp = I915_READ(ring->mmio_base + offset + 4);
+ u64 pdp = I915_READ(GEN8_RING_PDP_UDW(ring, i));
pdp <<= 32;
- pdp |= I915_READ(ring->mmio_base + offset);
+ pdp |= I915_READ(GEN8_RING_PDP_LDW(ring, i));
seq_printf(m, "\tPDP%d 0x%016llx\n", i, pdp);
}
}
@@ -2250,7 +2250,6 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *ring;
- struct drm_file *file;
int i;
if (INTEL_INFO(dev)->gen == 6)
@@ -2273,13 +2272,6 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
ppgtt->debug_dump(ppgtt, m);
}
- list_for_each_entry_reverse(file, &dev->filelist, lhead) {
- struct drm_i915_file_private *file_priv = file->driver_priv;
-
- seq_printf(m, "proc: %s\n",
- get_pid_task(file->pid, PIDTYPE_PID)->comm);
- idr_for_each(&file_priv->context_idr, per_file_ctx, m);
- }
seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
}
@@ -2288,6 +2280,7 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_file *file;
int ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
@@ -2299,10 +2292,26 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
else if (INTEL_INFO(dev)->gen >= 6)
gen6_ppgtt_info(m, dev);
+ list_for_each_entry_reverse(file, &dev->filelist, lhead) {
+ struct drm_i915_file_private *file_priv = file->driver_priv;
+ struct task_struct *task;
+
+ task = get_pid_task(file->pid, PIDTYPE_PID);
+ if (!task) {
+ ret = -ESRCH;
+ goto out_put;
+ }
+ seq_printf(m, "\nproc: %s\n", task->comm);
+ put_task_struct(task);
+ idr_for_each(&file_priv->context_idr, per_file_ctx,
+ (void *)(unsigned long)m);
+ }
+
+out_put:
intel_runtime_pm_put(dev_priv);
mutex_unlock(&dev->struct_mutex);
- return 0;
+ return ret;
}
static int count_irq_waiters(struct drm_i915_private *i915)
@@ -2372,6 +2381,147 @@ static int i915_llc(struct seq_file *m, void *data)
return 0;
}
+static int i915_guc_load_status_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_i915_private *dev_priv = node->minor->dev->dev_private;
+ struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ u32 tmp, i;
+
+ if (!HAS_GUC_UCODE(dev_priv->dev))
+ return 0;
+
+ seq_printf(m, "GuC firmware status:\n");
+ seq_printf(m, "\tpath: %s\n",
+ guc_fw->guc_fw_path);
+ seq_printf(m, "\tfetch: %s\n",
+ intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
+ seq_printf(m, "\tload: %s\n",
+ intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+ seq_printf(m, "\tversion wanted: %d.%d\n",
+ guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
+ seq_printf(m, "\tversion found: %d.%d\n",
+ guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found);
+
+ tmp = I915_READ(GUC_STATUS);
+
+ seq_printf(m, "\nGuC status 0x%08x:\n", tmp);
+ seq_printf(m, "\tBootrom status = 0x%x\n",
+ (tmp & GS_BOOTROM_MASK) >> GS_BOOTROM_SHIFT);
+ seq_printf(m, "\tuKernel status = 0x%x\n",
+ (tmp & GS_UKERNEL_MASK) >> GS_UKERNEL_SHIFT);
+ seq_printf(m, "\tMIA Core status = 0x%x\n",
+ (tmp & GS_MIA_MASK) >> GS_MIA_SHIFT);
+ seq_puts(m, "\nScratch registers:\n");
+ for (i = 0; i < 16; i++)
+ seq_printf(m, "\t%2d: \t0x%x\n", i, I915_READ(SOFT_SCRATCH(i)));
+
+ return 0;
+}
+
+static void i915_guc_client_info(struct seq_file *m,
+ struct drm_i915_private *dev_priv,
+ struct i915_guc_client *client)
+{
+ struct intel_engine_cs *ring;
+ uint64_t tot = 0;
+ uint32_t i;
+
+ seq_printf(m, "\tPriority %d, GuC ctx index: %u, PD offset 0x%x\n",
+ client->priority, client->ctx_index, client->proc_desc_offset);
+ seq_printf(m, "\tDoorbell id %d, offset: 0x%x, cookie 0x%x\n",
+ client->doorbell_id, client->doorbell_offset, client->cookie);
+ seq_printf(m, "\tWQ size %d, offset: 0x%x, tail %d\n",
+ client->wq_size, client->wq_offset, client->wq_tail);
+
+ seq_printf(m, "\tFailed to queue: %u\n", client->q_fail);
+ seq_printf(m, "\tFailed doorbell: %u\n", client->b_fail);
+ seq_printf(m, "\tLast submission result: %d\n", client->retcode);
+
+ for_each_ring(ring, dev_priv, i) {
+ seq_printf(m, "\tSubmissions: %llu %s\n",
+ client->submissions[i],
+ ring->name);
+ tot += client->submissions[i];
+ }
+ seq_printf(m, "\tTotal: %llu\n", tot);
+}
+
+static int i915_guc_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc guc;
+ struct i915_guc_client client = {};
+ struct intel_engine_cs *ring;
+ enum intel_ring_id i;
+ u64 total = 0;
+
+ if (!HAS_GUC_SCHED(dev_priv->dev))
+ return 0;
+
+ /* Take a local copy of the GuC data, so we can dump it at leisure */
+ spin_lock(&dev_priv->guc.host2guc_lock);
+ guc = dev_priv->guc;
+ if (guc.execbuf_client) {
+ spin_lock(&guc.execbuf_client->wq_lock);
+ client = *guc.execbuf_client;
+ spin_unlock(&guc.execbuf_client->wq_lock);
+ }
+ spin_unlock(&dev_priv->guc.host2guc_lock);
+
+ seq_printf(m, "GuC total action count: %llu\n", guc.action_count);
+ seq_printf(m, "GuC action failure count: %u\n", guc.action_fail);
+ seq_printf(m, "GuC last action command: 0x%x\n", guc.action_cmd);
+ seq_printf(m, "GuC last action status: 0x%x\n", guc.action_status);
+ seq_printf(m, "GuC last action error code: %d\n", guc.action_err);
+
+ seq_printf(m, "\nGuC submissions:\n");
+ for_each_ring(ring, dev_priv, i) {
+ seq_printf(m, "\t%-24s: %10llu, last seqno 0x%08x %9d\n",
+ ring->name, guc.submissions[i],
+ guc.last_seqno[i], guc.last_seqno[i]);
+ total += guc.submissions[i];
+ }
+ seq_printf(m, "\t%s: %llu\n", "Total", total);
+
+ seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client);
+ i915_guc_client_info(m, dev_priv, &client);
+
+ /* Add more as required ... */
+
+ return 0;
+}
+
+static int i915_guc_log_dump(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *log_obj = dev_priv->guc.log_obj;
+ u32 *log;
+ int i = 0, pg;
+
+ if (!log_obj)
+ return 0;
+
+ for (pg = 0; pg < log_obj->base.size / PAGE_SIZE; pg++) {
+ log = kmap_atomic(i915_gem_object_get_page(log_obj, pg));
+
+ for (i = 0; i < PAGE_SIZE / sizeof(u32); i += 4)
+ seq_printf(m, "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ *(log + i), *(log + i + 1),
+ *(log + i + 2), *(log + i + 3));
+
+ kunmap_atomic(log);
+ }
+
+ seq_putc(m, '\n');
+
+ return 0;
+}
+
static int i915_edp_psr_status(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
@@ -2680,11 +2830,13 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
struct drm_device *dev = node->minor->dev;
struct drm_crtc *crtc = &intel_crtc->base;
struct intel_encoder *intel_encoder;
+ struct drm_plane_state *plane_state = crtc->primary->state;
+ struct drm_framebuffer *fb = plane_state->fb;
- if (crtc->primary->fb)
+ if (fb)
seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n",
- crtc->primary->fb->base.id, crtc->x, crtc->y,
- crtc->primary->fb->width, crtc->primary->fb->height);
+ fb->base.id, plane_state->src_x >> 16,
+ plane_state->src_y >> 16, fb->width, fb->height);
else
seq_puts(m, "\tprimary plane disabled\n");
for_each_encoder_on_crtc(dev, crtc, intel_encoder)
@@ -2706,8 +2858,7 @@ static void intel_dp_info(struct seq_file *m,
struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]);
- seq_printf(m, "\taudio support: %s\n", intel_dp->has_audio ? "yes" :
- "no");
+ seq_printf(m, "\taudio support: %s\n", yesno(intel_dp->has_audio));
if (intel_encoder->type == INTEL_OUTPUT_EDP)
intel_panel_info(m, &intel_connector->panel);
}
@@ -2718,8 +2869,7 @@ static void intel_hdmi_info(struct seq_file *m,
struct intel_encoder *intel_encoder = intel_connector->encoder;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
- seq_printf(m, "\taudio support: %s\n", intel_hdmi->has_audio ? "yes" :
- "no");
+ seq_printf(m, "\taudio support: %s\n", yesno(intel_hdmi->has_audio));
}
static void intel_lvds_info(struct seq_file *m,
@@ -2769,7 +2919,7 @@ static bool cursor_active(struct drm_device *dev, int pipe)
u32 state;
if (IS_845G(dev) || IS_I865G(dev))
- state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
+ state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
else
state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
@@ -3007,7 +3157,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
skl_ddb_entry_size(entry));
}
- entry = &ddb->cursor[pipe];
+ entry = &ddb->plane[pipe][PLANE_CURSOR];
seq_printf(m, " %-13s%8u%8u%8u\n", "Cursor", entry->start,
entry->end, skl_ddb_entry_size(entry));
}
@@ -4807,7 +4957,7 @@ static void cherryview_sseu_device_status(struct drm_device *dev,
struct sseu_dev_status *stat)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- const int ss_max = 2;
+ int ss_max = 2;
int ss;
u32 sig1[ss_max], sig2[ss_max];
@@ -4900,13 +5050,38 @@ static void gen9_sseu_device_status(struct drm_device *dev,
}
}
+static void broadwell_sseu_device_status(struct drm_device *dev,
+ struct sseu_dev_status *stat)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int s;
+ u32 slice_info = I915_READ(GEN8_GT_SLICE_INFO);
+
+ stat->slice_total = hweight32(slice_info & GEN8_LSLICESTAT_MASK);
+
+ if (stat->slice_total) {
+ stat->subslice_per_slice = INTEL_INFO(dev)->subslice_per_slice;
+ stat->subslice_total = stat->slice_total *
+ stat->subslice_per_slice;
+ stat->eu_per_subslice = INTEL_INFO(dev)->eu_per_subslice;
+ stat->eu_total = stat->eu_per_subslice * stat->subslice_total;
+
+ /* subtract fused off EU(s) from enabled slice(s) */
+ for (s = 0; s < stat->slice_total; s++) {
+ u8 subslice_7eu = INTEL_INFO(dev)->subslice_7eu[s];
+
+ stat->eu_total -= hweight8(subslice_7eu);
+ }
+ }
+}
+
static int i915_sseu_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct sseu_dev_status stat;
- if ((INTEL_INFO(dev)->gen < 8) || IS_BROADWELL(dev))
+ if (INTEL_INFO(dev)->gen < 8)
return -ENODEV;
seq_puts(m, "SSEU Device Info\n");
@@ -4931,6 +5106,8 @@ static int i915_sseu_status(struct seq_file *m, void *unused)
memset(&stat, 0, sizeof(stat));
if (IS_CHERRYVIEW(dev)) {
cherryview_sseu_device_status(dev, &stat);
+ } else if (IS_BROADWELL(dev)) {
+ broadwell_sseu_device_status(dev, &stat);
} else if (INTEL_INFO(dev)->gen >= 9) {
gen9_sseu_device_status(dev, &stat);
}
@@ -5033,6 +5210,9 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
{"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
+ {"i915_guc_info", i915_guc_info, 0},
+ {"i915_guc_load_status", i915_guc_load_status_info, 0},
+ {"i915_guc_log_dump", i915_guc_log_dump, 0},
{"i915_frequency_info", i915_frequency_info, 0},
{"i915_hangcheck_info", i915_hangcheck_info, 0},
{"i915_drpc_info", i915_drpc_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 990f656e6ab0..b4741d121a74 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -75,7 +75,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
value = 1;
break;
case I915_PARAM_NUM_FENCES_AVAIL:
- value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
+ value = dev_priv->num_fence_regs;
break;
case I915_PARAM_HAS_OVERLAY:
value = dev_priv->overlay ? 1 : 0;
@@ -183,35 +183,6 @@ static int i915_getparam(struct drm_device *dev, void *data,
return 0;
}
-static int i915_setparam(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- drm_i915_setparam_t *param = data;
-
- switch (param->param) {
- case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
- case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
- case I915_SETPARAM_ALLOW_BATCHBUFFER:
- /* Reject all old ums/dri params. */
- return -ENODEV;
-
- case I915_SETPARAM_NUM_USED_FENCES:
- if (param->value > dev_priv->num_fence_regs ||
- param->value < 0)
- return -EINVAL;
- /* Userspace can use first N regs */
- dev_priv->fence_reg_start = param->value;
- break;
- default:
- DRM_DEBUG_DRIVER("unknown parameter %d\n",
- param->param);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int i915_get_bridge_dev(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -364,12 +335,12 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
- i915_resume_legacy(dev);
+ i915_resume_switcheroo(dev);
dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
pr_err("switched off\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
- i915_suspend_legacy(dev, pmm);
+ i915_suspend_switcheroo(dev, pmm);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
}
}
@@ -435,6 +406,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
* working irqs for e.g. gmbus and dp aux transfers. */
intel_modeset_init(dev);
+ intel_guc_ucode_init(dev);
+
ret = i915_gem_init(dev);
if (ret)
goto cleanup_irq;
@@ -476,6 +449,7 @@ cleanup_gem:
i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex);
cleanup_irq:
+ intel_guc_ucode_fini(dev);
drm_irq_uninstall(dev);
cleanup_gem_stolen:
i915_gem_cleanup_stolen(dev);
@@ -623,17 +597,6 @@ static void gen9_sseu_info_init(struct drm_device *dev)
u32 fuse2, s_enable, ss_disable, eu_disable;
u8 eu_mask = 0xff;
- /*
- * BXT has a single slice. BXT also has at most 6 EU per subslice,
- * and therefore only the lowest 6 bits of the 8-bit EU disable
- * fields are valid.
- */
- if (IS_BROXTON(dev)) {
- s_max = 1;
- eu_max = 6;
- eu_mask = 0x3f;
- }
-
info = (struct intel_device_info *)&dev_priv->info;
fuse2 = I915_READ(GEN8_FUSE2);
s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >>
@@ -705,6 +668,82 @@ static void gen9_sseu_info_init(struct drm_device *dev)
info->has_eu_pg = (info->eu_per_subslice > 2);
}
+static void broadwell_sseu_info_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_device_info *info;
+ const int s_max = 3, ss_max = 3, eu_max = 8;
+ int s, ss;
+ u32 fuse2, eu_disable[s_max], s_enable, ss_disable;
+
+ fuse2 = I915_READ(GEN8_FUSE2);
+ s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
+ ss_disable = (fuse2 & GEN8_F2_SS_DIS_MASK) >> GEN8_F2_SS_DIS_SHIFT;
+
+ eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK;
+ eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) |
+ ((I915_READ(GEN8_EU_DISABLE1) & GEN8_EU_DIS1_S1_MASK) <<
+ (32 - GEN8_EU_DIS0_S1_SHIFT));
+ eu_disable[2] = (I915_READ(GEN8_EU_DISABLE1) >> GEN8_EU_DIS1_S2_SHIFT) |
+ ((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) <<
+ (32 - GEN8_EU_DIS1_S2_SHIFT));
+
+
+ info = (struct intel_device_info *)&dev_priv->info;
+ info->slice_total = hweight32(s_enable);
+
+ /*
+ * The subslice disable field is global, i.e. it applies
+ * to each of the enabled slices.
+ */
+ info->subslice_per_slice = ss_max - hweight32(ss_disable);
+ info->subslice_total = info->slice_total * info->subslice_per_slice;
+
+ /*
+ * Iterate through enabled slices and subslices to
+ * count the total enabled EU.
+ */
+ for (s = 0; s < s_max; s++) {
+ if (!(s_enable & (0x1 << s)))
+ /* skip disabled slice */
+ continue;
+
+ for (ss = 0; ss < ss_max; ss++) {
+ u32 n_disabled;
+
+ if (ss_disable & (0x1 << ss))
+ /* skip disabled subslice */
+ continue;
+
+ n_disabled = hweight8(eu_disable[s] >> (ss * eu_max));
+
+ /*
+ * Record which subslices have 7 EUs.
+ */
+ if (eu_max - n_disabled == 7)
+ info->subslice_7eu[s] |= 1 << ss;
+
+ info->eu_total += eu_max - n_disabled;
+ }
+ }
+
+ /*
+ * BDW is expected to always have a uniform distribution of EU across
+ * subslices with the exception that any one EU in any one subslice may
+ * be fused off for die recovery.
+ */
+ info->eu_per_subslice = info->subslice_total ?
+ DIV_ROUND_UP(info->eu_total, info->subslice_total) : 0;
+
+ /*
+ * BDW supports slice power gating on devices with more than
+ * one slice.
+ */
+ info->has_slice_pg = (info->slice_total > 1);
+ info->has_subslice_pg = 0;
+ info->has_eu_pg = 0;
+}
+
/*
* Determine various intel_device_info fields at runtime.
*
@@ -775,6 +814,8 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
/* Initialize slice/subslice/EU info */
if (IS_CHERRYVIEW(dev))
cherryview_sseu_info_init(dev);
+ else if (IS_BROADWELL(dev))
+ broadwell_sseu_info_init(dev);
else if (INTEL_INFO(dev)->gen >= 9)
gen9_sseu_info_init(dev);
@@ -791,6 +832,24 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
info->has_eu_pg ? "y" : "n");
}
+static void intel_init_dpio(struct drm_i915_private *dev_priv)
+{
+ if (!IS_VALLEYVIEW(dev_priv))
+ return;
+
+ /*
+ * IOSF_PORT_DPIO is used for VLV x2 PHY (DP/HDMI B and C),
+ * CHV x1 PHY (DP/HDMI D)
+ * IOSF_PORT_DPIO_2 is used for CHV x2 PHY (DP/HDMI B and C)
+ */
+ if (IS_CHERRYVIEW(dev_priv)) {
+ DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO_2;
+ DPIO_PHY_IOSF_PORT(DPIO_PHY1) = IOSF_PORT_DPIO;
+ } else {
+ DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO;
+ }
+}
+
/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
@@ -972,8 +1031,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_setup_gmbus(dev);
intel_opregion_setup(dev);
- intel_setup_bios(dev);
-
i915_gem_load(dev);
/* On the 945G/GM, the chipset reports the MSI capability on the
@@ -992,6 +1049,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_device_info_runtime_init(dev);
+ intel_init_dpio(dev_priv);
+
if (INTEL_INFO(dev)->num_pipes) {
ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
if (ret)
@@ -1060,12 +1119,9 @@ out_freecsr:
put_bridge:
pci_dev_put(dev_priv->bridge_dev);
free_priv:
- if (dev_priv->requests)
- kmem_cache_destroy(dev_priv->requests);
- if (dev_priv->vmas)
- kmem_cache_destroy(dev_priv->vmas);
- if (dev_priv->objects)
- kmem_cache_destroy(dev_priv->objects);
+ kmem_cache_destroy(dev_priv->requests);
+ kmem_cache_destroy(dev_priv->vmas);
+ kmem_cache_destroy(dev_priv->objects);
kfree(dev_priv);
return ret;
}
@@ -1112,6 +1168,10 @@ int i915_driver_unload(struct drm_device *dev)
dev_priv->vbt.child_dev = NULL;
dev_priv->vbt.child_dev_num = 0;
}
+ kfree(dev_priv->vbt.sdvo_lvds_vbt_mode);
+ dev_priv->vbt.sdvo_lvds_vbt_mode = NULL;
+ kfree(dev_priv->vbt.lfp_lvds_vbt_mode);
+ dev_priv->vbt.lfp_lvds_vbt_mode = NULL;
vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
@@ -1128,6 +1188,7 @@ int i915_driver_unload(struct drm_device *dev)
/* Flush any outstanding unpin_work. */
flush_workqueue(dev_priv->wq);
+ intel_guc_ucode_fini(dev);
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev);
@@ -1151,13 +1212,9 @@ int i915_driver_unload(struct drm_device *dev)
if (dev_priv->regs != NULL)
pci_iounmap(dev->pdev, dev_priv->regs);
- if (dev_priv->requests)
- kmem_cache_destroy(dev_priv->requests);
- if (dev_priv->vmas)
- kmem_cache_destroy(dev_priv->vmas);
- if (dev_priv->objects)
- kmem_cache_destroy(dev_priv->objects);
-
+ kmem_cache_destroy(dev_priv->requests);
+ kmem_cache_destroy(dev_priv->vmas);
+ kmem_cache_destroy(dev_priv->objects);
pci_dev_put(dev_priv->bridge_dev);
kfree(dev_priv);
@@ -1227,7 +1284,7 @@ const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_IRQ_EMIT, drm_noop, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_IRQ_WAIT, drm_noop, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_GETPARAM, i915_getparam, DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_SETPARAM, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_ALLOC, drm_noop, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_FREE, drm_noop, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -1237,41 +1294,41 @@ const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, drm_noop, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_ENTERVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_GEM_LEAVEVT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CREATE, i915_gem_create_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_PREAD, i915_gem_pread_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_PWRITE, i915_gem_pwrite_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_MMAP, i915_gem_mmap_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
+ DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_OVERLAY_PUT_IMAGE, intel_overlay_put_image, DRM_MASTER|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_OVERLAY_ATTRS, intel_overlay_attrs, DRM_MASTER|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_SET_SPRITE_COLORKEY, intel_sprite_set_colorkey, DRM_MASTER|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GET_SPRITE_COLORKEY, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_WAIT, i915_gem_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_RENDER_ALLOW),
};
int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index ab64d68388f2..760e0ce4aa26 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -362,6 +362,7 @@ static const struct intel_device_info intel_skylake_info = {
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
.has_llc = 1,
.has_ddi = 1,
+ .has_fpga_dbg = 1,
.has_fbc = 1,
GEN_DEFAULT_PIPEOFFSETS,
IVB_CURSOR_OFFSETS,
@@ -374,6 +375,7 @@ static const struct intel_device_info intel_skylake_gt3_info = {
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
.has_llc = 1,
.has_ddi = 1,
+ .has_fpga_dbg = 1,
.has_fbc = 1,
GEN_DEFAULT_PIPEOFFSETS,
IVB_CURSOR_OFFSETS,
@@ -386,6 +388,7 @@ static const struct intel_device_info intel_broxton_info = {
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
.num_pipes = 3,
.has_ddi = 1,
+ .has_fpga_dbg = 1,
.has_fbc = 1,
GEN_DEFAULT_PIPEOFFSETS,
IVB_CURSOR_OFFSETS,
@@ -440,6 +443,34 @@ static const struct pci_device_id pciidlist[] = { /* aka */
MODULE_DEVICE_TABLE(pci, pciidlist);
+static enum intel_pch intel_virt_detect_pch(struct drm_device *dev)
+{
+ enum intel_pch ret = PCH_NOP;
+
+ /*
+ * In a virtualized passthrough environment we can be in a
+ * setup where the ISA bridge is not able to be passed through.
+ * In this case, a south bridge can be emulated and we have to
+ * make an educated guess as to which PCH is really there.
+ */
+
+ if (IS_GEN5(dev)) {
+ ret = PCH_IBX;
+ DRM_DEBUG_KMS("Assuming Ibex Peak PCH\n");
+ } else if (IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
+ ret = PCH_CPT;
+ DRM_DEBUG_KMS("Assuming CouarPoint PCH\n");
+ } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+ ret = PCH_LPT;
+ DRM_DEBUG_KMS("Assuming LynxPoint PCH\n");
+ } else if (IS_SKYLAKE(dev)) {
+ ret = PCH_SPT;
+ DRM_DEBUG_KMS("Assuming SunrisePoint PCH\n");
+ }
+
+ return ret;
+}
+
void intel_detect_pch(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -500,6 +531,8 @@ void intel_detect_pch(struct drm_device *dev)
dev_priv->pch_type = PCH_SPT;
DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n");
WARN_ON(!IS_SKYLAKE(dev));
+ } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) {
+ dev_priv->pch_type = intel_virt_detect_pch(dev);
} else
continue;
@@ -605,6 +638,8 @@ static int i915_drm_suspend(struct drm_device *dev)
return error;
}
+ intel_guc_suspend(dev);
+
intel_suspend_gt_powersave(dev);
/*
@@ -679,7 +714,7 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
return 0;
}
-int i915_suspend_legacy(struct drm_device *dev, pm_message_t state)
+int i915_suspend_switcheroo(struct drm_device *dev, pm_message_t state)
{
int error;
@@ -734,6 +769,8 @@ static int i915_drm_resume(struct drm_device *dev)
}
mutex_unlock(&dev->struct_mutex);
+ intel_guc_resume(dev);
+
intel_modeset_init_hw(dev);
spin_lock_irq(&dev_priv->irq_lock);
@@ -812,7 +849,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
return ret;
}
-int i915_resume_legacy(struct drm_device *dev)
+int i915_resume_switcheroo(struct drm_device *dev)
{
int ret;
@@ -1018,12 +1055,6 @@ static int skl_suspend_complete(struct drm_i915_private *dev_priv)
{
/* Enabling DC6 is not a hard requirement to enter runtime D3 */
- /*
- * This is to ensure that CSR isn't identified as loaded before
- * CSR-loading program is called during runtime-resume.
- */
- intel_csr_load_status_set(dev_priv, FW_UNINITIALIZED);
-
skl_uninit_cdclk(dev_priv);
return 0;
@@ -1117,7 +1148,7 @@ static void vlv_save_gunit_s0ix_state(struct drm_i915_private *dev_priv)
s->gfx_pend_tlb1 = I915_READ(GEN7_GFX_PEND_TLB1);
for (i = 0; i < ARRAY_SIZE(s->lra_limits); i++)
- s->lra_limits[i] = I915_READ(GEN7_LRA_LIMITS_BASE + i * 4);
+ s->lra_limits[i] = I915_READ(GEN7_LRA_LIMITS(i));
s->media_max_req_count = I915_READ(GEN7_MEDIA_MAX_REQ_COUNT);
s->gfx_max_req_count = I915_READ(GEN7_GFX_MAX_REQ_COUNT);
@@ -1161,7 +1192,7 @@ static void vlv_save_gunit_s0ix_state(struct drm_i915_private *dev_priv)
s->pm_ier = I915_READ(GEN6_PMIER);
for (i = 0; i < ARRAY_SIZE(s->gt_scratch); i++)
- s->gt_scratch[i] = I915_READ(GEN7_GT_SCRATCH_BASE + i * 4);
+ s->gt_scratch[i] = I915_READ(GEN7_GT_SCRATCH(i));
/* GT SA CZ domain, 0x100000-0x138124 */
s->tilectl = I915_READ(TILECTL);
@@ -1199,7 +1230,7 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *dev_priv)
I915_WRITE(GEN7_GFX_PEND_TLB1, s->gfx_pend_tlb1);
for (i = 0; i < ARRAY_SIZE(s->lra_limits); i++)
- I915_WRITE(GEN7_LRA_LIMITS_BASE + i * 4, s->lra_limits[i]);
+ I915_WRITE(GEN7_LRA_LIMITS(i), s->lra_limits[i]);
I915_WRITE(GEN7_MEDIA_MAX_REQ_COUNT, s->media_max_req_count);
I915_WRITE(GEN7_GFX_MAX_REQ_COUNT, s->gfx_max_req_count);
@@ -1243,7 +1274,7 @@ static void vlv_restore_gunit_s0ix_state(struct drm_i915_private *dev_priv)
I915_WRITE(GEN6_PMIER, s->pm_ier);
for (i = 0; i < ARRAY_SIZE(s->gt_scratch); i++)
- I915_WRITE(GEN7_GT_SCRATCH_BASE + i * 4, s->gt_scratch[i]);
+ I915_WRITE(GEN7_GT_SCRATCH(i), s->gt_scratch[i]);
/* GT SA CZ domain, 0x100000-0x138124 */
I915_WRITE(TILECTL, s->tilectl);
@@ -1473,6 +1504,8 @@ static int intel_runtime_suspend(struct device *device)
i915_gem_release_all_mmaps(dev_priv);
mutex_unlock(&dev->struct_mutex);
+ intel_guc_suspend(dev);
+
intel_suspend_gt_powersave(dev);
intel_runtime_pm_disable_interrupts(dev_priv);
@@ -1532,6 +1565,8 @@ static int intel_runtime_resume(struct device *device)
intel_opregion_notify_adapter(dev, PCI_D0);
dev_priv->pm.suspended = false;
+ intel_guc_resume(dev);
+
if (IS_GEN6(dev_priv))
intel_init_pch_refclk(dev);
@@ -1552,6 +1587,15 @@ static int intel_runtime_resume(struct device *device)
gen6_update_ring_freq(dev);
intel_runtime_pm_enable_interrupts(dev_priv);
+
+ /*
+ * On VLV/CHV display interrupts are part of the display
+ * power well, so hpd is reinitialized from there. For
+ * everyone else do it here.
+ */
+ if (!IS_VALLEYVIEW(dev_priv))
+ intel_hpd_init(dev_priv);
+
intel_enable_gt_powersave(dev);
if (ret)
@@ -1649,7 +1693,7 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME |
- DRIVER_RENDER,
+ DRIVER_RENDER | DRIVER_MODESET,
.load = i915_driver_load,
.unload = i915_driver_unload,
.open = i915_driver_open,
@@ -1658,10 +1702,6 @@ static struct drm_driver driver = {
.postclose = i915_driver_postclose,
.set_busid = drm_pci_set_busid,
- /* Used in place of i915_pm_ops for non-DRIVER_MODESET */
- .suspend = i915_suspend_legacy,
- .resume = i915_resume_legacy,
-
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = i915_debugfs_init,
.debugfs_cleanup = i915_debugfs_cleanup,
@@ -1704,7 +1744,6 @@ static int __init i915_init(void)
* either the i915.modeset prarameter or by the
* vga_text_mode_force boot option.
*/
- driver.driver_features |= DRIVER_MODESET;
if (i915.modeset == 0)
driver.driver_features &= ~DRIVER_MODESET;
@@ -1715,18 +1754,12 @@ static int __init i915_init(void)
#endif
if (!(driver.driver_features & DRIVER_MODESET)) {
- driver.get_vblank_timestamp = NULL;
/* Silently fail loading to not upset userspace. */
DRM_DEBUG_DRIVER("KMS and UMS disabled.\n");
return 0;
}
- /*
- * FIXME: Note that we're lying to the DRM core here so that we can get access
- * to the atomic ioctl and the atomic properties. Only plane operations on
- * a single CRTC will actually work.
- */
- if (driver.driver_features & DRIVER_MODESET)
+ if (i915.nuclear_pageflip)
driver.driver_features |= DRIVER_ATOMIC;
return drm_pci_init(&driver, &i915_pci_driver);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 22dd7043c9ef..8afda459a26e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -50,13 +50,14 @@
#include <linux/intel-iommu.h>
#include <linux/kref.h>
#include <linux/pm_qos.h>
+#include "intel_guc.h"
/* General customization:
*/
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20150731"
+#define DRIVER_DATE "20151010"
#undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */
@@ -67,11 +68,11 @@
BUILD_BUG_ON(__i915_warn_cond); \
WARN(__i915_warn_cond, "WARN_ON(" #x ")"); })
#else
-#define WARN_ON(x) WARN((x), "WARN_ON(" #x ")")
+#define WARN_ON(x) WARN((x), "WARN_ON(%s)", #x )
#endif
#undef WARN_ON_ONCE
-#define WARN_ON_ONCE(x) WARN_ONCE((x), "WARN_ON_ONCE(" #x ")")
+#define WARN_ON_ONCE(x) WARN_ONCE((x), "WARN_ON_ONCE(%s)", #x )
#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \
(long) (x), __func__);
@@ -105,6 +106,11 @@
unlikely(__ret_warn_on); \
})
+static inline const char *yesno(bool v)
+{
+ return v ? "yes" : "no";
+}
+
enum pipe {
INVALID_PIPE = -1,
PIPE_A = 0,
@@ -125,17 +131,17 @@ enum transcoder {
#define transcoder_name(t) ((t) + 'A')
/*
- * This is the maximum (across all platforms) number of planes (primary +
- * sprites) that can be active at the same time on one pipe.
- *
- * This value doesn't count the cursor plane.
+ * I915_MAX_PLANES in the enum below is the maximum (across all platforms)
+ * number of planes per CRTC. Not all platforms really have this many planes,
+ * which means some arrays of size I915_MAX_PLANES may have unused entries
+ * between the topmost sprite plane and the cursor plane.
*/
-#define I915_MAX_PLANES 4
-
enum plane {
PLANE_A = 0,
PLANE_B,
PLANE_C,
+ PLANE_CURSOR,
+ I915_MAX_PLANES,
};
#define plane_name(p) ((p) + 'A')
@@ -444,14 +450,14 @@ struct opregion_swsci;
struct opregion_asle;
struct intel_opregion {
- struct opregion_header __iomem *header;
- struct opregion_acpi __iomem *acpi;
- struct opregion_swsci __iomem *swsci;
+ struct opregion_header *header;
+ struct opregion_acpi *acpi;
+ struct opregion_swsci *swsci;
u32 swsci_gbda_sub_functions;
u32 swsci_sbcb_sub_functions;
- struct opregion_asle __iomem *asle;
- void __iomem *vbt;
- u32 __iomem *lid_state;
+ struct opregion_asle *asle;
+ void *vbt;
+ u32 *lid_state;
struct work_struct asle_work;
};
#define OPREGION_SIZE (8*1024)
@@ -549,7 +555,7 @@ struct drm_i915_error_state {
struct drm_i915_error_object {
int page_count;
- u32 gtt_offset;
+ u64 gtt_offset;
u32 *pages[0];
} *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
@@ -575,7 +581,7 @@ struct drm_i915_error_state {
u32 size;
u32 name;
u32 rseqno[I915_NUM_RINGS], wseqno;
- u32 gtt_offset;
+ u64 gtt_offset;
u32 read_domains;
u32 write_domain;
s32 fence_reg:I915_MAX_NUM_FENCE_BITS;
@@ -640,7 +646,7 @@ struct drm_i915_display_funcs {
void (*crtc_disable)(struct drm_crtc *crtc);
void (*audio_codec_enable)(struct drm_connector *connector,
struct intel_encoder *encoder,
- struct drm_display_mode *mode);
+ const struct drm_display_mode *adjusted_mode);
void (*audio_codec_disable)(struct intel_encoder *encoder);
void (*fdi_link_train)(struct drm_crtc *crtc);
void (*init_clock_gating)(struct drm_device *dev);
@@ -658,13 +664,6 @@ struct drm_i915_display_funcs {
/* render clock increase/decrease */
/* display clock increase/decrease */
/* pll clock increase/decrease */
-
- int (*setup_backlight)(struct intel_connector *connector, enum pipe pipe);
- uint32_t (*get_backlight)(struct intel_connector *connector);
- void (*set_backlight)(struct intel_connector *connector,
- uint32_t level);
- void (*disable_backlight)(struct intel_connector *connector);
- void (*enable_backlight)(struct intel_connector *connector);
};
enum forcewake_domain_id {
@@ -882,7 +881,6 @@ struct intel_context {
} legacy_hw_ctx;
/* Execlists */
- bool rcs_initialized;
struct {
struct drm_i915_gem_object *state;
struct intel_ringbuffer *ringbuf;
@@ -941,6 +939,9 @@ struct i915_fbc {
FBC_CHIP_DEFAULT, /* disabled by default on this chip */
FBC_ROTATION, /* rotation is not supported */
FBC_IN_DBG_MASTER, /* kernel debugger is active */
+ FBC_BAD_STRIDE, /* stride is not supported */
+ FBC_PIXEL_RATE, /* pixel rate is too big */
+ FBC_PIXEL_FORMAT /* pixel format is invalid */
} no_fbc_reason;
bool (*fbc_enabled)(struct drm_i915_private *dev_priv);
@@ -1034,7 +1035,7 @@ struct i915_suspend_saved_registers {
u32 saveMI_ARB_STATE;
u32 saveSWF0[16];
u32 saveSWF1[16];
- u32 saveSWF2[3];
+ u32 saveSWF3[3];
uint64_t saveFENCE[I915_MAX_NUM_FENCES];
u32 savePCH_PORT_HOTPLUG;
u16 saveGCDGMBUS;
@@ -1136,7 +1137,6 @@ struct intel_gen6_power_mgmt {
u8 efficient_freq; /* AKA RPe. Pre-determined balanced frequency */
u8 rp1_freq; /* "less than" RP0 power/freqency */
u8 rp0_freq; /* Non-overclocked max frequency. */
- u32 cz_freq;
u8 up_threshold; /* Current %busy required to uplock */
u8 down_threshold; /* Current %busy required to downclock */
@@ -1578,8 +1578,7 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
struct skl_ddb_allocation {
struct skl_ddb_entry pipe[I915_MAX_PIPES];
struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES]; /* packed/uv */
- struct skl_ddb_entry y_plane[I915_MAX_PIPES][I915_MAX_PLANES]; /* y-plane */
- struct skl_ddb_entry cursor[I915_MAX_PIPES];
+ struct skl_ddb_entry y_plane[I915_MAX_PIPES][I915_MAX_PLANES];
};
struct skl_wm_values {
@@ -1587,18 +1586,13 @@ struct skl_wm_values {
struct skl_ddb_allocation ddb;
uint32_t wm_linetime[I915_MAX_PIPES];
uint32_t plane[I915_MAX_PIPES][I915_MAX_PLANES][8];
- uint32_t cursor[I915_MAX_PIPES][8];
uint32_t plane_trans[I915_MAX_PIPES][I915_MAX_PLANES];
- uint32_t cursor_trans[I915_MAX_PIPES];
};
struct skl_wm_level {
bool plane_en[I915_MAX_PLANES];
- bool cursor_en;
uint16_t plane_res_b[I915_MAX_PLANES];
uint8_t plane_res_l[I915_MAX_PLANES];
- uint16_t cursor_res_b;
- uint8_t cursor_res_l;
};
/*
@@ -1693,7 +1687,7 @@ struct i915_execbuffer_params {
struct drm_file *file;
uint32_t dispatch_flags;
uint32_t args_batch_start_offset;
- uint32_t batch_obj_vm_offset;
+ uint64_t batch_obj_vm_offset;
struct intel_engine_cs *ring;
struct drm_i915_gem_object *batch_obj;
struct intel_context *ctx;
@@ -1716,6 +1710,8 @@ struct drm_i915_private {
struct i915_virtual_gpu vgpu;
+ struct intel_guc guc;
+
struct intel_csr csr;
/* Display CSR-related protection */
@@ -1790,13 +1786,14 @@ struct drm_i915_private {
struct mutex pps_mutex;
struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
- int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
unsigned int fsb_freq, mem_freq, is_ddr3;
unsigned int skl_boot_cdclk;
unsigned int cdclk_freq, max_cdclk_freq;
+ unsigned int max_dotclk_freq;
unsigned int hpll_freq;
+ unsigned int czclk_freq;
/**
* wq - Driver workqueue for GEM.
@@ -1952,6 +1949,9 @@ struct drm_i915_private {
bool edp_low_vswing;
+ /* perform PHY state sanity checks? */
+ bool chv_phy_assert[2];
+
/*
* NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
* will be rejected. Instead look for a better place.
@@ -1968,6 +1968,11 @@ static inline struct drm_i915_private *dev_to_i915(struct device *dev)
return to_i915(dev_get_drvdata(dev));
}
+static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
+{
+ return container_of(guc, struct drm_i915_private, guc);
+}
+
/* Iterate over initialised rings */
#define for_each_ring(ring__, dev_priv__, i__) \
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
@@ -2004,25 +2009,26 @@ struct drm_i915_gem_object_ops {
/*
* Frontbuffer tracking bits. Set in obj->frontbuffer_bits while a gem bo is
- * considered to be the frontbuffer for the given plane interface-vise. This
+ * considered to be the frontbuffer for the given plane interface-wise. This
* doesn't mean that the hw necessarily already scans it out, but that any
* rendering (by the cpu or gpu) will land in the frontbuffer eventually.
*
* We have one bit per pipe and per scanout plane type.
*/
-#define INTEL_FRONTBUFFER_BITS_PER_PIPE 4
+#define INTEL_MAX_SPRITE_BITS_PER_PIPE 5
+#define INTEL_FRONTBUFFER_BITS_PER_PIPE 8
#define INTEL_FRONTBUFFER_BITS \
(INTEL_FRONTBUFFER_BITS_PER_PIPE * I915_MAX_PIPES)
#define INTEL_FRONTBUFFER_PRIMARY(pipe) \
(1 << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
#define INTEL_FRONTBUFFER_CURSOR(pipe) \
- (1 << (1 +(INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
-#define INTEL_FRONTBUFFER_SPRITE(pipe) \
- (1 << (2 +(INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
+ (1 << (1 + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
+#define INTEL_FRONTBUFFER_SPRITE(pipe, plane) \
+ (1 << (2 + plane + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
#define INTEL_FRONTBUFFER_OVERLAY(pipe) \
- (1 << (3 +(INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
+ (1 << (2 + INTEL_MAX_SPRITE_BITS_PER_PIPE + (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe))))
#define INTEL_FRONTBUFFER_ALL_MASK(pipe) \
- (0xf << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
+ (0xff << (INTEL_FRONTBUFFER_BITS_PER_PIPE * (pipe)))
struct drm_i915_gem_object {
struct drm_gem_object base;
@@ -2480,6 +2486,11 @@ struct drm_i915_cmd_table {
#define IS_SKL_ULX(dev) (INTEL_DEVID(dev) == 0x190E || \
INTEL_DEVID(dev) == 0x1915 || \
INTEL_DEVID(dev) == 0x191E)
+#define IS_SKL_GT3(dev) (IS_SKYLAKE(dev) && \
+ (INTEL_DEVID(dev) & 0x00F0) == 0x0020)
+#define IS_SKL_GT4(dev) (IS_SKYLAKE(dev) && \
+ (INTEL_DEVID(dev) & 0x00F0) == 0x0030)
+
#define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
#define SKL_REVID_A0 (0x0)
@@ -2491,7 +2502,7 @@ struct drm_i915_cmd_table {
#define BXT_REVID_A0 (0x0)
#define BXT_REVID_B0 (0x3)
-#define BXT_REVID_C0 (0x6)
+#define BXT_REVID_C0 (0x9)
/*
* The genX designation typically refers to the render engine, so render
@@ -2525,7 +2536,8 @@ struct drm_i915_cmd_table {
#define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6)
#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 8)
#define USES_PPGTT(dev) (i915.enable_ppgtt)
-#define USES_FULL_PPGTT(dev) (i915.enable_ppgtt == 2)
+#define USES_FULL_PPGTT(dev) (i915.enable_ppgtt >= 2)
+#define USES_FULL_48BIT_PPGTT(dev) (i915.enable_ppgtt == 3)
#define HAS_OVERLAY(dev) (INTEL_INFO(dev)->has_overlay)
#define OVERLAY_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->overlay_needs_physical)
@@ -2569,7 +2581,10 @@ struct drm_i915_cmd_table {
#define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6)
#define HAS_RC6p(dev) (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev))
-#define HAS_CSR(dev) (IS_SKYLAKE(dev))
+#define HAS_CSR(dev) (IS_GEN9(dev))
+
+#define HAS_GUC_UCODE(dev) (IS_GEN9(dev))
+#define HAS_GUC_SCHED(dev) (IS_GEN9(dev))
#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \
INTEL_INFO(dev)->gen >= 8)
@@ -2585,10 +2600,12 @@ struct drm_i915_cmd_table {
#define INTEL_PCH_LPT_LP_DEVICE_ID_TYPE 0x9c00
#define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100
#define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00
+#define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100
#define INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type)
#define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT)
#define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT)
+#define HAS_PCH_LPT_LP(dev) (__I915__(dev)->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP)
@@ -2608,8 +2625,8 @@ struct drm_i915_cmd_table {
extern const struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
-extern int i915_suspend_legacy(struct drm_device *dev, pm_message_t state);
-extern int i915_resume_legacy(struct drm_device *dev);
+extern int i915_suspend_switcheroo(struct drm_device *dev, pm_message_t state);
+extern int i915_resume_switcheroo(struct drm_device *dev);
/* i915_params.c */
struct i915_params {
@@ -2631,7 +2648,6 @@ struct i915_params {
int enable_cmd_parser;
/* leave bools at the end to not create holes */
bool enable_hangcheck;
- bool fastboot;
bool prefault_disable;
bool load_detect_test;
bool reset;
@@ -2642,6 +2658,7 @@ struct i915_params {
int use_mmio_flip;
int mmio_debug;
bool verbose_state_checks;
+ bool nuclear_pageflip;
int edp_vswing;
};
extern struct i915_params i915 __read_mostly;
@@ -2721,6 +2738,9 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv);
void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
+void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
+ uint32_t mask,
+ uint32_t bits);
void
ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask);
void
@@ -2788,8 +2808,6 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
size_t size);
struct drm_i915_gem_object *i915_gem_object_create_from_data(
struct drm_device *dev, const void *data, size_t size);
-void i915_init_vm(struct drm_i915_private *dev_priv,
- struct i915_address_space *vm);
void i915_gem_free_object(struct drm_gem_object *obj);
void i915_gem_vma_destroy(struct i915_vma *vma);
@@ -2800,6 +2818,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_OFFSET_BIAS (1<<3)
#define PIN_USER (1<<4)
#define PIN_UPDATE (1<<5)
+#define PIN_ZONE_4G (1<<6)
+#define PIN_HIGH (1<<7)
#define PIN_OFFSET_MASK (~4095)
int __must_check
i915_gem_object_pin(struct drm_i915_gem_object *obj,
@@ -2815,6 +2835,11 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
u32 flags);
int __must_check i915_vma_unbind(struct i915_vma *vma);
+/*
+ * BEWARE: Do not use the function below unless you can _absolutely_
+ * _guarantee_ VMA in question is _not in use_ anywhere.
+ */
+int __must_check __i915_vma_unbind_no_wait(struct i915_vma *vma);
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
@@ -2991,13 +3016,11 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *gem_obj, int flags);
-unsigned long
-i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
- const struct i915_ggtt_view *view);
-unsigned long
-i915_gem_obj_offset(struct drm_i915_gem_object *o,
- struct i915_address_space *vm);
-static inline unsigned long
+u64 i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+ const struct i915_ggtt_view *view);
+u64 i915_gem_obj_offset(struct drm_i915_gem_object *o,
+ struct i915_address_space *vm);
+static inline u64
i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *o)
{
return i915_gem_obj_ggtt_offset_view(o, &i915_ggtt_view_normal);
@@ -3145,7 +3168,6 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
unsigned long end,
unsigned flags);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
-int i915_gem_evict_everything(struct drm_device *dev);
/* belongs in i915_gem_gtt.h */
static inline void i915_gem_chipset_flush(struct drm_device *dev)
@@ -3158,6 +3180,10 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev)
int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv,
struct drm_mm_node *node, u64 size,
unsigned alignment);
+int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
+ struct drm_mm_node *node, u64 size,
+ unsigned alignment, u64 start,
+ u64 end);
void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
struct drm_mm_node *node);
int i915_gem_init_stolen(struct drm_device *dev);
@@ -3172,11 +3198,12 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
/* i915_gem_shrinker.c */
unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
- long target,
+ unsigned long target,
unsigned flags);
#define I915_SHRINK_PURGEABLE 0x1
#define I915_SHRINK_UNBOUND 0x2
#define I915_SHRINK_BOUND 0x4
+#define I915_SHRINK_ACTIVE 0x8
unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
void i915_gem_shrinker_init(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 399aab265db3..5cf4a1998273 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1005,12 +1005,14 @@ out:
if (!needs_clflush_after &&
obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
if (i915_gem_clflush_object(obj, obj->pin_display))
- i915_gem_chipset_flush(dev);
+ needs_clflush_after = true;
}
}
if (needs_clflush_after)
i915_gem_chipset_flush(dev);
+ else
+ obj->cache_dirty = true;
intel_fb_obj_flush(obj, false, ORIGIN_CPU);
return ret;
@@ -1711,8 +1713,8 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
/**
* i915_gem_fault - fault a page into the GTT
- * vma: VMA in question
- * vmf: fault info
+ * @vma: VMA in question
+ * @vmf: fault info
*
* The fault handler is set up by drm_gem_mmap() when a object is GTT mapped
* from userspace. The fault handler takes care of binding the object to
@@ -3205,7 +3207,7 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
old_write_domain);
}
-int i915_vma_unbind(struct i915_vma *vma)
+static int __i915_vma_unbind(struct i915_vma *vma, bool wait)
{
struct drm_i915_gem_object *obj = vma->obj;
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
@@ -3224,13 +3226,11 @@ int i915_vma_unbind(struct i915_vma *vma)
BUG_ON(obj->pages == NULL);
- ret = i915_gem_object_wait_rendering(obj, false);
- if (ret)
- return ret;
- /* Continue on if we fail due to EIO, the GPU is hung so we
- * should be safe and we need to cleanup or else we might
- * cause memory corruption through use-after-free.
- */
+ if (wait) {
+ ret = i915_gem_object_wait_rendering(obj, false);
+ if (ret)
+ return ret;
+ }
if (i915_is_ggtt(vma->vm) &&
vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
@@ -3275,6 +3275,16 @@ int i915_vma_unbind(struct i915_vma *vma)
return 0;
}
+int i915_vma_unbind(struct i915_vma *vma)
+{
+ return __i915_vma_unbind(vma, true);
+}
+
+int __i915_vma_unbind_no_wait(struct i915_vma *vma)
+{
+ return __i915_vma_unbind(vma, false);
+}
+
int i915_gpu_idle(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3354,11 +3364,10 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 size, fence_size, fence_alignment, unfenced_alignment;
- u64 start =
- flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
- u64 end =
- flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total;
+ u32 fence_alignment, unfenced_alignment;
+ u32 search_flag, alloc_flag;
+ u64 start, end;
+ u64 size, fence_size;
struct i915_vma *vma;
int ret;
@@ -3398,6 +3407,13 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
size = flags & PIN_MAPPABLE ? fence_size : obj->base.size;
}
+ start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0;
+ end = vm->total;
+ if (flags & PIN_MAPPABLE)
+ end = min_t(u64, end, dev_priv->gtt.mappable_end);
+ if (flags & PIN_ZONE_4G)
+ end = min_t(u64, end, (1ULL << 32));
+
if (alignment == 0)
alignment = flags & PIN_MAPPABLE ? fence_alignment :
unfenced_alignment;
@@ -3413,7 +3429,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
* attempt to find space.
*/
if (size > end) {
- DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%llu\n",
+ DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%llu > %s aperture=%llu\n",
ggtt_view ? ggtt_view->type : 0,
size,
flags & PIN_MAPPABLE ? "mappable" : "total",
@@ -3433,13 +3449,21 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
if (IS_ERR(vma))
goto err_unpin;
+ if (flags & PIN_HIGH) {
+ search_flag = DRM_MM_SEARCH_BELOW;
+ alloc_flag = DRM_MM_CREATE_TOP;
+ } else {
+ search_flag = DRM_MM_SEARCH_DEFAULT;
+ alloc_flag = DRM_MM_CREATE_DEFAULT;
+ }
+
search_free:
ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
size, alignment,
obj->cache_level,
start, end,
- DRM_MM_SEARCH_DEFAULT,
- DRM_MM_CREATE_DEFAULT);
+ search_flag,
+ alloc_flag);
if (ret) {
ret = i915_gem_evict_something(dev, vm, size, alignment,
obj->cache_level,
@@ -3632,59 +3656,117 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
return 0;
}
+/**
+ * Changes the cache-level of an object across all VMA.
+ *
+ * After this function returns, the object will be in the new cache-level
+ * across all GTT and the contents of the backing storage will be coherent,
+ * with respect to the new cache-level. In order to keep the backing storage
+ * coherent for all users, we only allow a single cache level to be set
+ * globally on the object and prevent it from being changed whilst the
+ * hardware is reading from the object. That is if the object is currently
+ * on the scanout it will be set to uncached (or equivalent display
+ * cache coherency) and all non-MOCS GPU access will also be uncached so
+ * that all direct access to the scanout remains coherent.
+ */
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level)
{
struct drm_device *dev = obj->base.dev;
struct i915_vma *vma, *next;
- int ret;
+ bool bound = false;
+ int ret = 0;
if (obj->cache_level == cache_level)
- return 0;
-
- if (i915_gem_obj_is_pinned(obj)) {
- DRM_DEBUG("can not change the cache level of pinned objects\n");
- return -EBUSY;
- }
+ goto out;
+ /* Inspect the list of currently bound VMA and unbind any that would
+ * be invalid given the new cache-level. This is principally to
+ * catch the issue of the CS prefetch crossing page boundaries and
+ * reading an invalid PTE on older architectures.
+ */
list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
+ if (!drm_mm_node_allocated(&vma->node))
+ continue;
+
+ if (vma->pin_count) {
+ DRM_DEBUG("can not change the cache level of pinned objects\n");
+ return -EBUSY;
+ }
+
if (!i915_gem_valid_gtt_space(vma, cache_level)) {
ret = i915_vma_unbind(vma);
if (ret)
return ret;
- }
+ } else
+ bound = true;
}
- if (i915_gem_obj_bound_any(obj)) {
+ /* We can reuse the existing drm_mm nodes but need to change the
+ * cache-level on the PTE. We could simply unbind them all and
+ * rebind with the correct cache-level on next use. However since
+ * we already have a valid slot, dma mapping, pages etc, we may as
+ * rewrite the PTE in the belief that doing so tramples upon less
+ * state and so involves less work.
+ */
+ if (bound) {
+ /* Before we change the PTE, the GPU must not be accessing it.
+ * If we wait upon the object, we know that all the bound
+ * VMA are no longer active.
+ */
ret = i915_gem_object_wait_rendering(obj, false);
if (ret)
return ret;
- i915_gem_object_finish_gtt(obj);
-
- /* Before SandyBridge, you could not use tiling or fence
- * registers with snooped memory, so relinquish any fences
- * currently pointing to our region in the aperture.
- */
- if (INTEL_INFO(dev)->gen < 6) {
+ if (!HAS_LLC(dev) && cache_level != I915_CACHE_NONE) {
+ /* Access to snoopable pages through the GTT is
+ * incoherent and on some machines causes a hard
+ * lockup. Relinquish the CPU mmaping to force
+ * userspace to refault in the pages and we can
+ * then double check if the GTT mapping is still
+ * valid for that pointer access.
+ */
+ i915_gem_release_mmap(obj);
+
+ /* As we no longer need a fence for GTT access,
+ * we can relinquish it now (and so prevent having
+ * to steal a fence from someone else on the next
+ * fence request). Note GPU activity would have
+ * dropped the fence as all snoopable access is
+ * supposed to be linear.
+ */
ret = i915_gem_object_put_fence(obj);
if (ret)
return ret;
+ } else {
+ /* We either have incoherent backing store and
+ * so no GTT access or the architecture is fully
+ * coherent. In such cases, existing GTT mmaps
+ * ignore the cache bit in the PTE and we can
+ * rewrite it without confusing the GPU or having
+ * to force userspace to fault back in its mmaps.
+ */
}
- list_for_each_entry(vma, &obj->vma_list, vma_link)
- if (drm_mm_node_allocated(&vma->node)) {
- ret = i915_vma_bind(vma, cache_level,
- PIN_UPDATE);
- if (ret)
- return ret;
- }
+ list_for_each_entry(vma, &obj->vma_list, vma_link) {
+ if (!drm_mm_node_allocated(&vma->node))
+ continue;
+
+ ret = i915_vma_bind(vma, cache_level, PIN_UPDATE);
+ if (ret)
+ return ret;
+ }
}
list_for_each_entry(vma, &obj->vma_list, vma_link)
vma->node.color = cache_level;
obj->cache_level = cache_level;
+out:
+ /* Flush the dirty CPU caches to the backing storage so that the
+ * object is now coherent at its new cache level (with respect
+ * to the access domain).
+ */
if (obj->cache_dirty &&
obj->base.write_domain != I915_GEM_DOMAIN_CPU &&
cpu_write_needs_clflush(obj)) {
@@ -3737,6 +3819,15 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
level = I915_CACHE_NONE;
break;
case I915_CACHING_CACHED:
+ /*
+ * Due to a HW issue on BXT A stepping, GPU stores via a
+ * snooped mapping may leave stale data in a corresponding CPU
+ * cacheline, whereas normally such cachelines would get
+ * invalidated.
+ */
+ if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)
+ return -ENODEV;
+
level = I915_CACHE_LLC;
break;
case I915_CACHING_DISPLAY:
@@ -4010,15 +4101,13 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
return -EBUSY;
if (i915_vma_misplaced(vma, alignment, flags)) {
- unsigned long offset;
- offset = ggtt_view ? i915_gem_obj_ggtt_offset_view(obj, ggtt_view) :
- i915_gem_obj_offset(obj, vm);
WARN(vma->pin_count,
"bo is already pinned in %s with incorrect alignment:"
- " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
+ " offset=%08x %08x, req.alignment=%x, req.map_and_fenceable=%d,"
" obj->map_and_fenceable=%d\n",
ggtt_view ? "ggtt" : "ppgtt",
- offset,
+ upper_32_bits(vma->node.start),
+ lower_32_bits(vma->node.start),
alignment,
!!(flags & PIN_MAPPABLE),
obj->map_and_fenceable);
@@ -4525,22 +4614,6 @@ void i915_gem_init_swizzling(struct drm_device *dev)
BUG();
}
-static bool
-intel_enable_blt(struct drm_device *dev)
-{
- if (!HAS_BLT(dev))
- return false;
-
- /* The blitter was dysfunctional on early prototypes */
- if (IS_GEN6(dev) && dev->pdev->revision < 8) {
- DRM_INFO("BLT not supported on this pre-production hardware;"
- " graphics performance will be degraded.\n");
- return false;
- }
-
- return true;
-}
-
static void init_unused_ring(struct drm_device *dev, u32 base)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4583,7 +4656,7 @@ int i915_gem_init_rings(struct drm_device *dev)
goto cleanup_render_ring;
}
- if (intel_enable_blt(dev)) {
+ if (HAS_BLT(dev)) {
ret = intel_init_blt_ring_buffer(dev);
if (ret)
goto cleanup_bsd_ring;
@@ -4601,14 +4674,8 @@ int i915_gem_init_rings(struct drm_device *dev)
goto cleanup_vebox_ring;
}
- ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
- if (ret)
- goto cleanup_bsd2_ring;
-
return 0;
-cleanup_bsd2_ring:
- intel_cleanup_ring_buffer(&dev_priv->ring[VCS2]);
cleanup_vebox_ring:
intel_cleanup_ring_buffer(&dev_priv->ring[VECS]);
cleanup_blt_ring:
@@ -4678,6 +4745,33 @@ i915_gem_init_hw(struct drm_device *dev)
goto out;
}
+ /* We can't enable contexts until all firmware is loaded */
+ if (HAS_GUC_UCODE(dev)) {
+ ret = intel_guc_ucode_load(dev);
+ if (ret) {
+ /*
+ * If we got an error and GuC submission is enabled, map
+ * the error to -EIO so the GPU will be declared wedged.
+ * OTOH, if we didn't intend to use the GuC anyway, just
+ * discard the error and carry on.
+ */
+ DRM_ERROR("Failed to initialize GuC, error %d%s\n", ret,
+ i915.enable_guc_submission ? "" :
+ " (ignored)");
+ ret = i915.enable_guc_submission ? -EIO : 0;
+ if (ret)
+ goto out;
+ }
+ }
+
+ /*
+ * Increment the next seqno by 0x100 so we have a visible break
+ * on re-initialisation
+ */
+ ret = i915_gem_set_seqno(dev, dev_priv->next_seqno+0x100);
+ if (ret)
+ goto out;
+
/* Now it is safe to go back round and do everything else: */
for_each_ring(ring, dev_priv, i) {
struct drm_i915_gem_request *req;
@@ -4815,18 +4909,6 @@ init_ring_lists(struct intel_engine_cs *ring)
INIT_LIST_HEAD(&ring->request_list);
}
-void i915_init_vm(struct drm_i915_private *dev_priv,
- struct i915_address_space *vm)
-{
- if (!i915_is_ggtt(vm))
- drm_mm_init(&vm->mm, vm->start, vm->total);
- vm->dev = dev_priv->dev;
- INIT_LIST_HEAD(&vm->active_list);
- INIT_LIST_HEAD(&vm->inactive_list);
- INIT_LIST_HEAD(&vm->global_link);
- list_add_tail(&vm->global_link, &dev_priv->vm_list);
-}
-
void
i915_gem_load(struct drm_device *dev)
{
@@ -4850,8 +4932,6 @@ i915_gem_load(struct drm_device *dev)
NULL);
INIT_LIST_HEAD(&dev_priv->vm_list);
- i915_init_vm(dev_priv, &dev_priv->gtt.base);
-
INIT_LIST_HEAD(&dev_priv->context_list);
INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
INIT_LIST_HEAD(&dev_priv->mm.bound_list);
@@ -4879,6 +4959,14 @@ i915_gem_load(struct drm_device *dev)
dev_priv->num_fence_regs =
I915_READ(vgtif_reg(avail_rs.fence_num));
+ /*
+ * Set initial sequence number for requests.
+ * Using this number allows the wraparound to happen early,
+ * catching any obvious problems.
+ */
+ dev_priv->next_seqno = ((u32)~0 - 0x1100);
+ dev_priv->last_seqno = ((u32)~0 - 0x1101);
+
/* Initialize fence registers to zero */
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
i915_gem_restore_fences(dev);
@@ -4948,9 +5036,9 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
/**
* i915_gem_track_fb - update frontbuffer tracking
- * old: current GEM buffer for the frontbuffer slots
- * new: new GEM buffer for the frontbuffer slots
- * frontbuffer_bits: bitmask of frontbuffer slots
+ * @old: current GEM buffer for the frontbuffer slots
+ * @new: new GEM buffer for the frontbuffer slots
+ * @frontbuffer_bits: bitmask of frontbuffer slots
*
* This updates the frontbuffer tracking bits @frontbuffer_bits by clearing them
* from @old and setting them in @new. Both @old and @new can be NULL.
@@ -4973,9 +5061,8 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
}
/* All the new VM stuff */
-unsigned long
-i915_gem_obj_offset(struct drm_i915_gem_object *o,
- struct i915_address_space *vm)
+u64 i915_gem_obj_offset(struct drm_i915_gem_object *o,
+ struct i915_address_space *vm)
{
struct drm_i915_private *dev_priv = o->base.dev->dev_private;
struct i915_vma *vma;
@@ -4995,9 +5082,8 @@ i915_gem_obj_offset(struct drm_i915_gem_object *o,
return -1;
}
-unsigned long
-i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
- const struct i915_ggtt_view *view)
+u64 i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
+ const struct i915_ggtt_view *view)
{
struct i915_address_space *ggtt = i915_obj_to_ggtt(o);
struct i915_vma *vma;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 8e893b354bcc..8c688a5f1589 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -133,6 +133,23 @@ static int get_context_size(struct drm_device *dev)
return ret;
}
+static void i915_gem_context_clean(struct intel_context *ctx)
+{
+ struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
+ struct i915_vma *vma, *next;
+
+ if (!ppgtt)
+ return;
+
+ WARN_ON(!list_empty(&ppgtt->base.active_list));
+
+ list_for_each_entry_safe(vma, next, &ppgtt->base.inactive_list,
+ mm_list) {
+ if (WARN_ON(__i915_vma_unbind_no_wait(vma)))
+ break;
+ }
+}
+
void i915_gem_context_free(struct kref *ctx_ref)
{
struct intel_context *ctx = container_of(ctx_ref, typeof(*ctx), ref);
@@ -142,6 +159,13 @@ void i915_gem_context_free(struct kref *ctx_ref)
if (i915.enable_execlists)
intel_lr_context_free(ctx);
+ /*
+ * This context is going away and we need to remove all VMAs still
+ * around. This is to handle imported shared objects for which
+ * destructor did not run when their handles were closed.
+ */
+ i915_gem_context_clean(ctx);
+
i915_ppgtt_put(ctx->ppgtt);
if (ctx->legacy_hw_ctx.rcs_state)
@@ -332,6 +356,13 @@ int i915_gem_context_init(struct drm_device *dev)
if (WARN_ON(dev_priv->ring[RCS].default_context))
return 0;
+ if (intel_vgpu_active(dev) && HAS_LOGICAL_RING_CONTEXTS(dev)) {
+ if (!i915.enable_execlists) {
+ DRM_INFO("Only EXECLIST mode is supported in vgpu.\n");
+ return -EINVAL;
+ }
+ }
+
if (i915.enable_execlists) {
/* NB: intentionally left blank. We will allocate our own
* backing objects as we need them, thank you very much */
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index d09e35ed9c9a..d71a133ceff5 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -237,48 +237,3 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
return 0;
}
-
-/**
- * i915_gem_evict_everything - Try to evict all objects
- * @dev: Device to evict objects for
- *
- * This functions tries to evict all gem objects from all address spaces. Used
- * by the shrinker as a last-ditch effort and for suspend, before releasing the
- * backing storage of all unbound objects.
- */
-int
-i915_gem_evict_everything(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct i915_address_space *vm, *v;
- bool lists_empty = true;
- int ret;
-
- list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
- lists_empty = (list_empty(&vm->inactive_list) &&
- list_empty(&vm->active_list));
- if (!lists_empty)
- lists_empty = false;
- }
-
- if (lists_empty)
- return -ENOSPC;
-
- trace_i915_gem_evict_everything(dev);
-
- /* The gpu_idle will flush everything in the write domain to the
- * active list. Then we must move everything off the active list
- * with retire requests.
- */
- ret = i915_gpu_idle(dev);
- if (ret)
- return ret;
-
- i915_gem_retire_requests(dev);
-
- /* Having flushed everything, unbind() should never raise an error */
- list_for_each_entry_safe(vm, v, &dev_priv->vm_list, global_link)
- WARN_ON(i915_gem_evict_vm(vm, false));
-
- return 0;
-}
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index a953d4975b8c..6ed7d63a0688 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -590,10 +590,17 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
flags |= PIN_GLOBAL;
if (!drm_mm_node_allocated(&vma->node)) {
+ /* Wa32bitGeneralStateOffset & Wa32bitInstructionBaseOffset,
+ * limit address to the first 4GBs for unflagged objects.
+ */
+ if ((entry->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) == 0)
+ flags |= PIN_ZONE_4G;
if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
flags |= PIN_GLOBAL | PIN_MAPPABLE;
if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
+ if ((flags & PIN_MAPPABLE) == 0)
+ flags |= PIN_HIGH;
}
ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
@@ -671,6 +678,10 @@ eb_vma_misplaced(struct i915_vma *vma)
if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
return !only_mappable_for_reloc(entry->flags);
+ if ((entry->flags & EXEC_OBJECT_SUPPORTS_48B_ADDRESS) == 0 &&
+ (vma->node.start + vma->node.size - 1) >> 32)
+ return true;
+
return false;
}
@@ -934,7 +945,21 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS)
return false;
- return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0;
+ /* Kernel clipping was a DRI1 misfeature */
+ if (exec->num_cliprects || exec->cliprects_ptr)
+ return false;
+
+ if (exec->DR4 == 0xffffffff) {
+ DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
+ exec->DR4 = 0;
+ }
+ if (exec->DR1 || exec->DR4)
+ return false;
+
+ if ((exec->batch_start_offset | exec->batch_len) & 0x7)
+ return false;
+
+ return true;
}
static int
@@ -1009,7 +1034,7 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
}
if (i915.enable_execlists && !ctx->engine[ring->id].state) {
- int ret = intel_lr_context_deferred_create(ctx, ring);
+ int ret = intel_lr_context_deferred_alloc(ctx, ring);
if (ret) {
DRM_DEBUG("Could not create LRC %u: %d\n", ctx_id, ret);
return ERR_PTR(ret);
@@ -1098,47 +1123,6 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
return 0;
}
-static int
-i915_emit_box(struct drm_i915_gem_request *req,
- struct drm_clip_rect *box,
- int DR1, int DR4)
-{
- struct intel_engine_cs *ring = req->ring;
- int ret;
-
- if (box->y2 <= box->y1 || box->x2 <= box->x1 ||
- box->y2 <= 0 || box->x2 <= 0) {
- DRM_ERROR("Bad box %d,%d..%d,%d\n",
- box->x1, box->y1, box->x2, box->y2);
- return -EINVAL;
- }
-
- if (INTEL_INFO(ring->dev)->gen >= 4) {
- ret = intel_ring_begin(req, 4);
- if (ret)
- return ret;
-
- intel_ring_emit(ring, GFX_OP_DRAWRECT_INFO_I965);
- intel_ring_emit(ring, (box->x1 & 0xffff) | box->y1 << 16);
- intel_ring_emit(ring, ((box->x2 - 1) & 0xffff) | (box->y2 - 1) << 16);
- intel_ring_emit(ring, DR4);
- } else {
- ret = intel_ring_begin(req, 6);
- if (ret)
- return ret;
-
- intel_ring_emit(ring, GFX_OP_DRAWRECT_INFO);
- intel_ring_emit(ring, DR1);
- intel_ring_emit(ring, (box->x1 & 0xffff) | box->y1 << 16);
- intel_ring_emit(ring, ((box->x2 - 1) & 0xffff) | (box->y2 - 1) << 16);
- intel_ring_emit(ring, DR4);
- intel_ring_emit(ring, 0);
- }
- intel_ring_advance(ring);
-
- return 0;
-}
-
static struct drm_i915_gem_object*
i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
struct drm_i915_gem_exec_object2 *shadow_exec_entry,
@@ -1197,65 +1181,21 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
struct drm_i915_gem_execbuffer2 *args,
struct list_head *vmas)
{
- struct drm_clip_rect *cliprects = NULL;
struct drm_device *dev = params->dev;
struct intel_engine_cs *ring = params->ring;
struct drm_i915_private *dev_priv = dev->dev_private;
u64 exec_start, exec_len;
int instp_mode;
u32 instp_mask;
- int i, ret = 0;
-
- if (args->num_cliprects != 0) {
- if (ring != &dev_priv->ring[RCS]) {
- DRM_DEBUG("clip rectangles are only valid with the render ring\n");
- return -EINVAL;
- }
-
- if (INTEL_INFO(dev)->gen >= 5) {
- DRM_DEBUG("clip rectangles are only valid on pre-gen5\n");
- return -EINVAL;
- }
-
- if (args->num_cliprects > UINT_MAX / sizeof(*cliprects)) {
- DRM_DEBUG("execbuf with %u cliprects\n",
- args->num_cliprects);
- return -EINVAL;
- }
-
- cliprects = kcalloc(args->num_cliprects,
- sizeof(*cliprects),
- GFP_KERNEL);
- if (cliprects == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- if (copy_from_user(cliprects,
- to_user_ptr(args->cliprects_ptr),
- sizeof(*cliprects)*args->num_cliprects)) {
- ret = -EFAULT;
- goto error;
- }
- } else {
- if (args->DR4 == 0xffffffff) {
- DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
- args->DR4 = 0;
- }
-
- if (args->DR1 || args->DR4 || args->cliprects_ptr) {
- DRM_DEBUG("0 cliprects but dirt in cliprects fields\n");
- return -EINVAL;
- }
- }
+ int ret;
ret = i915_gem_execbuffer_move_to_gpu(params->request, vmas);
if (ret)
- goto error;
+ return ret;
ret = i915_switch_context(params->request);
if (ret)
- goto error;
+ return ret;
WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<<ring->id),
"%s didn't clear reload\n", ring->name);
@@ -1268,22 +1208,19 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
case I915_EXEC_CONSTANTS_REL_SURFACE:
if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
- ret = -EINVAL;
- goto error;
+ return -EINVAL;
}
if (instp_mode != dev_priv->relative_constants_mode) {
if (INTEL_INFO(dev)->gen < 4) {
DRM_DEBUG("no rel constants on pre-gen4\n");
- ret = -EINVAL;
- goto error;
+ return -EINVAL;
}
if (INTEL_INFO(dev)->gen > 5 &&
instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
- ret = -EINVAL;
- goto error;
+ return -EINVAL;
}
/* The HW changed the meaning on this bit on gen6 */
@@ -1293,15 +1230,14 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
break;
default:
DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
- ret = -EINVAL;
- goto error;
+ return -EINVAL;
}
if (ring == &dev_priv->ring[RCS] &&
- instp_mode != dev_priv->relative_constants_mode) {
+ instp_mode != dev_priv->relative_constants_mode) {
ret = intel_ring_begin(params->request, 4);
if (ret)
- goto error;
+ return ret;
intel_ring_emit(ring, MI_NOOP);
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
@@ -1315,42 +1251,25 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params,
if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
ret = i915_reset_gen7_sol_offsets(dev, params->request);
if (ret)
- goto error;
+ return ret;
}
exec_len = args->batch_len;
exec_start = params->batch_obj_vm_offset +
params->args_batch_start_offset;
- if (cliprects) {
- for (i = 0; i < args->num_cliprects; i++) {
- ret = i915_emit_box(params->request, &cliprects[i],
- args->DR1, args->DR4);
- if (ret)
- goto error;
-
- ret = ring->dispatch_execbuffer(params->request,
- exec_start, exec_len,
- params->dispatch_flags);
- if (ret)
- goto error;
- }
- } else {
- ret = ring->dispatch_execbuffer(params->request,
- exec_start, exec_len,
- params->dispatch_flags);
- if (ret)
- return ret;
- }
+ ret = ring->dispatch_execbuffer(params->request,
+ exec_start, exec_len,
+ params->dispatch_flags);
+ if (ret)
+ return ret;
trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags);
i915_gem_execbuffer_move_to_active(vmas, params->request);
i915_gem_execbuffer_retire_commands(params);
-error:
- kfree(cliprects);
- return ret;
+ return 0;
}
/**
diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c
index af1f8c461060..40a10b25956c 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence.c
+++ b/drivers/gpu/drm/i915/i915_gem_fence.c
@@ -59,19 +59,19 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int fence_reg;
+ int fence_reg_lo, fence_reg_hi;
int fence_pitch_shift;
if (INTEL_INFO(dev)->gen >= 6) {
- fence_reg = FENCE_REG_SANDYBRIDGE_0;
- fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT;
+ fence_reg_lo = FENCE_REG_GEN6_LO(reg);
+ fence_reg_hi = FENCE_REG_GEN6_HI(reg);
+ fence_pitch_shift = GEN6_FENCE_PITCH_SHIFT;
} else {
- fence_reg = FENCE_REG_965_0;
+ fence_reg_lo = FENCE_REG_965_LO(reg);
+ fence_reg_hi = FENCE_REG_965_HI(reg);
fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
}
- fence_reg += reg * 8;
-
/* To w/a incoherency with non-atomic 64-bit register updates,
* we split the 64-bit update into two 32-bit writes. In order
* for a partial fence not to be evaluated between writes, we
@@ -81,8 +81,8 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
* For extra levels of paranoia, we make sure each step lands
* before applying the next step.
*/
- I915_WRITE(fence_reg, 0);
- POSTING_READ(fence_reg);
+ I915_WRITE(fence_reg_lo, 0);
+ POSTING_READ(fence_reg_lo);
if (obj) {
u32 size = i915_gem_obj_ggtt_size(obj);
@@ -103,14 +103,14 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
val |= 1 << I965_FENCE_TILING_Y_SHIFT;
val |= I965_FENCE_REG_VALID;
- I915_WRITE(fence_reg + 4, val >> 32);
- POSTING_READ(fence_reg + 4);
+ I915_WRITE(fence_reg_hi, val >> 32);
+ POSTING_READ(fence_reg_hi);
- I915_WRITE(fence_reg + 0, val);
- POSTING_READ(fence_reg);
+ I915_WRITE(fence_reg_lo, val);
+ POSTING_READ(fence_reg_lo);
} else {
- I915_WRITE(fence_reg + 4, 0);
- POSTING_READ(fence_reg + 4);
+ I915_WRITE(fence_reg_hi, 0);
+ POSTING_READ(fence_reg_hi);
}
}
@@ -128,7 +128,7 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) ||
(size & -size) != size ||
(i915_gem_obj_ggtt_offset(obj) & (size - 1)),
- "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
+ "object 0x%08llx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size);
if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
@@ -149,13 +149,8 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
} else
val = 0;
- if (reg < 8)
- reg = FENCE_REG_830_0 + reg * 4;
- else
- reg = FENCE_REG_945_8 + (reg - 8) * 4;
-
- I915_WRITE(reg, val);
- POSTING_READ(reg);
+ I915_WRITE(FENCE_REG(reg), val);
+ POSTING_READ(FENCE_REG(reg));
}
static void i830_write_fence_reg(struct drm_device *dev, int reg,
@@ -171,7 +166,7 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg,
WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) ||
(size & -size) != size ||
(i915_gem_obj_ggtt_offset(obj) & (size - 1)),
- "object 0x%08lx not 512K or pot-size 0x%08x aligned\n",
+ "object 0x%08llx not 512K or pot-size 0x%08x aligned\n",
i915_gem_obj_ggtt_offset(obj), size);
pitch_val = obj->stride / 128;
@@ -186,8 +181,8 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg,
} else
val = 0;
- I915_WRITE(FENCE_REG_830_0 + reg * 4, val);
- POSTING_READ(FENCE_REG_830_0 + reg * 4);
+ I915_WRITE(FENCE_REG(reg), val);
+ POSTING_READ(FENCE_REG(reg));
}
inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj)
@@ -322,7 +317,7 @@ i915_find_fence_reg(struct drm_device *dev)
/* First try to find a free reg */
avail = NULL;
- for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
+ for (i = 0; i < dev_priv->num_fence_regs; i++) {
reg = &dev_priv->fence_regs[i];
if (!reg->obj)
return reg;
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 96054a560f4f..43f35d12b677 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -204,6 +204,9 @@ static gen8_pde_t gen8_pde_encode(const dma_addr_t addr,
return pde;
}
+#define gen8_pdpe_encode gen8_pde_encode
+#define gen8_pml4e_encode gen8_pde_encode
+
static gen6_pte_t snb_pte_encode(dma_addr_t addr,
enum i915_cache_level level,
bool valid, u32 unused)
@@ -522,6 +525,127 @@ static void gen8_initialize_pd(struct i915_address_space *vm,
fill_px(vm->dev, pd, scratch_pde);
}
+static int __pdp_init(struct drm_device *dev,
+ struct i915_page_directory_pointer *pdp)
+{
+ size_t pdpes = I915_PDPES_PER_PDP(dev);
+
+ pdp->used_pdpes = kcalloc(BITS_TO_LONGS(pdpes),
+ sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!pdp->used_pdpes)
+ return -ENOMEM;
+
+ pdp->page_directory = kcalloc(pdpes, sizeof(*pdp->page_directory),
+ GFP_KERNEL);
+ if (!pdp->page_directory) {
+ kfree(pdp->used_pdpes);
+ /* the PDP might be the statically allocated top level. Keep it
+ * as clean as possible */
+ pdp->used_pdpes = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void __pdp_fini(struct i915_page_directory_pointer *pdp)
+{
+ kfree(pdp->used_pdpes);
+ kfree(pdp->page_directory);
+ pdp->page_directory = NULL;
+}
+
+static struct
+i915_page_directory_pointer *alloc_pdp(struct drm_device *dev)
+{
+ struct i915_page_directory_pointer *pdp;
+ int ret = -ENOMEM;
+
+ WARN_ON(!USES_FULL_48BIT_PPGTT(dev));
+
+ pdp = kzalloc(sizeof(*pdp), GFP_KERNEL);
+ if (!pdp)
+ return ERR_PTR(-ENOMEM);
+
+ ret = __pdp_init(dev, pdp);
+ if (ret)
+ goto fail_bitmap;
+
+ ret = setup_px(dev, pdp);
+ if (ret)
+ goto fail_page_m;
+
+ return pdp;
+
+fail_page_m:
+ __pdp_fini(pdp);
+fail_bitmap:
+ kfree(pdp);
+
+ return ERR_PTR(ret);
+}
+
+static void free_pdp(struct drm_device *dev,
+ struct i915_page_directory_pointer *pdp)
+{
+ __pdp_fini(pdp);
+ if (USES_FULL_48BIT_PPGTT(dev)) {
+ cleanup_px(dev, pdp);
+ kfree(pdp);
+ }
+}
+
+static void gen8_initialize_pdp(struct i915_address_space *vm,
+ struct i915_page_directory_pointer *pdp)
+{
+ gen8_ppgtt_pdpe_t scratch_pdpe;
+
+ scratch_pdpe = gen8_pdpe_encode(px_dma(vm->scratch_pd), I915_CACHE_LLC);
+
+ fill_px(vm->dev, pdp, scratch_pdpe);
+}
+
+static void gen8_initialize_pml4(struct i915_address_space *vm,
+ struct i915_pml4 *pml4)
+{
+ gen8_ppgtt_pml4e_t scratch_pml4e;
+
+ scratch_pml4e = gen8_pml4e_encode(px_dma(vm->scratch_pdp),
+ I915_CACHE_LLC);
+
+ fill_px(vm->dev, pml4, scratch_pml4e);
+}
+
+static void
+gen8_setup_page_directory(struct i915_hw_ppgtt *ppgtt,
+ struct i915_page_directory_pointer *pdp,
+ struct i915_page_directory *pd,
+ int index)
+{
+ gen8_ppgtt_pdpe_t *page_directorypo;
+
+ if (!USES_FULL_48BIT_PPGTT(ppgtt->base.dev))
+ return;
+
+ page_directorypo = kmap_px(pdp);
+ page_directorypo[index] = gen8_pdpe_encode(px_dma(pd), I915_CACHE_LLC);
+ kunmap_px(ppgtt, page_directorypo);
+}
+
+static void
+gen8_setup_page_directory_pointer(struct i915_hw_ppgtt *ppgtt,
+ struct i915_pml4 *pml4,
+ struct i915_page_directory_pointer *pdp,
+ int index)
+{
+ gen8_ppgtt_pml4e_t *pagemap = kmap_px(pml4);
+
+ WARN_ON(!USES_FULL_48BIT_PPGTT(ppgtt->base.dev));
+ pagemap[index] = gen8_pml4e_encode(px_dma(pdp), I915_CACHE_LLC);
+ kunmap_px(ppgtt, pagemap);
+}
+
/* Broadwell Page Directory Pointer Descriptors */
static int gen8_write_pdp(struct drm_i915_gem_request *req,
unsigned entry,
@@ -547,8 +671,8 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req,
return 0;
}
-static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
- struct drm_i915_gem_request *req)
+static int gen8_legacy_mm_switch(struct i915_hw_ppgtt *ppgtt,
+ struct drm_i915_gem_request *req)
{
int i, ret;
@@ -563,31 +687,38 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
return 0;
}
-static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
- uint64_t start,
- uint64_t length,
- bool use_scratch)
+static int gen8_48b_mm_switch(struct i915_hw_ppgtt *ppgtt,
+ struct drm_i915_gem_request *req)
+{
+ return gen8_write_pdp(req, 0, px_dma(&ppgtt->pml4));
+}
+
+static void gen8_ppgtt_clear_pte_range(struct i915_address_space *vm,
+ struct i915_page_directory_pointer *pdp,
+ uint64_t start,
+ uint64_t length,
+ gen8_pte_t scratch_pte)
{
struct i915_hw_ppgtt *ppgtt =
container_of(vm, struct i915_hw_ppgtt, base);
- gen8_pte_t *pt_vaddr, scratch_pte;
- unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
- unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
- unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
+ gen8_pte_t *pt_vaddr;
+ unsigned pdpe = gen8_pdpe_index(start);
+ unsigned pde = gen8_pde_index(start);
+ unsigned pte = gen8_pte_index(start);
unsigned num_entries = length >> PAGE_SHIFT;
unsigned last_pte, i;
- scratch_pte = gen8_pte_encode(px_dma(ppgtt->base.scratch_page),
- I915_CACHE_LLC, use_scratch);
+ if (WARN_ON(!pdp))
+ return;
while (num_entries) {
struct i915_page_directory *pd;
struct i915_page_table *pt;
- if (WARN_ON(!ppgtt->pdp.page_directory[pdpe]))
+ if (WARN_ON(!pdp->page_directory[pdpe]))
break;
- pd = ppgtt->pdp.page_directory[pdpe];
+ pd = pdp->page_directory[pdpe];
if (WARN_ON(!pd->page_table[pde]))
break;
@@ -612,45 +743,69 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
pte = 0;
if (++pde == I915_PDES) {
- pdpe++;
+ if (++pdpe == I915_PDPES_PER_PDP(vm->dev))
+ break;
pde = 0;
}
}
}
-static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
- struct sg_table *pages,
- uint64_t start,
- enum i915_cache_level cache_level, u32 unused)
+static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
+ uint64_t start,
+ uint64_t length,
+ bool use_scratch)
+{
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+ gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
+ I915_CACHE_LLC, use_scratch);
+
+ if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
+ gen8_ppgtt_clear_pte_range(vm, &ppgtt->pdp, start, length,
+ scratch_pte);
+ } else {
+ uint64_t templ4, pml4e;
+ struct i915_page_directory_pointer *pdp;
+
+ gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, templ4, pml4e) {
+ gen8_ppgtt_clear_pte_range(vm, pdp, start, length,
+ scratch_pte);
+ }
+ }
+}
+
+static void
+gen8_ppgtt_insert_pte_entries(struct i915_address_space *vm,
+ struct i915_page_directory_pointer *pdp,
+ struct sg_page_iter *sg_iter,
+ uint64_t start,
+ enum i915_cache_level cache_level)
{
struct i915_hw_ppgtt *ppgtt =
container_of(vm, struct i915_hw_ppgtt, base);
gen8_pte_t *pt_vaddr;
- unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
- unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
- unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
- struct sg_page_iter sg_iter;
+ unsigned pdpe = gen8_pdpe_index(start);
+ unsigned pde = gen8_pde_index(start);
+ unsigned pte = gen8_pte_index(start);
pt_vaddr = NULL;
- for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
- if (WARN_ON(pdpe >= GEN8_LEGACY_PDPES))
- break;
-
+ while (__sg_page_iter_next(sg_iter)) {
if (pt_vaddr == NULL) {
- struct i915_page_directory *pd = ppgtt->pdp.page_directory[pdpe];
+ struct i915_page_directory *pd = pdp->page_directory[pdpe];
struct i915_page_table *pt = pd->page_table[pde];
pt_vaddr = kmap_px(pt);
}
pt_vaddr[pte] =
- gen8_pte_encode(sg_page_iter_dma_address(&sg_iter),
+ gen8_pte_encode(sg_page_iter_dma_address(sg_iter),
cache_level, true);
if (++pte == GEN8_PTES) {
kunmap_px(ppgtt, pt_vaddr);
pt_vaddr = NULL;
if (++pde == I915_PDES) {
- pdpe++;
+ if (++pdpe == I915_PDPES_PER_PDP(vm->dev))
+ break;
pde = 0;
}
pte = 0;
@@ -661,6 +816,33 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
kunmap_px(ppgtt, pt_vaddr);
}
+static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
+ struct sg_table *pages,
+ uint64_t start,
+ enum i915_cache_level cache_level,
+ u32 unused)
+{
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+ struct sg_page_iter sg_iter;
+
+ __sg_page_iter_start(&sg_iter, pages->sgl, sg_nents(pages->sgl), 0);
+
+ if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
+ gen8_ppgtt_insert_pte_entries(vm, &ppgtt->pdp, &sg_iter, start,
+ cache_level);
+ } else {
+ struct i915_page_directory_pointer *pdp;
+ uint64_t templ4, pml4e;
+ uint64_t length = (uint64_t)pages->orig_nents << PAGE_SHIFT;
+
+ gen8_for_each_pml4e(pdp, &ppgtt->pml4, start, length, templ4, pml4e) {
+ gen8_ppgtt_insert_pte_entries(vm, pdp, &sg_iter,
+ start, cache_level);
+ }
+ }
+}
+
static void gen8_free_page_tables(struct drm_device *dev,
struct i915_page_directory *pd)
{
@@ -699,8 +881,55 @@ static int gen8_init_scratch(struct i915_address_space *vm)
return PTR_ERR(vm->scratch_pd);
}
+ if (USES_FULL_48BIT_PPGTT(dev)) {
+ vm->scratch_pdp = alloc_pdp(dev);
+ if (IS_ERR(vm->scratch_pdp)) {
+ free_pd(dev, vm->scratch_pd);
+ free_pt(dev, vm->scratch_pt);
+ free_scratch_page(dev, vm->scratch_page);
+ return PTR_ERR(vm->scratch_pdp);
+ }
+ }
+
gen8_initialize_pt(vm, vm->scratch_pt);
gen8_initialize_pd(vm, vm->scratch_pd);
+ if (USES_FULL_48BIT_PPGTT(dev))
+ gen8_initialize_pdp(vm, vm->scratch_pdp);
+
+ return 0;
+}
+
+static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create)
+{
+ enum vgt_g2v_type msg;
+ struct drm_device *dev = ppgtt->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned int offset = vgtif_reg(pdp0_lo);
+ int i;
+
+ if (USES_FULL_48BIT_PPGTT(dev)) {
+ u64 daddr = px_dma(&ppgtt->pml4);
+
+ I915_WRITE(offset, lower_32_bits(daddr));
+ I915_WRITE(offset + 4, upper_32_bits(daddr));
+
+ msg = (create ? VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE :
+ VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY);
+ } else {
+ for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
+ u64 daddr = i915_page_dir_dma_addr(ppgtt, i);
+
+ I915_WRITE(offset, lower_32_bits(daddr));
+ I915_WRITE(offset + 4, upper_32_bits(daddr));
+
+ offset += 8;
+ }
+
+ msg = (create ? VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE :
+ VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY);
+ }
+
+ I915_WRITE(vgtif_reg(g2v_notify), msg);
return 0;
}
@@ -709,35 +938,65 @@ static void gen8_free_scratch(struct i915_address_space *vm)
{
struct drm_device *dev = vm->dev;
+ if (USES_FULL_48BIT_PPGTT(dev))
+ free_pdp(dev, vm->scratch_pdp);
free_pd(dev, vm->scratch_pd);
free_pt(dev, vm->scratch_pt);
free_scratch_page(dev, vm->scratch_page);
}
-static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
+static void gen8_ppgtt_cleanup_3lvl(struct drm_device *dev,
+ struct i915_page_directory_pointer *pdp)
{
- struct i915_hw_ppgtt *ppgtt =
- container_of(vm, struct i915_hw_ppgtt, base);
int i;
- for_each_set_bit(i, ppgtt->pdp.used_pdpes, GEN8_LEGACY_PDPES) {
- if (WARN_ON(!ppgtt->pdp.page_directory[i]))
+ for_each_set_bit(i, pdp->used_pdpes, I915_PDPES_PER_PDP(dev)) {
+ if (WARN_ON(!pdp->page_directory[i]))
continue;
- gen8_free_page_tables(ppgtt->base.dev,
- ppgtt->pdp.page_directory[i]);
- free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]);
+ gen8_free_page_tables(dev, pdp->page_directory[i]);
+ free_pd(dev, pdp->page_directory[i]);
}
+ free_pdp(dev, pdp);
+}
+
+static void gen8_ppgtt_cleanup_4lvl(struct i915_hw_ppgtt *ppgtt)
+{
+ int i;
+
+ for_each_set_bit(i, ppgtt->pml4.used_pml4es, GEN8_PML4ES_PER_PML4) {
+ if (WARN_ON(!ppgtt->pml4.pdps[i]))
+ continue;
+
+ gen8_ppgtt_cleanup_3lvl(ppgtt->base.dev, ppgtt->pml4.pdps[i]);
+ }
+
+ cleanup_px(ppgtt->base.dev, &ppgtt->pml4);
+}
+
+static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
+{
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+
+ if (intel_vgpu_active(vm->dev))
+ gen8_ppgtt_notify_vgt(ppgtt, false);
+
+ if (!USES_FULL_48BIT_PPGTT(ppgtt->base.dev))
+ gen8_ppgtt_cleanup_3lvl(ppgtt->base.dev, &ppgtt->pdp);
+ else
+ gen8_ppgtt_cleanup_4lvl(ppgtt);
+
gen8_free_scratch(vm);
}
/**
* gen8_ppgtt_alloc_pagetabs() - Allocate page tables for VA range.
- * @ppgtt: Master ppgtt structure.
- * @pd: Page directory for this address range.
+ * @vm: Master vm structure.
+ * @pd: Page directory for this address range.
* @start: Starting virtual address to begin allocations.
- * @length Size of the allocations.
+ * @length: Size of the allocations.
* @new_pts: Bitmap set by function with new allocations. Likely used by the
* caller to free on error.
*
@@ -750,22 +1009,22 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
*
* Return: 0 if success; negative error code otherwise.
*/
-static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt,
+static int gen8_ppgtt_alloc_pagetabs(struct i915_address_space *vm,
struct i915_page_directory *pd,
uint64_t start,
uint64_t length,
unsigned long *new_pts)
{
- struct drm_device *dev = ppgtt->base.dev;
+ struct drm_device *dev = vm->dev;
struct i915_page_table *pt;
uint64_t temp;
uint32_t pde;
gen8_for_each_pde(pt, pd, start, length, temp, pde) {
/* Don't reallocate page tables */
- if (pt) {
+ if (test_bit(pde, pd->used_pdes)) {
/* Scratch is never allocated this way */
- WARN_ON(pt == ppgtt->base.scratch_pt);
+ WARN_ON(pt == vm->scratch_pt);
continue;
}
@@ -773,9 +1032,10 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt,
if (IS_ERR(pt))
goto unwind_out;
- gen8_initialize_pt(&ppgtt->base, pt);
+ gen8_initialize_pt(vm, pt);
pd->page_table[pde] = pt;
__set_bit(pde, new_pts);
+ trace_i915_page_table_entry_alloc(vm, pde, start, GEN8_PDE_SHIFT);
}
return 0;
@@ -789,11 +1049,11 @@ unwind_out:
/**
* gen8_ppgtt_alloc_page_directories() - Allocate page directories for VA range.
- * @ppgtt: Master ppgtt structure.
+ * @vm: Master vm structure.
* @pdp: Page directory pointer for this address range.
* @start: Starting virtual address to begin allocations.
- * @length Size of the allocations.
- * @new_pds Bitmap set by function with new allocations. Likely used by the
+ * @length: Size of the allocations.
+ * @new_pds: Bitmap set by function with new allocations. Likely used by the
* caller to free on error.
*
* Allocate the required number of page directories starting at the pde index of
@@ -810,48 +1070,102 @@ unwind_out:
*
* Return: 0 if success; negative error code otherwise.
*/
-static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt,
- struct i915_page_directory_pointer *pdp,
- uint64_t start,
- uint64_t length,
- unsigned long *new_pds)
+static int
+gen8_ppgtt_alloc_page_directories(struct i915_address_space *vm,
+ struct i915_page_directory_pointer *pdp,
+ uint64_t start,
+ uint64_t length,
+ unsigned long *new_pds)
{
- struct drm_device *dev = ppgtt->base.dev;
+ struct drm_device *dev = vm->dev;
struct i915_page_directory *pd;
uint64_t temp;
uint32_t pdpe;
+ uint32_t pdpes = I915_PDPES_PER_PDP(dev);
- WARN_ON(!bitmap_empty(new_pds, GEN8_LEGACY_PDPES));
+ WARN_ON(!bitmap_empty(new_pds, pdpes));
gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
- if (pd)
+ if (test_bit(pdpe, pdp->used_pdpes))
continue;
pd = alloc_pd(dev);
if (IS_ERR(pd))
goto unwind_out;
- gen8_initialize_pd(&ppgtt->base, pd);
+ gen8_initialize_pd(vm, pd);
pdp->page_directory[pdpe] = pd;
__set_bit(pdpe, new_pds);
+ trace_i915_page_directory_entry_alloc(vm, pdpe, start, GEN8_PDPE_SHIFT);
}
return 0;
unwind_out:
- for_each_set_bit(pdpe, new_pds, GEN8_LEGACY_PDPES)
+ for_each_set_bit(pdpe, new_pds, pdpes)
free_pd(dev, pdp->page_directory[pdpe]);
return -ENOMEM;
}
-static void
-free_gen8_temp_bitmaps(unsigned long *new_pds, unsigned long **new_pts)
+/**
+ * gen8_ppgtt_alloc_page_dirpointers() - Allocate pdps for VA range.
+ * @vm: Master vm structure.
+ * @pml4: Page map level 4 for this address range.
+ * @start: Starting virtual address to begin allocations.
+ * @length: Size of the allocations.
+ * @new_pdps: Bitmap set by function with new allocations. Likely used by the
+ * caller to free on error.
+ *
+ * Allocate the required number of page directory pointers. Extremely similar to
+ * gen8_ppgtt_alloc_page_directories() and gen8_ppgtt_alloc_pagetabs().
+ * The main difference is here we are limited by the pml4 boundary (instead of
+ * the page directory pointer).
+ *
+ * Return: 0 if success; negative error code otherwise.
+ */
+static int
+gen8_ppgtt_alloc_page_dirpointers(struct i915_address_space *vm,
+ struct i915_pml4 *pml4,
+ uint64_t start,
+ uint64_t length,
+ unsigned long *new_pdps)
{
- int i;
+ struct drm_device *dev = vm->dev;
+ struct i915_page_directory_pointer *pdp;
+ uint64_t temp;
+ uint32_t pml4e;
+
+ WARN_ON(!bitmap_empty(new_pdps, GEN8_PML4ES_PER_PML4));
+
+ gen8_for_each_pml4e(pdp, pml4, start, length, temp, pml4e) {
+ if (!test_bit(pml4e, pml4->used_pml4es)) {
+ pdp = alloc_pdp(dev);
+ if (IS_ERR(pdp))
+ goto unwind_out;
+
+ gen8_initialize_pdp(vm, pdp);
+ pml4->pdps[pml4e] = pdp;
+ __set_bit(pml4e, new_pdps);
+ trace_i915_page_directory_pointer_entry_alloc(vm,
+ pml4e,
+ start,
+ GEN8_PML4E_SHIFT);
+ }
+ }
- for (i = 0; i < GEN8_LEGACY_PDPES; i++)
- kfree(new_pts[i]);
+ return 0;
+
+unwind_out:
+ for_each_set_bit(pml4e, new_pdps, GEN8_PML4ES_PER_PML4)
+ free_pdp(dev, pml4->pdps[pml4e]);
+
+ return -ENOMEM;
+}
+
+static void
+free_gen8_temp_bitmaps(unsigned long *new_pds, unsigned long *new_pts)
+{
kfree(new_pts);
kfree(new_pds);
}
@@ -861,28 +1175,20 @@ free_gen8_temp_bitmaps(unsigned long *new_pds, unsigned long **new_pts)
*/
static
int __must_check alloc_gen8_temp_bitmaps(unsigned long **new_pds,
- unsigned long ***new_pts)
+ unsigned long **new_pts,
+ uint32_t pdpes)
{
- int i;
unsigned long *pds;
- unsigned long **pts;
+ unsigned long *pts;
- pds = kcalloc(BITS_TO_LONGS(GEN8_LEGACY_PDPES), sizeof(unsigned long), GFP_KERNEL);
+ pds = kcalloc(BITS_TO_LONGS(pdpes), sizeof(unsigned long), GFP_TEMPORARY);
if (!pds)
return -ENOMEM;
- pts = kcalloc(GEN8_LEGACY_PDPES, sizeof(unsigned long *), GFP_KERNEL);
- if (!pts) {
- kfree(pds);
- return -ENOMEM;
- }
-
- for (i = 0; i < GEN8_LEGACY_PDPES; i++) {
- pts[i] = kcalloc(BITS_TO_LONGS(I915_PDES),
- sizeof(unsigned long), GFP_KERNEL);
- if (!pts[i])
- goto err_out;
- }
+ pts = kcalloc(pdpes, BITS_TO_LONGS(I915_PDES) * sizeof(unsigned long),
+ GFP_TEMPORARY);
+ if (!pts)
+ goto err_out;
*new_pds = pds;
*new_pts = pts;
@@ -904,18 +1210,21 @@ static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt)
ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask;
}
-static int gen8_alloc_va_range(struct i915_address_space *vm,
- uint64_t start,
- uint64_t length)
+static int gen8_alloc_va_range_3lvl(struct i915_address_space *vm,
+ struct i915_page_directory_pointer *pdp,
+ uint64_t start,
+ uint64_t length)
{
struct i915_hw_ppgtt *ppgtt =
container_of(vm, struct i915_hw_ppgtt, base);
- unsigned long *new_page_dirs, **new_page_tables;
+ unsigned long *new_page_dirs, *new_page_tables;
+ struct drm_device *dev = vm->dev;
struct i915_page_directory *pd;
const uint64_t orig_start = start;
const uint64_t orig_length = length;
uint64_t temp;
uint32_t pdpe;
+ uint32_t pdpes = I915_PDPES_PER_PDP(dev);
int ret;
/* Wrap is never okay since we can only represent 48b, and we don't
@@ -924,25 +1233,25 @@ static int gen8_alloc_va_range(struct i915_address_space *vm,
if (WARN_ON(start + length < start))
return -ENODEV;
- if (WARN_ON(start + length > ppgtt->base.total))
+ if (WARN_ON(start + length > vm->total))
return -ENODEV;
- ret = alloc_gen8_temp_bitmaps(&new_page_dirs, &new_page_tables);
+ ret = alloc_gen8_temp_bitmaps(&new_page_dirs, &new_page_tables, pdpes);
if (ret)
return ret;
/* Do the allocations first so we can easily bail out */
- ret = gen8_ppgtt_alloc_page_directories(ppgtt, &ppgtt->pdp, start, length,
- new_page_dirs);
+ ret = gen8_ppgtt_alloc_page_directories(vm, pdp, start, length,
+ new_page_dirs);
if (ret) {
free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
return ret;
}
/* For every page directory referenced, allocate page tables */
- gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) {
- ret = gen8_ppgtt_alloc_pagetabs(ppgtt, pd, start, length,
- new_page_tables[pdpe]);
+ gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
+ ret = gen8_ppgtt_alloc_pagetabs(vm, pd, start, length,
+ new_page_tables + pdpe * BITS_TO_LONGS(I915_PDES));
if (ret)
goto err_out;
}
@@ -952,10 +1261,10 @@ static int gen8_alloc_va_range(struct i915_address_space *vm,
/* Allocations have completed successfully, so set the bitmaps, and do
* the mappings. */
- gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) {
+ gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
gen8_pde_t *const page_directory = kmap_px(pd);
struct i915_page_table *pt;
- uint64_t pd_len = gen8_clamp_pd(start, length);
+ uint64_t pd_len = length;
uint64_t pd_start = start;
uint32_t pde;
@@ -979,14 +1288,18 @@ static int gen8_alloc_va_range(struct i915_address_space *vm,
/* Map the PDE to the page table */
page_directory[pde] = gen8_pde_encode(px_dma(pt),
I915_CACHE_LLC);
+ trace_i915_page_table_entry_map(&ppgtt->base, pde, pt,
+ gen8_pte_index(start),
+ gen8_pte_count(start, length),
+ GEN8_PTES);
/* NB: We haven't yet mapped ptes to pages. At this
* point we're still relying on insert_entries() */
}
kunmap_px(ppgtt, page_directory);
-
- __set_bit(pdpe, ppgtt->pdp.used_pdpes);
+ __set_bit(pdpe, pdp->used_pdpes);
+ gen8_setup_page_directory(ppgtt, pdp, pd, pdpe);
}
free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
@@ -995,18 +1308,191 @@ static int gen8_alloc_va_range(struct i915_address_space *vm,
err_out:
while (pdpe--) {
- for_each_set_bit(temp, new_page_tables[pdpe], I915_PDES)
- free_pt(vm->dev, ppgtt->pdp.page_directory[pdpe]->page_table[temp]);
+ for_each_set_bit(temp, new_page_tables + pdpe *
+ BITS_TO_LONGS(I915_PDES), I915_PDES)
+ free_pt(dev, pdp->page_directory[pdpe]->page_table[temp]);
}
- for_each_set_bit(pdpe, new_page_dirs, GEN8_LEGACY_PDPES)
- free_pd(vm->dev, ppgtt->pdp.page_directory[pdpe]);
+ for_each_set_bit(pdpe, new_page_dirs, pdpes)
+ free_pd(dev, pdp->page_directory[pdpe]);
free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
mark_tlbs_dirty(ppgtt);
return ret;
}
+static int gen8_alloc_va_range_4lvl(struct i915_address_space *vm,
+ struct i915_pml4 *pml4,
+ uint64_t start,
+ uint64_t length)
+{
+ DECLARE_BITMAP(new_pdps, GEN8_PML4ES_PER_PML4);
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+ struct i915_page_directory_pointer *pdp;
+ uint64_t temp, pml4e;
+ int ret = 0;
+
+ /* Do the pml4 allocations first, so we don't need to track the newly
+ * allocated tables below the pdp */
+ bitmap_zero(new_pdps, GEN8_PML4ES_PER_PML4);
+
+ /* The pagedirectory and pagetable allocations are done in the shared 3
+ * and 4 level code. Just allocate the pdps.
+ */
+ ret = gen8_ppgtt_alloc_page_dirpointers(vm, pml4, start, length,
+ new_pdps);
+ if (ret)
+ return ret;
+
+ WARN(bitmap_weight(new_pdps, GEN8_PML4ES_PER_PML4) > 2,
+ "The allocation has spanned more than 512GB. "
+ "It is highly likely this is incorrect.");
+
+ gen8_for_each_pml4e(pdp, pml4, start, length, temp, pml4e) {
+ WARN_ON(!pdp);
+
+ ret = gen8_alloc_va_range_3lvl(vm, pdp, start, length);
+ if (ret)
+ goto err_out;
+
+ gen8_setup_page_directory_pointer(ppgtt, pml4, pdp, pml4e);
+ }
+
+ bitmap_or(pml4->used_pml4es, new_pdps, pml4->used_pml4es,
+ GEN8_PML4ES_PER_PML4);
+
+ return 0;
+
+err_out:
+ for_each_set_bit(pml4e, new_pdps, GEN8_PML4ES_PER_PML4)
+ gen8_ppgtt_cleanup_3lvl(vm->dev, pml4->pdps[pml4e]);
+
+ return ret;
+}
+
+static int gen8_alloc_va_range(struct i915_address_space *vm,
+ uint64_t start, uint64_t length)
+{
+ struct i915_hw_ppgtt *ppgtt =
+ container_of(vm, struct i915_hw_ppgtt, base);
+
+ if (USES_FULL_48BIT_PPGTT(vm->dev))
+ return gen8_alloc_va_range_4lvl(vm, &ppgtt->pml4, start, length);
+ else
+ return gen8_alloc_va_range_3lvl(vm, &ppgtt->pdp, start, length);
+}
+
+static void gen8_dump_pdp(struct i915_page_directory_pointer *pdp,
+ uint64_t start, uint64_t length,
+ gen8_pte_t scratch_pte,
+ struct seq_file *m)
+{
+ struct i915_page_directory *pd;
+ uint64_t temp;
+ uint32_t pdpe;
+
+ gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) {
+ struct i915_page_table *pt;
+ uint64_t pd_len = length;
+ uint64_t pd_start = start;
+ uint32_t pde;
+
+ if (!test_bit(pdpe, pdp->used_pdpes))
+ continue;
+
+ seq_printf(m, "\tPDPE #%d\n", pdpe);
+ gen8_for_each_pde(pt, pd, pd_start, pd_len, temp, pde) {
+ uint32_t pte;
+ gen8_pte_t *pt_vaddr;
+
+ if (!test_bit(pde, pd->used_pdes))
+ continue;
+
+ pt_vaddr = kmap_px(pt);
+ for (pte = 0; pte < GEN8_PTES; pte += 4) {
+ uint64_t va =
+ (pdpe << GEN8_PDPE_SHIFT) |
+ (pde << GEN8_PDE_SHIFT) |
+ (pte << GEN8_PTE_SHIFT);
+ int i;
+ bool found = false;
+
+ for (i = 0; i < 4; i++)
+ if (pt_vaddr[pte + i] != scratch_pte)
+ found = true;
+ if (!found)
+ continue;
+
+ seq_printf(m, "\t\t0x%llx [%03d,%03d,%04d]: =", va, pdpe, pde, pte);
+ for (i = 0; i < 4; i++) {
+ if (pt_vaddr[pte + i] != scratch_pte)
+ seq_printf(m, " %llx", pt_vaddr[pte + i]);
+ else
+ seq_puts(m, " SCRATCH ");
+ }
+ seq_puts(m, "\n");
+ }
+ /* don't use kunmap_px, it could trigger
+ * an unnecessary flush.
+ */
+ kunmap_atomic(pt_vaddr);
+ }
+ }
+}
+
+static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
+{
+ struct i915_address_space *vm = &ppgtt->base;
+ uint64_t start = ppgtt->base.start;
+ uint64_t length = ppgtt->base.total;
+ gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
+ I915_CACHE_LLC, true);
+
+ if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
+ gen8_dump_pdp(&ppgtt->pdp, start, length, scratch_pte, m);
+ } else {
+ uint64_t templ4, pml4e;
+ struct i915_pml4 *pml4 = &ppgtt->pml4;
+ struct i915_page_directory_pointer *pdp;
+
+ gen8_for_each_pml4e(pdp, pml4, start, length, templ4, pml4e) {
+ if (!test_bit(pml4e, pml4->used_pml4es))
+ continue;
+
+ seq_printf(m, " PML4E #%llu\n", pml4e);
+ gen8_dump_pdp(pdp, start, length, scratch_pte, m);
+ }
+ }
+}
+
+static int gen8_preallocate_top_level_pdps(struct i915_hw_ppgtt *ppgtt)
+{
+ unsigned long *new_page_dirs, *new_page_tables;
+ uint32_t pdpes = I915_PDPES_PER_PDP(dev);
+ int ret;
+
+ /* We allocate temp bitmap for page tables for no gain
+ * but as this is for init only, lets keep the things simple
+ */
+ ret = alloc_gen8_temp_bitmaps(&new_page_dirs, &new_page_tables, pdpes);
+ if (ret)
+ return ret;
+
+ /* Allocate for all pdps regardless of how the ppgtt
+ * was defined.
+ */
+ ret = gen8_ppgtt_alloc_page_directories(&ppgtt->base, &ppgtt->pdp,
+ 0, 1ULL << 32,
+ new_page_dirs);
+ if (!ret)
+ *ppgtt->pdp.used_pdpes = *new_page_dirs;
+
+ free_gen8_temp_bitmaps(new_page_dirs, new_page_tables);
+
+ return ret;
+}
+
/*
* GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
* with a net effect resembling a 2-level page table in normal x86 terms. Each
@@ -1023,24 +1509,49 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
return ret;
ppgtt->base.start = 0;
- ppgtt->base.total = 1ULL << 32;
- if (IS_ENABLED(CONFIG_X86_32))
- /* While we have a proliferation of size_t variables
- * we cannot represent the full ppgtt size on 32bit,
- * so limit it to the same size as the GGTT (currently
- * 2GiB).
- */
- ppgtt->base.total = to_i915(ppgtt->base.dev)->gtt.base.total;
ppgtt->base.cleanup = gen8_ppgtt_cleanup;
ppgtt->base.allocate_va_range = gen8_alloc_va_range;
ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
ppgtt->base.clear_range = gen8_ppgtt_clear_range;
ppgtt->base.unbind_vma = ppgtt_unbind_vma;
ppgtt->base.bind_vma = ppgtt_bind_vma;
+ ppgtt->debug_dump = gen8_dump_ppgtt;
- ppgtt->switch_mm = gen8_mm_switch;
+ if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+ ret = setup_px(ppgtt->base.dev, &ppgtt->pml4);
+ if (ret)
+ goto free_scratch;
+
+ gen8_initialize_pml4(&ppgtt->base, &ppgtt->pml4);
+
+ ppgtt->base.total = 1ULL << 48;
+ ppgtt->switch_mm = gen8_48b_mm_switch;
+ } else {
+ ret = __pdp_init(ppgtt->base.dev, &ppgtt->pdp);
+ if (ret)
+ goto free_scratch;
+
+ ppgtt->base.total = 1ULL << 32;
+ ppgtt->switch_mm = gen8_legacy_mm_switch;
+ trace_i915_page_directory_pointer_entry_alloc(&ppgtt->base,
+ 0, 0,
+ GEN8_PML4E_SHIFT);
+
+ if (intel_vgpu_active(ppgtt->base.dev)) {
+ ret = gen8_preallocate_top_level_pdps(ppgtt);
+ if (ret)
+ goto free_scratch;
+ }
+ }
+
+ if (intel_vgpu_active(ppgtt->base.dev))
+ gen8_ppgtt_notify_vgt(ppgtt, true);
return 0;
+
+free_scratch:
+ gen8_free_scratch(&ppgtt->base);
+ return ret;
}
static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
@@ -1228,8 +1739,9 @@ static void gen8_ppgtt_enable(struct drm_device *dev)
int j;
for_each_ring(ring, dev_priv, j) {
+ u32 four_level = USES_FULL_48BIT_PPGTT(dev) ? GEN8_GFX_PPGTT_48B : 0;
I915_WRITE(RING_MODE_GEN7(ring),
- _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+ _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE | four_level));
}
}
@@ -1609,6 +2121,16 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
return gen8_ppgtt_init(ppgtt);
}
+static void i915_address_space_init(struct i915_address_space *vm,
+ struct drm_i915_private *dev_priv)
+{
+ drm_mm_init(&vm->mm, vm->start, vm->total);
+ vm->dev = dev_priv->dev;
+ INIT_LIST_HEAD(&vm->active_list);
+ INIT_LIST_HEAD(&vm->inactive_list);
+ list_add_tail(&vm->global_link, &dev_priv->vm_list);
+}
+
int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1617,9 +2139,7 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
ret = __hw_ppgtt_init(dev, ppgtt);
if (ret == 0) {
kref_init(&ppgtt->ref);
- drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
- ppgtt->base.total);
- i915_init_vm(dev_priv, &ppgtt->base);
+ i915_address_space_init(&ppgtt->base, dev_priv);
}
return ret;
@@ -1982,6 +2502,36 @@ static int ggtt_bind_vma(struct i915_vma *vma,
enum i915_cache_level cache_level,
u32 flags)
{
+ struct drm_i915_gem_object *obj = vma->obj;
+ u32 pte_flags = 0;
+ int ret;
+
+ ret = i915_get_ggtt_vma_pages(vma);
+ if (ret)
+ return ret;
+
+ /* Currently applicable only to VLV */
+ if (obj->gt_ro)
+ pte_flags |= PTE_READ_ONLY;
+
+ vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
+ vma->node.start,
+ cache_level, pte_flags);
+
+ /*
+ * Without aliasing PPGTT there's no difference between
+ * GLOBAL/LOCAL_BIND, it's all the same ptes. Hence unconditionally
+ * upgrade to both bound if we bind either to avoid double-binding.
+ */
+ vma->bound |= GLOBAL_BIND | LOCAL_BIND;
+
+ return 0;
+}
+
+static int aliasing_gtt_bind_vma(struct i915_vma *vma,
+ enum i915_cache_level cache_level,
+ u32 flags)
+{
struct drm_device *dev = vma->vm->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj = vma->obj;
@@ -1999,24 +2549,13 @@ static int ggtt_bind_vma(struct i915_vma *vma,
pte_flags |= PTE_READ_ONLY;
- if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
+ if (flags & GLOBAL_BIND) {
vma->vm->insert_entries(vma->vm, pages,
vma->node.start,
cache_level, pte_flags);
-
- /* Note the inconsistency here is due to absence of the
- * aliasing ppgtt on gen4 and earlier. Though we always
- * request PIN_USER for execbuffer (translated to LOCAL_BIND),
- * without the appgtt, we cannot honour that request and so
- * must substitute it with a global binding. Since we do this
- * behind the upper layers back, we need to explicitly set
- * the bound flag ourselves.
- */
- vma->bound |= GLOBAL_BIND;
-
}
- if (dev_priv->mm.aliasing_ppgtt && flags & LOCAL_BIND) {
+ if (flags & LOCAL_BIND) {
struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
appgtt->base.insert_entries(&appgtt->base, pages,
vma->node.start,
@@ -2084,9 +2623,9 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
}
static int i915_gem_setup_global_gtt(struct drm_device *dev,
- unsigned long start,
- unsigned long mappable_end,
- unsigned long end)
+ u64 start,
+ u64 mappable_end,
+ u64 end)
{
/* Let GEM Manage all of the aperture.
*
@@ -2106,11 +2645,13 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
BUG_ON(mappable_end > end);
- /* Subtract the guard page ... */
- drm_mm_init(&ggtt_vm->mm, start, end - start - PAGE_SIZE);
+ ggtt_vm->start = start;
- dev_priv->gtt.base.start = start;
- dev_priv->gtt.base.total = end - start;
+ /* Subtract the guard page before address space initialization to
+ * shrink the range used by drm_mm */
+ ggtt_vm->total = end - start - PAGE_SIZE;
+ i915_address_space_init(ggtt_vm, dev_priv);
+ ggtt_vm->total += PAGE_SIZE;
if (intel_vgpu_active(dev)) {
ret = intel_vgt_balloon(dev);
@@ -2119,13 +2660,13 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
}
if (!HAS_LLC(dev))
- dev_priv->gtt.base.mm.color_adjust = i915_gtt_color_adjust;
+ ggtt_vm->mm.color_adjust = i915_gtt_color_adjust;
/* Mark any preallocated objects as occupied */
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm);
- DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n",
+ DRM_DEBUG_KMS("reserving preallocated space: %llx + %zx\n",
i915_gem_obj_ggtt_offset(obj), obj->base.size);
WARN_ON(i915_gem_obj_ggtt_bound(obj));
@@ -2135,6 +2676,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
return ret;
}
vma->bound |= GLOBAL_BIND;
+ list_add_tail(&vma->mm_list, &ggtt_vm->inactive_list);
}
/* Clear any non-preallocated blocks */
@@ -2177,6 +2719,8 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
true);
dev_priv->mm.aliasing_ppgtt = ppgtt;
+ WARN_ON(dev_priv->gtt.base.bind_vma != ggtt_bind_vma);
+ dev_priv->gtt.base.bind_vma = aliasing_gtt_bind_vma;
}
return 0;
@@ -2367,8 +2911,8 @@ static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv)
/* XXX: spec defines this as 2 distinct registers. It's unclear if a 64b
* write would work. */
- I915_WRITE(GEN8_PRIVATE_PAT, pat);
- I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32);
+ I915_WRITE(GEN8_PRIVATE_PAT_LO, pat);
+ I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32);
}
static void chv_setup_private_ppat(struct drm_i915_private *dev_priv)
@@ -2402,8 +2946,8 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv)
GEN8_PPAT(6, CHV_PPAT_SNOOP) |
GEN8_PPAT(7, CHV_PPAT_SNOOP);
- I915_WRITE(GEN8_PRIVATE_PAT, pat);
- I915_WRITE(GEN8_PRIVATE_PAT + 4, pat >> 32);
+ I915_WRITE(GEN8_PRIVATE_PAT_LO, pat);
+ I915_WRITE(GEN8_PRIVATE_PAT_HI, pat >> 32);
}
static int gen8_gmch_probe(struct drm_device *dev,
@@ -2722,15 +3266,18 @@ i915_gem_obj_lookup_or_create_ggtt_vma(struct drm_i915_gem_object *obj,
}
-static void
-rotate_pages(dma_addr_t *in, unsigned int width, unsigned int height,
- struct sg_table *st)
+static struct scatterlist *
+rotate_pages(dma_addr_t *in, unsigned int offset,
+ unsigned int width, unsigned int height,
+ struct sg_table *st, struct scatterlist *sg)
{
unsigned int column, row;
unsigned int src_idx;
- struct scatterlist *sg = st->sgl;
- st->nents = 0;
+ if (!sg) {
+ st->nents = 0;
+ sg = st->sgl;
+ }
for (column = 0; column < width; column++) {
src_idx = width * (height - 1) + column;
@@ -2741,12 +3288,14 @@ rotate_pages(dma_addr_t *in, unsigned int width, unsigned int height,
* The only thing we need are DMA addresses.
*/
sg_set_page(sg, NULL, PAGE_SIZE, 0);
- sg_dma_address(sg) = in[src_idx];
+ sg_dma_address(sg) = in[offset + src_idx];
sg_dma_len(sg) = PAGE_SIZE;
sg = sg_next(sg);
src_idx -= width;
}
}
+
+ return sg;
}
static struct sg_table *
@@ -2755,10 +3304,13 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
{
struct intel_rotation_info *rot_info = &ggtt_view->rotation_info;
unsigned int size_pages = rot_info->size >> PAGE_SHIFT;
+ unsigned int size_pages_uv;
struct sg_page_iter sg_iter;
unsigned long i;
dma_addr_t *page_addr_list;
struct sg_table *st;
+ unsigned int uv_start_page;
+ struct scatterlist *sg;
int ret = -ENOMEM;
/* Allocate a temporary list of source pages for random access. */
@@ -2767,12 +3319,18 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
if (!page_addr_list)
return ERR_PTR(ret);
+ /* Account for UV plane with NV12. */
+ if (rot_info->pixel_format == DRM_FORMAT_NV12)
+ size_pages_uv = rot_info->size_uv >> PAGE_SHIFT;
+ else
+ size_pages_uv = 0;
+
/* Allocate target SG list. */
st = kmalloc(sizeof(*st), GFP_KERNEL);
if (!st)
goto err_st_alloc;
- ret = sg_alloc_table(st, size_pages, GFP_KERNEL);
+ ret = sg_alloc_table(st, size_pages + size_pages_uv, GFP_KERNEL);
if (ret)
goto err_sg_alloc;
@@ -2784,15 +3342,32 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view,
}
/* Rotate the pages. */
- rotate_pages(page_addr_list,
+ sg = rotate_pages(page_addr_list, 0,
rot_info->width_pages, rot_info->height_pages,
- st);
+ st, NULL);
+
+ /* Append the UV plane if NV12. */
+ if (rot_info->pixel_format == DRM_FORMAT_NV12) {
+ uv_start_page = size_pages;
+
+ /* Check for tile-row un-alignment. */
+ if (offset_in_page(rot_info->uv_offset))
+ uv_start_page--;
+
+ 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,
+ 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).\n",
+ "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);
+ rot_info->height_pages, size_pages + size_pages_uv,
+ size_pages);
drm_free_large(page_addr_list);
@@ -2804,10 +3379,11 @@ 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)\n",
+ "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);
+ rot_info->height_pages, size_pages + size_pages_uv,
+ size_pages);
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index e1cfa292f9ad..a216397ead52 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -39,6 +39,8 @@ struct drm_i915_file_private;
typedef uint32_t gen6_pte_t;
typedef uint64_t gen8_pte_t;
typedef uint64_t gen8_pde_t;
+typedef uint64_t gen8_ppgtt_pdpe_t;
+typedef uint64_t gen8_ppgtt_pml4e_t;
#define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
@@ -88,9 +90,18 @@ typedef uint64_t gen8_pde_t;
* PDPE | PDE | PTE | offset
* The difference as compared to normal x86 3 level page table is the PDPEs are
* programmed via register.
+ *
+ * GEN8 48b legacy style address is defined as a 4 level page table:
+ * 47:39 | 38:30 | 29:21 | 20:12 | 11:0
+ * PML4E | PDPE | PDE | PTE | offset
*/
+#define GEN8_PML4ES_PER_PML4 512
+#define GEN8_PML4E_SHIFT 39
+#define GEN8_PML4E_MASK (GEN8_PML4ES_PER_PML4 - 1)
#define GEN8_PDPE_SHIFT 30
-#define GEN8_PDPE_MASK 0x3
+/* NB: GEN8_PDPE_MASK is untrue for 32b platforms, but it has no impact on 32b page
+ * tables */
+#define GEN8_PDPE_MASK 0x1ff
#define GEN8_PDE_SHIFT 21
#define GEN8_PDE_MASK 0x1ff
#define GEN8_PTE_SHIFT 12
@@ -98,6 +109,9 @@ typedef uint64_t gen8_pde_t;
#define GEN8_LEGACY_PDPES 4
#define GEN8_PTES I915_PTES(sizeof(gen8_pte_t))
+#define I915_PDPES_PER_PDP(dev) (USES_FULL_48BIT_PPGTT(dev) ?\
+ GEN8_PML4ES_PER_PML4 : GEN8_LEGACY_PDPES)
+
#define PPAT_UNCACHED_INDEX (_PAGE_PWT | _PAGE_PCD)
#define PPAT_CACHED_PDE_INDEX 0 /* WB LLC */
#define PPAT_CACHED_INDEX _PAGE_PAT /* WB LLCeLLC */
@@ -124,10 +138,14 @@ 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 i915_ggtt_view {
@@ -135,7 +153,7 @@ struct i915_ggtt_view {
union {
struct {
- unsigned long offset;
+ u64 offset;
unsigned int size;
} partial;
} params;
@@ -241,9 +259,17 @@ struct i915_page_directory {
};
struct i915_page_directory_pointer {
- /* struct page *page; */
- DECLARE_BITMAP(used_pdpes, GEN8_LEGACY_PDPES);
- struct i915_page_directory *page_directory[GEN8_LEGACY_PDPES];
+ struct i915_page_dma base;
+
+ unsigned long *used_pdpes;
+ struct i915_page_directory **page_directory;
+};
+
+struct i915_pml4 {
+ struct i915_page_dma base;
+
+ DECLARE_BITMAP(used_pml4es, GEN8_PML4ES_PER_PML4);
+ struct i915_page_directory_pointer *pdps[GEN8_PML4ES_PER_PML4];
};
struct i915_address_space {
@@ -256,6 +282,7 @@ struct i915_address_space {
struct i915_page_scratch *scratch_page;
struct i915_page_table *scratch_pt;
struct i915_page_directory *scratch_pd;
+ struct i915_page_directory_pointer *scratch_pdp; /* GEN8+ & 48b PPGTT */
/**
* List of objects currently involved in rendering.
@@ -318,6 +345,7 @@ struct i915_gtt {
struct i915_address_space base;
size_t stolen_size; /* Total size of stolen memory */
+ size_t stolen_usable_size; /* Total size minus BIOS reserved */
u64 mappable_end; /* End offset that we can CPU map */
struct io_mapping *mappable; /* Mapping to our CPU mappable region */
phys_addr_t mappable_base; /* PA of our GMADR */
@@ -341,8 +369,9 @@ struct i915_hw_ppgtt {
struct drm_mm_node node;
unsigned long pd_dirty_rings;
union {
- struct i915_page_directory_pointer pdp;
- struct i915_page_directory pd;
+ struct i915_pml4 pml4; /* GEN8+ & 48b PPGTT */
+ struct i915_page_directory_pointer pdp; /* GEN8+ */
+ struct i915_page_directory pd; /* GEN6-7 */
};
struct drm_i915_file_private *file_priv;
@@ -365,7 +394,8 @@ struct i915_hw_ppgtt {
*/
#define gen6_for_each_pde(pt, pd, start, length, temp, iter) \
for (iter = gen6_pde_index(start); \
- pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \
+ length > 0 && iter < I915_PDES ? \
+ (pt = (pd)->page_table[iter]), 1 : 0; \
iter++, \
temp = ALIGN(start+1, 1 << GEN6_PDE_SHIFT) - start, \
temp = min_t(unsigned, temp, length), \
@@ -430,30 +460,30 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
*/
#define gen8_for_each_pde(pt, pd, start, length, temp, iter) \
for (iter = gen8_pde_index(start); \
- pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \
+ length > 0 && iter < I915_PDES ? \
+ (pt = (pd)->page_table[iter]), 1 : 0; \
iter++, \
temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \
temp = min(temp, length), \
start += temp, length -= temp)
-#define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \
- for (iter = gen8_pdpe_index(start); \
- pd = (pdp)->page_directory[iter], length > 0 && iter < GEN8_LEGACY_PDPES; \
+#define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \
+ for (iter = gen8_pdpe_index(start); \
+ length > 0 && (iter < I915_PDPES_PER_PDP(dev)) ? \
+ (pd = (pdp)->page_directory[iter]), 1 : 0; \
iter++, \
temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \
temp = min(temp, length), \
start += temp, length -= temp)
-/* Clamp length to the next page_directory boundary */
-static inline uint64_t gen8_clamp_pd(uint64_t start, uint64_t length)
-{
- uint64_t next_pd = ALIGN(start + 1, 1 << GEN8_PDPE_SHIFT);
-
- if (next_pd > (start + length))
- return length;
-
- return next_pd - start;
-}
+#define gen8_for_each_pml4e(pdp, pml4, start, length, temp, iter) \
+ for (iter = gen8_pml4e_index(start); \
+ length > 0 && iter < GEN8_PML4ES_PER_PML4 ? \
+ (pdp = (pml4)->pdps[iter]), 1 : 0; \
+ iter++, \
+ temp = ALIGN(start+1, 1ULL << GEN8_PML4E_SHIFT) - start, \
+ temp = min(temp, length), \
+ start += temp, length -= temp)
static inline uint32_t gen8_pte_index(uint64_t address)
{
@@ -472,8 +502,7 @@ static inline uint32_t gen8_pdpe_index(uint64_t address)
static inline uint32_t gen8_pml4e_index(uint64_t address)
{
- WARN_ON(1); /* For 64B */
- return 0;
+ return (address >> GEN8_PML4E_SHIFT) & GEN8_PML4E_MASK;
}
static inline size_t gen8_pte_count(uint64_t address, uint64_t length)
diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c
index 674341708033..f7df54a8ee2b 100644
--- a/drivers/gpu/drm/i915/i915_gem_shrinker.c
+++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c
@@ -73,7 +73,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
*/
unsigned long
i915_gem_shrink(struct drm_i915_private *dev_priv,
- long target, unsigned flags)
+ unsigned long target, unsigned flags)
{
const struct {
struct list_head *list;
@@ -85,6 +85,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
}, *phase;
unsigned long count = 0;
+ trace_i915_gem_shrink(dev_priv, target, flags);
+ i915_gem_retire_requests(dev_priv->dev);
+
/*
* As we may completely rewrite the (un)bound list whilst unbinding
* (due to retiring requests) we have to strictly process only
@@ -123,6 +126,9 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
obj->madv != I915_MADV_DONTNEED)
continue;
+ if ((flags & I915_SHRINK_ACTIVE) == 0 && obj->active)
+ continue;
+
drm_gem_object_reference(&obj->base);
/* For the unbound phase, this should be a no-op! */
@@ -139,6 +145,8 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
list_splice(&still_in_list, phase->list);
}
+ i915_gem_retire_requests(dev_priv->dev);
+
return count;
}
@@ -158,9 +166,10 @@ i915_gem_shrink(struct drm_i915_private *dev_priv,
*/
unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv)
{
- i915_gem_evict_everything(dev_priv->dev);
- return i915_gem_shrink(dev_priv, LONG_MAX,
- I915_SHRINK_BOUND | I915_SHRINK_UNBOUND);
+ return i915_gem_shrink(dev_priv, -1UL,
+ I915_SHRINK_BOUND |
+ I915_SHRINK_UNBOUND |
+ I915_SHRINK_ACTIVE);
}
static bool i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock)
@@ -213,7 +222,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
count += obj->base.size >> PAGE_SHIFT;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
- if (obj->pages_pin_count == num_vma_bound(obj))
+ if (!obj->active && obj->pages_pin_count == num_vma_bound(obj))
count += obj->base.size >> PAGE_SHIFT;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index f361c4a56995..cdacf3f5b77a 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -30,6 +30,9 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
+#define KB(x) ((x) * 1024)
+#define MB(x) (KB(x) * 1024)
+
/*
* The BIOS typically reserves some of the system's memory for the exclusive
* use of the integrated graphics. This memory is no longer available for
@@ -42,23 +45,38 @@
* for is a boon.
*/
-int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv,
- struct drm_mm_node *node, u64 size,
- unsigned alignment)
+int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv,
+ struct drm_mm_node *node, u64 size,
+ unsigned alignment, u64 start, u64 end)
{
int ret;
if (!drm_mm_initialized(&dev_priv->mm.stolen))
return -ENODEV;
+ /* See the comment at the drm_mm_init() call for more about this check.
+ * WaSkipStolenMemoryFirstPage:bdw,chv (incomplete) */
+ if (INTEL_INFO(dev_priv)->gen == 8 && start < 4096)
+ start = 4096;
+
mutex_lock(&dev_priv->mm.stolen_lock);
- ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment,
- DRM_MM_SEARCH_DEFAULT);
+ ret = drm_mm_insert_node_in_range(&dev_priv->mm.stolen, node, size,
+ alignment, start, end,
+ DRM_MM_SEARCH_DEFAULT);
mutex_unlock(&dev_priv->mm.stolen_lock);
return ret;
}
+int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv,
+ struct drm_mm_node *node, u64 size,
+ unsigned alignment)
+{
+ return i915_gem_stolen_insert_node_in_range(dev_priv, node, size,
+ alignment, 0,
+ dev_priv->gtt.stolen_usable_size);
+}
+
void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
struct drm_mm_node *node)
{
@@ -76,24 +94,91 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
/* Almost universally we can find the Graphics Base of Stolen Memory
* at offset 0x5c in the igfx configuration space. On a few (desktop)
* machines this is also mirrored in the bridge device at different
- * locations, or in the MCHBAR. On gen2, the layout is again slightly
- * different with the Graphics Segment immediately following Top of
- * Memory (or Top of Usable DRAM). Note it appears that TOUD is only
- * reported by 865g, so we just use the top of memory as determined
- * by the e820 probe.
+ * locations, or in the MCHBAR.
+ *
+ * On 865 we just check the TOUD register.
+ *
+ * On 830/845/85x the stolen memory base isn't available in any
+ * register. We need to calculate it as TOM-TSEG_SIZE-stolen_size.
*
- * XXX However gen2 requires an unavailable symbol.
*/
base = 0;
if (INTEL_INFO(dev)->gen >= 3) {
/* Read Graphics Base of Stolen Memory directly */
pci_read_config_dword(dev->pdev, 0x5c, &base);
base &= ~((1<<20) - 1);
- } else { /* GEN2 */
-#if 0
- /* Stolen is immediately above Top of Memory */
- base = max_low_pfn_mapped << PAGE_SHIFT;
-#endif
+ } else if (IS_I865G(dev)) {
+ u16 toud = 0;
+
+ /*
+ * FIXME is the graphics stolen memory region
+ * always at TOUD? Ie. is it always the last
+ * one to be allocated by the BIOS?
+ */
+ pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
+ I865_TOUD, &toud);
+
+ base = toud << 16;
+ } else if (IS_I85X(dev)) {
+ u32 tseg_size = 0;
+ u32 tom;
+ u8 tmp;
+
+ pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+ I85X_ESMRAMC, &tmp);
+
+ if (tmp & TSEG_ENABLE)
+ tseg_size = MB(1);
+
+ pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1),
+ I85X_DRB3, &tmp);
+ tom = tmp * MB(32);
+
+ base = tom - tseg_size - dev_priv->gtt.stolen_size;
+ } else if (IS_845G(dev)) {
+ u32 tseg_size = 0;
+ u32 tom;
+ u8 tmp;
+
+ pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+ I845_ESMRAMC, &tmp);
+
+ if (tmp & TSEG_ENABLE) {
+ switch (tmp & I845_TSEG_SIZE_MASK) {
+ case I845_TSEG_SIZE_512K:
+ tseg_size = KB(512);
+ break;
+ case I845_TSEG_SIZE_1M:
+ tseg_size = MB(1);
+ break;
+ }
+ }
+
+ pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+ I830_DRB3, &tmp);
+ tom = tmp * MB(32);
+
+ base = tom - tseg_size - dev_priv->gtt.stolen_size;
+ } else if (IS_I830(dev)) {
+ u32 tseg_size = 0;
+ u32 tom;
+ u8 tmp;
+
+ pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+ I830_ESMRAMC, &tmp);
+
+ if (tmp & TSEG_ENABLE) {
+ if (tmp & I830_TSEG_SIZE_1M)
+ tseg_size = MB(1);
+ else
+ tseg_size = KB(512);
+ }
+
+ pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
+ I830_DRB3, &tmp);
+ tom = tmp * MB(32);
+
+ base = tom - tseg_size - dev_priv->gtt.stolen_size;
}
if (base == 0)
@@ -186,6 +271,29 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
drm_mm_takedown(&dev_priv->mm.stolen);
}
+static void g4x_get_stolen_reserved(struct drm_i915_private *dev_priv,
+ unsigned long *base, unsigned long *size)
+{
+ uint32_t reg_val = I915_READ(IS_GM45(dev_priv) ?
+ CTG_STOLEN_RESERVED :
+ ELK_STOLEN_RESERVED);
+ unsigned long stolen_top = dev_priv->mm.stolen_base +
+ dev_priv->gtt.stolen_size;
+
+ *base = (reg_val & G4X_STOLEN_RESERVED_ADDR2_MASK) << 16;
+
+ WARN_ON((reg_val & G4X_STOLEN_RESERVED_ADDR1_MASK) < *base);
+
+ /* On these platforms, the register doesn't have a size field, so the
+ * size is the distance between the base and the top of the stolen
+ * memory. We also have the genuine case where base is zero and there's
+ * nothing reserved. */
+ if (*base == 0)
+ *size = 0;
+ else
+ *size = stolen_top - *base;
+}
+
static void gen6_get_stolen_reserved(struct drm_i915_private *dev_priv,
unsigned long *base, unsigned long *size)
{
@@ -281,7 +389,7 @@ static void bdw_get_stolen_reserved(struct drm_i915_private *dev_priv,
int i915_gem_init_stolen(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long reserved_total, reserved_base, reserved_size;
+ unsigned long reserved_total, reserved_base = 0, reserved_size;
unsigned long stolen_top;
mutex_init(&dev_priv->mm.stolen_lock);
@@ -305,7 +413,12 @@ int i915_gem_init_stolen(struct drm_device *dev)
switch (INTEL_INFO(dev_priv)->gen) {
case 2:
case 3:
+ break;
case 4:
+ if (IS_G4X(dev))
+ g4x_get_stolen_reserved(dev_priv, &reserved_base,
+ &reserved_size);
+ break;
case 5:
/* Assume the gen6 maximum for the older platforms. */
reserved_size = 1024 * 1024;
@@ -352,9 +465,21 @@ int i915_gem_init_stolen(struct drm_device *dev)
dev_priv->gtt.stolen_size >> 10,
(dev_priv->gtt.stolen_size - reserved_total) >> 10);
- /* Basic memrange allocator for stolen space */
- drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size -
- reserved_total);
+ dev_priv->gtt.stolen_usable_size = dev_priv->gtt.stolen_size -
+ reserved_total;
+
+ /*
+ * Basic memrange allocator for stolen space.
+ *
+ * TODO: Notice that some platforms require us to not use the first page
+ * of the stolen memory but their BIOSes may still put the framebuffer
+ * on the first page. So we don't reserve this page for now because of
+ * that. Our current solution is to just prevent new nodes from being
+ * inserted on the first page - see the check we have at
+ * i915_gem_stolen_insert_node_in_range(). We may want to fix the fbcon
+ * problem later.
+ */
+ drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_usable_size);
return 0;
}
@@ -544,7 +669,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
vma = i915_gem_obj_lookup_or_create_vma(obj, ggtt);
if (IS_ERR(vma)) {
ret = PTR_ERR(vma);
- goto err_out;
+ goto err;
}
/* To simplify the initialisation sequence between KMS and GTT,
@@ -558,23 +683,19 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
ret = drm_mm_reserve_node(&ggtt->mm, &vma->node);
if (ret) {
DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
- goto err_vma;
+ goto err;
}
- }
- vma->bound |= GLOBAL_BIND;
+ vma->bound |= GLOBAL_BIND;
+ list_add_tail(&vma->mm_list, &ggtt->inactive_list);
+ }
list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
- list_add_tail(&vma->mm_list, &ggtt->inactive_list);
i915_gem_object_pin_pages(obj);
return obj;
-err_vma:
- i915_gem_vma_destroy(vma);
-err_out:
- i915_gem_stolen_remove_node(dev_priv, stolen);
- kfree(stolen);
+err:
drm_gem_object_unreference(&obj->base);
return NULL;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index a96b9006a51e..19fb0bddc1cd 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -50,7 +50,6 @@ struct i915_mmu_notifier {
struct mmu_notifier mn;
struct rb_root objects;
struct list_head linear;
- unsigned long serial;
bool has_linear;
};
@@ -59,13 +58,16 @@ struct i915_mmu_object {
struct interval_tree_node it;
struct list_head link;
struct drm_i915_gem_object *obj;
+ struct work_struct work;
+ bool active;
bool is_linear;
};
-static unsigned long cancel_userptr(struct drm_i915_gem_object *obj)
+static void __cancel_userptr__worker(struct work_struct *work)
{
+ struct i915_mmu_object *mo = container_of(work, typeof(*mo), work);
+ struct drm_i915_gem_object *obj = mo->obj;
struct drm_device *dev = obj->base.dev;
- unsigned long end;
mutex_lock(&dev->struct_mutex);
/* Cancel any active worker and force us to re-evaluate gup */
@@ -88,45 +90,28 @@ static unsigned long cancel_userptr(struct drm_i915_gem_object *obj)
dev_priv->mm.interruptible = was_interruptible;
}
- end = obj->userptr.ptr + obj->base.size;
-
drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
-
- return end;
}
-static void *invalidate_range__linear(struct i915_mmu_notifier *mn,
- struct mm_struct *mm,
- unsigned long start,
- unsigned long end)
+static unsigned long cancel_userptr(struct i915_mmu_object *mo)
{
- struct i915_mmu_object *mo;
- unsigned long serial;
-
-restart:
- serial = mn->serial;
- list_for_each_entry(mo, &mn->linear, link) {
- struct drm_i915_gem_object *obj;
-
- if (mo->it.last < start || mo->it.start > end)
- continue;
-
- obj = mo->obj;
-
- if (!kref_get_unless_zero(&obj->base.refcount))
- continue;
-
- spin_unlock(&mn->lock);
-
- cancel_userptr(obj);
-
- spin_lock(&mn->lock);
- if (serial != mn->serial)
- goto restart;
+ unsigned long end = mo->obj->userptr.ptr + mo->obj->base.size;
+
+ /* The mmu_object is released late when destroying the
+ * GEM object so it is entirely possible to gain a
+ * reference on an object in the process of being freed
+ * since our serialisation is via the spinlock and not
+ * the struct_mutex - and consequently use it after it
+ * is freed and then double free it.
+ */
+ if (mo->active && kref_get_unless_zero(&mo->obj->base.refcount)) {
+ schedule_work(&mo->work);
+ /* only schedule one work packet to avoid the refleak */
+ mo->active = false;
}
- return NULL;
+ return end;
}
static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
@@ -134,46 +119,32 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
unsigned long start,
unsigned long end)
{
- struct i915_mmu_notifier *mn = container_of(_mn, struct i915_mmu_notifier, mn);
- struct interval_tree_node *it = NULL;
- unsigned long next = start;
- unsigned long serial = 0;
-
- end--; /* interval ranges are inclusive, but invalidate range is exclusive */
- while (next < end) {
- struct drm_i915_gem_object *obj = NULL;
-
- spin_lock(&mn->lock);
- if (mn->has_linear)
- it = invalidate_range__linear(mn, mm, start, end);
- else if (serial == mn->serial)
- it = interval_tree_iter_next(it, next, end);
- else
- it = interval_tree_iter_first(&mn->objects, start, end);
- if (it != NULL) {
- obj = container_of(it, struct i915_mmu_object, it)->obj;
-
- /* The mmu_object is released late when destroying the
- * GEM object so it is entirely possible to gain a
- * reference on an object in the process of being freed
- * since our serialisation is via the spinlock and not
- * the struct_mutex - and consequently use it after it
- * is freed and then double free it.
- */
- if (!kref_get_unless_zero(&obj->base.refcount)) {
- spin_unlock(&mn->lock);
- serial = 0;
+ struct i915_mmu_notifier *mn =
+ container_of(_mn, struct i915_mmu_notifier, mn);
+ struct i915_mmu_object *mo;
+
+ /* interval ranges are inclusive, but invalidate range is exclusive */
+ end--;
+
+ spin_lock(&mn->lock);
+ if (mn->has_linear) {
+ list_for_each_entry(mo, &mn->linear, link) {
+ if (mo->it.last < start || mo->it.start > end)
continue;
- }
- serial = mn->serial;
+ cancel_userptr(mo);
}
- spin_unlock(&mn->lock);
- if (obj == NULL)
- return;
+ } else {
+ struct interval_tree_node *it;
- next = cancel_userptr(obj);
+ it = interval_tree_iter_first(&mn->objects, start, end);
+ while (it) {
+ mo = container_of(it, struct i915_mmu_object, it);
+ start = cancel_userptr(mo);
+ it = interval_tree_iter_next(it, start, end);
+ }
}
+ spin_unlock(&mn->lock);
}
static const struct mmu_notifier_ops i915_gem_userptr_notifier = {
@@ -193,7 +164,6 @@ i915_mmu_notifier_create(struct mm_struct *mm)
spin_lock_init(&mn->lock);
mn->mn.ops = &i915_gem_userptr_notifier;
mn->objects = RB_ROOT;
- mn->serial = 1;
INIT_LIST_HEAD(&mn->linear);
mn->has_linear = false;
@@ -207,12 +177,6 @@ i915_mmu_notifier_create(struct mm_struct *mm)
return mn;
}
-static void __i915_mmu_notifier_update_serial(struct i915_mmu_notifier *mn)
-{
- if (++mn->serial == 0)
- mn->serial = 1;
-}
-
static int
i915_mmu_notifier_add(struct drm_device *dev,
struct i915_mmu_notifier *mn,
@@ -259,10 +223,9 @@ i915_mmu_notifier_add(struct drm_device *dev,
} else
interval_tree_insert(&mo->it, &mn->objects);
- if (ret == 0) {
+ if (ret == 0)
list_add(&mo->link, &mn->linear);
- __i915_mmu_notifier_update_serial(mn);
- }
+
spin_unlock(&mn->lock);
mutex_unlock(&dev->struct_mutex);
@@ -290,7 +253,6 @@ i915_mmu_notifier_del(struct i915_mmu_notifier *mn,
mn->has_linear = i915_mmu_notifier_has_linear(mn);
else
interval_tree_remove(&mo->it, &mn->objects);
- __i915_mmu_notifier_update_serial(mn);
spin_unlock(&mn->lock);
}
@@ -357,6 +319,7 @@ i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj,
mo->it.start = obj->userptr.ptr;
mo->it.last = mo->it.start + obj->base.size - 1;
mo->obj = obj;
+ INIT_WORK(&mo->work, __cancel_userptr__worker);
ret = i915_mmu_notifier_add(obj->base.dev, mn, mo);
if (ret) {
@@ -565,31 +528,65 @@ __i915_gem_userptr_set_pages(struct drm_i915_gem_object *obj,
return ret;
}
+static int
+__i915_gem_userptr_set_active(struct drm_i915_gem_object *obj,
+ bool value)
+{
+ int ret = 0;
+
+ /* During mm_invalidate_range we need to cancel any userptr that
+ * overlaps the range being invalidated. Doing so requires the
+ * struct_mutex, and that risks recursion. In order to cause
+ * recursion, the user must alias the userptr address space with
+ * a GTT mmapping (possible with a MAP_FIXED) - then when we have
+ * to invalidate that mmaping, mm_invalidate_range is called with
+ * the userptr address *and* the struct_mutex held. To prevent that
+ * we set a flag under the i915_mmu_notifier spinlock to indicate
+ * whether this object is valid.
+ */
+#if defined(CONFIG_MMU_NOTIFIER)
+ if (obj->userptr.mmu_object == NULL)
+ return 0;
+
+ spin_lock(&obj->userptr.mmu_object->mn->lock);
+ /* In order to serialise get_pages with an outstanding
+ * cancel_userptr, we must drop the struct_mutex and try again.
+ */
+ if (!value || !work_pending(&obj->userptr.mmu_object->work))
+ obj->userptr.mmu_object->active = value;
+ else
+ ret = -EAGAIN;
+ spin_unlock(&obj->userptr.mmu_object->mn->lock);
+#endif
+
+ return ret;
+}
+
static void
__i915_gem_userptr_get_pages_worker(struct work_struct *_work)
{
struct get_pages_work *work = container_of(_work, typeof(*work), work);
struct drm_i915_gem_object *obj = work->obj;
struct drm_device *dev = obj->base.dev;
- const int num_pages = obj->base.size >> PAGE_SHIFT;
+ const int npages = obj->base.size >> PAGE_SHIFT;
struct page **pvec;
int pinned, ret;
ret = -ENOMEM;
pinned = 0;
- pvec = kmalloc(num_pages*sizeof(struct page *),
+ pvec = kmalloc(npages*sizeof(struct page *),
GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (pvec == NULL)
- pvec = drm_malloc_ab(num_pages, sizeof(struct page *));
+ pvec = drm_malloc_ab(npages, sizeof(struct page *));
if (pvec != NULL) {
struct mm_struct *mm = obj->userptr.mm->mm;
down_read(&mm->mmap_sem);
- while (pinned < num_pages) {
+ while (pinned < npages) {
ret = get_user_pages(work->task, mm,
obj->userptr.ptr + pinned * PAGE_SIZE,
- num_pages - pinned,
+ npages - pinned,
!obj->userptr.read_only, 0,
pvec + pinned, NULL);
if (ret < 0)
@@ -601,20 +598,22 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
}
mutex_lock(&dev->struct_mutex);
- if (obj->userptr.work != &work->work) {
- ret = 0;
- } else if (pinned == num_pages) {
- ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
- if (ret == 0) {
- list_add_tail(&obj->global_list, &to_i915(dev)->mm.unbound_list);
- obj->get_page.sg = obj->pages->sgl;
- obj->get_page.last = 0;
-
- pinned = 0;
+ if (obj->userptr.work == &work->work) {
+ if (pinned == npages) {
+ ret = __i915_gem_userptr_set_pages(obj, pvec, npages);
+ if (ret == 0) {
+ list_add_tail(&obj->global_list,
+ &to_i915(dev)->mm.unbound_list);
+ obj->get_page.sg = obj->pages->sgl;
+ obj->get_page.last = 0;
+ pinned = 0;
+ }
}
+ obj->userptr.work = ERR_PTR(ret);
+ if (ret)
+ __i915_gem_userptr_set_active(obj, false);
}
- obj->userptr.work = ERR_PTR(ret);
obj->userptr.workers--;
drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
@@ -627,11 +626,60 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
}
static int
+__i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj,
+ bool *active)
+{
+ struct get_pages_work *work;
+
+ /* Spawn a worker so that we can acquire the
+ * user pages without holding our mutex. Access
+ * to the user pages requires mmap_sem, and we have
+ * a strict lock ordering of mmap_sem, struct_mutex -
+ * we already hold struct_mutex here and so cannot
+ * call gup without encountering a lock inversion.
+ *
+ * Userspace will keep on repeating the operation
+ * (thanks to EAGAIN) until either we hit the fast
+ * path or the worker completes. If the worker is
+ * cancelled or superseded, the task is still run
+ * but the results ignored. (This leads to
+ * complications that we may have a stray object
+ * refcount that we need to be wary of when
+ * checking for existing objects during creation.)
+ * If the worker encounters an error, it reports
+ * that error back to this function through
+ * obj->userptr.work = ERR_PTR.
+ */
+ if (obj->userptr.workers >= I915_GEM_USERPTR_MAX_WORKERS)
+ return -EAGAIN;
+
+ work = kmalloc(sizeof(*work), GFP_KERNEL);
+ if (work == NULL)
+ return -ENOMEM;
+
+ obj->userptr.work = &work->work;
+ obj->userptr.workers++;
+
+ work->obj = obj;
+ drm_gem_object_reference(&obj->base);
+
+ work->task = current;
+ get_task_struct(work->task);
+
+ INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker);
+ schedule_work(&work->work);
+
+ *active = true;
+ return -EAGAIN;
+}
+
+static int
i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
{
const int num_pages = obj->base.size >> PAGE_SHIFT;
struct page **pvec;
int pinned, ret;
+ bool active;
/* If userspace should engineer that these pages are replaced in
* the vma between us binding this page into the GTT and completion
@@ -649,6 +697,20 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
* to the vma (discard or cloning) which should prevent the more
* egregious cases from causing harm.
*/
+ if (IS_ERR(obj->userptr.work)) {
+ /* active flag will have been dropped already by the worker */
+ ret = PTR_ERR(obj->userptr.work);
+ obj->userptr.work = NULL;
+ return ret;
+ }
+ if (obj->userptr.work)
+ /* active flag should still be held for the pending work */
+ return -EAGAIN;
+
+ /* Let the mmu-notifier know that we have begun and need cancellation */
+ ret = __i915_gem_userptr_set_active(obj, true);
+ if (ret)
+ return ret;
pvec = NULL;
pinned = 0;
@@ -657,73 +719,27 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (pvec == NULL) {
pvec = drm_malloc_ab(num_pages, sizeof(struct page *));
- if (pvec == NULL)
+ if (pvec == NULL) {
+ __i915_gem_userptr_set_active(obj, false);
return -ENOMEM;
+ }
}
pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages,
!obj->userptr.read_only, pvec);
}
- if (pinned < num_pages) {
- if (pinned < 0) {
- ret = pinned;
- pinned = 0;
- } else {
- /* Spawn a worker so that we can acquire the
- * user pages without holding our mutex. Access
- * to the user pages requires mmap_sem, and we have
- * a strict lock ordering of mmap_sem, struct_mutex -
- * we already hold struct_mutex here and so cannot
- * call gup without encountering a lock inversion.
- *
- * Userspace will keep on repeating the operation
- * (thanks to EAGAIN) until either we hit the fast
- * path or the worker completes. If the worker is
- * cancelled or superseded, the task is still run
- * but the results ignored. (This leads to
- * complications that we may have a stray object
- * refcount that we need to be wary of when
- * checking for existing objects during creation.)
- * If the worker encounters an error, it reports
- * that error back to this function through
- * obj->userptr.work = ERR_PTR.
- */
- ret = -EAGAIN;
- if (obj->userptr.work == NULL &&
- obj->userptr.workers < I915_GEM_USERPTR_MAX_WORKERS) {
- struct get_pages_work *work;
-
- work = kmalloc(sizeof(*work), GFP_KERNEL);
- if (work != NULL) {
- obj->userptr.work = &work->work;
- obj->userptr.workers++;
-
- work->obj = obj;
- drm_gem_object_reference(&obj->base);
-
- work->task = current;
- get_task_struct(work->task);
-
- INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker);
- schedule_work(&work->work);
- } else
- ret = -ENOMEM;
- } else {
- if (IS_ERR(obj->userptr.work)) {
- ret = PTR_ERR(obj->userptr.work);
- obj->userptr.work = NULL;
- }
- }
- }
- } else {
+
+ active = false;
+ if (pinned < 0)
+ ret = pinned, pinned = 0;
+ else if (pinned < num_pages)
+ ret = __i915_gem_userptr_get_pages_schedule(obj, &active);
+ else
ret = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
- if (ret == 0) {
- obj->userptr.work = NULL;
- pinned = 0;
- }
+ if (ret) {
+ __i915_gem_userptr_set_active(obj, active);
+ release_pages(pvec, pinned, 0);
}
-
- release_pages(pvec, pinned, 0);
drm_free_large(pvec);
return ret;
}
@@ -734,6 +750,7 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj)
struct sg_page_iter sg_iter;
BUG_ON(obj->userptr.work != NULL);
+ __i915_gem_userptr_set_active(obj, false);
if (obj->madv != I915_MADV_WILLNEED)
obj->dirty = 0;
@@ -816,7 +833,6 @@ static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
int
i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_userptr *args = data;
struct drm_i915_gem_object *obj;
int ret;
@@ -829,9 +845,6 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file
if (offset_in_page(args->user_ptr | args->user_size))
return -EINVAL;
- if (args->user_size > dev_priv->gtt.base.total)
- return -E2BIG;
-
if (!access_ok(args->flags & I915_USERPTR_READ_ONLY ? VERIFY_READ : VERIFY_WRITE,
(char __user *)(unsigned long)args->user_ptr, args->user_size))
return -EFAULT;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 41d0739e6fdf..2f04e4f2ff35 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -30,11 +30,6 @@
#include <generated/utsrelease.h>
#include "i915_drv.h"
-static const char *yesno(int v)
-{
- return v ? "yes" : "no";
-}
-
static const char *ring_str(int ring)
{
switch (ring) {
@@ -197,8 +192,9 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
err_printf(m, " %s [%d]:\n", name, count);
while (count--) {
- err_printf(m, " %08x %8u %02x %02x [ ",
- err->gtt_offset,
+ err_printf(m, " %08x_%08x %8u %02x %02x [ ",
+ upper_32_bits(err->gtt_offset),
+ lower_32_bits(err->gtt_offset),
err->size,
err->read_domains,
err->write_domain);
@@ -427,15 +423,17 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
err_printf(m, " (submitted by %s [%d])",
error->ring[i].comm,
error->ring[i].pid);
- err_printf(m, " --- gtt_offset = 0x%08x\n",
- obj->gtt_offset);
+ err_printf(m, " --- gtt_offset = 0x%08x %08x\n",
+ upper_32_bits(obj->gtt_offset),
+ lower_32_bits(obj->gtt_offset));
print_error_obj(m, obj);
}
obj = error->ring[i].wa_batchbuffer;
if (obj) {
err_printf(m, "%s (w/a) --- gtt_offset = 0x%08x\n",
- dev_priv->ring[i].name, obj->gtt_offset);
+ dev_priv->ring[i].name,
+ lower_32_bits(obj->gtt_offset));
print_error_obj(m, obj);
}
@@ -454,22 +452,28 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
if ((obj = error->ring[i].ringbuffer)) {
err_printf(m, "%s --- ringbuffer = 0x%08x\n",
dev_priv->ring[i].name,
- obj->gtt_offset);
+ lower_32_bits(obj->gtt_offset));
print_error_obj(m, obj);
}
if ((obj = error->ring[i].hws_page)) {
- err_printf(m, "%s --- HW Status = 0x%08x\n",
- dev_priv->ring[i].name,
- obj->gtt_offset);
+ u64 hws_offset = obj->gtt_offset;
+ u32 *hws_page = &obj->pages[0][0];
+
+ if (i915.enable_execlists) {
+ hws_offset += LRC_PPHWSP_PN * PAGE_SIZE;
+ hws_page = &obj->pages[LRC_PPHWSP_PN][0];
+ }
+ err_printf(m, "%s --- HW Status = 0x%08llx\n",
+ dev_priv->ring[i].name, hws_offset);
offset = 0;
for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
err_printf(m, "[%04x] %08x %08x %08x %08x\n",
offset,
- obj->pages[0][elt],
- obj->pages[0][elt+1],
- obj->pages[0][elt+2],
- obj->pages[0][elt+3]);
+ hws_page[elt],
+ hws_page[elt+1],
+ hws_page[elt+2],
+ hws_page[elt+3]);
offset += 16;
}
}
@@ -477,13 +481,14 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
if ((obj = error->ring[i].ctx)) {
err_printf(m, "%s --- HW Context = 0x%08x\n",
dev_priv->ring[i].name,
- obj->gtt_offset);
+ lower_32_bits(obj->gtt_offset));
print_error_obj(m, obj);
}
}
if ((obj = error->semaphore_obj)) {
- err_printf(m, "Semaphore page = 0x%08x\n", obj->gtt_offset);
+ err_printf(m, "Semaphore page = 0x%08x\n",
+ lower_32_bits(obj->gtt_offset));
for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
err_printf(m, "[%04x] %08x %08x %08x %08x\n",
elt * 4,
@@ -591,7 +596,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
int num_pages;
bool use_ggtt;
int i = 0;
- u32 reloc_offset;
+ u64 reloc_offset;
if (src == NULL || src->pages == NULL)
return NULL;
@@ -787,20 +792,15 @@ static void i915_gem_record_fences(struct drm_device *dev,
int i;
if (IS_GEN3(dev) || IS_GEN2(dev)) {
- for (i = 0; i < 8; i++)
- error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- for (i = 0; i < 8; i++)
- error->fence[i+8] = I915_READ(FENCE_REG_945_8 +
- (i * 4));
- } else if (IS_GEN5(dev) || IS_GEN4(dev))
- for (i = 0; i < 16; i++)
- error->fence[i] = I915_READ64(FENCE_REG_965_0 +
- (i * 8));
- else if (INTEL_INFO(dev)->gen >= 6)
for (i = 0; i < dev_priv->num_fence_regs; i++)
- error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 +
- (i * 8));
+ error->fence[i] = I915_READ(FENCE_REG(i));
+ } else if (IS_GEN5(dev) || IS_GEN4(dev)) {
+ for (i = 0; i < dev_priv->num_fence_regs; i++)
+ error->fence[i] = I915_READ64(FENCE_REG_965_LO(i));
+ } else if (INTEL_INFO(dev)->gen >= 6) {
+ for (i = 0; i < dev_priv->num_fence_regs; i++)
+ error->fence[i] = I915_READ64(FENCE_REG_GEN6_LO(i));
+ }
}
@@ -886,7 +886,7 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->faddr = I915_READ(DMA_FADD_I8XX);
ering->ipeir = I915_READ(IPEIR);
ering->ipehr = I915_READ(IPEHR);
- ering->instdone = I915_READ(INSTDONE);
+ ering->instdone = I915_READ(GEN2_INSTDONE);
}
ering->waiting = waitqueue_active(&ring->irq_queue);
@@ -1388,12 +1388,12 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone)
memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
if (IS_GEN2(dev) || IS_GEN3(dev))
- instdone[0] = I915_READ(INSTDONE);
+ instdone[0] = I915_READ(GEN2_INSTDONE);
else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
- instdone[0] = I915_READ(INSTDONE_I965);
- instdone[1] = I915_READ(INSTDONE1);
+ instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE));
+ instdone[1] = I915_READ(GEN4_INSTDONE1);
} else if (INTEL_INFO(dev)->gen >= 7) {
- instdone[0] = I915_READ(GEN7_INSTDONE_1);
+ instdone[0] = I915_READ(RING_INSTDONE(RENDER_RING_BASE));
instdone[1] = I915_READ(GEN7_SC_INSTDONE);
instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h
index ccdc6c8ac20b..c4cb1c0c4d0d 100644
--- a/drivers/gpu/drm/i915/i915_guc_reg.h
+++ b/drivers/gpu/drm/i915/i915_guc_reg.h
@@ -37,14 +37,11 @@
#define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT)
#define GS_MIA_SHIFT 16
#define GS_MIA_MASK (0x07 << GS_MIA_SHIFT)
-
-#define GUC_WOPCM_SIZE 0xc050
-#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */
-#define GUC_WOPCM_OFFSET 0x80000 /* 512KB */
+#define GS_MIA_CORE_STATE (1 << GS_MIA_SHIFT)
#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4))
-#define UOS_RSA_SCRATCH_0 0xc200
+#define UOS_RSA_SCRATCH(i) (0xc200 + (i) * 4)
#define DMA_ADDR_0_LOW 0xc300
#define DMA_ADDR_0_HIGH 0xc304
#define DMA_ADDR_1_LOW 0xc308
@@ -56,10 +53,19 @@
#define UOS_MOVE (1<<4)
#define START_DMA (1<<0)
#define DMA_GUC_WOPCM_OFFSET 0xc340
+#define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */
+#define GUC_MAX_IDLE_COUNT 0xC3E4
+
+#define GUC_WOPCM_SIZE 0xc050
+#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */
+
+/* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */
+#define GUC_WOPCM_TOP (GUC_WOPCM_SIZE_VALUE)
#define GEN8_GT_PM_CONFIG 0x138140
+#define GEN9LP_GT_PM_CONFIG 0x138140
#define GEN9_GT_PM_CONFIG 0x13816c
-#define GEN8_GT_DOORBELL_ENABLE (1<<0)
+#define GT_DOORBELL_ENABLE (1<<0)
#define GEN8_GTCR 0x4274
#define GEN8_GTCR_INVALIDATE (1<<0)
@@ -80,7 +86,8 @@
GUC_ENABLE_READ_CACHE_LOGIC | \
GUC_ENABLE_MIA_CACHING | \
GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \
- GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
+ GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA | \
+ GUC_ENABLE_MIA_CLOCK_GATING)
#define HOST2GUC_INTERRUPT 0xc4c8
#define HOST2GUC_TRIGGER (1<<0)
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
new file mode 100644
index 000000000000..036b42bae827
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -0,0 +1,975 @@
+/*
+ * Copyright © 2014 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 <linux/firmware.h>
+#include <linux/circ_buf.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+/**
+ * DOC: GuC Client
+ *
+ * i915_guc_client:
+ * We use the term client to avoid confusion with contexts. A i915_guc_client is
+ * equivalent to GuC object guc_context_desc. This context descriptor is
+ * allocated from a pool of 1024 entries. Kernel driver will allocate doorbell
+ * and workqueue for it. Also the process descriptor (guc_process_desc), which
+ * is mapped to client space. So the client can write Work Item then ring the
+ * doorbell.
+ *
+ * To simplify the implementation, we allocate one gem object that contains all
+ * pages for doorbell, process descriptor and workqueue.
+ *
+ * The Scratch registers:
+ * There are 16 MMIO-based registers start from 0xC180. The kernel driver writes
+ * a value to the action register (SOFT_SCRATCH_0) along with any data. It then
+ * triggers an interrupt on the GuC via another register write (0xC4C8).
+ * Firmware writes a success/fail code back to the action register after
+ * processes the request. The kernel driver polls waiting for this update and
+ * then proceeds.
+ * See host2guc_action()
+ *
+ * Doorbells:
+ * Doorbells are interrupts to uKernel. A doorbell is a single cache line (QW)
+ * mapped into process space.
+ *
+ * Work Items:
+ * There are several types of work items that the host may place into a
+ * workqueue, each with its own requirements and limitations. Currently only
+ * WQ_TYPE_INORDER is needed to support legacy submission via GuC, which
+ * represents in-order queue. The kernel driver packs ring tail pointer and an
+ * ELSP context descriptor dword into Work Item.
+ * See guc_add_workqueue_item()
+ *
+ */
+
+/*
+ * Read GuC command/status register (SOFT_SCRATCH_0)
+ * Return true if it contains a response rather than a command
+ */
+static inline bool host2guc_action_response(struct drm_i915_private *dev_priv,
+ u32 *status)
+{
+ u32 val = I915_READ(SOFT_SCRATCH(0));
+ *status = val;
+ return GUC2HOST_IS_RESPONSE(val);
+}
+
+static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ u32 status;
+ int i;
+ int ret;
+
+ if (WARN_ON(len < 1 || len > 15))
+ return -EINVAL;
+
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+ spin_lock(&dev_priv->guc.host2guc_lock);
+
+ dev_priv->guc.action_count += 1;
+ dev_priv->guc.action_cmd = data[0];
+
+ for (i = 0; i < len; i++)
+ I915_WRITE(SOFT_SCRATCH(i), data[i]);
+
+ POSTING_READ(SOFT_SCRATCH(i - 1));
+
+ I915_WRITE(HOST2GUC_INTERRUPT, HOST2GUC_TRIGGER);
+
+ /* No HOST2GUC command should take longer than 10ms */
+ ret = wait_for_atomic(host2guc_action_response(dev_priv, &status), 10);
+ if (status != GUC2HOST_STATUS_SUCCESS) {
+ /*
+ * Either the GuC explicitly returned an error (which
+ * we convert to -EIO here) or no response at all was
+ * received within the timeout limit (-ETIMEDOUT)
+ */
+ if (ret != -ETIMEDOUT)
+ ret = -EIO;
+
+ DRM_ERROR("GUC: host2guc action 0x%X failed. ret=%d "
+ "status=0x%08X response=0x%08X\n",
+ data[0], ret, status,
+ I915_READ(SOFT_SCRATCH(15)));
+
+ dev_priv->guc.action_fail += 1;
+ dev_priv->guc.action_err = ret;
+ }
+ dev_priv->guc.action_status = status;
+
+ spin_unlock(&dev_priv->guc.host2guc_lock);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+ return ret;
+}
+
+/*
+ * Tell the GuC to allocate or deallocate a specific doorbell
+ */
+
+static int host2guc_allocate_doorbell(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ u32 data[2];
+
+ data[0] = HOST2GUC_ACTION_ALLOCATE_DOORBELL;
+ data[1] = client->ctx_index;
+
+ return host2guc_action(guc, data, 2);
+}
+
+static int host2guc_release_doorbell(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ u32 data[2];
+
+ data[0] = HOST2GUC_ACTION_DEALLOCATE_DOORBELL;
+ data[1] = client->ctx_index;
+
+ return host2guc_action(guc, data, 2);
+}
+
+static int host2guc_sample_forcewake(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ struct drm_device *dev = dev_priv->dev;
+ u32 data[2];
+
+ data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE;
+ /* WaRsDisableCoarsePowerGating:skl,bxt */
+ if (!intel_enable_rc6(dev_priv->dev) ||
+ (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
+ (IS_SKL_GT3(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)) ||
+ (IS_SKL_GT4(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
+ data[1] = 0;
+ else
+ /* bit 0 and 1 are for Render and Media domain separately */
+ data[1] = GUC_FORCEWAKE_RENDER | GUC_FORCEWAKE_MEDIA;
+
+ return host2guc_action(guc, data, ARRAY_SIZE(data));
+}
+
+/*
+ * Initialise, update, or clear doorbell data shared with the GuC
+ *
+ * These functions modify shared data and so need access to the mapped
+ * client object which contains the page being used for the doorbell
+ */
+
+static void guc_init_doorbell(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ struct guc_doorbell_info *doorbell;
+ void *base;
+
+ base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+ doorbell = base + client->doorbell_offset;
+
+ doorbell->db_status = 1;
+ doorbell->cookie = 0;
+
+ kunmap_atomic(base);
+}
+
+static int guc_ring_doorbell(struct i915_guc_client *gc)
+{
+ struct guc_process_desc *desc;
+ union guc_doorbell_qw db_cmp, db_exc, db_ret;
+ union guc_doorbell_qw *db;
+ void *base;
+ int attempt = 2, ret = -EAGAIN;
+
+ base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
+ desc = base + gc->proc_desc_offset;
+
+ /* Update the tail so it is visible to GuC */
+ desc->tail = gc->wq_tail;
+
+ /* current cookie */
+ db_cmp.db_status = GUC_DOORBELL_ENABLED;
+ db_cmp.cookie = gc->cookie;
+
+ /* cookie to be updated */
+ db_exc.db_status = GUC_DOORBELL_ENABLED;
+ db_exc.cookie = gc->cookie + 1;
+ if (db_exc.cookie == 0)
+ db_exc.cookie = 1;
+
+ /* pointer of current doorbell cacheline */
+ db = base + gc->doorbell_offset;
+
+ while (attempt--) {
+ /* lets ring the doorbell */
+ db_ret.value_qw = atomic64_cmpxchg((atomic64_t *)db,
+ db_cmp.value_qw, db_exc.value_qw);
+
+ /* if the exchange was successfully executed */
+ if (db_ret.value_qw == db_cmp.value_qw) {
+ /* db was successfully rung */
+ gc->cookie = db_exc.cookie;
+ ret = 0;
+ break;
+ }
+
+ /* XXX: doorbell was lost and need to acquire it again */
+ if (db_ret.db_status == GUC_DOORBELL_DISABLED)
+ break;
+
+ DRM_ERROR("Cookie mismatch. Expected %d, returned %d\n",
+ db_cmp.cookie, db_ret.cookie);
+
+ /* update the cookie to newly read cookie from GuC */
+ db_cmp.cookie = db_ret.cookie;
+ db_exc.cookie = db_ret.cookie + 1;
+ if (db_exc.cookie == 0)
+ db_exc.cookie = 1;
+ }
+
+ kunmap_atomic(base);
+ return ret;
+}
+
+static void guc_disable_doorbell(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ struct guc_doorbell_info *doorbell;
+ void *base;
+ int drbreg = GEN8_DRBREGL(client->doorbell_id);
+ int value;
+
+ base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+ doorbell = base + client->doorbell_offset;
+
+ doorbell->db_status = 0;
+
+ kunmap_atomic(base);
+
+ I915_WRITE(drbreg, I915_READ(drbreg) & ~GEN8_DRB_VALID);
+
+ value = I915_READ(drbreg);
+ WARN_ON((value & GEN8_DRB_VALID) != 0);
+
+ I915_WRITE(GEN8_DRBREGU(client->doorbell_id), 0);
+ I915_WRITE(drbreg, 0);
+
+ /* XXX: wait for any interrupts */
+ /* XXX: wait for workqueue to drain */
+}
+
+/*
+ * Select, assign and relase doorbell cachelines
+ *
+ * These functions track which doorbell cachelines are in use.
+ * The data they manipulate is protected by the host2guc lock.
+ */
+
+static uint32_t select_doorbell_cacheline(struct intel_guc *guc)
+{
+ const uint32_t cacheline_size = cache_line_size();
+ uint32_t offset;
+
+ spin_lock(&guc->host2guc_lock);
+
+ /* Doorbell uses a single cache line within a page */
+ offset = offset_in_page(guc->db_cacheline);
+
+ /* Moving to next cache line to reduce contention */
+ guc->db_cacheline += cacheline_size;
+
+ spin_unlock(&guc->host2guc_lock);
+
+ DRM_DEBUG_DRIVER("selected doorbell cacheline 0x%x, next 0x%x, linesize %u\n",
+ offset, guc->db_cacheline, cacheline_size);
+
+ return offset;
+}
+
+static uint16_t assign_doorbell(struct intel_guc *guc, uint32_t priority)
+{
+ /*
+ * The bitmap is split into two halves; the first half is used for
+ * normal priority contexts, the second half for high-priority ones.
+ * Note that logically higher priorities are numerically less than
+ * normal ones, so the test below means "is it high-priority?"
+ */
+ const bool hi_pri = (priority <= GUC_CTX_PRIORITY_HIGH);
+ const uint16_t half = GUC_MAX_DOORBELLS / 2;
+ const uint16_t start = hi_pri ? half : 0;
+ const uint16_t end = start + half;
+ uint16_t id;
+
+ spin_lock(&guc->host2guc_lock);
+ id = find_next_zero_bit(guc->doorbell_bitmap, end, start);
+ if (id == end)
+ id = GUC_INVALID_DOORBELL_ID;
+ else
+ bitmap_set(guc->doorbell_bitmap, id, 1);
+ spin_unlock(&guc->host2guc_lock);
+
+ DRM_DEBUG_DRIVER("assigned %s priority doorbell id 0x%x\n",
+ hi_pri ? "high" : "normal", id);
+
+ return id;
+}
+
+static void release_doorbell(struct intel_guc *guc, uint16_t id)
+{
+ spin_lock(&guc->host2guc_lock);
+ bitmap_clear(guc->doorbell_bitmap, id, 1);
+ spin_unlock(&guc->host2guc_lock);
+}
+
+/*
+ * Initialise the process descriptor shared with the GuC firmware.
+ */
+static void guc_init_proc_desc(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ struct guc_process_desc *desc;
+ void *base;
+
+ base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+ desc = base + client->proc_desc_offset;
+
+ memset(desc, 0, sizeof(*desc));
+
+ /*
+ * XXX: pDoorbell and WQVBaseAddress are pointers in process address
+ * space for ring3 clients (set them as in mmap_ioctl) or kernel
+ * space for kernel clients (map on demand instead? May make debug
+ * easier to have it mapped).
+ */
+ desc->wq_base_addr = 0;
+ desc->db_base_addr = 0;
+
+ desc->context_id = client->ctx_index;
+ desc->wq_size_bytes = client->wq_size;
+ desc->wq_status = WQ_STATUS_ACTIVE;
+ desc->priority = client->priority;
+
+ kunmap_atomic(base);
+}
+
+/*
+ * Initialise/clear the context descriptor shared with the GuC firmware.
+ *
+ * This descriptor tells the GuC where (in GGTT space) to find the important
+ * data structures relating to this client (doorbell, process descriptor,
+ * write queue, etc).
+ */
+
+static void guc_init_ctx_desc(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ struct intel_context *ctx = client->owner;
+ struct guc_context_desc desc;
+ struct sg_table *sg;
+ int i;
+
+ memset(&desc, 0, sizeof(desc));
+
+ desc.attribute = GUC_CTX_DESC_ATTR_ACTIVE | GUC_CTX_DESC_ATTR_KERNEL;
+ desc.context_id = client->ctx_index;
+ desc.priority = client->priority;
+ desc.db_id = client->doorbell_id;
+
+ for (i = 0; i < I915_NUM_RINGS; i++) {
+ struct guc_execlist_context *lrc = &desc.lrc[i];
+ struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf;
+ struct intel_engine_cs *ring;
+ struct drm_i915_gem_object *obj;
+ uint64_t ctx_desc;
+
+ /* TODO: We have a design issue to be solved here. Only when we
+ * receive the first batch, we know which engine is used by the
+ * user. But here GuC expects the lrc and ring to be pinned. It
+ * is not an issue for default context, which is the only one
+ * for now who owns a GuC client. But for future owner of GuC
+ * client, need to make sure lrc is pinned prior to enter here.
+ */
+ obj = ctx->engine[i].state;
+ if (!obj)
+ break; /* XXX: continue? */
+
+ ring = ringbuf->ring;
+ ctx_desc = intel_lr_context_descriptor(ctx, ring);
+ lrc->context_desc = (u32)ctx_desc;
+
+ /* The state page is after PPHWSP */
+ lrc->ring_lcra = i915_gem_obj_ggtt_offset(obj) +
+ LRC_STATE_PN * PAGE_SIZE;
+ lrc->context_id = (client->ctx_index << GUC_ELC_CTXID_OFFSET) |
+ (ring->id << GUC_ELC_ENGINE_OFFSET);
+
+ obj = ringbuf->obj;
+
+ lrc->ring_begin = i915_gem_obj_ggtt_offset(obj);
+ lrc->ring_end = lrc->ring_begin + obj->base.size - 1;
+ lrc->ring_next_free_location = lrc->ring_begin;
+ lrc->ring_current_tail_pointer_value = 0;
+
+ desc.engines_used |= (1 << ring->id);
+ }
+
+ WARN_ON(desc.engines_used == 0);
+
+ /*
+ * The CPU address is only needed at certain points, so kmap_atomic on
+ * demand instead of storing it in the ctx descriptor.
+ * XXX: May make debug easier to have it mapped
+ */
+ desc.db_trigger_cpu = 0;
+ desc.db_trigger_uk = client->doorbell_offset +
+ i915_gem_obj_ggtt_offset(client->client_obj);
+ desc.db_trigger_phy = client->doorbell_offset +
+ sg_dma_address(client->client_obj->pages->sgl);
+
+ desc.process_desc = client->proc_desc_offset +
+ i915_gem_obj_ggtt_offset(client->client_obj);
+
+ desc.wq_addr = client->wq_offset +
+ i915_gem_obj_ggtt_offset(client->client_obj);
+
+ desc.wq_size = client->wq_size;
+
+ /*
+ * XXX: Take LRCs from an existing intel_context if this is not an
+ * IsKMDCreatedContext client
+ */
+ desc.desc_private = (uintptr_t)client;
+
+ /* Pool context is pinned already */
+ sg = guc->ctx_pool_obj->pages;
+ sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
+ sizeof(desc) * client->ctx_index);
+}
+
+static void guc_fini_ctx_desc(struct intel_guc *guc,
+ struct i915_guc_client *client)
+{
+ struct guc_context_desc desc;
+ struct sg_table *sg;
+
+ memset(&desc, 0, sizeof(desc));
+
+ sg = guc->ctx_pool_obj->pages;
+ sg_pcopy_from_buffer(sg->sgl, sg->nents, &desc, sizeof(desc),
+ sizeof(desc) * client->ctx_index);
+}
+
+/* Get valid workqueue item and return it back to offset */
+static int guc_get_workqueue_space(struct i915_guc_client *gc, u32 *offset)
+{
+ struct guc_process_desc *desc;
+ void *base;
+ u32 size = sizeof(struct guc_wq_item);
+ int ret = 0, timeout_counter = 200;
+
+ base = kmap_atomic(i915_gem_object_get_page(gc->client_obj, 0));
+ desc = base + gc->proc_desc_offset;
+
+ while (timeout_counter-- > 0) {
+ ret = wait_for_atomic(CIRC_SPACE(gc->wq_tail, desc->head,
+ gc->wq_size) >= size, 1);
+
+ if (!ret) {
+ *offset = gc->wq_tail;
+
+ /* advance the tail for next workqueue item */
+ gc->wq_tail += size;
+ gc->wq_tail &= gc->wq_size - 1;
+
+ /* this will break the loop */
+ timeout_counter = 0;
+ }
+ };
+
+ kunmap_atomic(base);
+
+ return ret;
+}
+
+static int guc_add_workqueue_item(struct i915_guc_client *gc,
+ struct drm_i915_gem_request *rq)
+{
+ enum intel_ring_id ring_id = rq->ring->id;
+ struct guc_wq_item *wqi;
+ void *base;
+ u32 tail, wq_len, wq_off = 0;
+ int ret;
+
+ ret = guc_get_workqueue_space(gc, &wq_off);
+ if (ret)
+ return ret;
+
+ /* For now workqueue item is 4 DWs; workqueue buffer is 2 pages. So we
+ * should not have the case where structure wqi is across page, neither
+ * wrapped to the beginning. This simplifies the implementation below.
+ *
+ * XXX: if not the case, we need save data to a temp wqi and copy it to
+ * workqueue buffer dw by dw.
+ */
+ WARN_ON(sizeof(struct guc_wq_item) != 16);
+ WARN_ON(wq_off & 3);
+
+ /* wq starts from the page after doorbell / process_desc */
+ base = kmap_atomic(i915_gem_object_get_page(gc->client_obj,
+ (wq_off + GUC_DB_SIZE) >> PAGE_SHIFT));
+ wq_off &= PAGE_SIZE - 1;
+ wqi = (struct guc_wq_item *)((char *)base + wq_off);
+
+ /* len does not include the header */
+ wq_len = sizeof(struct guc_wq_item) / sizeof(u32) - 1;
+ wqi->header = WQ_TYPE_INORDER |
+ (wq_len << WQ_LEN_SHIFT) |
+ (ring_id << WQ_TARGET_SHIFT) |
+ WQ_NO_WCFLUSH_WAIT;
+
+ /* The GuC wants only the low-order word of the context descriptor */
+ wqi->context_desc = (u32)intel_lr_context_descriptor(rq->ctx, rq->ring);
+
+ /* The GuC firmware wants the tail index in QWords, not bytes */
+ tail = rq->ringbuf->tail >> 3;
+ wqi->ring_tail = tail << WQ_RING_TAIL_SHIFT;
+ wqi->fence_id = 0; /*XXX: what fence to be here */
+
+ kunmap_atomic(base);
+
+ return 0;
+}
+
+#define CTX_RING_BUFFER_START 0x08
+
+/* Update the ringbuffer pointer in a saved context image */
+static void lr_context_update(struct drm_i915_gem_request *rq)
+{
+ enum intel_ring_id ring_id = rq->ring->id;
+ struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring_id].state;
+ struct drm_i915_gem_object *rb_obj = rq->ringbuf->obj;
+ struct page *page;
+ uint32_t *reg_state;
+
+ BUG_ON(!ctx_obj);
+ WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
+ WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
+
+ page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
+ reg_state = kmap_atomic(page);
+
+ reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj);
+
+ kunmap_atomic(reg_state);
+}
+
+/**
+ * i915_guc_submit() - Submit commands through GuC
+ * @client: the guc client where commands will go through
+ * @ctx: LRC where commands come from
+ * @ring: HW engine that will excute the commands
+ *
+ * Return: 0 if succeed
+ */
+int i915_guc_submit(struct i915_guc_client *client,
+ struct drm_i915_gem_request *rq)
+{
+ struct intel_guc *guc = client->guc;
+ enum intel_ring_id ring_id = rq->ring->id;
+ unsigned long flags;
+ int q_ret, b_ret;
+
+ /* Need this because of the deferred pin ctx and ring */
+ /* Shall we move this right after ring is pinned? */
+ lr_context_update(rq);
+
+ spin_lock_irqsave(&client->wq_lock, flags);
+
+ q_ret = guc_add_workqueue_item(client, rq);
+ if (q_ret == 0)
+ b_ret = guc_ring_doorbell(client);
+
+ client->submissions[ring_id] += 1;
+ if (q_ret) {
+ client->q_fail += 1;
+ client->retcode = q_ret;
+ } else if (b_ret) {
+ client->b_fail += 1;
+ client->retcode = q_ret = b_ret;
+ } else {
+ client->retcode = 0;
+ }
+ spin_unlock_irqrestore(&client->wq_lock, flags);
+
+ spin_lock(&guc->host2guc_lock);
+ guc->submissions[ring_id] += 1;
+ guc->last_seqno[ring_id] = rq->seqno;
+ spin_unlock(&guc->host2guc_lock);
+
+ return q_ret;
+}
+
+/*
+ * Everything below here is concerned with setup & teardown, and is
+ * therefore not part of the somewhat time-critical batch-submission
+ * path of i915_guc_submit() above.
+ */
+
+/**
+ * gem_allocate_guc_obj() - Allocate gem object for GuC usage
+ * @dev: drm device
+ * @size: size of object
+ *
+ * This is a wrapper to create a gem obj. In order to use it inside GuC, the
+ * object needs to be pinned lifetime. Also we must pin it to gtt space other
+ * than [0, GUC_WOPCM_TOP) because this range is reserved inside GuC.
+ *
+ * Return: A drm_i915_gem_object if successful, otherwise NULL.
+ */
+static struct drm_i915_gem_object *gem_allocate_guc_obj(struct drm_device *dev,
+ u32 size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+
+ obj = i915_gem_alloc_object(dev, size);
+ if (!obj)
+ return NULL;
+
+ if (i915_gem_object_get_pages(obj)) {
+ drm_gem_object_unreference(&obj->base);
+ return NULL;
+ }
+
+ if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
+ PIN_OFFSET_BIAS | GUC_WOPCM_TOP)) {
+ drm_gem_object_unreference(&obj->base);
+ return NULL;
+ }
+
+ /* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
+ I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
+ return obj;
+}
+
+/**
+ * gem_release_guc_obj() - Release gem object allocated for GuC usage
+ * @obj: gem obj to be released
+ */
+static void gem_release_guc_obj(struct drm_i915_gem_object *obj)
+{
+ if (!obj)
+ return;
+
+ if (i915_gem_obj_is_pinned(obj))
+ i915_gem_object_ggtt_unpin(obj);
+
+ drm_gem_object_unreference(&obj->base);
+}
+
+static void guc_client_free(struct drm_device *dev,
+ struct i915_guc_client *client)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+
+ if (!client)
+ return;
+
+ if (client->doorbell_id != GUC_INVALID_DOORBELL_ID) {
+ /*
+ * First disable the doorbell, then tell the GuC we've
+ * finished with it, finally deallocate it in our bitmap
+ */
+ guc_disable_doorbell(guc, client);
+ host2guc_release_doorbell(guc, client);
+ release_doorbell(guc, client->doorbell_id);
+ }
+
+ /*
+ * XXX: wait for any outstanding submissions before freeing memory.
+ * Be sure to drop any locks
+ */
+
+ gem_release_guc_obj(client->client_obj);
+
+ if (client->ctx_index != GUC_INVALID_CTX_ID) {
+ guc_fini_ctx_desc(guc, client);
+ ida_simple_remove(&guc->ctx_ids, client->ctx_index);
+ }
+
+ kfree(client);
+}
+
+/**
+ * guc_client_alloc() - Allocate an i915_guc_client
+ * @dev: drm device
+ * @priority: four levels priority _CRITICAL, _HIGH, _NORMAL and _LOW
+ * The kernel client to replace ExecList submission is created with
+ * NORMAL priority. Priority of a client for scheduler can be HIGH,
+ * while a preemption context can use CRITICAL.
+ * @ctx the context to own the client (we use the default render context)
+ *
+ * Return: An i915_guc_client object if success.
+ */
+static struct i915_guc_client *guc_client_alloc(struct drm_device *dev,
+ uint32_t priority,
+ struct intel_context *ctx)
+{
+ struct i915_guc_client *client;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+ struct drm_i915_gem_object *obj;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return NULL;
+
+ client->doorbell_id = GUC_INVALID_DOORBELL_ID;
+ client->priority = priority;
+ client->owner = ctx;
+ client->guc = guc;
+
+ client->ctx_index = (uint32_t)ida_simple_get(&guc->ctx_ids, 0,
+ GUC_MAX_GPU_CONTEXTS, GFP_KERNEL);
+ if (client->ctx_index >= GUC_MAX_GPU_CONTEXTS) {
+ client->ctx_index = GUC_INVALID_CTX_ID;
+ goto err;
+ }
+
+ /* The first page is doorbell/proc_desc. Two followed pages are wq. */
+ obj = gem_allocate_guc_obj(dev, GUC_DB_SIZE + GUC_WQ_SIZE);
+ if (!obj)
+ goto err;
+
+ client->client_obj = obj;
+ client->wq_offset = GUC_DB_SIZE;
+ client->wq_size = GUC_WQ_SIZE;
+ spin_lock_init(&client->wq_lock);
+
+ client->doorbell_offset = select_doorbell_cacheline(guc);
+
+ /*
+ * Since the doorbell only requires a single cacheline, we can save
+ * space by putting the application process descriptor in the same
+ * page. Use the half of the page that doesn't include the doorbell.
+ */
+ if (client->doorbell_offset >= (GUC_DB_SIZE / 2))
+ client->proc_desc_offset = 0;
+ else
+ client->proc_desc_offset = (GUC_DB_SIZE / 2);
+
+ client->doorbell_id = assign_doorbell(guc, client->priority);
+ if (client->doorbell_id == GUC_INVALID_DOORBELL_ID)
+ /* XXX: evict a doorbell instead */
+ goto err;
+
+ guc_init_proc_desc(guc, client);
+ guc_init_ctx_desc(guc, client);
+ guc_init_doorbell(guc, client);
+
+ /* XXX: Any cache flushes needed? General domain mgmt calls? */
+
+ if (host2guc_allocate_doorbell(guc, client))
+ goto err;
+
+ DRM_DEBUG_DRIVER("new priority %u client %p: ctx_index %u db_id %u\n",
+ priority, client, client->ctx_index, client->doorbell_id);
+
+ return client;
+
+err:
+ DRM_ERROR("FAILED to create priority %u GuC client!\n", priority);
+
+ guc_client_free(dev, client);
+ return NULL;
+}
+
+static void guc_create_log(struct intel_guc *guc)
+{
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+ struct drm_i915_gem_object *obj;
+ unsigned long offset;
+ uint32_t size, flags;
+
+ if (i915.guc_log_level < GUC_LOG_VERBOSITY_MIN)
+ return;
+
+ if (i915.guc_log_level > GUC_LOG_VERBOSITY_MAX)
+ i915.guc_log_level = GUC_LOG_VERBOSITY_MAX;
+
+ /* The first page is to save log buffer state. Allocate one
+ * extra page for others in case for overlap */
+ size = (1 + GUC_LOG_DPC_PAGES + 1 +
+ GUC_LOG_ISR_PAGES + 1 +
+ GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT;
+
+ obj = guc->log_obj;
+ if (!obj) {
+ obj = gem_allocate_guc_obj(dev_priv->dev, size);
+ if (!obj) {
+ /* logging will be off */
+ i915.guc_log_level = -1;
+ return;
+ }
+
+ guc->log_obj = obj;
+ }
+
+ /* each allocated unit is a page */
+ flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL |
+ (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) |
+ (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) |
+ (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT);
+
+ offset = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */
+ guc->log_flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
+}
+
+/*
+ * Set up the memory resources to be shared with the GuC. At this point,
+ * we require just one object that can be mapped through the GGTT.
+ */
+int i915_guc_submission_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const size_t ctxsize = sizeof(struct guc_context_desc);
+ const size_t poolsize = GUC_MAX_GPU_CONTEXTS * ctxsize;
+ const size_t gemsize = round_up(poolsize, PAGE_SIZE);
+ struct intel_guc *guc = &dev_priv->guc;
+
+ if (!i915.enable_guc_submission)
+ return 0; /* not enabled */
+
+ if (guc->ctx_pool_obj)
+ return 0; /* already allocated */
+
+ guc->ctx_pool_obj = gem_allocate_guc_obj(dev_priv->dev, gemsize);
+ if (!guc->ctx_pool_obj)
+ return -ENOMEM;
+
+ spin_lock_init(&dev_priv->guc.host2guc_lock);
+
+ ida_init(&guc->ctx_ids);
+
+ guc_create_log(guc);
+
+ return 0;
+}
+
+int i915_guc_submission_enable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+ struct intel_context *ctx = dev_priv->ring[RCS].default_context;
+ struct i915_guc_client *client;
+
+ /* client for execbuf submission */
+ client = guc_client_alloc(dev, GUC_CTX_PRIORITY_KMD_NORMAL, ctx);
+ if (!client) {
+ DRM_ERROR("Failed to create execbuf guc_client\n");
+ return -ENOMEM;
+ }
+
+ guc->execbuf_client = client;
+
+ host2guc_sample_forcewake(guc, client);
+
+ return 0;
+}
+
+void i915_guc_submission_disable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+
+ guc_client_free(dev, guc->execbuf_client);
+ guc->execbuf_client = NULL;
+}
+
+void i915_guc_submission_fini(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+
+ gem_release_guc_obj(dev_priv->guc.log_obj);
+ guc->log_obj = NULL;
+
+ if (guc->ctx_pool_obj)
+ ida_destroy(&guc->ctx_ids);
+ gem_release_guc_obj(guc->ctx_pool_obj);
+ guc->ctx_pool_obj = NULL;
+}
+
+/**
+ * intel_guc_suspend() - notify GuC entering suspend state
+ * @dev: drm device
+ */
+int intel_guc_suspend(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+ struct intel_context *ctx;
+ u32 data[3];
+
+ if (!i915.enable_guc_submission)
+ return 0;
+
+ ctx = dev_priv->ring[RCS].default_context;
+
+ data[0] = HOST2GUC_ACTION_ENTER_S_STATE;
+ /* any value greater than GUC_POWER_D0 */
+ data[1] = GUC_POWER_D1;
+ /* first page is shared data with GuC */
+ data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state);
+
+ return host2guc_action(guc, data, ARRAY_SIZE(data));
+}
+
+
+/**
+ * intel_guc_resume() - notify GuC resuming from suspend state
+ * @dev: drm device
+ */
+int intel_guc_resume(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc *guc = &dev_priv->guc;
+ struct intel_context *ctx;
+ u32 data[3];
+
+ if (!i915.enable_guc_submission)
+ return 0;
+
+ ctx = dev_priv->ring[RCS].default_context;
+
+ data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
+ data[1] = GUC_POWER_D0;
+ /* first page is shared data with GuC */
+ data[2] = i915_gem_obj_ggtt_offset(ctx->engine[RCS].state);
+
+ return host2guc_action(guc, data, ARRAY_SIZE(data));
+}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 39d73dbc1c47..0d228f909dcb 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -45,6 +45,18 @@
* and related files, but that will be described in separate chapters.
*/
+static const u32 hpd_ilk[HPD_NUM_PINS] = {
+ [HPD_PORT_A] = DE_DP_A_HOTPLUG,
+};
+
+static const u32 hpd_ivb[HPD_NUM_PINS] = {
+ [HPD_PORT_A] = DE_DP_A_HOTPLUG_IVB,
+};
+
+static const u32 hpd_bdw[HPD_NUM_PINS] = {
+ [HPD_PORT_A] = GEN8_PORT_DP_A_HOTPLUG,
+};
+
static const u32 hpd_ibx[HPD_NUM_PINS] = {
[HPD_CRT] = SDE_CRT_HOTPLUG,
[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
@@ -62,6 +74,7 @@ static const u32 hpd_cpt[HPD_NUM_PINS] = {
};
static const u32 hpd_spt[HPD_NUM_PINS] = {
+ [HPD_PORT_A] = SDE_PORTA_HOTPLUG_SPT,
[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
[HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT,
[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT,
@@ -97,6 +110,7 @@ static const u32 hpd_status_i915[HPD_NUM_PINS] = {
/* BXT hpd list */
static const u32 hpd_bxt[HPD_NUM_PINS] = {
+ [HPD_PORT_A] = BXT_DE_PORT_HP_DDIA,
[HPD_PORT_B] = BXT_DE_PORT_HP_DDIB,
[HPD_PORT_C] = BXT_DE_PORT_HP_DDIC
};
@@ -125,27 +139,30 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
/*
* We should clear IMR at preinstall/uninstall, and just check at postinstall.
*/
-#define GEN5_ASSERT_IIR_IS_ZERO(reg) do { \
- u32 val = I915_READ(reg); \
- if (val) { \
- WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", \
- (reg), val); \
- I915_WRITE((reg), 0xffffffff); \
- POSTING_READ(reg); \
- I915_WRITE((reg), 0xffffffff); \
- POSTING_READ(reg); \
- } \
-} while (0)
+static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg)
+{
+ u32 val = I915_READ(reg);
+
+ if (val == 0)
+ return;
+
+ WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n",
+ reg, val);
+ I915_WRITE(reg, 0xffffffff);
+ POSTING_READ(reg);
+ I915_WRITE(reg, 0xffffffff);
+ POSTING_READ(reg);
+}
#define GEN8_IRQ_INIT_NDX(type, which, imr_val, ier_val) do { \
- GEN5_ASSERT_IIR_IS_ZERO(GEN8_##type##_IIR(which)); \
+ gen5_assert_iir_is_zero(dev_priv, GEN8_##type##_IIR(which)); \
I915_WRITE(GEN8_##type##_IER(which), (ier_val)); \
I915_WRITE(GEN8_##type##_IMR(which), (imr_val)); \
POSTING_READ(GEN8_##type##_IMR(which)); \
} while (0)
#define GEN5_IRQ_INIT(type, imr_val, ier_val) do { \
- GEN5_ASSERT_IIR_IS_ZERO(type##IIR); \
+ gen5_assert_iir_is_zero(dev_priv, type##IIR); \
I915_WRITE(type##IER, (ier_val)); \
I915_WRITE(type##IMR, (imr_val)); \
POSTING_READ(type##IMR); \
@@ -154,36 +171,85 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = {
static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir);
/* For display hotplug interrupt */
-void
-ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
+static inline void
+i915_hotplug_interrupt_update_locked(struct drm_i915_private *dev_priv,
+ uint32_t mask,
+ uint32_t bits)
{
+ uint32_t val;
+
assert_spin_locked(&dev_priv->irq_lock);
+ WARN_ON(bits & ~mask);
- if (WARN_ON(!intel_irqs_enabled(dev_priv)))
- return;
+ val = I915_READ(PORT_HOTPLUG_EN);
+ val &= ~mask;
+ val |= bits;
+ I915_WRITE(PORT_HOTPLUG_EN, val);
+}
- if ((dev_priv->irq_mask & mask) != 0) {
- dev_priv->irq_mask &= ~mask;
- I915_WRITE(DEIMR, dev_priv->irq_mask);
- POSTING_READ(DEIMR);
- }
+/**
+ * i915_hotplug_interrupt_update - update hotplug interrupt enable
+ * @dev_priv: driver private
+ * @mask: bits to update
+ * @bits: bits to enable
+ * NOTE: the HPD enable bits are modified both inside and outside
+ * of an interrupt context. To avoid that read-modify-write cycles
+ * interfer, these bits are protected by a spinlock. Since this
+ * function is usually not called from a context where the lock is
+ * held already, this function acquires the lock itself. A non-locking
+ * version is also available.
+ */
+void i915_hotplug_interrupt_update(struct drm_i915_private *dev_priv,
+ uint32_t mask,
+ uint32_t bits)
+{
+ spin_lock_irq(&dev_priv->irq_lock);
+ i915_hotplug_interrupt_update_locked(dev_priv, mask, bits);
+ spin_unlock_irq(&dev_priv->irq_lock);
}
-void
-ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
+/**
+ * ilk_update_display_irq - update DEIMR
+ * @dev_priv: driver private
+ * @interrupt_mask: mask of interrupt bits to update
+ * @enabled_irq_mask: mask of interrupt bits to enable
+ */
+static void ilk_update_display_irq(struct drm_i915_private *dev_priv,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask)
{
+ uint32_t new_val;
+
assert_spin_locked(&dev_priv->irq_lock);
+ WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
if (WARN_ON(!intel_irqs_enabled(dev_priv)))
return;
- if ((dev_priv->irq_mask & mask) != mask) {
- dev_priv->irq_mask |= mask;
+ new_val = dev_priv->irq_mask;
+ new_val &= ~interrupt_mask;
+ new_val |= (~enabled_irq_mask & interrupt_mask);
+
+ if (new_val != dev_priv->irq_mask) {
+ dev_priv->irq_mask = new_val;
I915_WRITE(DEIMR, dev_priv->irq_mask);
POSTING_READ(DEIMR);
}
}
+void
+ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
+{
+ ilk_update_display_irq(dev_priv, mask, mask);
+}
+
+void
+ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
+{
+ ilk_update_display_irq(dev_priv, mask, 0);
+}
+
/**
* ilk_update_gt_irq - update GTIMR
* @dev_priv: driver private
@@ -351,6 +417,38 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
}
/**
+ * bdw_update_port_irq - update DE port interrupt
+ * @dev_priv: driver private
+ * @interrupt_mask: mask of interrupt bits to update
+ * @enabled_irq_mask: mask of interrupt bits to enable
+ */
+static void bdw_update_port_irq(struct drm_i915_private *dev_priv,
+ uint32_t interrupt_mask,
+ uint32_t enabled_irq_mask)
+{
+ uint32_t new_val;
+ uint32_t old_val;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
+ if (WARN_ON(!intel_irqs_enabled(dev_priv)))
+ return;
+
+ old_val = I915_READ(GEN8_DE_PORT_IMR);
+
+ new_val = old_val;
+ new_val &= ~interrupt_mask;
+ new_val |= (~enabled_irq_mask & interrupt_mask);
+
+ if (new_val != old_val) {
+ I915_WRITE(GEN8_DE_PORT_IMR, new_val);
+ POSTING_READ(GEN8_DE_PORT_IMR);
+ }
+}
+
+/**
* ibx_display_interrupt_update - update SDEIMR
* @dev_priv: driver private
* @interrupt_mask: mask of interrupt bits to update
@@ -486,6 +584,7 @@ i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
/**
* i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
+ * @dev: drm device
*/
static void i915_enable_asle_pipestat(struct drm_device *dev)
{
@@ -554,7 +653,7 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
* of horizontal active on the first line of vertical active
*/
-static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 i8xx_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
/* Gen2 doesn't have a hardware frame counter */
return 0;
@@ -563,7 +662,7 @@ static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
/* Called from drm generic code, passed a 'crtc', which
* we use as a pipe index
*/
-static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long high_frame;
@@ -611,12 +710,11 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
}
-static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
+static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int reg = PIPE_FRMCOUNT_GM45(pipe);
- return I915_READ(reg);
+ return I915_READ(PIPE_FRMCOUNT_G4X(pipe));
}
/* raw reads, only for fast reads of display block, no need for forcewake etc. */
@@ -651,7 +749,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
* problem. We may need to extend this to include other platforms,
* but so far testing only shows the problem on HSW.
*/
- if (IS_HASWELL(dev) && !position) {
+ if (HAS_DDI(dev) && !position) {
int i, temp;
for (i = 0; i < 100; i++) {
@@ -672,14 +770,14 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
return (position + crtc->scanline_offset) % vtotal;
}
-static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
+static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
unsigned int flags, int *vpos, int *hpos,
- ktime_t *stime, ktime_t *etime)
+ ktime_t *stime, ktime_t *etime,
+ const struct drm_display_mode *mode)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- const struct drm_display_mode *mode = &intel_crtc->base.hwmode;
int position;
int vbl_start, vbl_end, hsync_start, htotal, vtotal;
bool in_vbl = true;
@@ -809,34 +907,33 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc)
return position;
}
-static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
+static int i915_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct drm_crtc *crtc;
- if (pipe < 0 || pipe >= INTEL_INFO(dev)->num_pipes) {
- DRM_ERROR("Invalid crtc %d\n", pipe);
+ if (pipe >= INTEL_INFO(dev)->num_pipes) {
+ DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
/* Get drm_crtc to timestamp: */
crtc = intel_get_crtc_for_pipe(dev, pipe);
if (crtc == NULL) {
- DRM_ERROR("Invalid crtc %d\n", pipe);
+ DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
if (!crtc->hwmode.crtc_clock) {
- DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
+ DRM_DEBUG_KMS("crtc %u is disabled\n", pipe);
return -EBUSY;
}
/* Helper routine in DRM core does all the work: */
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
vblank_time, flags,
- crtc,
&crtc->hwmode);
}
@@ -903,12 +1000,16 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv,
int threshold)
{
u64 time, c0;
+ unsigned int mul = 100;
if (old->cz_clock == 0)
return false;
+ if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
+ mul <<= 8;
+
time = now->cz_clock - old->cz_clock;
- time *= threshold * dev_priv->mem_freq;
+ time *= threshold * dev_priv->czclk_freq;
/* Workload can be split between render + media, e.g. SwapBuffers
* being blitted in X after being rendered in mesa. To account for
@@ -916,7 +1017,7 @@ static bool vlv_c0_above(struct drm_i915_private *dev_priv,
*/
c0 = now->render_c0 - old->render_c0;
c0 += now->media_c0 - old->media_c0;
- c0 *= 100 * VLV_CZ_CLOCK_TO_MILLI_SEC * 4 / 1000;
+ c0 *= mul * VLV_CZ_CLOCK_TO_MILLI_SEC;
return c0 >= time;
}
@@ -1264,7 +1365,31 @@ static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
{
switch (port) {
case PORT_A:
- return val & BXT_PORTA_HOTPLUG_LONG_DETECT;
+ return val & PORTA_HOTPLUG_LONG_DETECT;
+ case PORT_B:
+ return val & PORTB_HOTPLUG_LONG_DETECT;
+ case PORT_C:
+ return val & PORTC_HOTPLUG_LONG_DETECT;
+ default:
+ return false;
+ }
+}
+
+static bool spt_port_hotplug2_long_detect(enum port port, u32 val)
+{
+ switch (port) {
+ case PORT_E:
+ return val & PORTE_HOTPLUG_LONG_DETECT;
+ default:
+ return false;
+ }
+}
+
+static bool spt_port_hotplug_long_detect(enum port port, u32 val)
+{
+ switch (port) {
+ case PORT_A:
+ return val & PORTA_HOTPLUG_LONG_DETECT;
case PORT_B:
return val & PORTB_HOTPLUG_LONG_DETECT;
case PORT_C:
@@ -1276,6 +1401,16 @@ static bool bxt_port_hotplug_long_detect(enum port port, u32 val)
}
}
+static bool ilk_port_hotplug_long_detect(enum port port, u32 val)
+{
+ switch (port) {
+ case PORT_A:
+ return val & DIGITAL_PORTA_HOTPLUG_LONG_DETECT;
+ default:
+ return false;
+ }
+}
+
static bool pch_port_hotplug_long_detect(enum port port, u32 val)
{
switch (port) {
@@ -1285,8 +1420,6 @@ static bool pch_port_hotplug_long_detect(enum port port, u32 val)
return val & PORTC_HOTPLUG_LONG_DETECT;
case PORT_D:
return val & PORTD_HOTPLUG_LONG_DETECT;
- case PORT_E:
- return val & PORTE_HOTPLUG_LONG_DETECT;
default:
return false;
}
@@ -1306,7 +1439,13 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val)
}
}
-/* Get a bit mask of pins that have triggered, and which ones may be long. */
+/*
+ * Get a bit mask of pins that have triggered, and which ones may be long.
+ * This can be called multiple times with the same masks to accumulate
+ * hotplug detection results from several registers.
+ *
+ * Note that the caller is expected to zero out the masks initially.
+ */
static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
u32 hotplug_trigger, u32 dig_hotplug_reg,
const u32 hpd[HPD_NUM_PINS],
@@ -1315,9 +1454,6 @@ static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask,
enum port port;
int i;
- *pin_mask = 0;
- *long_mask = 0;
-
for_each_hpd_pin(i) {
if ((hpd[i] & hotplug_trigger) == 0)
continue;
@@ -1558,7 +1694,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
- u32 pin_mask, long_mask;
+ u32 pin_mask = 0, long_mask = 0;
if (!hotplug_status)
return;
@@ -1573,20 +1709,25 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev)
if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X;
- intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
- hotplug_trigger, hpd_status_g4x,
- i9xx_port_hotplug_long_detect);
- intel_hpd_irq_handler(dev, pin_mask, long_mask);
+ if (hotplug_trigger) {
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+ hotplug_trigger, hpd_status_g4x,
+ i9xx_port_hotplug_long_detect);
+
+ intel_hpd_irq_handler(dev, pin_mask, long_mask);
+ }
if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
dp_aux_irq_handler(dev);
} else {
u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
- intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
- hotplug_trigger, hpd_status_i915,
- i9xx_port_hotplug_long_detect);
- intel_hpd_irq_handler(dev, pin_mask, long_mask);
+ if (hotplug_trigger) {
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+ hotplug_trigger, hpd_status_i915,
+ i9xx_port_hotplug_long_detect);
+ intel_hpd_irq_handler(dev, pin_mask, long_mask);
+ }
}
}
@@ -1680,23 +1821,30 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
return ret;
}
+static void ibx_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
+ const u32 hpd[HPD_NUM_PINS])
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
+
+ dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
+ I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
+
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+ dig_hotplug_reg, hpd,
+ pch_port_hotplug_long_detect);
+
+ intel_hpd_irq_handler(dev, pin_mask, long_mask);
+}
+
static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
- if (hotplug_trigger) {
- u32 dig_hotplug_reg, pin_mask, long_mask;
-
- dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
- I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
-
- intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
- dig_hotplug_reg, hpd_ibx,
- pch_port_hotplug_long_detect);
- intel_hpd_irq_handler(dev, pin_mask, long_mask);
- }
+ if (hotplug_trigger)
+ ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
if (pch_iir & SDE_AUDIO_POWER_MASK) {
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
@@ -1787,38 +1935,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe;
- u32 hotplug_trigger;
+ u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
- if (HAS_PCH_SPT(dev))
- hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT;
- else
- hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
-
- if (hotplug_trigger) {
- u32 dig_hotplug_reg, pin_mask, long_mask;
-
- dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
- I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
-
- if (HAS_PCH_SPT(dev)) {
- intel_get_hpd_pins(&pin_mask, &long_mask,
- hotplug_trigger,
- dig_hotplug_reg, hpd_spt,
- pch_port_hotplug_long_detect);
-
- /* detect PORTE HP event */
- dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
- if (pch_port_hotplug_long_detect(PORT_E,
- dig_hotplug_reg))
- long_mask |= 1 << HPD_PORT_E;
- } else
- intel_get_hpd_pins(&pin_mask, &long_mask,
- hotplug_trigger,
- dig_hotplug_reg, hpd_cpt,
- pch_port_hotplug_long_detect);
-
- intel_hpd_irq_handler(dev, pin_mask, long_mask);
- }
+ if (hotplug_trigger)
+ ibx_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
@@ -1849,10 +1969,67 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
cpt_serr_int_handler(dev);
}
+static void spt_irq_handler(struct drm_device *dev, u32 pch_iir)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT &
+ ~SDE_PORTE_HOTPLUG_SPT;
+ u32 hotplug2_trigger = pch_iir & SDE_PORTE_HOTPLUG_SPT;
+ u32 pin_mask = 0, long_mask = 0;
+
+ if (hotplug_trigger) {
+ u32 dig_hotplug_reg;
+
+ dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
+ I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
+
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+ dig_hotplug_reg, hpd_spt,
+ spt_port_hotplug_long_detect);
+ }
+
+ if (hotplug2_trigger) {
+ u32 dig_hotplug_reg;
+
+ dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2);
+ I915_WRITE(PCH_PORT_HOTPLUG2, dig_hotplug_reg);
+
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug2_trigger,
+ dig_hotplug_reg, hpd_spt,
+ spt_port_hotplug2_long_detect);
+ }
+
+ if (pin_mask)
+ intel_hpd_irq_handler(dev, pin_mask, long_mask);
+
+ if (pch_iir & SDE_GMBUS_CPT)
+ gmbus_irq_handler(dev);
+}
+
+static void ilk_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
+ const u32 hpd[HPD_NUM_PINS])
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
+
+ dig_hotplug_reg = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
+ I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, dig_hotplug_reg);
+
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+ dig_hotplug_reg, hpd,
+ ilk_port_hotplug_long_detect);
+
+ intel_hpd_irq_handler(dev, pin_mask, long_mask);
+}
+
static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
{
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe;
+ u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG;
+
+ if (hotplug_trigger)
+ ilk_hpd_irq_handler(dev, hotplug_trigger, hpd_ilk);
if (de_iir & DE_AUX_CHANNEL_A)
dp_aux_irq_handler(dev);
@@ -1902,6 +2079,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
{
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe;
+ u32 hotplug_trigger = de_iir & DE_DP_A_HOTPLUG_IVB;
+
+ if (hotplug_trigger)
+ ilk_hpd_irq_handler(dev, hotplug_trigger, hpd_ivb);
if (de_iir & DE_ERR_INT_IVB)
ivb_err_int_handler(dev);
@@ -2014,27 +2195,19 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
return ret;
}
-static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status)
+static void bxt_hpd_irq_handler(struct drm_device *dev, u32 hotplug_trigger,
+ const u32 hpd[HPD_NUM_PINS])
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 hp_control, hp_trigger;
- u32 pin_mask, long_mask;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ u32 dig_hotplug_reg, pin_mask = 0, long_mask = 0;
- /* Get the status */
- hp_trigger = iir_status & BXT_DE_PORT_HOTPLUG_MASK;
- hp_control = I915_READ(BXT_HOTPLUG_CTL);
+ dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG);
+ I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg);
- /* Hotplug not enabled ? */
- if (!(hp_control & BXT_HOTPLUG_CTL_MASK)) {
- DRM_ERROR("Interrupt when HPD disabled\n");
- return;
- }
+ intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger,
+ dig_hotplug_reg, hpd,
+ bxt_port_hotplug_long_detect);
- /* Clear sticky bits in hpd status */
- I915_WRITE(BXT_HOTPLUG_CTL, hp_control);
-
- intel_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control,
- hpd_bxt, bxt_port_hotplug_long_detect);
intel_hpd_irq_handler(dev, pin_mask, long_mask);
}
@@ -2051,7 +2224,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
if (!intel_irqs_enabled(dev_priv))
return IRQ_NONE;
- if (IS_GEN9(dev))
+ if (INTEL_INFO(dev_priv)->gen >= 9)
aux_mask |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
GEN9_AUX_CHANNEL_D;
@@ -2084,6 +2257,12 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
tmp = I915_READ(GEN8_DE_PORT_IIR);
if (tmp) {
bool found = false;
+ u32 hotplug_trigger = 0;
+
+ if (IS_BROXTON(dev_priv))
+ hotplug_trigger = tmp & BXT_DE_PORT_HOTPLUG_MASK;
+ else if (IS_BROADWELL(dev_priv))
+ hotplug_trigger = tmp & GEN8_PORT_DP_A_HOTPLUG;
I915_WRITE(GEN8_DE_PORT_IIR, tmp);
ret = IRQ_HANDLED;
@@ -2093,8 +2272,11 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
found = true;
}
- if (IS_BROXTON(dev) && tmp & BXT_DE_PORT_HOTPLUG_MASK) {
- bxt_hpd_handler(dev, tmp);
+ if (hotplug_trigger) {
+ if (IS_BROXTON(dev))
+ bxt_hpd_irq_handler(dev, hotplug_trigger, hpd_bxt);
+ else
+ ilk_hpd_irq_handler(dev, hotplug_trigger, hpd_bdw);
found = true;
}
@@ -2125,7 +2307,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
intel_pipe_handle_vblank(dev, pipe))
intel_check_page_flip(dev, pipe);
- if (IS_GEN9(dev))
+ if (INTEL_INFO(dev_priv)->gen >= 9)
flip_done = pipe_iir & GEN9_PIPE_PLANE1_FLIP_DONE;
else
flip_done = pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE;
@@ -2143,7 +2325,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
pipe);
- if (IS_GEN9(dev))
+ if (INTEL_INFO(dev_priv)->gen >= 9)
fault_errors = pipe_iir & GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
else
fault_errors = pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
@@ -2167,7 +2349,11 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
if (pch_iir) {
I915_WRITE(SDEIIR, pch_iir);
ret = IRQ_HANDLED;
- cpt_irq_handler(dev, pch_iir);
+
+ if (HAS_PCH_SPT(dev_priv))
+ spt_irq_handler(dev, pch_iir);
+ else
+ cpt_irq_handler(dev, pch_iir);
} else
DRM_ERROR("The master control interrupt lied (SDE)!\n");
@@ -2209,6 +2395,7 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
/**
* i915_reset_and_wakeup - do process context error handling work
+ * @dev: drm device
*
* Fire an error uevent so userspace can see that a hang or error
* was detected.
@@ -2386,7 +2573,7 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
* i915_handle_error - handle a gpu error
* @dev: drm device
*
- * Do some basic checking of regsiter state at error time and
+ * Do some basic checking of register state at error time and
* dump it to the syslog. Also call i915_capture_error_state() to make
* sure we get a record and make it available in debugfs. Fire a uevent
* so userspace knows something bad happened (should trigger collection
@@ -2432,7 +2619,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
-static int i915_enable_vblank(struct drm_device *dev, int pipe)
+static int i915_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2449,7 +2636,7 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
return 0;
}
-static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
+static int ironlake_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2463,7 +2650,7 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
return 0;
}
-static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
+static int valleyview_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2476,7 +2663,7 @@ static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
return 0;
}
-static int gen8_enable_vblank(struct drm_device *dev, int pipe)
+static int gen8_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2492,7 +2679,7 @@ static int gen8_enable_vblank(struct drm_device *dev, int pipe)
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
-static void i915_disable_vblank(struct drm_device *dev, int pipe)
+static void i915_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2504,7 +2691,7 @@ static void i915_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
+static void ironlake_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2516,7 +2703,7 @@ static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
+static void valleyview_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2527,7 +2714,7 @@ static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-static void gen8_disable_vblank(struct drm_device *dev, int pipe)
+static void gen8_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
@@ -2599,6 +2786,26 @@ semaphore_waits_for(struct intel_engine_cs *ring, u32 *seqno)
u64 offset = 0;
int i, backwards;
+ /*
+ * This function does not support execlist mode - any attempt to
+ * proceed further into this function will result in a kernel panic
+ * when dereferencing ring->buffer, which is not set up in execlist
+ * mode.
+ *
+ * The correct way of doing it would be to derive the currently
+ * executing ring buffer from the current context, which is derived
+ * from the currently running request. Unfortunately, to get the
+ * current request we would have to grab the struct_mutex before doing
+ * anything else, which would be ill-advised since some other thread
+ * might have grabbed it already and managed to hang itself, causing
+ * the hang checker to deadlock.
+ *
+ * Therefore, this function does not support execlist mode in its
+ * current form. Just return NULL and move on.
+ */
+ if (ring->buffer == NULL)
+ return NULL;
+
ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
if (!ipehr_is_semaphore_wait(ring->dev, ipehr))
return NULL;
@@ -2933,7 +3140,7 @@ static void vlv_display_irq_reset(struct drm_i915_private *dev_priv)
{
enum pipe pipe;
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xFFFFFFFF, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
for_each_pipe(dev_priv, pipe)
@@ -3027,86 +3234,124 @@ static void cherryview_irq_preinstall(struct drm_device *dev)
vlv_display_irq_reset(dev_priv);
}
+static u32 intel_hpd_enabled_irqs(struct drm_device *dev,
+ const u32 hpd[HPD_NUM_PINS])
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_encoder *encoder;
+ u32 enabled_irqs = 0;
+
+ for_each_intel_encoder(dev, encoder)
+ if (dev_priv->hotplug.stats[encoder->hpd_pin].state == HPD_ENABLED)
+ enabled_irqs |= hpd[encoder->hpd_pin];
+
+ return enabled_irqs;
+}
+
static void ibx_hpd_irq_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *intel_encoder;
- u32 hotplug_irqs, hotplug, enabled_irqs = 0;
+ u32 hotplug_irqs, hotplug, enabled_irqs;
if (HAS_PCH_IBX(dev)) {
hotplug_irqs = SDE_HOTPLUG_MASK;
- for_each_intel_encoder(dev, intel_encoder)
- if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED)
- enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin];
- } else if (HAS_PCH_SPT(dev)) {
- hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
- for_each_intel_encoder(dev, intel_encoder)
- if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED)
- enabled_irqs |= hpd_spt[intel_encoder->hpd_pin];
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_ibx);
} else {
hotplug_irqs = SDE_HOTPLUG_MASK_CPT;
- for_each_intel_encoder(dev, intel_encoder)
- if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED)
- enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin];
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_cpt);
}
ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
/*
* Enable digital hotplug on the PCH, and configure the DP short pulse
- * duration to 2ms (which is the minimum in the Display Port spec)
- *
- * This register is the same on all known PCH chips.
+ * duration to 2ms (which is the minimum in the Display Port spec).
+ * The pulse duration bits are reserved on LPT+.
*/
hotplug = I915_READ(PCH_PORT_HOTPLUG);
hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
+ /*
+ * When CPU and PCH are on the same package, port A
+ * HPD must be enabled in both north and south.
+ */
+ if (HAS_PCH_LPT_LP(dev))
+ hotplug |= PORTA_HOTPLUG_ENABLE;
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
+}
- /* enable SPT PORTE hot plug */
- if (HAS_PCH_SPT(dev)) {
- hotplug = I915_READ(PCH_PORT_HOTPLUG2);
- hotplug |= PORTE_HOTPLUG_ENABLE;
- I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
- }
+static void spt_hpd_irq_setup(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 hotplug_irqs, hotplug, enabled_irqs;
+
+ hotplug_irqs = SDE_HOTPLUG_MASK_SPT;
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_spt);
+
+ ibx_display_interrupt_update(dev_priv, hotplug_irqs, enabled_irqs);
+
+ /* Enable digital hotplug on the PCH */
+ hotplug = I915_READ(PCH_PORT_HOTPLUG);
+ hotplug |= PORTD_HOTPLUG_ENABLE | PORTC_HOTPLUG_ENABLE |
+ PORTB_HOTPLUG_ENABLE | PORTA_HOTPLUG_ENABLE;
+ I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
+
+ hotplug = I915_READ(PCH_PORT_HOTPLUG2);
+ hotplug |= PORTE_HOTPLUG_ENABLE;
+ I915_WRITE(PCH_PORT_HOTPLUG2, hotplug);
}
-static void bxt_hpd_irq_setup(struct drm_device *dev)
+static void ilk_hpd_irq_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *intel_encoder;
- u32 hotplug_port = 0;
- u32 hotplug_ctrl;
-
- /* Now, enable HPD */
- for_each_intel_encoder(dev, intel_encoder) {
- if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state
- == HPD_ENABLED)
- hotplug_port |= hpd_bxt[intel_encoder->hpd_pin];
+ u32 hotplug_irqs, hotplug, enabled_irqs;
+
+ if (INTEL_INFO(dev)->gen >= 8) {
+ hotplug_irqs = GEN8_PORT_DP_A_HOTPLUG;
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_bdw);
+
+ bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
+ } else if (INTEL_INFO(dev)->gen >= 7) {
+ hotplug_irqs = DE_DP_A_HOTPLUG_IVB;
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_ivb);
+
+ ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
+ } else {
+ hotplug_irqs = DE_DP_A_HOTPLUG;
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_ilk);
+
+ ilk_update_display_irq(dev_priv, hotplug_irqs, enabled_irqs);
}
- /* Mask all HPD control bits */
- hotplug_ctrl = I915_READ(BXT_HOTPLUG_CTL) & ~BXT_HOTPLUG_CTL_MASK;
+ /*
+ * Enable digital hotplug on the CPU, and configure the DP short pulse
+ * duration to 2ms (which is the minimum in the Display Port spec)
+ * The pulse duration bits are reserved on HSW+.
+ */
+ hotplug = I915_READ(DIGITAL_PORT_HOTPLUG_CNTRL);
+ hotplug &= ~DIGITAL_PORTA_PULSE_DURATION_MASK;
+ hotplug |= DIGITAL_PORTA_HOTPLUG_ENABLE | DIGITAL_PORTA_PULSE_DURATION_2ms;
+ I915_WRITE(DIGITAL_PORT_HOTPLUG_CNTRL, hotplug);
+
+ ibx_hpd_irq_setup(dev);
+}
+
+static void bxt_hpd_irq_setup(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 hotplug_irqs, hotplug, enabled_irqs;
- /* Enable requested port in hotplug control */
- /* TODO: implement (short) HPD support on port A */
- WARN_ON_ONCE(hotplug_port & BXT_DE_PORT_HP_DDIA);
- if (hotplug_port & BXT_DE_PORT_HP_DDIB)
- hotplug_ctrl |= BXT_DDIB_HPD_ENABLE;
- if (hotplug_port & BXT_DE_PORT_HP_DDIC)
- hotplug_ctrl |= BXT_DDIC_HPD_ENABLE;
- I915_WRITE(BXT_HOTPLUG_CTL, hotplug_ctrl);
+ enabled_irqs = intel_hpd_enabled_irqs(dev, hpd_bxt);
+ hotplug_irqs = BXT_DE_PORT_HOTPLUG_MASK;
- /* Unmask DDI hotplug in IMR */
- hotplug_ctrl = I915_READ(GEN8_DE_PORT_IMR) & ~hotplug_port;
- I915_WRITE(GEN8_DE_PORT_IMR, hotplug_ctrl);
+ bdw_update_port_irq(dev_priv, hotplug_irqs, enabled_irqs);
- /* Enable DDI hotplug in IER */
- hotplug_ctrl = I915_READ(GEN8_DE_PORT_IER) | hotplug_port;
- I915_WRITE(GEN8_DE_PORT_IER, hotplug_ctrl);
- POSTING_READ(GEN8_DE_PORT_IER);
+ hotplug = I915_READ(PCH_PORT_HOTPLUG);
+ hotplug |= PORTC_HOTPLUG_ENABLE | PORTB_HOTPLUG_ENABLE |
+ PORTA_HOTPLUG_ENABLE;
+ I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
}
static void ibx_irq_postinstall(struct drm_device *dev)
@@ -3122,7 +3367,7 @@ static void ibx_irq_postinstall(struct drm_device *dev)
else
mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
- GEN5_ASSERT_IIR_IS_ZERO(SDEIIR);
+ gen5_assert_iir_is_zero(dev_priv, SDEIIR);
I915_WRITE(SDEIMR, ~mask);
}
@@ -3174,15 +3419,17 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
DE_PLANEB_FLIP_DONE_IVB |
DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
- DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
+ DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB |
+ DE_DP_A_HOTPLUG_IVB);
} else {
display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
DE_AUX_CHANNEL_A |
DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
DE_POISON);
- extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
- DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN;
+ extra_mask = (DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+ DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
+ DE_DP_A_HOTPLUG);
}
dev_priv->irq_mask = ~display_mask;
@@ -3309,7 +3556,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
{
dev_priv->irq_mask = ~0;
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
POSTING_READ(PORT_HOTPLUG_EN);
I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3378,24 +3625,31 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
{
uint32_t de_pipe_masked = GEN8_PIPE_CDCLK_CRC_DONE;
uint32_t de_pipe_enables;
- int pipe;
- u32 de_port_en = GEN8_AUX_CHANNEL_A;
+ u32 de_port_masked = GEN8_AUX_CHANNEL_A;
+ u32 de_port_enables;
+ enum pipe pipe;
- if (IS_GEN9(dev_priv)) {
+ if (INTEL_INFO(dev_priv)->gen >= 9) {
de_pipe_masked |= GEN9_PIPE_PLANE1_FLIP_DONE |
GEN9_DE_PIPE_IRQ_FAULT_ERRORS;
- de_port_en |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
- GEN9_AUX_CHANNEL_D;
-
+ de_port_masked |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
+ GEN9_AUX_CHANNEL_D;
if (IS_BROXTON(dev_priv))
- de_port_en |= BXT_DE_PORT_GMBUS;
- } else
+ de_port_masked |= BXT_DE_PORT_GMBUS;
+ } else {
de_pipe_masked |= GEN8_PIPE_PRIMARY_FLIP_DONE |
GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
+ }
de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
GEN8_PIPE_FIFO_UNDERRUN;
+ de_port_enables = de_port_masked;
+ if (IS_BROXTON(dev_priv))
+ de_port_enables |= BXT_DE_PORT_HOTPLUG_MASK;
+ else if (IS_BROADWELL(dev_priv))
+ de_port_enables |= GEN8_PORT_DP_A_HOTPLUG;
+
dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
dev_priv->de_irq_mask[PIPE_C] = ~de_pipe_masked;
@@ -3407,7 +3661,7 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
dev_priv->de_irq_mask[pipe],
de_pipe_enables);
- GEN5_IRQ_INIT(GEN8_DE_PORT_, ~de_port_en, de_port_en);
+ GEN5_IRQ_INIT(GEN8_DE_PORT_, ~de_port_masked, de_port_enables);
}
static int gen8_irq_postinstall(struct drm_device *dev)
@@ -3676,7 +3930,7 @@ static void i915_irq_preinstall(struct drm_device * dev)
int pipe;
if (I915_HAS_HOTPLUG(dev)) {
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
}
@@ -3710,7 +3964,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
I915_USER_INTERRUPT;
if (I915_HAS_HOTPLUG(dev)) {
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
POSTING_READ(PORT_HOTPLUG_EN);
/* Enable in IER... */
@@ -3872,7 +4126,7 @@ static void i915_irq_uninstall(struct drm_device * dev)
int pipe;
if (I915_HAS_HOTPLUG(dev)) {
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
}
@@ -3893,7 +4147,7 @@ static void i965_irq_preinstall(struct drm_device * dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe;
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
I915_WRITE(HWSTAM, 0xeffe);
@@ -3954,7 +4208,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
I915_WRITE(IER, enable_mask);
POSTING_READ(IER);
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
POSTING_READ(PORT_HOTPLUG_EN);
i915_enable_asle_pipestat(dev);
@@ -3965,29 +4219,27 @@ static int i965_irq_postinstall(struct drm_device *dev)
static void i915_hpd_irq_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *intel_encoder;
u32 hotplug_en;
assert_spin_locked(&dev_priv->irq_lock);
- hotplug_en = I915_READ(PORT_HOTPLUG_EN);
- hotplug_en &= ~HOTPLUG_INT_EN_MASK;
/* Note HDMI and DP share hotplug bits */
/* enable bits are the same for all generations */
- for_each_intel_encoder(dev, intel_encoder)
- if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED)
- hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
+ hotplug_en = intel_hpd_enabled_irqs(dev, hpd_mask_i915);
/* Programming the CRT detection parameters tends
to generate a spurious hotplug event about three
seconds later. So just do it once.
*/
if (IS_G4X(dev))
hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
- hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
/* Ignore TV since it's buggy */
- I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+ i915_hotplug_interrupt_update_locked(dev_priv,
+ HOTPLUG_INT_EN_MASK |
+ CRT_HOTPLUG_VOLTAGE_COMPARE_MASK |
+ CRT_HOTPLUG_ACTIVATION_PERIOD_64,
+ hotplug_en);
}
static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -4100,7 +4352,7 @@ static void i965_irq_uninstall(struct drm_device * dev)
if (!dev_priv)
return;
- I915_WRITE(PORT_HOTPLUG_EN, 0);
+ i915_hotplug_interrupt_update(dev_priv, 0xffffffff, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
I915_WRITE(HWSTAM, 0xffffffff);
@@ -4148,7 +4400,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
dev->driver->get_vblank_counter = i8xx_get_vblank_counter;
} else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
- dev->driver->get_vblank_counter = gm45_get_vblank_counter;
+ dev->driver->get_vblank_counter = g4x_get_vblank_counter;
} else {
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
@@ -4188,10 +4440,12 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
dev->driver->irq_uninstall = gen8_irq_uninstall;
dev->driver->enable_vblank = gen8_enable_vblank;
dev->driver->disable_vblank = gen8_disable_vblank;
- if (HAS_PCH_SPLIT(dev))
- dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
- else
+ if (IS_BROXTON(dev))
dev_priv->display.hpd_irq_setup = bxt_hpd_irq_setup;
+ else if (HAS_PCH_SPT(dev))
+ dev_priv->display.hpd_irq_setup = spt_hpd_irq_setup;
+ else
+ dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
} else if (HAS_PCH_SPLIT(dev)) {
dev->driver->irq_handler = ironlake_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_reset;
@@ -4199,7 +4453,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ironlake_enable_vblank;
dev->driver->disable_vblank = ironlake_disable_vblank;
- dev_priv->display.hpd_irq_setup = ibx_hpd_irq_setup;
+ dev_priv->display.hpd_irq_setup = ilk_hpd_irq_setup;
} else {
if (INTEL_INFO(dev_priv)->gen == 2) {
dev->driver->irq_preinstall = i8xx_irq_preinstall;
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 5ae4b0aba564..96bb23865eac 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -38,9 +38,8 @@ struct i915_params i915 __read_mostly = {
.enable_ppgtt = -1,
.enable_psr = 0,
.preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
- .disable_power_well = 1,
+ .disable_power_well = -1,
.enable_ips = 1,
- .fastboot = 0,
.prefault_disable = 0,
.load_detect_test = 0,
.reset = true,
@@ -51,6 +50,7 @@ struct i915_params i915 __read_mostly = {
.use_mmio_flip = 0,
.mmio_debug = 0,
.verbose_state_checks = 1,
+ .nuclear_pageflip = 0,
.edp_vswing = 0,
.enable_guc_submission = false,
.guc_log_level = -1,
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(modeset,
"Use kernel modesetting [KMS] (0=disable, "
"1=on, -1=force vga console preference [default])");
-module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600);
+module_param_named_unsafe(panel_ignore_lid, i915.panel_ignore_lid, int, 0600);
MODULE_PARM_DESC(panel_ignore_lid,
"Override lid status (0=autodetect, 1=autodetect disabled [default], "
"-1=force lid closed, -2=force lid open)");
@@ -84,17 +84,17 @@ MODULE_PARM_DESC(enable_fbc,
"Enable frame buffer compression for power savings "
"(default: -1 (use per-chip default))");
-module_param_named(lvds_channel_mode, i915.lvds_channel_mode, int, 0600);
+module_param_named_unsafe(lvds_channel_mode, i915.lvds_channel_mode, int, 0600);
MODULE_PARM_DESC(lvds_channel_mode,
"Specify LVDS channel mode "
"(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
-module_param_named(lvds_use_ssc, i915.panel_use_ssc, int, 0600);
+module_param_named_unsafe(lvds_use_ssc, i915.panel_use_ssc, int, 0600);
MODULE_PARM_DESC(lvds_use_ssc,
"Use Spread Spectrum Clock with panels [LVDS/eDP] "
"(default: auto from VBT)");
-module_param_named(vbt_sdvo_panel_type, i915.vbt_sdvo_panel_type, int, 0600);
+module_param_named_unsafe(vbt_sdvo_panel_type, i915.vbt_sdvo_panel_type, int, 0600);
MODULE_PARM_DESC(vbt_sdvo_panel_type,
"Override/Ignore selection of SDVO panel mode in the VBT "
"(-2=ignore, -1=auto [default], index in VBT BIOS table)");
@@ -102,7 +102,7 @@ MODULE_PARM_DESC(vbt_sdvo_panel_type,
module_param_named_unsafe(reset, i915.reset, bool, 0600);
MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
-module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644);
+module_param_named_unsafe(enable_hangcheck, i915.enable_hangcheck, bool, 0644);
MODULE_PARM_DESC(enable_hangcheck,
"Periodically check GPU activity for detecting hangs. "
"WARNING: Disabling this can cause system wide hangs. "
@@ -113,29 +113,26 @@ MODULE_PARM_DESC(enable_ppgtt,
"Override PPGTT usage. "
"(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
-module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
+module_param_named_unsafe(enable_execlists, i915.enable_execlists, int, 0400);
MODULE_PARM_DESC(enable_execlists,
"Override execlists usage. "
"(-1=auto [default], 0=disabled, 1=enabled)");
-module_param_named(enable_psr, i915.enable_psr, int, 0600);
+module_param_named_unsafe(enable_psr, i915.enable_psr, int, 0600);
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
-module_param_named(preliminary_hw_support, i915.preliminary_hw_support, int, 0600);
+module_param_named_unsafe(preliminary_hw_support, i915.preliminary_hw_support, int, 0600);
MODULE_PARM_DESC(preliminary_hw_support,
"Enable preliminary hardware support.");
-module_param_named(disable_power_well, i915.disable_power_well, int, 0600);
+module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0600);
MODULE_PARM_DESC(disable_power_well,
- "Disable the power well when possible (default: true)");
+ "Disable display power wells when possible "
+ "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)");
-module_param_named(enable_ips, i915.enable_ips, int, 0600);
+module_param_named_unsafe(enable_ips, i915.enable_ips, int, 0600);
MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
-module_param_named(fastboot, i915.fastboot, bool, 0600);
-MODULE_PARM_DESC(fastboot,
- "Try to skip unnecessary mode sets at boot time (default: false)");
-
module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600);
MODULE_PARM_DESC(prefault_disable,
"Disable page prefaulting for pread/pwrite/reloc (default:false). "
@@ -146,7 +143,7 @@ MODULE_PARM_DESC(load_detect_test,
"Force-enable the VGA load detect code for testing (default:false). "
"For developers only.");
-module_param_named(invert_brightness, i915.invert_brightness, int, 0600);
+module_param_named_unsafe(invert_brightness, i915.invert_brightness, int, 0600);
MODULE_PARM_DESC(invert_brightness,
"Invert backlight brightness "
"(-1 force normal, 0 machine defaults, 1 force inversion), please "
@@ -157,14 +154,14 @@ MODULE_PARM_DESC(invert_brightness,
module_param_named(disable_display, i915.disable_display, bool, 0600);
MODULE_PARM_DESC(disable_display, "Disable display (default: false)");
-module_param_named(disable_vtd_wa, i915.disable_vtd_wa, bool, 0600);
+module_param_named_unsafe(disable_vtd_wa, i915.disable_vtd_wa, bool, 0600);
MODULE_PARM_DESC(disable_vtd_wa, "Disable all VT-d workarounds (default: false)");
-module_param_named(enable_cmd_parser, i915.enable_cmd_parser, int, 0600);
+module_param_named_unsafe(enable_cmd_parser, i915.enable_cmd_parser, int, 0600);
MODULE_PARM_DESC(enable_cmd_parser,
"Enable command parsing (1=enabled [default], 0=disabled)");
-module_param_named(use_mmio_flip, i915.use_mmio_flip, int, 0600);
+module_param_named_unsafe(use_mmio_flip, i915.use_mmio_flip, int, 0600);
MODULE_PARM_DESC(use_mmio_flip,
"use MMIO flips (-1=never, 0=driver discretion [default], 1=always)");
@@ -177,6 +174,10 @@ module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
MODULE_PARM_DESC(verbose_state_checks,
"Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");
+module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600);
+MODULE_PARM_DESC(nuclear_pageflip,
+ "Force atomic modeset functionality; asynchronous mode is not yet supported. (default: false).");
+
/* WA to get away with the default setting in VBT for early platforms.Will be removed */
module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400);
MODULE_PARM_DESC(edp_vswing,
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 83a0888756d6..bc7b8faba84d 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -105,7 +105,7 @@
#define GRDOM_RESET_STATUS (1<<1)
#define GRDOM_RESET_ENABLE (1<<0)
-#define ILK_GDSR 0x2ca4 /* MCHBAR offset */
+#define ILK_GDSR (MCHBAR_MIRROR_BASE + 0x2ca4)
#define ILK_GRDOM_FULL (0<<1)
#define ILK_GRDOM_RENDER (1<<1)
#define ILK_GRDOM_MEDIA (3<<1)
@@ -352,8 +352,8 @@
*/
#define MI_LOAD_REGISTER_IMM(x) MI_INSTR(0x22, 2*(x)-1)
#define MI_LRI_FORCE_POSTED (1<<12)
-#define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1)
-#define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1)
+#define MI_STORE_REGISTER_MEM MI_INSTR(0x24, 1)
+#define MI_STORE_REGISTER_MEM_GEN8 MI_INSTR(0x24, 2)
#define MI_SRM_LRM_GLOBAL_GTT (1<<22)
#define MI_FLUSH_DW MI_INSTR(0x26, 1) /* for GEN6 */
#define MI_FLUSH_DW_STORE_INDEX (1<<21)
@@ -364,8 +364,8 @@
#define MI_INVALIDATE_BSD (1<<7)
#define MI_FLUSH_DW_USE_GTT (1<<2)
#define MI_FLUSH_DW_USE_PPGTT (0<<2)
-#define MI_LOAD_REGISTER_MEM(x) MI_INSTR(0x29, 2*(x)-1)
-#define MI_LOAD_REGISTER_MEM_GEN8(x) MI_INSTR(0x29, 3*(x)-1)
+#define MI_LOAD_REGISTER_MEM MI_INSTR(0x29, 1)
+#define MI_LOAD_REGISTER_MEM_GEN8 MI_INSTR(0x29, 2)
#define MI_BATCH_BUFFER MI_INSTR(0x30, 1)
#define MI_BATCH_NON_SECURE (1)
/* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */
@@ -429,7 +429,7 @@
#define ASYNC_FLIP (1<<22)
#define DISPLAY_PLANE_A (0<<20)
#define DISPLAY_PLANE_B (1<<20)
-#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2))
+#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2))
#define PIPE_CONTROL_FLUSH_L3 (1<<27)
#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */
#define PIPE_CONTROL_MMIO_WRITE (1<<23)
@@ -536,6 +536,10 @@
#define GEN7_3DPRIM_START_INSTANCE 0x243C
#define GEN7_3DPRIM_BASE_VERTEX 0x2440
+#define GEN7_GPGPU_DISPATCHDIMX 0x2500
+#define GEN7_GPGPU_DISPATCHDIMY 0x2504
+#define GEN7_GPGPU_DISPATCHDIMZ 0x2508
+
#define OACONTROL 0x2360
#define _GEN7_PIPEA_DE_LOAD_SL 0x70068
@@ -728,12 +732,13 @@ enum skl_disp_power_wells {
#define DSI_PLL_N1_DIV_MASK (3 << 16)
#define DSI_PLL_M1_DIV_SHIFT 0
#define DSI_PLL_M1_DIV_MASK (0x1ff << 0)
+#define CCK_CZ_CLOCK_CONTROL 0x62
#define CCK_DISPLAY_CLOCK_CONTROL 0x6b
-#define DISPLAY_TRUNK_FORCE_ON (1 << 17)
-#define DISPLAY_TRUNK_FORCE_OFF (1 << 16)
-#define DISPLAY_FREQUENCY_STATUS (0x1f << 8)
-#define DISPLAY_FREQUENCY_STATUS_SHIFT 8
-#define DISPLAY_FREQUENCY_VALUES (0x1f << 0)
+#define CCK_TRUNK_FORCE_ON (1 << 17)
+#define CCK_TRUNK_FORCE_OFF (1 << 16)
+#define CCK_FREQUENCY_STATUS (0x1f << 8)
+#define CCK_FREQUENCY_STATUS_SHIFT 8
+#define CCK_FREQUENCY_VALUES (0x1f << 0)
/**
* DOC: DPIO
@@ -1099,6 +1104,12 @@ enum skl_disp_power_wells {
#define DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE 1 /* 1: coarse & 0 : fine */
#define CHV_PLL_DW9(ch) _PIPE(ch, _CHV_PLL_DW9_CH0, _CHV_PLL_DW9_CH1)
+#define _CHV_CMN_DW0_CH0 0x8100
+#define DPIO_ALLDL_POWERDOWN_SHIFT_CH0 19
+#define DPIO_ANYDL_POWERDOWN_SHIFT_CH0 18
+#define DPIO_ALLDL_POWERDOWN (1 << 1)
+#define DPIO_ANYDL_POWERDOWN (1 << 0)
+
#define _CHV_CMN_DW5_CH0 0x8114
#define CHV_BUFRIGHTENA1_DISABLE (0 << 20)
#define CHV_BUFRIGHTENA1_NORMAL (1 << 20)
@@ -1135,10 +1146,23 @@ enum skl_disp_power_wells {
#define _CHV_CMN_DW19_CH0 0x814c
#define _CHV_CMN_DW6_CH1 0x8098
+#define DPIO_ALLDL_POWERDOWN_SHIFT_CH1 30 /* CL2 DW6 only */
+#define DPIO_ANYDL_POWERDOWN_SHIFT_CH1 29 /* CL2 DW6 only */
+#define DPIO_DYNPWRDOWNEN_CH1 (1 << 28) /* CL2 DW6 only */
#define CHV_CMN_USEDCLKCHANNEL (1 << 13)
+
#define CHV_CMN_DW19(ch) _PIPE(ch, _CHV_CMN_DW19_CH0, _CHV_CMN_DW6_CH1)
+#define CHV_CMN_DW28 0x8170
+#define DPIO_CL1POWERDOWNEN (1 << 23)
+#define DPIO_DYNPWRDOWNEN_CH0 (1 << 22)
+#define DPIO_SUS_CLK_CONFIG_ON (0 << 0)
+#define DPIO_SUS_CLK_CONFIG_CLKREQ (1 << 0)
+#define DPIO_SUS_CLK_CONFIG_GATE (2 << 0)
+#define DPIO_SUS_CLK_CONFIG_GATE_CLKREQ (3 << 0)
+
#define CHV_CMN_DW30 0x8178
+#define DPIO_CL2_LDOFUSE_PWRENB (1 << 6)
#define DPIO_LRC_BYPASS (1 << 3)
#define _TXLANE(ch, lane, offset) ((ch ? 0x2400 : 0) + \
@@ -1231,7 +1255,7 @@ enum skl_disp_power_wells {
#define PORT_PLL_DCO_AMP_OVR_EN_H (1<<27)
#define PORT_PLL_DCO_AMP_DEFAULT 15
#define PORT_PLL_DCO_AMP_MASK 0x3c00
-#define PORT_PLL_DCO_AMP(x) (x<<10)
+#define PORT_PLL_DCO_AMP(x) ((x)<<10)
#define _PORT_PLL_BASE(port) _PORT3(port, _PORT_PLL_0_A, \
_PORT_PLL_0_B, \
_PORT_PLL_0_C)
@@ -1376,7 +1400,8 @@ enum skl_disp_power_wells {
#define BXT_PORT_TX_DW3_LN0(port) _PORT3(port, _PORT_TX_DW3_LN0_A, \
_PORT_TX_DW3_LN0_B, \
_PORT_TX_DW3_LN0_C)
-#define UNIQE_TRANGE_EN_METHOD (1 << 27)
+#define SCALE_DCOMP_METHOD (1 << 26)
+#define UNIQUE_TRANGE_EN_METHOD (1 << 27)
#define _PORT_TX_DW4_LN0_A 0x162510
#define _PORT_TX_DW4_LN0_B 0x6C510
@@ -1417,9 +1442,15 @@ enum skl_disp_power_wells {
/*
* Fence registers
+ * [0-7] @ 0x2000 gen2,gen3
+ * [8-15] @ 0x3000 945,g33,pnv
+ *
+ * [0-15] @ 0x3000 gen4,gen5
+ *
+ * [0-15] @ 0x100000 gen6,vlv,chv
+ * [0-31] @ 0x100000 gen7+
*/
-#define FENCE_REG_830_0 0x2000
-#define FENCE_REG_945_8 0x3000
+#define FENCE_REG(i) (0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4)
#define I830_FENCE_START_MASK 0x07f80000
#define I830_FENCE_TILING_Y_SHIFT 12
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
@@ -1432,14 +1463,16 @@ enum skl_disp_power_wells {
#define I915_FENCE_START_MASK 0x0ff00000
#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8)
-#define FENCE_REG_965_0 0x03000
+#define FENCE_REG_965_LO(i) (0x03000 + (i) * 8)
+#define FENCE_REG_965_HI(i) (0x03000 + (i) * 8 + 4)
#define I965_FENCE_PITCH_SHIFT 2
#define I965_FENCE_TILING_Y_SHIFT 1
#define I965_FENCE_REG_VALID (1<<0)
#define I965_FENCE_MAX_PITCH_VAL 0x0400
-#define FENCE_REG_SANDYBRIDGE_0 0x100000
-#define SANDYBRIDGE_FENCE_PITCH_SHIFT 32
+#define FENCE_REG_GEN6_LO(i) (0x100000 + (i) * 8)
+#define FENCE_REG_GEN6_HI(i) (0x100000 + (i) * 8 + 4)
+#define GEN6_FENCE_PITCH_SHIFT 32
#define GEN7_FENCE_MAX_PITCH_VAL 0x0800
@@ -1508,7 +1541,7 @@ enum skl_disp_power_wells {
#define GEN7_GFX_PEND_TLB0 0x4034
#define GEN7_GFX_PEND_TLB1 0x4038
/* L3, CVS, ZTLB, RCC, CASC LRA min, max values */
-#define GEN7_LRA_LIMITS_BASE 0x403C
+#define GEN7_LRA_LIMITS(i) (0x403C + (i) * 4)
#define GEN7_LRA_LIMITS_REG_NUM 13
#define GEN7_MEDIA_MAX_REQ_COUNT 0x4070
#define GEN7_GFX_MAX_REQ_COUNT 0x4074
@@ -1519,11 +1552,12 @@ enum skl_disp_power_wells {
#define RENDER_HWS_PGA_GEN7 (0x04080)
#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id)
#define RING_FAULT_GTTSEL_MASK (1<<11)
-#define RING_FAULT_SRCID(x) ((x >> 3) & 0xff)
-#define RING_FAULT_FAULT_TYPE(x) ((x >> 1) & 0x3)
+#define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff)
+#define RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3)
#define RING_FAULT_VALID (1<<0)
#define DONE_REG 0x40b0
-#define GEN8_PRIVATE_PAT 0x40e0
+#define GEN8_PRIVATE_PAT_LO 0x40e0
+#define GEN8_PRIVATE_PAT_HI (0x40e0 + 4)
#define BSD_HWS_PGA_GEN7 (0x04180)
#define BLT_HWS_PGA_GEN7 (0x04280)
#define VEBOX_HWS_PGA_GEN7 (0x04380)
@@ -1563,14 +1597,17 @@ enum skl_disp_power_wells {
#endif
#define IPEIR_I965 0x02064
#define IPEHR_I965 0x02068
-#define INSTDONE_I965 0x0206c
-#define GEN7_INSTDONE_1 0x0206c
#define GEN7_SC_INSTDONE 0x07100
#define GEN7_SAMPLER_INSTDONE 0x0e160
#define GEN7_ROW_INSTDONE 0x0e164
#define I915_NUM_INSTDONE_REG 4
#define RING_IPEIR(base) ((base)+0x64)
#define RING_IPEHR(base) ((base)+0x68)
+/*
+ * On GEN4, only the render ring INSTDONE exists and has a different
+ * layout than the GEN7+ version.
+ * The GEN2 counterpart of this register is GEN2_INSTDONE.
+ */
#define RING_INSTDONE(base) ((base)+0x6c)
#define RING_INSTPS(base) ((base)+0x70)
#define RING_DMA_FADD(base) ((base)+0x78)
@@ -1578,7 +1615,7 @@ enum skl_disp_power_wells {
#define RING_INSTPM(base) ((base)+0xc0)
#define RING_MI_MODE(base) ((base)+0x9c)
#define INSTPS 0x02070 /* 965+ only */
-#define INSTDONE1 0x0207c /* 965+ only */
+#define GEN4_INSTDONE1 0x0207c /* 965+ only, aka INSTDONE_2 on SNB */
#define ACTHD_I965 0x02074
#define HWS_PGA 0x02080
#define HWS_ADDRESS_MASK 0xfffff000
@@ -1587,7 +1624,7 @@ enum skl_disp_power_wells {
#define PWRCTX_EN (1<<0)
#define IPEIR 0x02088
#define IPEHR 0x0208c
-#define INSTDONE 0x02090
+#define GEN2_INSTDONE 0x02090
#define NOPID 0x02094
#define HWSTAM 0x02098
#define DMA_FADD_I8XX 0x020d0
@@ -1604,9 +1641,9 @@ enum skl_disp_power_wells {
#define ERR_INT_PIPE_CRC_DONE_B (1<<5)
#define ERR_INT_FIFO_UNDERRUN_B (1<<3)
#define ERR_INT_PIPE_CRC_DONE_A (1<<2)
-#define ERR_INT_PIPE_CRC_DONE(pipe) (1<<(2 + pipe*3))
+#define ERR_INT_PIPE_CRC_DONE(pipe) (1<<(2 + (pipe)*3))
#define ERR_INT_FIFO_UNDERRUN_A (1<<0)
-#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<(pipe*3))
+#define ERR_INT_FIFO_UNDERRUN(pipe) (1<<((pipe)*3))
#define GEN8_FAULT_TLB_DATA0 0x04b10
#define GEN8_FAULT_TLB_DATA1 0x04b14
@@ -1667,18 +1704,25 @@ enum skl_disp_power_wells {
#define GEN6_WIZ_HASHING_16x4 GEN6_WIZ_HASHING(1, 0)
#define GEN6_WIZ_HASHING_MASK GEN6_WIZ_HASHING(1, 1)
#define GEN6_TD_FOUR_ROW_DISPATCH_DISABLE (1 << 5)
-#define GEN9_IZ_HASHING_MASK(slice) (0x3 << (slice * 2))
-#define GEN9_IZ_HASHING(slice, val) ((val) << (slice * 2))
+#define GEN9_IZ_HASHING_MASK(slice) (0x3 << ((slice) * 2))
+#define GEN9_IZ_HASHING(slice, val) ((val) << ((slice) * 2))
#define GFX_MODE 0x02520
#define GFX_MODE_GEN7 0x0229c
#define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c)
#define GFX_RUN_LIST_ENABLE (1<<15)
+#define GFX_INTERRUPT_STEERING (1<<14)
#define GFX_TLB_INVALIDATE_EXPLICIT (1<<13)
#define GFX_SURFACE_FAULT_ENABLE (1<<12)
#define GFX_REPLAY_MODE (1<<11)
#define GFX_PSMI_GRANULARITY (1<<10)
#define GFX_PPGTT_ENABLE (1<<9)
+#define GEN8_GFX_PPGTT_48B (1<<7)
+
+#define GFX_FORWARD_VBLANK_MASK (3<<5)
+#define GFX_FORWARD_VBLANK_NEVER (0<<5)
+#define GFX_FORWARD_VBLANK_ALWAYS (1<<5)
+#define GFX_FORWARD_VBLANK_COND (2<<5)
#define VLV_DISPLAY_BASE 0x180000
#define VLV_MIPI_BASE VLV_DISPLAY_BASE
@@ -1850,12 +1894,27 @@ enum skl_disp_power_wells {
#define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
#define GEN8_FUSE2 0x9120
+#define GEN8_F2_SS_DIS_SHIFT 21
+#define GEN8_F2_SS_DIS_MASK (0x7 << GEN8_F2_SS_DIS_SHIFT)
#define GEN8_F2_S_ENA_SHIFT 25
#define GEN8_F2_S_ENA_MASK (0x7 << GEN8_F2_S_ENA_SHIFT)
#define GEN9_F2_SS_DIS_SHIFT 20
#define GEN9_F2_SS_DIS_MASK (0xf << GEN9_F2_SS_DIS_SHIFT)
+#define GEN8_EU_DISABLE0 0x9134
+#define GEN8_EU_DIS0_S0_MASK 0xffffff
+#define GEN8_EU_DIS0_S1_SHIFT 24
+#define GEN8_EU_DIS0_S1_MASK (0xff << GEN8_EU_DIS0_S1_SHIFT)
+
+#define GEN8_EU_DISABLE1 0x9138
+#define GEN8_EU_DIS1_S1_MASK 0xffff
+#define GEN8_EU_DIS1_S2_SHIFT 16
+#define GEN8_EU_DIS1_S2_MASK (0xffff << GEN8_EU_DIS1_S2_SHIFT)
+
+#define GEN8_EU_DISABLE2 0x913c
+#define GEN8_EU_DIS2_S2_MASK 0xff
+
#define GEN9_EU_DISABLE(slice) (0x9134 + (slice)*0x4)
#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
@@ -1985,7 +2044,7 @@ enum skl_disp_power_wells {
#define FBC_CTL_CPU_FENCE (1<<1)
#define FBC_CTL_PLANE(plane) ((plane)<<0)
#define FBC_FENCE_OFF 0x03218 /* BSpec typo has 321Bh */
-#define FBC_TAG 0x03300
+#define FBC_TAG(i) (0x03300 + (i) * 4)
#define FBC_STATUS2 0x43214
#define FBC_COMPRESSION_MASK 0x7ff
@@ -2085,7 +2144,7 @@ enum skl_disp_power_wells {
# define GPIO_DATA_VAL_IN (1 << 12)
# define GPIO_DATA_PULLUP_DISABLE (1 << 13)
-#define GMBUS0 0x5100 /* clock/port select */
+#define GMBUS0 (dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */
#define GMBUS_RATE_100KHZ (0<<8)
#define GMBUS_RATE_50KHZ (1<<8)
#define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */
@@ -2104,7 +2163,7 @@ enum skl_disp_power_wells {
#define GMBUS_PIN_2_BXT 2
#define GMBUS_PIN_3_BXT 3
#define GMBUS_NUM_PINS 7 /* including 0 */
-#define GMBUS1 0x5104 /* command/status */
+#define GMBUS1 (dev_priv->gpio_mmio_base + 0x5104) /* command/status */
#define GMBUS_SW_CLR_INT (1<<31)
#define GMBUS_SW_RDY (1<<30)
#define GMBUS_ENT (1<<29) /* enable timeout */
@@ -2118,7 +2177,7 @@ enum skl_disp_power_wells {
#define GMBUS_SLAVE_ADDR_SHIFT 1
#define GMBUS_SLAVE_READ (1<<0)
#define GMBUS_SLAVE_WRITE (0<<0)
-#define GMBUS2 0x5108 /* status */
+#define GMBUS2 (dev_priv->gpio_mmio_base + 0x5108) /* status */
#define GMBUS_INUSE (1<<15)
#define GMBUS_HW_WAIT_PHASE (1<<14)
#define GMBUS_STALL_TIMEOUT (1<<13)
@@ -2126,14 +2185,14 @@ enum skl_disp_power_wells {
#define GMBUS_HW_RDY (1<<11)
#define GMBUS_SATOER (1<<10)
#define GMBUS_ACTIVE (1<<9)
-#define GMBUS3 0x510c /* data buffer bytes 3-0 */
-#define GMBUS4 0x5110 /* interrupt mask (Pineview+) */
+#define GMBUS3 (dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */
+#define GMBUS4 (dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */
#define GMBUS_SLAVE_TIMEOUT_EN (1<<4)
#define GMBUS_NAK_EN (1<<3)
#define GMBUS_IDLE_EN (1<<2)
#define GMBUS_HW_WAIT_EN (1<<1)
#define GMBUS_HW_RDY_EN (1<<0)
-#define GMBUS5 0x5120 /* byte index */
+#define GMBUS5 (dev_priv->gpio_mmio_base + 0x5120) /* byte index */
#define GMBUS_2BYTE_INDEX_EN (1<<31)
/*
@@ -2185,16 +2244,20 @@ enum skl_disp_power_wells {
#define DPIO_PHY_STATUS (VLV_DISPLAY_BASE + 0x6240)
#define DPLL_PORTD_READY_MASK (0xf)
#define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100)
+#define PHY_CH_POWER_DOWN_OVRD_EN(phy, ch) (1 << (2*(phy)+(ch)+27))
#define PHY_LDO_DELAY_0NS 0x0
#define PHY_LDO_DELAY_200NS 0x1
#define PHY_LDO_DELAY_600NS 0x2
#define PHY_LDO_SEQ_DELAY(delay, phy) ((delay) << (2*(phy)+23))
+#define PHY_CH_POWER_DOWN_OVRD(mask, phy, ch) ((mask) << (8*(phy)+4*(ch)+11))
#define PHY_CH_SU_PSR 0x1
#define PHY_CH_DEEP_PSR 0x7
#define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6*(phy)+3*(ch)+2))
#define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy))
#define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104)
#define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30))
+#define PHY_STATUS_CMN_LDO(phy, ch) (1 << (6-(6*(phy)+3*(ch))))
+#define PHY_STATUS_SPLINE_LDO(phy, ch, spline) (1 << (8-(6*(phy)+3*(ch)+(spline))))
/*
* The i830 generation, in LVDS mode, defines P1 as the bit number set within
@@ -2445,8 +2508,8 @@ enum skl_disp_power_wells {
#define PALETTE_A_OFFSET 0xa000
#define PALETTE_B_OFFSET 0xa800
#define CHV_PALETTE_C_OFFSET 0xc000
-#define PALETTE(pipe) (dev_priv->info.palette_offsets[pipe] + \
- dev_priv->info.display_mmio_offset)
+#define PALETTE(pipe, i) (dev_priv->info.palette_offsets[pipe] + \
+ dev_priv->info.display_mmio_offset + (i) * 4)
/* MCH MMIO space */
@@ -2464,6 +2527,11 @@ enum skl_disp_power_wells {
#define MCHBAR_MIRROR_BASE_SNB 0x140000
+#define CTG_STOLEN_RESERVED (MCHBAR_MIRROR_BASE + 0x34)
+#define ELK_STOLEN_RESERVED (MCHBAR_MIRROR_BASE + 0x48)
+#define G4X_STOLEN_RESERVED_ADDR1_MASK (0xFFFF << 16)
+#define G4X_STOLEN_RESERVED_ADDR2_MASK (0xFFF << 4)
+
/* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */
#define DCLK (MCHBAR_MIRROR_BASE_SNB + 0x5e04)
@@ -2544,7 +2612,7 @@ enum skl_disp_power_wells {
#define TSFS_INTR_MASK 0x000000ff
#define CRSTANDVID 0x11100
-#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
+#define PXVFREQ(i) (0x11110 + (i) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
#define PXVFREQ_PX_MASK 0x7f000000
#define PXVFREQ_PX_SHIFT 24
#define VIDFREQ_BASE 0x11110
@@ -2728,8 +2796,8 @@ enum skl_disp_power_wells {
#define CSIEW0 0x11250
#define CSIEW1 0x11254
#define CSIEW2 0x11258
-#define PEW 0x1125c
-#define DEW 0x11270
+#define PEW(i) (0x1125c + (i) * 4) /* 5 registers */
+#define DEW(i) (0x11270 + (i) * 4) /* 3 registers */
#define MCHAFE 0x112c0
#define CSIEC 0x112e0
#define DMIEC 0x112e4
@@ -2753,8 +2821,8 @@ enum skl_disp_power_wells {
#define EG5 0x11624
#define EG6 0x11628
#define EG7 0x1162c
-#define PXW 0x11664
-#define PXWL 0x11680
+#define PXW(i) (0x11664 + (i) * 4) /* 4 registers */
+#define PXWL(i) (0x11680 + (i) * 4) /* 8 registers */
#define LCFUSE02 0x116c0
#define LCFUSE_HIV_MASK 0x000000ff
#define CSIPLL0 0x12c10
@@ -2772,8 +2840,11 @@ enum skl_disp_power_wells {
#define INTERVAL_1_28_US(us) (((us) * 100) >> 7)
#define INTERVAL_1_33_US(us) (((us) * 3) >> 2)
+#define INTERVAL_0_833_US(us) (((us) * 6) / 5)
#define GT_INTERVAL_FROM_US(dev_priv, us) (IS_GEN9(dev_priv) ? \
- INTERVAL_1_33_US(us) : \
+ (IS_BROXTON(dev_priv) ? \
+ INTERVAL_0_833_US(us) : \
+ INTERVAL_1_33_US(us)) : \
INTERVAL_1_28_US(us))
/*
@@ -2795,21 +2866,21 @@ enum skl_disp_power_wells {
* doesn't need saving on GT1
*/
#define CXT_SIZE 0x21a0
-#define GEN6_CXT_POWER_SIZE(cxt_reg) ((cxt_reg >> 24) & 0x3f)
-#define GEN6_CXT_RING_SIZE(cxt_reg) ((cxt_reg >> 18) & 0x3f)
-#define GEN6_CXT_RENDER_SIZE(cxt_reg) ((cxt_reg >> 12) & 0x3f)
-#define GEN6_CXT_EXTENDED_SIZE(cxt_reg) ((cxt_reg >> 6) & 0x3f)
-#define GEN6_CXT_PIPELINE_SIZE(cxt_reg) ((cxt_reg >> 0) & 0x3f)
+#define GEN6_CXT_POWER_SIZE(cxt_reg) (((cxt_reg) >> 24) & 0x3f)
+#define GEN6_CXT_RING_SIZE(cxt_reg) (((cxt_reg) >> 18) & 0x3f)
+#define GEN6_CXT_RENDER_SIZE(cxt_reg) (((cxt_reg) >> 12) & 0x3f)
+#define GEN6_CXT_EXTENDED_SIZE(cxt_reg) (((cxt_reg) >> 6) & 0x3f)
+#define GEN6_CXT_PIPELINE_SIZE(cxt_reg) (((cxt_reg) >> 0) & 0x3f)
#define GEN6_CXT_TOTAL_SIZE(cxt_reg) (GEN6_CXT_RING_SIZE(cxt_reg) + \
GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \
GEN6_CXT_PIPELINE_SIZE(cxt_reg))
#define GEN7_CXT_SIZE 0x21a8
-#define GEN7_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 25) & 0x7f)
-#define GEN7_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 22) & 0x7)
-#define GEN7_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 16) & 0x3f)
-#define GEN7_CXT_EXTENDED_SIZE(ctx_reg) ((ctx_reg >> 9) & 0x7f)
-#define GEN7_CXT_GT1_SIZE(ctx_reg) ((ctx_reg >> 6) & 0x7)
-#define GEN7_CXT_VFSTATE_SIZE(ctx_reg) ((ctx_reg >> 0) & 0x3f)
+#define GEN7_CXT_POWER_SIZE(ctx_reg) (((ctx_reg) >> 25) & 0x7f)
+#define GEN7_CXT_RING_SIZE(ctx_reg) (((ctx_reg) >> 22) & 0x7)
+#define GEN7_CXT_RENDER_SIZE(ctx_reg) (((ctx_reg) >> 16) & 0x3f)
+#define GEN7_CXT_EXTENDED_SIZE(ctx_reg) (((ctx_reg) >> 9) & 0x7f)
+#define GEN7_CXT_GT1_SIZE(ctx_reg) (((ctx_reg) >> 6) & 0x7)
+#define GEN7_CXT_VFSTATE_SIZE(ctx_reg) (((ctx_reg) >> 0) & 0x3f)
#define GEN7_CXT_TOTAL_SIZE(ctx_reg) (GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \
GEN7_CXT_VFSTATE_SIZE(ctx_reg))
/* Haswell does have the CXT_SIZE register however it does not appear to be
@@ -3229,7 +3300,9 @@ enum skl_disp_power_wells {
#define GEN3_SDVOC 0x61160
#define GEN4_HDMIB GEN3_SDVOB
#define GEN4_HDMIC GEN3_SDVOC
-#define CHV_HDMID 0x6116C
+#define VLV_HDMIB (VLV_DISPLAY_BASE + GEN4_HDMIB)
+#define VLV_HDMIC (VLV_DISPLAY_BASE + GEN4_HDMIC)
+#define CHV_HDMID (VLV_DISPLAY_BASE + 0x6116C)
#define PCH_SDVOB 0xe1140
#define PCH_HDMIB PCH_SDVOB
#define PCH_HDMIC 0xe1150
@@ -3561,17 +3634,29 @@ enum skl_disp_power_wells {
#define UTIL_PIN_CTL 0x48400
#define UTIL_PIN_ENABLE (1 << 31)
+#define UTIL_PIN_PIPE(x) ((x) << 29)
+#define UTIL_PIN_PIPE_MASK (3 << 29)
+#define UTIL_PIN_MODE_PWM (1 << 24)
+#define UTIL_PIN_MODE_MASK (0xf << 24)
+#define UTIL_PIN_POLARITY (1 << 22)
+
/* BXT backlight register definition. */
-#define BXT_BLC_PWM_CTL1 0xC8250
+#define _BXT_BLC_PWM_CTL1 0xC8250
#define BXT_BLC_PWM_ENABLE (1 << 31)
#define BXT_BLC_PWM_POLARITY (1 << 29)
-#define BXT_BLC_PWM_FREQ1 0xC8254
-#define BXT_BLC_PWM_DUTY1 0xC8258
+#define _BXT_BLC_PWM_FREQ1 0xC8254
+#define _BXT_BLC_PWM_DUTY1 0xC8258
-#define BXT_BLC_PWM_CTL2 0xC8350
-#define BXT_BLC_PWM_FREQ2 0xC8354
-#define BXT_BLC_PWM_DUTY2 0xC8358
+#define _BXT_BLC_PWM_CTL2 0xC8350
+#define _BXT_BLC_PWM_FREQ2 0xC8354
+#define _BXT_BLC_PWM_DUTY2 0xC8358
+#define BXT_BLC_PWM_CTL(controller) _PIPE(controller, \
+ _BXT_BLC_PWM_CTL1, _BXT_BLC_PWM_CTL2)
+#define BXT_BLC_PWM_FREQ(controller) _PIPE(controller, \
+ _BXT_BLC_PWM_FREQ1, _BXT_BLC_PWM_FREQ2)
+#define BXT_BLC_PWM_DUTY(controller) _PIPE(controller, \
+ _BXT_BLC_PWM_DUTY1, _BXT_BLC_PWM_DUTY2)
#define PCH_GTC_CTL 0xe7000
#define PCH_GTC_ENABLE (1 << 31)
@@ -4047,14 +4132,10 @@ enum skl_disp_power_wells {
# define TV_CC_DATA_1_MASK 0x0000007f
# define TV_CC_DATA_1_SHIFT 0
-#define TV_H_LUMA_0 0x68100
-#define TV_H_LUMA_59 0x681ec
-#define TV_H_CHROMA_0 0x68200
-#define TV_H_CHROMA_59 0x682ec
-#define TV_V_LUMA_0 0x68300
-#define TV_V_LUMA_42 0x683a8
-#define TV_V_CHROMA_0 0x68400
-#define TV_V_CHROMA_42 0x684a8
+#define TV_H_LUMA(i) (0x68100 + (i) * 4) /* 60 registers */
+#define TV_H_CHROMA(i) (0x68200 + (i) * 4) /* 60 registers */
+#define TV_V_LUMA(i) (0x68300 + (i) * 4) /* 43 registers */
+#define TV_V_CHROMA(i) (0x68400 + (i) * 4) /* 43 registers */
/* Display Port */
#define DP_A 0x64000 /* eDP */
@@ -4062,6 +4143,10 @@ enum skl_disp_power_wells {
#define DP_C 0x64200
#define DP_D 0x64300
+#define VLV_DP_B (VLV_DISPLAY_BASE + DP_B)
+#define VLV_DP_C (VLV_DISPLAY_BASE + DP_C)
+#define CHV_DP_D (VLV_DISPLAY_BASE + DP_D)
+
#define DP_PORT_EN (1 << 31)
#define DP_PIPEB_SELECT (1 << 30)
#define DP_PIPE_MASK (1 << 30)
@@ -4107,6 +4192,7 @@ enum skl_disp_power_wells {
/* How many wires to use. I guess 3 was too hard */
#define DP_PORT_WIDTH(width) (((width) - 1) << 19)
#define DP_PORT_WIDTH_MASK (7 << 19)
+#define DP_PORT_WIDTH_SHIFT 19
/* Mystic DPCD version 1.1 special mode */
#define DP_ENHANCED_FRAMING (1 << 18)
@@ -4198,7 +4284,7 @@ enum skl_disp_power_wells {
#define DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL (1 << 14)
#define DP_AUX_CH_CTL_FS_DATA_AUX_REG_SKL (1 << 13)
#define DP_AUX_CH_CTL_GTC_DATA_AUX_REG_SKL (1 << 12)
-#define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL_MASK (1f << 5)
+#define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL_MASK (0x1f << 5)
#define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(c) (((c) - 1) << 5)
#define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) ((c) - 1)
@@ -4617,6 +4703,7 @@ enum skl_disp_power_wells {
#define CBR1_VLV (VLV_DISPLAY_BASE + 0x70400)
#define CBR_PND_DEADLINE_DISABLE (1<<31)
+#define CBR_PWM_CLOCK_MUX_SELECT (1<<30)
/* FIFO watermark sizes etc */
#define G4X_FIFO_LINE_SIZE 64
@@ -4759,10 +4846,10 @@ enum skl_disp_power_wells {
#define PIPE_PIXEL_MASK 0x00ffffff
#define PIPE_PIXEL_SHIFT 0
/* GM45+ just has to be different */
-#define _PIPEA_FRMCOUNT_GM45 0x70040
-#define _PIPEA_FLIPCOUNT_GM45 0x70044
-#define PIPE_FRMCOUNT_GM45(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_GM45)
-#define PIPE_FLIPCOUNT_GM45(pipe) _PIPE2(pipe, _PIPEA_FLIPCOUNT_GM45)
+#define _PIPEA_FRMCOUNT_G4X 0x70040
+#define _PIPEA_FLIPCOUNT_G4X 0x70044
+#define PIPE_FRMCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_G4X)
+#define PIPE_FLIPCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X)
/* Cursor A & B regs */
#define _CURACNTR 0x70080
@@ -4904,20 +4991,20 @@ enum skl_disp_power_wells {
#define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK)
#define I915_HI_DISPBASE(val) (val & DISP_BASEADDR_MASK)
-/* VBIOS flags */
-#define SWF00 (dev_priv->info.display_mmio_offset + 0x71410)
-#define SWF01 (dev_priv->info.display_mmio_offset + 0x71414)
-#define SWF02 (dev_priv->info.display_mmio_offset + 0x71418)
-#define SWF03 (dev_priv->info.display_mmio_offset + 0x7141c)
-#define SWF04 (dev_priv->info.display_mmio_offset + 0x71420)
-#define SWF05 (dev_priv->info.display_mmio_offset + 0x71424)
-#define SWF06 (dev_priv->info.display_mmio_offset + 0x71428)
-#define SWF10 (dev_priv->info.display_mmio_offset + 0x70410)
-#define SWF11 (dev_priv->info.display_mmio_offset + 0x70414)
-#define SWF14 (dev_priv->info.display_mmio_offset + 0x71420)
-#define SWF30 (dev_priv->info.display_mmio_offset + 0x72414)
-#define SWF31 (dev_priv->info.display_mmio_offset + 0x72418)
-#define SWF32 (dev_priv->info.display_mmio_offset + 0x7241c)
+/*
+ * VBIOS flags
+ * gen2:
+ * [00:06] alm,mgm
+ * [10:16] all
+ * [30:32] alm,mgm
+ * gen3+:
+ * [00:0f] all
+ * [10:1f] all
+ * [30:32] all
+ */
+#define SWF0(i) (dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4)
+#define SWF1(i) (dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4)
+#define SWF3(i) (dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4)
/* Pipe B */
#define _PIPEBDSL (dev_priv->info.display_mmio_offset + 0x71000)
@@ -4925,8 +5012,8 @@ enum skl_disp_power_wells {
#define _PIPEBSTAT (dev_priv->info.display_mmio_offset + 0x71024)
#define _PIPEBFRAMEHIGH 0x71040
#define _PIPEBFRAMEPIXEL 0x71044
-#define _PIPEB_FRMCOUNT_GM45 (dev_priv->info.display_mmio_offset + 0x71040)
-#define _PIPEB_FLIPCOUNT_GM45 (dev_priv->info.display_mmio_offset + 0x71044)
+#define _PIPEB_FRMCOUNT_G4X (dev_priv->info.display_mmio_offset + 0x71040)
+#define _PIPEB_FLIPCOUNT_G4X (dev_priv->info.display_mmio_offset + 0x71044)
/* Display B control */
@@ -5136,18 +5223,18 @@ enum skl_disp_power_wells {
#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8)
#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4)
-#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR)
-#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF)
-#define SPSTRIDE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASTRIDE, _SPBSTRIDE)
-#define SPPOS(pipe, plane) _PIPE(pipe * 2 + plane, _SPAPOS, _SPBPOS)
-#define SPSIZE(pipe, plane) _PIPE(pipe * 2 + plane, _SPASIZE, _SPBSIZE)
-#define SPKEYMINVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMINVAL, _SPBKEYMINVAL)
-#define SPKEYMSK(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMSK, _SPBKEYMSK)
-#define SPSURF(pipe, plane) _PIPE(pipe * 2 + plane, _SPASURF, _SPBSURF)
-#define SPKEYMAXVAL(pipe, plane) _PIPE(pipe * 2 + plane, _SPAKEYMAXVAL, _SPBKEYMAXVAL)
-#define SPTILEOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPATILEOFF, _SPBTILEOFF)
-#define SPCONSTALPHA(pipe, plane) _PIPE(pipe * 2 + plane, _SPACONSTALPHA, _SPBCONSTALPHA)
-#define SPGAMC(pipe, plane) _PIPE(pipe * 2 + plane, _SPAGAMC, _SPBGAMC)
+#define SPCNTR(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR)
+#define SPLINOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF)
+#define SPSTRIDE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE)
+#define SPPOS(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS)
+#define SPSIZE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE)
+#define SPKEYMINVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL)
+#define SPKEYMSK(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK)
+#define SPSURF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF)
+#define SPKEYMAXVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL)
+#define SPTILEOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF)
+#define SPCONSTALPHA(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA)
+#define SPGAMC(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC)
/*
* CHV pipe B sprite CSC
@@ -5363,15 +5450,17 @@ enum skl_disp_power_wells {
#define CPU_VGACNTRL 0x41000
-#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030
-#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4)
-#define DIGITAL_PORTA_SHORT_PULSE_2MS (0 << 2)
-#define DIGITAL_PORTA_SHORT_PULSE_4_5MS (1 << 2)
-#define DIGITAL_PORTA_SHORT_PULSE_6MS (2 << 2)
-#define DIGITAL_PORTA_SHORT_PULSE_100MS (3 << 2)
-#define DIGITAL_PORTA_NO_DETECT (0 << 0)
-#define DIGITAL_PORTA_LONG_PULSE_DETECT_MASK (1 << 1)
-#define DIGITAL_PORTA_SHORT_PULSE_DETECT_MASK (1 << 0)
+#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030
+#define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4)
+#define DIGITAL_PORTA_PULSE_DURATION_2ms (0 << 2) /* pre-HSW */
+#define DIGITAL_PORTA_PULSE_DURATION_4_5ms (1 << 2) /* pre-HSW */
+#define DIGITAL_PORTA_PULSE_DURATION_6ms (2 << 2) /* pre-HSW */
+#define DIGITAL_PORTA_PULSE_DURATION_100ms (3 << 2) /* pre-HSW */
+#define DIGITAL_PORTA_PULSE_DURATION_MASK (3 << 2) /* pre-HSW */
+#define DIGITAL_PORTA_HOTPLUG_STATUS_MASK (3 << 0)
+#define DIGITAL_PORTA_HOTPLUG_NO_DETECT (0 << 0)
+#define DIGITAL_PORTA_HOTPLUG_SHORT_DETECT (1 << 0)
+#define DIGITAL_PORTA_HOTPLUG_LONG_DETECT (2 << 0)
/* refresh rate hardware control */
#define RR_HW_CTL 0x45300
@@ -5491,7 +5580,7 @@ enum skl_disp_power_wells {
#define PS_SCALER_MODE_DYN (0 << 28)
#define PS_SCALER_MODE_HQ (1 << 28)
#define PS_PLANE_SEL_MASK (7 << 25)
-#define PS_PLANE_SEL(plane) ((plane + 1) << 25)
+#define PS_PLANE_SEL(plane) (((plane) + 1) << 25)
#define PS_FILTER_MASK (3 << 23)
#define PS_FILTER_MEDIUM (0 << 23)
#define PS_FILTER_EDGE_ENHANCE (2 << 23)
@@ -5596,7 +5685,7 @@ enum skl_disp_power_wells {
/* legacy palette */
#define _LGC_PALETTE_A 0x4a000
#define _LGC_PALETTE_B 0x4a800
-#define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B)
+#define LGC_PALETTE(pipe, i) (_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4)
#define _GAMMA_MODE_A 0x4a480
#define _GAMMA_MODE_B 0x4ac80
@@ -5656,7 +5745,7 @@ enum skl_disp_power_wells {
#define DE_PLANEA_FLIP_DONE_IVB (1<<3)
#define DE_PLANE_FLIP_DONE_IVB(plane) (1<< (3 + 5*(plane)))
#define DE_PIPEA_VBLANK_IVB (1<<0)
-#define DE_PIPE_VBLANK_IVB(pipe) (1 << (pipe * 5))
+#define DE_PIPE_VBLANK_IVB(pipe) (1 << ((pipe) * 5))
#define VLV_MASTER_IER 0x4400c /* Gunit master IER */
#define MASTER_INTERRUPT_ENABLE (1<<31)
@@ -5680,7 +5769,7 @@ enum skl_disp_power_wells {
#define GEN8_DE_PIPE_C_IRQ (1<<18)
#define GEN8_DE_PIPE_B_IRQ (1<<17)
#define GEN8_DE_PIPE_A_IRQ (1<<16)
-#define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+pipe))
+#define GEN8_DE_PIPE_IRQ(pipe) (1<<(16+(pipe)))
#define GEN8_GT_VECS_IRQ (1<<6)
#define GEN8_GT_PM_IRQ (1<<4)
#define GEN8_GT_VCS2_IRQ (1<<3)
@@ -5693,11 +5782,12 @@ enum skl_disp_power_wells {
#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
-#define GEN8_BCS_IRQ_SHIFT 16
#define GEN8_RCS_IRQ_SHIFT 0
-#define GEN8_VCS2_IRQ_SHIFT 16
+#define GEN8_BCS_IRQ_SHIFT 16
#define GEN8_VCS1_IRQ_SHIFT 0
+#define GEN8_VCS2_IRQ_SHIFT 16
#define GEN8_VECS_IRQ_SHIFT 0
+#define GEN8_WD_IRQ_SHIFT 16
#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe)))
#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe)))
@@ -5723,7 +5813,7 @@ enum skl_disp_power_wells {
#define GEN9_PIPE_PLANE3_FLIP_DONE (1 << 5)
#define GEN9_PIPE_PLANE2_FLIP_DONE (1 << 4)
#define GEN9_PIPE_PLANE1_FLIP_DONE (1 << 3)
-#define GEN9_PIPE_PLANE_FLIP_DONE(p) (1 << (3 + p))
+#define GEN9_PIPE_PLANE_FLIP_DONE(p) (1 << (3 + (p)))
#define GEN8_DE_PIPE_IRQ_FAULT_ERRORS \
(GEN8_PIPE_CURSOR_FAULT | \
GEN8_PIPE_SPRITE_FAULT | \
@@ -5763,21 +5853,6 @@ enum skl_disp_power_wells {
#define GEN8_PCU_IIR 0x444e8
#define GEN8_PCU_IER 0x444ec
-/* BXT hotplug control */
-#define BXT_HOTPLUG_CTL 0xC4030
-#define BXT_DDIA_HPD_ENABLE (1 << 28)
-#define BXT_DDIA_HPD_STATUS (3 << 24)
-#define BXT_DDIC_HPD_ENABLE (1 << 12)
-#define BXT_DDIC_HPD_STATUS (3 << 8)
-#define BXT_DDIB_HPD_ENABLE (1 << 4)
-#define BXT_DDIB_HPD_STATUS (3 << 0)
-#define BXT_HOTPLUG_CTL_MASK (BXT_DDIA_HPD_ENABLE | \
- BXT_DDIB_HPD_ENABLE | \
- BXT_DDIC_HPD_ENABLE)
-#define BXT_HPD_STATUS_MASK (BXT_DDIA_HPD_STATUS | \
- BXT_DDIB_HPD_STATUS | \
- BXT_DDIC_HPD_STATUS)
-
#define ILK_DISPLAY_CHICKEN2 0x42004
/* Required on all Ironlake and Sandybridge according to the B-Spec. */
#define ILK_ELPIN_409_SELECT (1 << 25)
@@ -5950,6 +6025,7 @@ enum skl_disp_power_wells {
#define SDE_AUXB_CPT (1 << 25)
#define SDE_AUX_MASK_CPT (7 << 25)
#define SDE_PORTE_HOTPLUG_SPT (1 << 25)
+#define SDE_PORTA_HOTPLUG_SPT (1 << 24)
#define SDE_PORTD_HOTPLUG_CPT (1 << 23)
#define SDE_PORTC_HOTPLUG_CPT (1 << 22)
#define SDE_PORTB_HOTPLUG_CPT (1 << 21)
@@ -5963,7 +6039,8 @@ enum skl_disp_power_wells {
#define SDE_HOTPLUG_MASK_SPT (SDE_PORTE_HOTPLUG_SPT | \
SDE_PORTD_HOTPLUG_CPT | \
SDE_PORTC_HOTPLUG_CPT | \
- SDE_PORTB_HOTPLUG_CPT)
+ SDE_PORTB_HOTPLUG_CPT | \
+ SDE_PORTA_HOTPLUG_SPT)
#define SDE_GMBUS_CPT (1 << 17)
#define SDE_ERROR_CPT (1 << 16)
#define SDE_AUDIO_CP_REQ_C_CPT (1 << 10)
@@ -5995,49 +6072,49 @@ enum skl_disp_power_wells {
#define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6)
#define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3)
#define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0)
-#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<(pipe*3))
+#define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<((pipe)*3))
/* digital port hotplug */
-#define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */
-#define BXT_PORTA_HOTPLUG_ENABLE (1 << 28)
-#define BXT_PORTA_HOTPLUG_STATUS_MASK (0x3 << 24)
-#define BXT_PORTA_HOTPLUG_NO_DETECT (0 << 24)
-#define BXT_PORTA_HOTPLUG_SHORT_DETECT (1 << 24)
-#define BXT_PORTA_HOTPLUG_LONG_DETECT (2 << 24)
-#define PORTD_HOTPLUG_ENABLE (1 << 20)
-#define PORTD_PULSE_DURATION_2ms (0)
-#define PORTD_PULSE_DURATION_4_5ms (1 << 18)
-#define PORTD_PULSE_DURATION_6ms (2 << 18)
-#define PORTD_PULSE_DURATION_100ms (3 << 18)
-#define PORTD_PULSE_DURATION_MASK (3 << 18)
-#define PORTD_HOTPLUG_STATUS_MASK (0x3 << 16)
+#define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */
+#define PORTA_HOTPLUG_ENABLE (1 << 28) /* LPT:LP+ & BXT */
+#define PORTA_HOTPLUG_STATUS_MASK (3 << 24) /* SPT+ & BXT */
+#define PORTA_HOTPLUG_NO_DETECT (0 << 24) /* SPT+ & BXT */
+#define PORTA_HOTPLUG_SHORT_DETECT (1 << 24) /* SPT+ & BXT */
+#define PORTA_HOTPLUG_LONG_DETECT (2 << 24) /* SPT+ & BXT */
+#define PORTD_HOTPLUG_ENABLE (1 << 20)
+#define PORTD_PULSE_DURATION_2ms (0 << 18) /* pre-LPT */
+#define PORTD_PULSE_DURATION_4_5ms (1 << 18) /* pre-LPT */
+#define PORTD_PULSE_DURATION_6ms (2 << 18) /* pre-LPT */
+#define PORTD_PULSE_DURATION_100ms (3 << 18) /* pre-LPT */
+#define PORTD_PULSE_DURATION_MASK (3 << 18) /* pre-LPT */
+#define PORTD_HOTPLUG_STATUS_MASK (3 << 16)
#define PORTD_HOTPLUG_NO_DETECT (0 << 16)
#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16)
#define PORTD_HOTPLUG_LONG_DETECT (2 << 16)
-#define PORTC_HOTPLUG_ENABLE (1 << 12)
-#define PORTC_PULSE_DURATION_2ms (0)
-#define PORTC_PULSE_DURATION_4_5ms (1 << 10)
-#define PORTC_PULSE_DURATION_6ms (2 << 10)
-#define PORTC_PULSE_DURATION_100ms (3 << 10)
-#define PORTC_PULSE_DURATION_MASK (3 << 10)
-#define PORTC_HOTPLUG_STATUS_MASK (0x3 << 8)
+#define PORTC_HOTPLUG_ENABLE (1 << 12)
+#define PORTC_PULSE_DURATION_2ms (0 << 10) /* pre-LPT */
+#define PORTC_PULSE_DURATION_4_5ms (1 << 10) /* pre-LPT */
+#define PORTC_PULSE_DURATION_6ms (2 << 10) /* pre-LPT */
+#define PORTC_PULSE_DURATION_100ms (3 << 10) /* pre-LPT */
+#define PORTC_PULSE_DURATION_MASK (3 << 10) /* pre-LPT */
+#define PORTC_HOTPLUG_STATUS_MASK (3 << 8)
#define PORTC_HOTPLUG_NO_DETECT (0 << 8)
#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8)
#define PORTC_HOTPLUG_LONG_DETECT (2 << 8)
-#define PORTB_HOTPLUG_ENABLE (1 << 4)
-#define PORTB_PULSE_DURATION_2ms (0)
-#define PORTB_PULSE_DURATION_4_5ms (1 << 2)
-#define PORTB_PULSE_DURATION_6ms (2 << 2)
-#define PORTB_PULSE_DURATION_100ms (3 << 2)
-#define PORTB_PULSE_DURATION_MASK (3 << 2)
-#define PORTB_HOTPLUG_STATUS_MASK (0x3 << 0)
+#define PORTB_HOTPLUG_ENABLE (1 << 4)
+#define PORTB_PULSE_DURATION_2ms (0 << 2) /* pre-LPT */
+#define PORTB_PULSE_DURATION_4_5ms (1 << 2) /* pre-LPT */
+#define PORTB_PULSE_DURATION_6ms (2 << 2) /* pre-LPT */
+#define PORTB_PULSE_DURATION_100ms (3 << 2) /* pre-LPT */
+#define PORTB_PULSE_DURATION_MASK (3 << 2) /* pre-LPT */
+#define PORTB_HOTPLUG_STATUS_MASK (3 << 0)
#define PORTB_HOTPLUG_NO_DETECT (0 << 0)
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTB_HOTPLUG_LONG_DETECT (2 << 0)
-#define PCH_PORT_HOTPLUG2 0xc403C /* SHOTPLUG_CTL2 */
-#define PORTE_HOTPLUG_ENABLE (1 << 4)
-#define PORTE_HOTPLUG_STATUS_MASK (0x3 << 0)
+#define PCH_PORT_HOTPLUG2 0xc403C /* SHOTPLUG_CTL2 SPT+ */
+#define PORTE_HOTPLUG_ENABLE (1 << 4)
+#define PORTE_HOTPLUG_STATUS_MASK (3 << 0)
#define PORTE_HOTPLUG_NO_DETECT (0 << 0)
#define PORTE_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTE_HOTPLUG_LONG_DETECT (2 << 0)
@@ -6106,9 +6183,9 @@ enum skl_disp_power_wells {
#define PCH_SSC4_AUX_PARMS 0xc6214
#define PCH_DPLL_SEL 0xc7000
-#define TRANS_DPLLB_SEL(pipe) (1 << (pipe * 4))
+#define TRANS_DPLLB_SEL(pipe) (1 << ((pipe) * 4))
#define TRANS_DPLLA_SEL(pipe) 0
-#define TRANS_DPLL_ENABLE(pipe) (1 << (pipe * 4 + 3))
+#define TRANS_DPLL_ENABLE(pipe) (1 << ((pipe) * 4 + 3))
/* transcoder */
@@ -6209,16 +6286,16 @@ enum skl_disp_power_wells {
#define HSW_TVIDEO_DIP_CTL(trans) \
_TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A)
-#define HSW_TVIDEO_DIP_AVI_DATA(trans) \
- _TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A)
-#define HSW_TVIDEO_DIP_VS_DATA(trans) \
- _TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A)
-#define HSW_TVIDEO_DIP_SPD_DATA(trans) \
- _TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A)
+#define HSW_TVIDEO_DIP_AVI_DATA(trans, i) \
+ (_TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A) + (i) * 4)
+#define HSW_TVIDEO_DIP_VS_DATA(trans, i) \
+ (_TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A) + (i) * 4)
+#define HSW_TVIDEO_DIP_SPD_DATA(trans, i) \
+ (_TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A) + (i) * 4)
#define HSW_TVIDEO_DIP_GCP(trans) \
_TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A)
-#define HSW_TVIDEO_DIP_VSC_DATA(trans) \
- _TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A)
+#define HSW_TVIDEO_DIP_VSC_DATA(trans, i) \
+ (_TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A) + (i) * 4)
#define HSW_STEREO_3D_CTL_A 0x70020
#define S3D_ENABLE (1<<31)
@@ -6304,9 +6381,11 @@ enum skl_disp_power_wells {
#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2)))
#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2)))
#define FDI_BC_BIFURCATION_SELECT (1 << 12)
+#define SPT_PWM_GRANULARITY (1<<0)
#define SOUTH_CHICKEN2 0xc2004
#define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13)
#define FDI_MPHY_IOSFSB_RESET_CTL (1<<12)
+#define LPT_PWM_GRANULARITY (1<<5)
#define DPLS_EDP_PPS_FIX_DIS (1<<0)
#define _FDI_RXA_CHICKEN 0xc200c
@@ -6508,10 +6587,10 @@ enum skl_disp_power_wells {
#define _BXT_PP_ON_DELAYS2 0xc7308
#define _BXT_PP_OFF_DELAYS2 0xc730c
-#define BXT_PP_STATUS(n) ((!n) ? PCH_PP_STATUS : _BXT_PP_STATUS2)
-#define BXT_PP_CONTROL(n) ((!n) ? PCH_PP_CONTROL : _BXT_PP_CONTROL2)
-#define BXT_PP_ON_DELAYS(n) ((!n) ? PCH_PP_ON_DELAYS : _BXT_PP_ON_DELAYS2)
-#define BXT_PP_OFF_DELAYS(n) ((!n) ? PCH_PP_OFF_DELAYS : _BXT_PP_OFF_DELAYS2)
+#define BXT_PP_STATUS(n) _PIPE(n, PCH_PP_STATUS, _BXT_PP_STATUS2)
+#define BXT_PP_CONTROL(n) _PIPE(n, PCH_PP_CONTROL, _BXT_PP_CONTROL2)
+#define BXT_PP_ON_DELAYS(n) _PIPE(n, PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2)
+#define BXT_PP_OFF_DELAYS(n) _PIPE(n, PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2)
#define PCH_DP_B 0xe4100
#define PCH_DPB_AUX_CH_CTL 0xe4110
@@ -6784,7 +6863,7 @@ enum skl_disp_power_wells {
GEN6_PM_RP_DOWN_THRESHOLD | \
GEN6_PM_RP_DOWN_TIMEOUT)
-#define GEN7_GT_SCRATCH_BASE 0x4F100
+#define GEN7_GT_SCRATCH(i) (0x4F100 + (i) * 4)
#define GEN7_GT_SCRATCH_REG_NUM 8
#define VLV_GTLC_SURVIVABILITY_REG 0x130098
@@ -6843,6 +6922,9 @@ enum skl_disp_power_wells {
#define GEN6_RC6 3
#define GEN6_RC7 4
+#define GEN8_GT_SLICE_INFO 0x138064
+#define GEN8_LSLICESTAT_MASK 0x7
+
#define CHV_POWER_SS0_SIG1 0xa720
#define CHV_POWER_SS1_SIG1 0xa728
#define CHV_SS_PG_ENABLE (1<<1)
@@ -6870,7 +6952,10 @@ enum skl_disp_power_wells {
#define GEN9_PGCTL_SSB_EU311_ACK (1 << 14)
#define GEN7_MISCCPCTL (0x9424)
-#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0)
+#define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0)
+#define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1<<2)
+#define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1<<4)
+#define GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE (1<<6)
#define GEN8_GARBCNTL 0xB004
#define GEN9_GAPS_TSV_CREDIT_DISABLE (1<<7)
@@ -6916,6 +7001,9 @@ enum skl_disp_power_wells {
#define HSW_ROW_CHICKEN3 0xe49c
#define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6)
+#define HALF_SLICE_CHICKEN2 0xe180
+#define GEN8_ST_PO_DISABLE (1<<13)
+
#define HALF_SLICE_CHICKEN3 0xe184
#define HSW_SAMPLE_C_PERFORMANCE (1<<9)
#define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8)
@@ -7159,12 +7247,15 @@ enum skl_disp_power_wells {
#define DDI_BUF_IS_IDLE (1<<7)
#define DDI_A_4_LANES (1<<4)
#define DDI_PORT_WIDTH(width) (((width) - 1) << 1)
+#define DDI_PORT_WIDTH_MASK (7 << 1)
+#define DDI_PORT_WIDTH_SHIFT 1
#define DDI_INIT_DISPLAY_DETECTED (1<<0)
/* DDI Buffer Translations */
#define DDI_BUF_TRANS_A 0x64E00
#define DDI_BUF_TRANS_B 0x64E60
-#define DDI_BUF_TRANS(port) _PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B)
+#define DDI_BUF_TRANS_LO(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8)
+#define DDI_BUF_TRANS_HI(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8 + 4)
/* Sideband Interface (SBI) is programmed indirectly, via
* SBI_ADDR, which contains the register offset; and SBI_DATA,
@@ -7257,7 +7348,7 @@ enum skl_disp_power_wells {
#define TRANS_CLK_SEL(tran) _TRANSCODER(tran, TRANS_CLK_SEL_A, TRANS_CLK_SEL_B)
/* For each transcoder, we need to select the corresponding port clock */
#define TRANS_CLK_SEL_DISABLED (0x0<<29)
-#define TRANS_CLK_SEL_PORT(x) ((x+1)<<29)
+#define TRANS_CLK_SEL_PORT(x) (((x)+1)<<29)
#define TRANSA_MSA_MISC 0x60410
#define TRANSB_MSA_MISC 0x61410
@@ -7330,10 +7421,10 @@ enum skl_disp_power_wells {
/* DPLL control2 */
#define DPLL_CTRL2 0x6C05C
-#define DPLL_CTRL2_DDI_CLK_OFF(port) (1<<(port+15))
+#define DPLL_CTRL2_DDI_CLK_OFF(port) (1<<((port)+15))
#define DPLL_CTRL2_DDI_CLK_SEL_MASK(port) (3<<((port)*3+1))
#define DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port) ((port)*3+1)
-#define DPLL_CTRL2_DDI_CLK_SEL(clk, port) (clk<<((port)*3+1))
+#define DPLL_CTRL2_DDI_CLK_SEL(clk, port) ((clk)<<((port)*3+1))
#define DPLL_CTRL2_DDI_SEL_OVERRIDE(port) (1<<((port)*3))
/* DPLL Status */
@@ -7346,31 +7437,31 @@ enum skl_disp_power_wells {
#define DPLL3_CFGCR1 0x6C050
#define DPLL_CFGCR1_FREQ_ENABLE (1<<31)
#define DPLL_CFGCR1_DCO_FRACTION_MASK (0x7fff<<9)
-#define DPLL_CFGCR1_DCO_FRACTION(x) (x<<9)
+#define DPLL_CFGCR1_DCO_FRACTION(x) ((x)<<9)
#define DPLL_CFGCR1_DCO_INTEGER_MASK (0x1ff)
#define DPLL1_CFGCR2 0x6C044
#define DPLL2_CFGCR2 0x6C04C
#define DPLL3_CFGCR2 0x6C054
#define DPLL_CFGCR2_QDIV_RATIO_MASK (0xff<<8)
-#define DPLL_CFGCR2_QDIV_RATIO(x) (x<<8)
-#define DPLL_CFGCR2_QDIV_MODE(x) (x<<7)
+#define DPLL_CFGCR2_QDIV_RATIO(x) ((x)<<8)
+#define DPLL_CFGCR2_QDIV_MODE(x) ((x)<<7)
#define DPLL_CFGCR2_KDIV_MASK (3<<5)
-#define DPLL_CFGCR2_KDIV(x) (x<<5)
+#define DPLL_CFGCR2_KDIV(x) ((x)<<5)
#define DPLL_CFGCR2_KDIV_5 (0<<5)
#define DPLL_CFGCR2_KDIV_2 (1<<5)
#define DPLL_CFGCR2_KDIV_3 (2<<5)
#define DPLL_CFGCR2_KDIV_1 (3<<5)
#define DPLL_CFGCR2_PDIV_MASK (7<<2)
-#define DPLL_CFGCR2_PDIV(x) (x<<2)
+#define DPLL_CFGCR2_PDIV(x) ((x)<<2)
#define DPLL_CFGCR2_PDIV_1 (0<<2)
#define DPLL_CFGCR2_PDIV_2 (1<<2)
#define DPLL_CFGCR2_PDIV_3 (2<<2)
#define DPLL_CFGCR2_PDIV_7 (4<<2)
#define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3)
-#define GET_CFG_CR1_REG(id) (DPLL1_CFGCR1 + (id - SKL_DPLL1) * 8)
-#define GET_CFG_CR2_REG(id) (DPLL1_CFGCR2 + (id - SKL_DPLL1) * 8)
+#define DPLL_CFGCR1(id) (DPLL1_CFGCR1 + ((id) - SKL_DPLL1) * 8)
+#define DPLL_CFGCR2(id) (DPLL1_CFGCR2 + ((id) - SKL_DPLL1) * 8)
/* BXT display engine PLL */
#define BXT_DE_PLL_CTL 0x6d000
@@ -7475,9 +7566,116 @@ enum skl_disp_power_wells {
#define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */
+/* BXT MIPI clock controls */
+#define BXT_MAX_VAR_OUTPUT_KHZ 39500
+
+#define BXT_MIPI_CLOCK_CTL 0x46090
+#define BXT_MIPI1_DIV_SHIFT 26
+#define BXT_MIPI2_DIV_SHIFT 10
+#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_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_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 MIPI mode configure */
+#define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8
+#define _BXT_MIPIC_TRANS_HACTIVE 0x6B8F8
+#define BXT_MIPI_TRANS_HACTIVE(tc) _MIPI_PORT(tc, \
+ _BXT_MIPIA_TRANS_HACTIVE, _BXT_MIPIC_TRANS_HACTIVE)
+
+#define _BXT_MIPIA_TRANS_VACTIVE 0x6B0FC
+#define _BXT_MIPIC_TRANS_VACTIVE 0x6B8FC
+#define BXT_MIPI_TRANS_VACTIVE(tc) _MIPI_PORT(tc, \
+ _BXT_MIPIA_TRANS_VACTIVE, _BXT_MIPIC_TRANS_VACTIVE)
+
+#define _BXT_MIPIA_TRANS_VTOTAL 0x6B100
+#define _BXT_MIPIC_TRANS_VTOTAL 0x6B900
+#define BXT_MIPI_TRANS_VTOTAL(tc) _MIPI_PORT(tc, \
+ _BXT_MIPIA_TRANS_VTOTAL, _BXT_MIPIC_TRANS_VTOTAL)
+
+#define BXT_DSI_PLL_CTL 0x161000
+#define BXT_DSI_PLL_PVD_RATIO_SHIFT 16
+#define BXT_DSI_PLL_PVD_RATIO_MASK (3 << BXT_DSI_PLL_PVD_RATIO_SHIFT)
+#define BXT_DSI_PLL_PVD_RATIO_1 (1 << BXT_DSI_PLL_PVD_RATIO_SHIFT)
+#define BXT_DSIC_16X_BY2 (1 << 10)
+#define BXT_DSIC_16X_BY3 (2 << 10)
+#define BXT_DSIC_16X_BY4 (3 << 10)
+#define BXT_DSIA_16X_BY2 (1 << 8)
+#define BXT_DSIA_16X_BY3 (2 << 8)
+#define BXT_DSIA_16X_BY4 (3 << 8)
+#define BXT_DSI_FREQ_SEL_SHIFT 8
+#define BXT_DSI_FREQ_SEL_MASK (0xF << BXT_DSI_FREQ_SEL_SHIFT)
+
+#define BXT_DSI_PLL_RATIO_MAX 0x7D
+#define BXT_DSI_PLL_RATIO_MIN 0x22
+#define BXT_DSI_PLL_RATIO_MASK 0xFF
+#define BXT_REF_CLOCK_KHZ 19500
+
+#define BXT_DSI_PLL_ENABLE 0x46080
+#define BXT_DSI_PLL_DO_ENABLE (1 << 31)
+#define BXT_DSI_PLL_LOCKED (1 << 30)
+
#define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190)
#define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700)
#define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
+
+ /* BXT port control */
+#define _BXT_MIPIA_PORT_CTRL 0x6B0C0
+#define _BXT_MIPIC_PORT_CTRL 0x6B8C0
+#define BXT_MIPI_PORT_CTRL(tc) _MIPI_PORT(tc, _BXT_MIPIA_PORT_CTRL, \
+ _BXT_MIPIC_PORT_CTRL)
+
#define DPI_ENABLE (1 << 31) /* A + C */
#define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27
#define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27)
@@ -7781,7 +7979,7 @@ enum skl_disp_power_wells {
#define VIRTUAL_CHANNEL_SHIFT 6
#define VIRTUAL_CHANNEL_MASK (3 << 6)
#define DATA_TYPE_SHIFT 0
-#define DATA_TYPE_MASK (3f << 0)
+#define DATA_TYPE_MASK (0x3f << 0)
/* data type values, see include/video/mipi_display.h */
#define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074)
@@ -7888,6 +8086,11 @@ enum skl_disp_power_wells {
#define READ_REQUEST_PRIORITY_HIGH (3 << 3)
#define RGB_FLIP_TO_BGR (1 << 2)
+#define BXT_PIPE_SELECT_MASK (7 << 7)
+#define BXT_PIPE_SELECT_C (2 << 7)
+#define BXT_PIPE_SELECT_B (1 << 7)
+#define BXT_PIPE_SELECT_A (0 << 7)
+
#define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108)
#define _MIPIC_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908)
#define MIPI_DATA_ADDRESS(port) _MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 1ccac618468e..2d9182189422 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -122,12 +122,24 @@ int i915_save_state(struct drm_device *dev)
dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE);
/* Scratch space */
- for (i = 0; i < 16; i++) {
- dev_priv->regfile.saveSWF0[i] = I915_READ(SWF00 + (i << 2));
- dev_priv->regfile.saveSWF1[i] = I915_READ(SWF10 + (i << 2));
+ if (IS_GEN2(dev_priv) && IS_MOBILE(dev_priv)) {
+ for (i = 0; i < 7; i++) {
+ dev_priv->regfile.saveSWF0[i] = I915_READ(SWF0(i));
+ dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i));
+ }
+ for (i = 0; i < 3; i++)
+ dev_priv->regfile.saveSWF3[i] = I915_READ(SWF3(i));
+ } else if (IS_GEN2(dev_priv)) {
+ for (i = 0; i < 7; i++)
+ dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i));
+ } else if (HAS_GMCH_DISPLAY(dev_priv)) {
+ for (i = 0; i < 16; i++) {
+ dev_priv->regfile.saveSWF0[i] = I915_READ(SWF0(i));
+ dev_priv->regfile.saveSWF1[i] = I915_READ(SWF1(i));
+ }
+ for (i = 0; i < 3; i++)
+ dev_priv->regfile.saveSWF3[i] = I915_READ(SWF3(i));
}
- for (i = 0; i < 3; i++)
- dev_priv->regfile.saveSWF2[i] = I915_READ(SWF30 + (i << 2));
mutex_unlock(&dev->struct_mutex);
@@ -156,12 +168,25 @@ int i915_restore_state(struct drm_device *dev)
/* Memory arbitration state */
I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000);
- for (i = 0; i < 16; i++) {
- I915_WRITE(SWF00 + (i << 2), dev_priv->regfile.saveSWF0[i]);
- I915_WRITE(SWF10 + (i << 2), dev_priv->regfile.saveSWF1[i]);
+ /* Scratch space */
+ if (IS_GEN2(dev_priv) && IS_MOBILE(dev_priv)) {
+ for (i = 0; i < 7; i++) {
+ I915_WRITE(SWF0(i), dev_priv->regfile.saveSWF0[i]);
+ I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]);
+ }
+ for (i = 0; i < 3; i++)
+ I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]);
+ } else if (IS_GEN2(dev_priv)) {
+ for (i = 0; i < 7; i++)
+ I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]);
+ } else if (HAS_GMCH_DISPLAY(dev_priv)) {
+ for (i = 0; i < 16; i++) {
+ I915_WRITE(SWF0(i), dev_priv->regfile.saveSWF0[i]);
+ I915_WRITE(SWF1(i), dev_priv->regfile.saveSWF1[i]);
+ }
+ for (i = 0; i < 3; i++)
+ I915_WRITE(SWF3(i), dev_priv->regfile.saveSWF3[i]);
}
- for (i = 0; i < 3; i++)
- I915_WRITE(SWF30 + (i << 2), dev_priv->regfile.saveSWF2[i]);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 55bd04c6b939..50ce9ce2b269 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -39,7 +39,7 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u64 raw_time; /* 32b value may overflow during fixed point math */
- u64 units = 128ULL, div = 100000ULL, bias = 100ULL;
+ u64 units = 128ULL, div = 100000ULL;
u32 ret;
if (!intel_enable_rc6(dev))
@@ -49,41 +49,19 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
if (IS_VALLEYVIEW(dev)) {
- u32 clk_reg, czcount_30ns;
-
- if (IS_CHERRYVIEW(dev))
- clk_reg = CHV_CLK_CTL1;
- else
- clk_reg = VLV_CLK_CTL2;
-
- czcount_30ns = I915_READ(clk_reg) >> CLK_CTL2_CZCOUNT_30NS_SHIFT;
-
- if (!czcount_30ns) {
- WARN(!czcount_30ns, "bogus CZ count value");
- ret = 0;
- goto out;
- }
-
- if (IS_CHERRYVIEW(dev) && czcount_30ns == 1) {
- /* Special case for 320Mhz */
- div = 10000000ULL;
- units = 3125ULL;
- } else {
- czcount_30ns += 1;
- div = 1000000ULL;
- units = DIV_ROUND_UP_ULL(30ULL * bias, czcount_30ns);
- }
+ units = 1;
+ div = dev_priv->czclk_freq;
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
units <<= 8;
-
- div = div * bias;
+ } else if (IS_BROXTON(dev)) {
+ units = 1;
+ div = 1200; /* 833.33ns */
}
raw_time = I915_READ(reg) * units;
ret = DIV_ROUND_UP_ULL(raw_time, div);
-out:
intel_runtime_pm_put(dev_priv);
return ret;
}
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 2f34c47bd4bf..04fe8491c8b6 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -17,8 +17,8 @@
/* pipe updates */
TRACE_EVENT(i915_pipe_update_start,
- TP_PROTO(struct intel_crtc *crtc, u32 min, u32 max),
- TP_ARGS(crtc, min, max),
+ TP_PROTO(struct intel_crtc *crtc),
+ TP_ARGS(crtc),
TP_STRUCT__entry(
__field(enum pipe, pipe)
@@ -33,8 +33,8 @@ TRACE_EVENT(i915_pipe_update_start,
__entry->frame = crtc->base.dev->driver->get_vblank_counter(crtc->base.dev,
crtc->pipe);
__entry->scanline = intel_get_crtc_scanline(crtc);
- __entry->min = min;
- __entry->max = max;
+ __entry->min = crtc->debug.min_vbl;
+ __entry->max = crtc->debug.max_vbl;
),
TP_printk("pipe %c, frame=%u, scanline=%u, min=%u, max=%u",
@@ -43,8 +43,8 @@ TRACE_EVENT(i915_pipe_update_start,
);
TRACE_EVENT(i915_pipe_update_vblank_evaded,
- TP_PROTO(struct intel_crtc *crtc, u32 min, u32 max, u32 frame),
- TP_ARGS(crtc, min, max, frame),
+ TP_PROTO(struct intel_crtc *crtc),
+ TP_ARGS(crtc),
TP_STRUCT__entry(
__field(enum pipe, pipe)
@@ -56,10 +56,10 @@ TRACE_EVENT(i915_pipe_update_vblank_evaded,
TP_fast_assign(
__entry->pipe = crtc->pipe;
- __entry->frame = frame;
- __entry->scanline = intel_get_crtc_scanline(crtc);
- __entry->min = min;
- __entry->max = max;
+ __entry->frame = crtc->debug.start_vbl_count;
+ __entry->scanline = crtc->debug.scanline_start;
+ __entry->min = crtc->debug.min_vbl;
+ __entry->max = crtc->debug.max_vbl;
),
TP_printk("pipe %c, frame=%u, scanline=%u, min=%u, max=%u",
@@ -68,8 +68,8 @@ TRACE_EVENT(i915_pipe_update_vblank_evaded,
);
TRACE_EVENT(i915_pipe_update_end,
- TP_PROTO(struct intel_crtc *crtc, u32 frame),
- TP_ARGS(crtc, frame),
+ TP_PROTO(struct intel_crtc *crtc, u32 frame, int scanline_end),
+ TP_ARGS(crtc, frame, scanline_end),
TP_STRUCT__entry(
__field(enum pipe, pipe)
@@ -80,7 +80,7 @@ TRACE_EVENT(i915_pipe_update_end,
TP_fast_assign(
__entry->pipe = crtc->pipe;
__entry->frame = frame;
- __entry->scanline = intel_get_crtc_scanline(crtc);
+ __entry->scanline = scanline_end;
),
TP_printk("pipe %c, frame=%u, scanline=%u",
@@ -107,6 +107,26 @@ TRACE_EVENT(i915_gem_object_create,
TP_printk("obj=%p, size=%u", __entry->obj, __entry->size)
);
+TRACE_EVENT(i915_gem_shrink,
+ TP_PROTO(struct drm_i915_private *i915, unsigned long target, unsigned flags),
+ TP_ARGS(i915, target, flags),
+
+ TP_STRUCT__entry(
+ __field(int, dev)
+ __field(unsigned long, target)
+ __field(unsigned, flags)
+ ),
+
+ TP_fast_assign(
+ __entry->dev = i915->dev->primary->index;
+ __entry->target = target;
+ __entry->flags = flags;
+ ),
+
+ TP_printk("dev=%d, target=%lu, flags=%x",
+ __entry->dev, __entry->target, __entry->flags)
+);
+
TRACE_EVENT(i915_vma_bind,
TP_PROTO(struct i915_vma *vma, unsigned flags),
TP_ARGS(vma, flags),
@@ -186,33 +206,49 @@ DEFINE_EVENT(i915_va, i915_va_alloc,
TP_ARGS(vm, start, length, name)
);
-DECLARE_EVENT_CLASS(i915_page_table_entry,
- TP_PROTO(struct i915_address_space *vm, u32 pde, u64 start, u64 pde_shift),
- TP_ARGS(vm, pde, start, pde_shift),
+DECLARE_EVENT_CLASS(i915_px_entry,
+ TP_PROTO(struct i915_address_space *vm, u32 px, u64 start, u64 px_shift),
+ TP_ARGS(vm, px, start, px_shift),
TP_STRUCT__entry(
__field(struct i915_address_space *, vm)
- __field(u32, pde)
+ __field(u32, px)
__field(u64, start)
__field(u64, end)
),
TP_fast_assign(
__entry->vm = vm;
- __entry->pde = pde;
+ __entry->px = px;
__entry->start = start;
- __entry->end = ((start + (1ULL << pde_shift)) & ~((1ULL << pde_shift)-1)) - 1;
+ __entry->end = ((start + (1ULL << px_shift)) & ~((1ULL << px_shift)-1)) - 1;
),
TP_printk("vm=%p, pde=%d (0x%llx-0x%llx)",
- __entry->vm, __entry->pde, __entry->start, __entry->end)
+ __entry->vm, __entry->px, __entry->start, __entry->end)
);
-DEFINE_EVENT(i915_page_table_entry, i915_page_table_entry_alloc,
+DEFINE_EVENT(i915_px_entry, i915_page_table_entry_alloc,
TP_PROTO(struct i915_address_space *vm, u32 pde, u64 start, u64 pde_shift),
TP_ARGS(vm, pde, start, pde_shift)
);
+DEFINE_EVENT_PRINT(i915_px_entry, i915_page_directory_entry_alloc,
+ TP_PROTO(struct i915_address_space *vm, u32 pdpe, u64 start, u64 pdpe_shift),
+ TP_ARGS(vm, pdpe, start, pdpe_shift),
+
+ TP_printk("vm=%p, pdpe=%d (0x%llx-0x%llx)",
+ __entry->vm, __entry->px, __entry->start, __entry->end)
+);
+
+DEFINE_EVENT_PRINT(i915_px_entry, i915_page_directory_pointer_entry_alloc,
+ TP_PROTO(struct i915_address_space *vm, u32 pml4e, u64 start, u64 pml4e_shift),
+ TP_ARGS(vm, pml4e, start, pml4e_shift),
+
+ TP_printk("vm=%p, pml4e=%d (0x%llx-0x%llx)",
+ __entry->vm, __entry->px, __entry->start, __entry->end)
+);
+
/* Avoid extra math because we only support two sizes. The format is defined by
* bitmap_scnprintf. Each 32 bits is 8 HEX digits followed by comma */
#define TRACE_PT_SIZE(bits) \
diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h
index 97a88b5f6a26..21c97f44d637 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.h
+++ b/drivers/gpu/drm/i915/i915_vgpu.h
@@ -40,6 +40,19 @@
#define INTEL_VGT_IF_VERSION \
INTEL_VGT_IF_VERSION_ENCODE(VGT_VERSION_MAJOR, VGT_VERSION_MINOR)
+/*
+ * notifications from guest to vgpu device model
+ */
+enum vgt_g2v_type {
+ VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE = 2,
+ VGT_G2V_PPGTT_L3_PAGE_TABLE_DESTROY,
+ VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE,
+ VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY,
+ VGT_G2V_EXECLIST_CONTEXT_CREATE,
+ VGT_G2V_EXECLIST_CONTEXT_DESTROY,
+ VGT_G2V_MAX,
+};
+
struct vgt_if {
uint64_t magic; /* VGT_MAGIC */
uint16_t version_major;
@@ -70,11 +83,28 @@ struct vgt_if {
uint32_t rsv3[0x200 - 24]; /* pad to half page */
/*
* The bottom half page is for response from Gfx driver to hypervisor.
- * Set to reserved fields temporarily by now.
*/
uint32_t rsv4;
uint32_t display_ready; /* ready for display owner switch */
- uint32_t rsv5[0x200 - 2]; /* pad to one page */
+
+ uint32_t rsv5[4];
+
+ uint32_t g2v_notify;
+ uint32_t rsv6[7];
+
+ uint32_t pdp0_lo;
+ uint32_t pdp0_hi;
+ uint32_t pdp1_lo;
+ uint32_t pdp1_hi;
+ uint32_t pdp2_lo;
+ uint32_t pdp2_hi;
+ uint32_t pdp3_lo;
+ uint32_t pdp3_hi;
+
+ uint32_t execlist_context_descriptor_lo;
+ uint32_t execlist_context_descriptor_hi;
+
+ uint32_t rsv7[0x200 - 24]; /* pad to one page */
} __packed;
#define vgtif_reg(x) \
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
index d96eee1ae9c5..eb638a1e69d2 100644
--- a/drivers/gpu/drm/i915/intel_acpi.c
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -5,7 +5,6 @@
*/
#include <linux/pci.h>
#include <linux/acpi.h>
-#include <linux/vga_switcheroo.h>
#include <drm/drmP.h>
#include "i915_drv.h"
@@ -146,7 +145,7 @@ static bool intel_dsm_detect(void)
if (vga_count == 2 && has_dsm) {
acpi_get_name(intel_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
- DRM_DEBUG_DRIVER("VGA switcheroo: detected DSM switching method %s handle\n",
+ DRM_DEBUG_DRIVER("vga_switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
return true;
}
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index e2531cf59266..f1975f267710 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -85,21 +85,15 @@ intel_connector_atomic_get_property(struct drm_connector *connector,
struct drm_crtc_state *
intel_crtc_duplicate_state(struct drm_crtc *crtc)
{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_crtc_state *crtc_state;
- if (WARN_ON(!intel_crtc->config))
- crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
- else
- crtc_state = kmemdup(intel_crtc->config,
- sizeof(*intel_crtc->config), GFP_KERNEL);
-
+ crtc_state = kmemdup(crtc->state, sizeof(*crtc_state), GFP_KERNEL);
if (!crtc_state)
return NULL;
__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base);
- crtc_state->base.crtc = crtc;
+ crtc_state->update_pipe = false;
return &crtc_state->base;
}
@@ -149,9 +143,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev,
int i, j;
num_scalers_need = hweight32(scaler_state->scaler_users);
- DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users = 0x%x\n",
- crtc_state, num_scalers_need, intel_crtc->num_scalers,
- scaler_state->scaler_users);
/*
* High level flow:
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
index f1ab8e4b9c11..a11980696595 100644
--- a/drivers/gpu/drm/i915/intel_atomic_plane.c
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -76,11 +76,7 @@ intel_plane_duplicate_state(struct drm_plane *plane)
struct drm_plane_state *state;
struct intel_plane_state *intel_state;
- if (WARN_ON(!plane->state))
- intel_state = intel_create_plane_state(plane);
- else
- intel_state = kmemdup(plane->state, sizeof(*intel_state),
- GFP_KERNEL);
+ intel_state = kmemdup(plane->state, sizeof(*intel_state), GFP_KERNEL);
if (!intel_state)
return NULL;
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index ae8df0a43de6..4dccd9b003a1 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -50,27 +50,32 @@
* co-operation between the graphics and audio drivers is handled via audio
* related registers. (The notable exception is the power management, not
* covered here.)
+ *
+ * The struct i915_audio_component is used to interact between the graphics
+ * and audio drivers. The struct i915_audio_component_ops *ops in it is
+ * defined in graphics driver and called in audio driver. The
+ * struct i915_audio_component_audio_ops *audio_ops is called from i915 driver.
*/
static const struct {
int clock;
u32 config;
} hdmi_audio_clock[] = {
- { DIV_ROUND_UP(25200 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 },
+ { 25175, AUD_CONFIG_PIXEL_CLOCK_HDMI_25175 },
{ 25200, AUD_CONFIG_PIXEL_CLOCK_HDMI_25200 }, /* default per bspec */
{ 27000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27000 },
- { 27000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 },
+ { 27027, AUD_CONFIG_PIXEL_CLOCK_HDMI_27027 },
{ 54000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54000 },
- { 54000 * 1001 / 1000, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 },
- { DIV_ROUND_UP(74250 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 },
+ { 54054, AUD_CONFIG_PIXEL_CLOCK_HDMI_54054 },
+ { 74176, AUD_CONFIG_PIXEL_CLOCK_HDMI_74176 },
{ 74250, AUD_CONFIG_PIXEL_CLOCK_HDMI_74250 },
- { DIV_ROUND_UP(148500 * 1000, 1001), AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 },
+ { 148352, AUD_CONFIG_PIXEL_CLOCK_HDMI_148352 },
{ 148500, AUD_CONFIG_PIXEL_CLOCK_HDMI_148500 },
};
/* HDMI N/CTS table */
#define TMDS_297M 297000
-#define TMDS_296M DIV_ROUND_UP(297000 * 1000, 1001)
+#define TMDS_296M 296703
static const struct {
int sample_rate;
int clock;
@@ -94,17 +99,18 @@ static const struct {
};
/* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
-static u32 audio_config_hdmi_pixel_clock(struct drm_display_mode *mode)
+static u32 audio_config_hdmi_pixel_clock(const struct drm_display_mode *adjusted_mode)
{
int i;
for (i = 0; i < ARRAY_SIZE(hdmi_audio_clock); i++) {
- if (mode->clock == hdmi_audio_clock[i].clock)
+ if (adjusted_mode->crtc_clock == hdmi_audio_clock[i].clock)
break;
}
if (i == ARRAY_SIZE(hdmi_audio_clock)) {
- DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n", mode->clock);
+ DRM_DEBUG_KMS("HDMI audio pixel clock setting for %d not found, falling back to defaults\n",
+ adjusted_mode->crtc_clock);
i = 1;
}
@@ -202,7 +208,7 @@ static void g4x_audio_codec_disable(struct intel_encoder *encoder)
static void g4x_audio_codec_enable(struct drm_connector *connector,
struct intel_encoder *encoder,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
uint8_t *eld = connector->eld;
@@ -271,7 +277,7 @@ static void hsw_audio_codec_disable(struct intel_encoder *encoder)
static void hsw_audio_codec_enable(struct drm_connector *connector,
struct intel_encoder *encoder,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
@@ -325,10 +331,10 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
tmp |= AUD_CONFIG_N_VALUE_INDEX;
else
- tmp |= audio_config_hdmi_pixel_clock(mode);
+ tmp |= audio_config_hdmi_pixel_clock(adjusted_mode);
tmp &= ~AUD_CONFIG_N_PROG_ENABLE;
- if (audio_rate_need_prog(intel_crtc, mode)) {
+ if (audio_rate_need_prog(intel_crtc, adjusted_mode)) {
if (!acomp)
rate = 0;
else if (port >= PORT_A && port <= PORT_E)
@@ -337,7 +343,7 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
DRM_ERROR("invalid port: %d\n", port);
rate = 0;
}
- n = audio_config_get_n(mode, rate);
+ n = audio_config_get_n(adjusted_mode, rate);
if (n != 0)
tmp = audio_config_setup_n_reg(n, tmp);
else
@@ -398,7 +404,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder)
static void ilk_audio_codec_enable(struct drm_connector *connector,
struct intel_encoder *encoder,
- struct drm_display_mode *mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
@@ -475,7 +481,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DISPLAYPORT))
tmp |= AUD_CONFIG_N_VALUE_INDEX;
else
- tmp |= audio_config_hdmi_pixel_clock(mode);
+ tmp |= audio_config_hdmi_pixel_clock(adjusted_mode);
I915_WRITE(aud_config, tmp);
}
@@ -490,7 +496,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
{
struct drm_encoder *encoder = &intel_encoder->base;
struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
- struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
struct drm_connector *connector;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -498,7 +504,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
enum port port = intel_dig_port->port;
- connector = drm_select_eld(encoder, mode);
+ connector = drm_select_eld(encoder);
if (!connector)
return;
@@ -513,10 +519,11 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
connector->eld[5] |= (1 << 2);
- connector->eld[6] = drm_av_sync_delay(connector, mode) / 2;
+ connector->eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
if (dev_priv->display.audio_codec_enable)
- dev_priv->display.audio_codec_enable(connector, intel_encoder, mode);
+ dev_priv->display.audio_codec_enable(connector, intel_encoder,
+ adjusted_mode);
if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index c19e669ffe50..ce82f9c7df24 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -1231,20 +1231,13 @@ static const struct dmi_system_id intel_no_opregion_vbt[] = {
{ }
};
-static const struct bdb_header *validate_vbt(const void __iomem *_base,
+static const struct bdb_header *validate_vbt(const void *base,
size_t size,
- const void __iomem *_vbt,
+ const void *_vbt,
const char *source)
{
- /*
- * This is the one place where we explicitly discard the address space
- * (__iomem) of the BIOS/VBT. (And this will cause a sparse complaint.)
- * From now on everything is based on 'base', and treated as regular
- * memory.
- */
- const void *base = (const void *) _base;
- size_t offset = _vbt - _base;
- const struct vbt_header *vbt = base + offset;
+ size_t offset = _vbt - base;
+ const struct vbt_header *vbt = _vbt;
const struct bdb_header *bdb;
if (offset + sizeof(struct vbt_header) > size) {
@@ -1282,7 +1275,15 @@ static const struct bdb_header *find_vbt(void __iomem *bios, size_t size)
/* Scour memory looking for the VBT signature. */
for (i = 0; i + 4 < size; i++) {
if (ioread32(bios + i) == *((const u32 *) "$VBT")) {
- bdb = validate_vbt(bios, size, bios + i, "PCI ROM");
+ /*
+ * This is the one place where we explicitly discard the
+ * address space (__iomem) of the BIOS/VBT. From now on
+ * everything is based on 'base', and treated as regular
+ * memory.
+ */
+ void *_bios = (void __force *) bios;
+
+ bdb = validate_vbt(_bios, size, _bios + i, "PCI ROM");
break;
}
}
@@ -1350,21 +1351,3 @@ intel_parse_bios(struct drm_device *dev)
return 0;
}
-
-/* Ensure that vital registers have been initialised, even if the BIOS
- * is absent or just failing to do its job.
- */
-void intel_setup_bios(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- /* Set the Panel Power On/Off timings if uninitialized. */
- if (!HAS_PCH_SPLIT(dev) &&
- I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) {
- /* Set T2 to 40ms and T5 to 200ms */
- I915_WRITE(PP_ON_DELAYS, 0x019007d0);
-
- /* Set T3 to 35ms and Tx to 200ms */
- I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
- }
-}
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 46cd5c7ebacd..7ec8c9aefb84 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -588,7 +588,6 @@ struct bdb_psr {
struct psr_table psr_table[16];
} __packed;
-void intel_setup_bios(struct drm_device *dev);
int intel_parse_bios(struct drm_device *dev);
/*
@@ -742,7 +741,6 @@ int intel_parse_bios(struct drm_device *dev);
*/
#define DEVICE_TYPE_eDP_BITS \
(DEVICE_TYPE_INTERNAL_CONNECTOR | \
- DEVICE_TYPE_NOT_HDMI_OUTPUT | \
DEVICE_TYPE_MIPI_OUTPUT | \
DEVICE_TYPE_COMPOSITE_OUTPUT | \
DEVICE_TYPE_DUAL_CHANNEL | \
@@ -750,7 +748,6 @@ int intel_parse_bios(struct drm_device *dev);
DEVICE_TYPE_TMDS_DVI_SIGNALING | \
DEVICE_TYPE_VIDEO_SIGNALING | \
DEVICE_TYPE_DISPLAYPORT_OUTPUT | \
- DEVICE_TYPE_DIGITAL_OUTPUT | \
DEVICE_TYPE_ANALOG_OUTPUT)
/* define the DVO port for HDMI output type */
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index af5e43bef4a4..b84aaa0bb48a 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -158,7 +158,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder);
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
u32 adpa;
if (INTEL_INFO(dev)->gen >= 5)
@@ -376,7 +376,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 hotplug_en, orig, stat;
+ u32 stat;
bool ret = false;
int i, tries = 0;
@@ -395,12 +395,12 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
tries = 2;
else
tries = 1;
- hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
- hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
for (i = 0; i < tries ; i++) {
/* turn on the FORCE_DETECT */
- I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+ i915_hotplug_interrupt_update(dev_priv,
+ CRT_HOTPLUG_FORCE_DETECT,
+ CRT_HOTPLUG_FORCE_DETECT);
/* wait for FORCE_DETECT to go off */
if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
CRT_HOTPLUG_FORCE_DETECT) == 0,
@@ -415,8 +415,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
/* clear the interrupt we just generated, if any */
I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
- /* and put the bits back */
- I915_WRITE(PORT_HOTPLUG_EN, orig);
+ i915_hotplug_interrupt_update(dev_priv, CRT_HOTPLUG_FORCE_DETECT, 0);
return ret;
}
@@ -891,7 +890,7 @@ void intel_crt_init(struct drm_device *dev)
u32 fdi_config = FDI_RX_POLARITY_REVERSED_LPT |
FDI_RX_LINK_REVERSAL_OVERRIDE;
- dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config;
+ dev_priv->fdi_rx_config = I915_READ(FDI_RX_CTL(PIPE_A)) & fdi_config;
}
intel_crt_reset(connector);
diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
index d0f1b8d833cd..9e530a739354 100644
--- a/drivers/gpu/drm/i915/intel_csr.c
+++ b/drivers/gpu/drm/i915/intel_csr.c
@@ -42,13 +42,15 @@
*/
#define I915_CSR_SKL "i915/skl_dmc_ver1.bin"
+#define I915_CSR_BXT "i915/bxt_dmc_ver1.bin"
MODULE_FIRMWARE(I915_CSR_SKL);
+MODULE_FIRMWARE(I915_CSR_BXT);
/*
* SKL CSR registers for DC5 and DC6
*/
-#define CSR_PROGRAM_BASE 0x80000
+#define CSR_PROGRAM(i) (0x80000 + (i) * 4)
#define CSR_SSP_BASE_ADDR_GEN9 0x00002FC0
#define CSR_HTP_ADDR_SKL 0x00500034
#define CSR_SSP_BASE 0x8F074
@@ -181,11 +183,19 @@ static const struct stepping_info skl_stepping_info[] = {
{'G', '0'}, {'H', '0'}, {'I', '0'}
};
+static struct stepping_info bxt_stepping_info[] = {
+ {'A', '0'}, {'A', '1'}, {'A', '2'},
+ {'B', '0'}, {'B', '1'}, {'B', '2'}
+};
+
static char intel_get_stepping(struct drm_device *dev)
{
if (IS_SKYLAKE(dev) && (dev->pdev->revision <
ARRAY_SIZE(skl_stepping_info)))
return skl_stepping_info[dev->pdev->revision].stepping;
+ else if (IS_BROXTON(dev) && (dev->pdev->revision <
+ ARRAY_SIZE(bxt_stepping_info)))
+ return bxt_stepping_info[dev->pdev->revision].stepping;
else
return -ENODATA;
}
@@ -195,6 +205,9 @@ static char intel_get_substepping(struct drm_device *dev)
if (IS_SKYLAKE(dev) && (dev->pdev->revision <
ARRAY_SIZE(skl_stepping_info)))
return skl_stepping_info[dev->pdev->revision].substepping;
+ else if (IS_BROXTON(dev) && (dev->pdev->revision <
+ ARRAY_SIZE(bxt_stepping_info)))
+ return bxt_stepping_info[dev->pdev->revision].substepping;
else
return -ENODATA;
}
@@ -252,11 +265,19 @@ void intel_csr_load_program(struct drm_device *dev)
return;
}
+ /*
+ * FIXME: Firmware gets lost on S3/S4, but not when entering system
+ * standby or suspend-to-idle (which is just like forced runtime pm).
+ * Unfortunately the ACPI subsystem doesn't yet give us a way to
+ * differentiate this, hence figure it out with this hack.
+ */
+ if (I915_READ(CSR_PROGRAM(0)))
+ return;
+
mutex_lock(&dev_priv->csr_lock);
fw_size = dev_priv->csr.dmc_fw_size;
for (i = 0; i < fw_size; i++)
- I915_WRITE(CSR_PROGRAM_BASE + i * 4,
- payload[i]);
+ I915_WRITE(CSR_PROGRAM(i), payload[i]);
for (i = 0; i < dev_priv->csr.mmio_count; i++) {
I915_WRITE(dev_priv->csr.mmioaddr[i],
@@ -409,6 +430,8 @@ void intel_csr_ucode_init(struct drm_device *dev)
if (IS_SKYLAKE(dev))
csr->fw_path = I915_CSR_SKL;
+ else if (IS_BROXTON(dev_priv))
+ csr->fw_path = I915_CSR_BXT;
else {
DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
intel_csr_load_status_set(dev_priv, FW_FAILED);
@@ -454,10 +477,10 @@ void intel_csr_ucode_fini(struct drm_device *dev)
void assert_csr_loaded(struct drm_i915_private *dev_priv)
{
- WARN(intel_csr_load_status_get(dev_priv) != FW_LOADED,
- "CSR is not loaded.\n");
- WARN(!I915_READ(CSR_PROGRAM_BASE),
- "CSR program storage start is NULL\n");
- WARN(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
- WARN(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
+ WARN_ONCE(intel_csr_load_status_get(dev_priv) != FW_LOADED,
+ "CSR is not loaded.\n");
+ WARN_ONCE(!I915_READ(CSR_PROGRAM(0)),
+ "CSR program storage start is NULL\n");
+ WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n");
+ WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n");
}
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 61575f67a626..b25e99a432fb 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -256,9 +256,6 @@ struct bxt_ddi_buf_trans {
bool default_index; /* true if the entry represents default value */
};
-/* BSpec does not define separate vswing/pre-emphasis values for eDP.
- * Using DP values for eDP as well.
- */
static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
/* Idx NT mV diff db */
{ 52, 0x9A, 0, 128, true }, /* 0: 400 0 */
@@ -273,6 +270,20 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = {
{ 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */
};
+static const struct bxt_ddi_buf_trans bxt_ddi_translations_edp[] = {
+ /* Idx NT mV diff db */
+ { 26, 0, 0, 128, false }, /* 0: 200 0 */
+ { 38, 0, 0, 112, false }, /* 1: 200 1.5 */
+ { 48, 0, 0, 96, false }, /* 2: 200 4 */
+ { 54, 0, 0, 69, false }, /* 3: 200 6 */
+ { 32, 0, 0, 128, false }, /* 4: 250 0 */
+ { 48, 0, 0, 104, false }, /* 5: 250 1.5 */
+ { 54, 0, 0, 85, false }, /* 6: 250 4 */
+ { 43, 0, 0, 128, false }, /* 7: 300 0 */
+ { 54, 0, 0, 101, false }, /* 8: 300 1.5 */
+ { 48, 0, 0, 128, false }, /* 9: 300 0 */
+};
+
/* BSpec has 2 recommended values - entries 0 and 8.
* Using the entry with higher vswing.
*/
@@ -298,21 +309,26 @@ static void ddi_get_encoder_port(struct intel_encoder *intel_encoder,
enum port *port)
{
struct drm_encoder *encoder = &intel_encoder->base;
- int type = intel_encoder->type;
- if (type == INTEL_OUTPUT_DP_MST) {
+ switch (intel_encoder->type) {
+ case INTEL_OUTPUT_DP_MST:
*dig_port = enc_to_mst(encoder)->primary;
*port = (*dig_port)->port;
- } else if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP ||
- type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) {
+ break;
+ case INTEL_OUTPUT_DISPLAYPORT:
+ case INTEL_OUTPUT_EDP:
+ case INTEL_OUTPUT_HDMI:
+ case INTEL_OUTPUT_UNKNOWN:
*dig_port = enc_to_dig_port(encoder);
*port = (*dig_port)->port;
- } else if (type == INTEL_OUTPUT_ANALOG) {
+ break;
+ case INTEL_OUTPUT_ANALOG:
*dig_port = NULL;
*port = PORT_E;
- } else {
- DRM_ERROR("Invalid DDI encoder type %d\n", type);
- BUG();
+ break;
+ default:
+ WARN(1, "Invalid DDI encoder type %d\n", intel_encoder->type);
+ break;
}
}
@@ -414,7 +430,6 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
bool supports_hdmi)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg;
u32 iboost_bit = 0;
int i, n_hdmi_entries, n_dp_entries, n_edp_entries, hdmi_default_entry,
size;
@@ -505,11 +520,11 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
BUG();
}
- for (i = 0, reg = DDI_BUF_TRANS(port); i < size; i++) {
- I915_WRITE(reg, ddi_translations[i].trans1 | iboost_bit);
- reg += 4;
- I915_WRITE(reg, ddi_translations[i].trans2);
- reg += 4;
+ for (i = 0; i < size; i++) {
+ I915_WRITE(DDI_BUF_TRANS_LO(port, i),
+ ddi_translations[i].trans1 | iboost_bit);
+ I915_WRITE(DDI_BUF_TRANS_HI(port, i),
+ ddi_translations[i].trans2);
}
if (!supports_hdmi)
@@ -521,10 +536,10 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port,
hdmi_level = hdmi_default_entry;
/* Entry 9 is for HDMI: */
- I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans1 | iboost_bit);
- reg += 4;
- I915_WRITE(reg, ddi_translations_hdmi[hdmi_level].trans2);
- reg += 4;
+ I915_WRITE(DDI_BUF_TRANS_LO(port, i),
+ ddi_translations_hdmi[hdmi_level].trans1 | iboost_bit);
+ I915_WRITE(DDI_BUF_TRANS_HI(port, i),
+ ddi_translations_hdmi[hdmi_level].trans2);
}
/* Program DDI buffers translations for DP. By default, program ports A-D in DP
@@ -543,8 +558,10 @@ void intel_prepare_ddi(struct drm_device *dev)
enum port port;
bool supports_hdmi;
- ddi_get_encoder_port(intel_encoder, &intel_dig_port, &port);
+ if (intel_encoder->type == INTEL_OUTPUT_DSI)
+ continue;
+ ddi_get_encoder_port(intel_encoder, &intel_dig_port, &port);
if (visited[port])
continue;
@@ -593,7 +610,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
*
* WaFDIAutoLinkSetTimingOverrride:hsw
*/
- I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) |
+ I915_WRITE(FDI_RX_MISC(PIPE_A), FDI_RX_PWRDN_LANE1_VAL(2) |
FDI_RX_PWRDN_LANE0_VAL(2) |
FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
@@ -601,13 +618,13 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
FDI_RX_PLL_ENABLE |
FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
- I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
- POSTING_READ(_FDI_RXA_CTL);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+ POSTING_READ(FDI_RX_CTL(PIPE_A));
udelay(220);
/* Switch from Rawclk to PCDclk */
rx_ctl_val |= FDI_PCDCLK;
- I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
/* Configure Port Clock Select */
I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
@@ -636,21 +653,21 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
udelay(600);
/* Program PCH FDI Receiver TU */
- I915_WRITE(_FDI_RXA_TUSIZE1, TU_SIZE(64));
+ I915_WRITE(FDI_RX_TUSIZE1(PIPE_A), TU_SIZE(64));
/* Enable PCH FDI Receiver with auto-training */
rx_ctl_val |= FDI_RX_ENABLE | FDI_LINK_TRAIN_AUTO;
- I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
- POSTING_READ(_FDI_RXA_CTL);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+ POSTING_READ(FDI_RX_CTL(PIPE_A));
/* Wait for FDI receiver lane calibration */
udelay(30);
/* Unset FDI_RX_MISC pwrdn lanes */
- temp = I915_READ(_FDI_RXA_MISC);
+ temp = I915_READ(FDI_RX_MISC(PIPE_A));
temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
- I915_WRITE(_FDI_RXA_MISC, temp);
- POSTING_READ(_FDI_RXA_MISC);
+ I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
+ POSTING_READ(FDI_RX_MISC(PIPE_A));
/* Wait for FDI auto training time */
udelay(5);
@@ -684,15 +701,15 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
intel_wait_ddi_buf_idle(dev_priv, PORT_E);
rx_ctl_val &= ~FDI_RX_ENABLE;
- I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
- POSTING_READ(_FDI_RXA_CTL);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
+ POSTING_READ(FDI_RX_CTL(PIPE_A));
/* Reset FDI_RX_MISC pwrdn lanes */
- temp = I915_READ(_FDI_RXA_MISC);
+ temp = I915_READ(FDI_RX_MISC(PIPE_A));
temp &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
temp |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
- I915_WRITE(_FDI_RXA_MISC, temp);
- POSTING_READ(_FDI_RXA_MISC);
+ I915_WRITE(FDI_RX_MISC(PIPE_A), temp);
+ POSTING_READ(FDI_RX_MISC(PIPE_A));
}
DRM_ERROR("FDI link training failed!\n");
@@ -707,7 +724,6 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder)
intel_dp->DP = intel_dig_port->saved_port_bits |
DDI_BUF_CTL_ENABLE | DDI_BUF_TRANS_SELECT(0);
intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
-
}
static struct intel_encoder *
@@ -955,8 +971,8 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
uint32_t cfgcr1_val, cfgcr2_val;
uint32_t p0, p1, p2, dco_freq;
- cfgcr1_reg = GET_CFG_CR1_REG(dpll);
- cfgcr2_reg = GET_CFG_CR2_REG(dpll);
+ cfgcr1_reg = DPLL_CFGCR1(dpll);
+ cfgcr2_reg = DPLL_CFGCR2(dpll);
cfgcr1_val = I915_READ(cfgcr1_reg);
cfgcr2_val = I915_READ(cfgcr2_reg);
@@ -1242,9 +1258,10 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
static bool
hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state,
- struct intel_encoder *intel_encoder,
- int clock)
+ 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;
@@ -1523,11 +1540,11 @@ skip_remaining_dividers:
static bool
skl_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state,
- struct intel_encoder *intel_encoder,
- int clock)
+ 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
@@ -1615,14 +1632,14 @@ static const struct bxt_clk_div bxt_dp_clk_val[] = {
static bool
bxt_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state,
- struct intel_encoder *intel_encoder,
- int clock)
+ 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;
@@ -1750,17 +1767,16 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
struct drm_device *dev = intel_crtc->base.dev;
struct intel_encoder *intel_encoder =
intel_ddi_get_crtc_new_encoder(crtc_state);
- int clock = crtc_state->port_clock;
if (IS_SKYLAKE(dev))
return skl_ddi_pll_select(intel_crtc, crtc_state,
- intel_encoder, clock);
+ intel_encoder);
else if (IS_BROXTON(dev))
return bxt_ddi_pll_select(intel_crtc, crtc_state,
- intel_encoder, clock);
+ intel_encoder);
else
return hsw_ddi_pll_select(intel_crtc, crtc_state,
- intel_encoder, clock);
+ intel_encoder);
}
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
@@ -1893,7 +1909,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
} else
temp |= TRANS_DDI_MODE_SELECT_DP_SST;
- temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
+ temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
} else if (type == INTEL_OUTPUT_DP_MST) {
struct intel_dp *intel_dp = &enc_to_mst(encoder)->primary->dp;
@@ -1902,7 +1918,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
} else
temp |= TRANS_DDI_MODE_SELECT_DP_SST;
- temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
+ temp |= DDI_PORT_WIDTH(intel_crtc->config->lane_count);
} else {
WARN(1, "Invalid encoder type %d for pipe %c\n",
intel_encoder->type, pipe_name(pipe));
@@ -2029,7 +2045,8 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
{
struct drm_crtc *crtc = &intel_crtc->base;
- struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
enum port port = intel_ddi_get_encoder_port(intel_encoder);
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
@@ -2114,7 +2131,11 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
u32 n_entries, i;
uint32_t val;
- if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
+ if (type == INTEL_OUTPUT_EDP && dev_priv->edp_low_vswing) {
+ n_entries = ARRAY_SIZE(bxt_ddi_translations_edp);
+ ddi_translations = bxt_ddi_translations_edp;
+ } else if (type == INTEL_OUTPUT_DISPLAYPORT
+ || type == INTEL_OUTPUT_EDP) {
n_entries = ARRAY_SIZE(bxt_ddi_translations_dp);
ddi_translations = bxt_ddi_translations_dp;
} else if (type == INTEL_OUTPUT_HDMI) {
@@ -2152,9 +2173,13 @@ static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level,
I915_WRITE(BXT_PORT_TX_DW2_GRP(port), val);
val = I915_READ(BXT_PORT_TX_DW3_LN0(port));
- val &= ~UNIQE_TRANGE_EN_METHOD;
+ val &= ~SCALE_DCOMP_METHOD;
if (ddi_translations[level].enable)
- val |= UNIQE_TRANGE_EN_METHOD;
+ val |= SCALE_DCOMP_METHOD;
+
+ if ((val & UNIQUE_TRANGE_EN_METHOD) && !(val & SCALE_DCOMP_METHOD))
+ DRM_ERROR("Disabled scaling while ouniqetrangenmethod was set");
+
I915_WRITE(BXT_PORT_TX_DW3_GRP(port), val);
val = I915_READ(BXT_PORT_TX_DW4_LN0(port));
@@ -2289,11 +2314,12 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ intel_dp_set_link_params(intel_dp, crtc->config);
+
intel_ddi_init_dp_buf_reg(intel_encoder);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
if (port != PORT_A || INTEL_INFO(dev)->gen >= 9)
intel_dp_stop_link_train(intel_dp);
} else if (type == INTEL_OUTPUT_HDMI) {
@@ -2480,20 +2506,20 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = {
{
/* DPLL 1 */
.ctl = LCPLL2_CTL,
- .cfgcr1 = DPLL1_CFGCR1,
- .cfgcr2 = DPLL1_CFGCR2,
+ .cfgcr1 = DPLL_CFGCR1(SKL_DPLL1),
+ .cfgcr2 = DPLL_CFGCR2(SKL_DPLL1),
},
{
/* DPLL 2 */
.ctl = WRPLL_CTL1,
- .cfgcr1 = DPLL2_CFGCR1,
- .cfgcr2 = DPLL2_CFGCR2,
+ .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2),
+ .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2),
},
{
/* DPLL 3 */
.ctl = WRPLL_CTL2,
- .cfgcr1 = DPLL3_CFGCR1,
- .cfgcr2 = DPLL3_CFGCR2,
+ .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3),
+ .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3),
},
};
@@ -2881,7 +2907,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
* 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))
+ 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)));
@@ -2999,22 +3025,22 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc)
intel_ddi_post_disable(intel_encoder);
- val = I915_READ(_FDI_RXA_CTL);
+ val = I915_READ(FDI_RX_CTL(PIPE_A));
val &= ~FDI_RX_ENABLE;
- I915_WRITE(_FDI_RXA_CTL, val);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), val);
- val = I915_READ(_FDI_RXA_MISC);
+ val = I915_READ(FDI_RX_MISC(PIPE_A));
val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
- I915_WRITE(_FDI_RXA_MISC, val);
+ I915_WRITE(FDI_RX_MISC(PIPE_A), val);
- val = I915_READ(_FDI_RXA_CTL);
+ val = I915_READ(FDI_RX_CTL(PIPE_A));
val &= ~FDI_PCDCLK;
- I915_WRITE(_FDI_RXA_CTL, val);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), val);
- val = I915_READ(_FDI_RXA_CTL);
+ val = I915_READ(FDI_RX_CTL(PIPE_A));
val &= ~FDI_RX_PLL_ENABLE;
- I915_WRITE(_FDI_RXA_CTL, val);
+ I915_WRITE(FDI_RX_CTL(PIPE_A), val);
}
void intel_ddi_get_config(struct intel_encoder *encoder,
@@ -3069,6 +3095,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
case TRANS_DDI_MODE_SELECT_DP_SST:
case TRANS_DDI_MODE_SELECT_DP_MST:
pipe_config->has_dp_encoder = true;
+ pipe_config->lane_count =
+ ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
intel_dp_get_m_n(intel_crtc, pipe_config);
break;
default:
@@ -3215,7 +3243,15 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
goto err;
intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
- dev_priv->hotplug.irq_port[port] = intel_dig_port;
+ /*
+ * On BXT A0/A1, sw needs to activate DDIA HPD logic and
+ * interrupts to check the external panel connection.
+ */
+ if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)
+ && port == PORT_B)
+ dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port;
+ else
+ dev_priv->hotplug.irq_port[port] = intel_dig_port;
}
/* In theory we don't need the encoder->type check, but leave it just in
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b2270d576979..f62ffc04c21d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -72,6 +72,10 @@ static const uint32_t skl_primary_formats[] = {
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
};
/* Cursor formats */
@@ -108,6 +112,9 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr
struct intel_crtc_state *crtc_state);
static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state,
int num_connectors);
+static void skylake_pfit_enable(struct intel_crtc *crtc);
+static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
+static void ironlake_pfit_enable(struct intel_crtc *crtc);
static void intel_modeset_setup_hw_state(struct drm_device *dev);
typedef struct {
@@ -125,6 +132,42 @@ struct intel_limit {
intel_p2_t p2;
};
+/* returns HPLL frequency in kHz */
+static int valleyview_get_vco(struct drm_i915_private *dev_priv)
+{
+ int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
+
+ /* Obtain SKU information */
+ mutex_lock(&dev_priv->sb_lock);
+ hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) &
+ CCK_FUSE_HPLL_FREQ_MASK;
+ mutex_unlock(&dev_priv->sb_lock);
+
+ return vco_freq[hpll_freq] * 1000;
+}
+
+static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv,
+ const char *name, u32 reg)
+{
+ u32 val;
+ int divider;
+
+ if (dev_priv->hpll_freq == 0)
+ dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
+
+ mutex_lock(&dev_priv->sb_lock);
+ val = vlv_cck_read(dev_priv, reg);
+ mutex_unlock(&dev_priv->sb_lock);
+
+ divider = val & CCK_FREQUENCY_VALUES;
+
+ WARN((val & CCK_FREQUENCY_STATUS) !=
+ (divider << CCK_FREQUENCY_STATUS_SHIFT),
+ "%s change in progress\n", name);
+
+ return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1);
+}
+
int
intel_pch_rawclk(struct drm_device *dev)
{
@@ -135,6 +178,50 @@ intel_pch_rawclk(struct drm_device *dev)
return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK;
}
+/* hrawclock is 1/4 the FSB frequency */
+int intel_hrawclk(struct drm_device *dev)
+{
+ 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))
+ return 200;
+
+ clkcfg = I915_READ(CLKCFG);
+ switch (clkcfg & CLKCFG_FSB_MASK) {
+ case CLKCFG_FSB_400:
+ return 100;
+ case CLKCFG_FSB_533:
+ return 133;
+ case CLKCFG_FSB_667:
+ return 166;
+ case CLKCFG_FSB_800:
+ return 200;
+ case CLKCFG_FSB_1067:
+ return 266;
+ case CLKCFG_FSB_1333:
+ return 333;
+ /* these two are just a guess; one of them might be right */
+ case CLKCFG_FSB_1600:
+ case CLKCFG_FSB_1600_ALT:
+ return 400;
+ default:
+ return 133;
+ }
+}
+
+static void intel_update_czclk(struct drm_i915_private *dev_priv)
+{
+ if (!IS_VALLEYVIEW(dev_priv))
+ return;
+
+ dev_priv->czclk_freq = vlv_get_cck_clock_hpll(dev_priv, "czclk",
+ CCK_CZ_CLOCK_CONTROL);
+
+ DRM_DEBUG_DRIVER("CZ clock rate: %d kHz\n", dev_priv->czclk_freq);
+}
+
static inline u32 /* units of 100MHz */
intel_fdi_link_freq(struct drm_device *dev)
{
@@ -1061,54 +1148,6 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
}
}
-/*
- * ibx_digital_port_connected - is the specified port connected?
- * @dev_priv: i915 private structure
- * @port: the port to test
- *
- * Returns true if @port is connected, false otherwise.
- */
-bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
- struct intel_digital_port *port)
-{
- u32 bit;
-
- if (HAS_PCH_IBX(dev_priv->dev)) {
- switch (port->port) {
- case PORT_B:
- bit = SDE_PORTB_HOTPLUG;
- break;
- case PORT_C:
- bit = SDE_PORTC_HOTPLUG;
- break;
- case PORT_D:
- bit = SDE_PORTD_HOTPLUG;
- break;
- default:
- return true;
- }
- } else {
- switch (port->port) {
- case PORT_B:
- bit = SDE_PORTB_HOTPLUG_CPT;
- break;
- case PORT_C:
- bit = SDE_PORTC_HOTPLUG_CPT;
- break;
- case PORT_D:
- bit = SDE_PORTD_HOTPLUG_CPT;
- break;
- case PORT_E:
- bit = SDE_PORTE_HOTPLUG_SPT;
- break;
- default:
- return true;
- }
- }
-
- return I915_READ(SDEISR) & bit;
-}
-
static const char *state_string(bool enabled)
{
return enabled ? "on" : "off";
@@ -1118,12 +1157,10 @@ static const char *state_string(bool enabled)
void assert_pll(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
- int reg;
u32 val;
bool cur_state;
- reg = DPLL(pipe);
- val = I915_READ(reg);
+ val = I915_READ(DPLL(pipe));
cur_state = !!(val & DPLL_VCO_ENABLE);
I915_STATE_WARN(cur_state != state,
"PLL state assertion failure (expected %s, current %s)\n",
@@ -1180,20 +1217,16 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
static void assert_fdi_tx(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
- int reg;
- u32 val;
bool cur_state;
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
pipe);
if (HAS_DDI(dev_priv->dev)) {
/* DDI does not have a specific FDI_TX register */
- reg = TRANS_DDI_FUNC_CTL(cpu_transcoder);
- val = I915_READ(reg);
+ u32 val = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
cur_state = !!(val & TRANS_DDI_FUNC_ENABLE);
} else {
- reg = FDI_TX_CTL(pipe);
- val = I915_READ(reg);
+ u32 val = I915_READ(FDI_TX_CTL(pipe));
cur_state = !!(val & FDI_TX_ENABLE);
}
I915_STATE_WARN(cur_state != state,
@@ -1206,12 +1239,10 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
static void assert_fdi_rx(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
- int reg;
u32 val;
bool cur_state;
- reg = FDI_RX_CTL(pipe);
- val = I915_READ(reg);
+ val = I915_READ(FDI_RX_CTL(pipe));
cur_state = !!(val & FDI_RX_ENABLE);
I915_STATE_WARN(cur_state != state,
"FDI RX state assertion failure (expected %s, current %s)\n",
@@ -1223,7 +1254,6 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
- int reg;
u32 val;
/* ILK FDI PLL is always enabled */
@@ -1234,20 +1264,17 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
if (HAS_DDI(dev_priv->dev))
return;
- reg = FDI_TX_CTL(pipe);
- val = I915_READ(reg);
+ val = I915_READ(FDI_TX_CTL(pipe));
I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
}
void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
- int reg;
u32 val;
bool cur_state;
- reg = FDI_RX_CTL(pipe);
- val = I915_READ(reg);
+ val = I915_READ(FDI_RX_CTL(pipe));
cur_state = !!(val & FDI_RX_PLL_ENABLE);
I915_STATE_WARN(cur_state != state,
"FDI RX PLL assertion failure (expected %s, current %s)\n",
@@ -1303,7 +1330,7 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
bool cur_state;
if (IS_845G(dev) || IS_I865G(dev))
- cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
+ cur_state = I915_READ(CURCNTR(PIPE_A)) & CURSOR_ENABLE;
else
cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
@@ -1317,8 +1344,6 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
void assert_pipe(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
{
- int reg;
- u32 val;
bool cur_state;
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
pipe);
@@ -1332,8 +1357,7 @@ void assert_pipe(struct drm_i915_private *dev_priv,
POWER_DOMAIN_TRANSCODER(cpu_transcoder))) {
cur_state = false;
} else {
- reg = PIPECONF(cpu_transcoder);
- val = I915_READ(reg);
+ u32 val = I915_READ(PIPECONF(cpu_transcoder));
cur_state = !!(val & PIPECONF_ENABLE);
}
@@ -1345,12 +1369,10 @@ void assert_pipe(struct drm_i915_private *dev_priv,
static void assert_plane(struct drm_i915_private *dev_priv,
enum plane plane, bool state)
{
- int reg;
u32 val;
bool cur_state;
- reg = DSPCNTR(plane);
- val = I915_READ(reg);
+ val = I915_READ(DSPCNTR(plane));
cur_state = !!(val & DISPLAY_PLANE_ENABLE);
I915_STATE_WARN(cur_state != state,
"plane %c assertion failure (expected %s, current %s)\n",
@@ -1364,14 +1386,11 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
struct drm_device *dev = dev_priv->dev;
- int reg, i;
- u32 val;
- int cur_pipe;
+ int i;
/* Primary planes are fixed to pipes on gen4+ */
if (INTEL_INFO(dev)->gen >= 4) {
- reg = DSPCNTR(pipe);
- val = I915_READ(reg);
+ u32 val = I915_READ(DSPCNTR(pipe));
I915_STATE_WARN(val & DISPLAY_PLANE_ENABLE,
"plane %c assertion failure, should be disabled but not\n",
plane_name(pipe));
@@ -1380,9 +1399,8 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
/* Need to check both planes against the pipe */
for_each_pipe(dev_priv, i) {
- reg = DSPCNTR(i);
- val = I915_READ(reg);
- cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
+ u32 val = I915_READ(DSPCNTR(i));
+ enum pipe cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
DISPPLANE_SEL_PIPE_SHIFT;
I915_STATE_WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
"plane %c assertion failure, should be off on pipe %c but is still active\n",
@@ -1394,33 +1412,29 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
struct drm_device *dev = dev_priv->dev;
- int reg, sprite;
- u32 val;
+ int sprite;
if (INTEL_INFO(dev)->gen >= 9) {
for_each_sprite(dev_priv, pipe, sprite) {
- val = I915_READ(PLANE_CTL(pipe, sprite));
+ u32 val = I915_READ(PLANE_CTL(pipe, sprite));
I915_STATE_WARN(val & PLANE_CTL_ENABLE,
"plane %d assertion failure, should be off on pipe %c but is still active\n",
sprite, pipe_name(pipe));
}
} else if (IS_VALLEYVIEW(dev)) {
for_each_sprite(dev_priv, pipe, sprite) {
- reg = SPCNTR(pipe, sprite);
- val = I915_READ(reg);
+ u32 val = I915_READ(SPCNTR(pipe, sprite));
I915_STATE_WARN(val & SP_ENABLE,
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
sprite_name(pipe, sprite), pipe_name(pipe));
}
} else if (INTEL_INFO(dev)->gen >= 7) {
- reg = SPRCTL(pipe);
- val = I915_READ(reg);
+ u32 val = I915_READ(SPRCTL(pipe));
I915_STATE_WARN(val & SPRITE_ENABLE,
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
plane_name(pipe), pipe_name(pipe));
} else if (INTEL_INFO(dev)->gen >= 5) {
- reg = DVSCNTR(pipe);
- val = I915_READ(reg);
+ u32 val = I915_READ(DVSCNTR(pipe));
I915_STATE_WARN(val & DVS_ENABLE,
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
plane_name(pipe), pipe_name(pipe));
@@ -1449,12 +1463,10 @@ static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
- int reg;
u32 val;
bool enabled;
- reg = PCH_TRANSCONF(pipe);
- val = I915_READ(reg);
+ val = I915_READ(PCH_TRANSCONF(pipe));
enabled = !!(val & TRANS_ENABLE);
I915_STATE_WARN(enabled,
"transcoder assertion failed, should be off on pipe %c but is still active\n",
@@ -1561,21 +1573,18 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
- int reg;
u32 val;
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
- reg = PCH_ADPA;
- val = I915_READ(reg);
+ val = I915_READ(PCH_ADPA);
I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val),
"PCH VGA enabled on transcoder %c, should be disabled\n",
pipe_name(pipe));
- reg = PCH_LVDS;
- val = I915_READ(reg);
+ val = I915_READ(PCH_LVDS);
I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val),
"PCH LVDS enabled on transcoder %c, should be disabled\n",
pipe_name(pipe));
@@ -1585,26 +1594,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
}
-static void intel_init_dpio(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (!IS_VALLEYVIEW(dev))
- return;
-
- /*
- * IOSF_PORT_DPIO is used for VLV x2 PHY (DP/HDMI B and C),
- * CHV x1 PHY (DP/HDMI D)
- * IOSF_PORT_DPIO_2 is used for CHV x2 PHY (DP/HDMI B and C)
- */
- if (IS_CHERRYVIEW(dev)) {
- DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO_2;
- DPIO_PHY_IOSF_PORT(DPIO_PHY1) = IOSF_PORT_DPIO;
- } else {
- DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO;
- }
-}
-
static void vlv_enable_pll(struct intel_crtc *crtc,
const struct intel_crtc_state *pipe_config)
{
@@ -1840,17 +1829,6 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
val &= ~DPIO_DCLKP_EN;
vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val);
- /* disable left/right clock distribution */
- if (pipe != PIPE_B) {
- val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
- val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
- vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
- } else {
- val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
- val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
- vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
- }
-
mutex_unlock(&dev_priv->sb_lock);
}
@@ -2051,9 +2029,9 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
assert_fdi_rx_enabled(dev_priv, TRANSCODER_A);
/* Workaround: set timing override bit. */
- val = I915_READ(_TRANSA_CHICKEN2);
+ val = I915_READ(TRANS_CHICKEN2(PIPE_A));
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
- I915_WRITE(_TRANSA_CHICKEN2, val);
+ I915_WRITE(TRANS_CHICKEN2(PIPE_A), val);
val = TRANS_ENABLE;
pipeconf_val = I915_READ(PIPECONF(cpu_transcoder));
@@ -2111,9 +2089,9 @@ static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
DRM_ERROR("Failed to disable PCH transcoder\n");
/* Workaround: clear timing override bit. */
- val = I915_READ(_TRANSA_CHICKEN2);
+ val = I915_READ(TRANS_CHICKEN2(PIPE_A));
val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE;
- I915_WRITE(_TRANSA_CHICKEN2, val);
+ I915_WRITE(TRANS_CHICKEN2(PIPE_A), val);
}
/**
@@ -2238,7 +2216,7 @@ static bool need_vtd_wa(struct drm_device *dev)
unsigned int
intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
- uint64_t fb_format_modifier)
+ uint64_t fb_format_modifier, unsigned int plane)
{
unsigned int tile_height;
uint32_t pixel_bytes;
@@ -2254,7 +2232,7 @@ intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
tile_height = 32;
break;
case I915_FORMAT_MOD_Yf_TILED:
- pixel_bytes = drm_format_plane_cpp(pixel_format, 0);
+ pixel_bytes = drm_format_plane_cpp(pixel_format, plane);
switch (pixel_bytes) {
default:
case 1:
@@ -2288,7 +2266,7 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height,
uint32_t pixel_format, uint64_t fb_format_modifier)
{
return ALIGN(height, intel_tile_height(dev, pixel_format,
- fb_format_modifier));
+ fb_format_modifier, 0));
}
static int
@@ -2311,15 +2289,27 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb,
info->height = fb->height;
info->pixel_format = fb->pixel_format;
info->pitch = fb->pitches[0];
+ info->uv_offset = fb->offsets[1];
info->fb_modifier = fb->modifier[0];
tile_height = intel_tile_height(fb->dev, fb->pixel_format,
- fb->modifier[0]);
+ fb->modifier[0], 0);
tile_pitch = PAGE_SIZE / tile_height;
info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_pitch);
info->height_pages = DIV_ROUND_UP(fb->height, tile_height);
info->size = info->width_pages * info->height_pages * PAGE_SIZE;
+ if (info->pixel_format == DRM_FORMAT_NV12) {
+ tile_height = intel_tile_height(fb->dev, fb->pixel_format,
+ fb->modifier[0], 1);
+ tile_pitch = PAGE_SIZE / tile_height;
+ info->width_pages_uv = DIV_ROUND_UP(fb->pitches[0], tile_pitch);
+ info->height_pages_uv = DIV_ROUND_UP(fb->height / 2,
+ tile_height);
+ info->size_uv = info->width_pages_uv * info->height_pages_uv *
+ PAGE_SIZE;
+ }
+
return 0;
}
@@ -2408,22 +2398,24 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane,
* framebuffer compression. For simplicity, we always install
* a fence as the cost is not that onerous.
*/
- ret = i915_gem_object_get_fence(obj);
- if (ret == -EDEADLK) {
- /*
- * -EDEADLK means there are no free fences
- * no pending flips.
- *
- * This is propagated to atomic, but it uses
- * -EDEADLK to force a locking recovery, so
- * change the returned error to -EBUSY.
- */
- ret = -EBUSY;
- goto err_unpin;
- } else if (ret)
- goto err_unpin;
+ if (view.type == I915_GGTT_VIEW_NORMAL) {
+ ret = i915_gem_object_get_fence(obj);
+ if (ret == -EDEADLK) {
+ /*
+ * -EDEADLK means there are no free fences
+ * no pending flips.
+ *
+ * This is propagated to atomic, but it uses
+ * -EDEADLK to force a locking recovery, so
+ * change the returned error to -EBUSY.
+ */
+ ret = -EBUSY;
+ goto err_unpin;
+ } else if (ret)
+ goto err_unpin;
- i915_gem_object_pin_fence(obj);
+ i915_gem_object_pin_fence(obj);
+ }
dev_priv->mm.interruptible = true;
intel_runtime_pm_put(dev_priv);
@@ -2449,7 +2441,9 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb,
ret = intel_fill_fb_ggtt_view(&view, fb, plane_state);
WARN_ONCE(ret, "Couldn't get view from plane state!");
- i915_gem_object_unpin_fence(obj);
+ if (view.type == I915_GGTT_VIEW_NORMAL)
+ i915_gem_object_unpin_fence(obj);
+
i915_gem_object_unpin_from_display_plane(obj, &view);
}
@@ -2534,6 +2528,7 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
struct intel_initial_plane_config *plane_config)
{
struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_i915_gem_object *obj = NULL;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct drm_framebuffer *fb = &plane_config->fb->base;
@@ -2546,6 +2541,12 @@ intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
if (plane_config->size == 0)
return false;
+ /* If the FB is too big, just don't use it since fbdev is not very
+ * important and we should probably use that space with FBC or other
+ * features. */
+ if (size_aligned * 2 > dev_priv->gtt.stolen_usable_size)
+ return false;
+
obj = i915_gem_object_create_stolen_for_preallocated(dev,
base_aligned,
base_aligned,
@@ -2778,6 +2779,9 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
(intel_crtc->config->pipe_src_w - 1) * pixel_size;
}
+ intel_crtc->adjusted_x = x;
+ intel_crtc->adjusted_y = y;
+
I915_WRITE(reg, dspcntr);
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
@@ -2878,6 +2882,9 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
}
}
+ intel_crtc->adjusted_x = x;
+ intel_crtc->adjusted_y = y;
+
I915_WRITE(reg, dspcntr);
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
@@ -2927,14 +2934,29 @@ u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier,
}
unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
- struct drm_i915_gem_object *obj)
+ struct drm_i915_gem_object *obj,
+ unsigned int plane)
{
const struct i915_ggtt_view *view = &i915_ggtt_view_normal;
+ struct i915_vma *vma;
+ unsigned char *offset;
if (intel_rotation_90_or_270(intel_plane->base.state->rotation))
view = &i915_ggtt_view_rotated;
- return i915_gem_obj_ggtt_offset_view(obj, view);
+ vma = i915_gem_obj_to_ggtt_view(obj, view);
+ if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
+ view->type))
+ return -1;
+
+ offset = (unsigned char *)vma->node.start;
+
+ if (plane == 1) {
+ offset += vma->ggtt_view.rotation_info.uv_start_page *
+ PAGE_SIZE;
+ }
+
+ return (unsigned long)offset;
}
static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
@@ -2945,8 +2967,6 @@ static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, id), 0);
I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, id), 0);
I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0);
- DRM_DEBUG_KMS("CRTC:%d Disabled scaler id %u.%u\n",
- intel_crtc->base.base.id, intel_crtc->pipe, id);
}
/*
@@ -3092,34 +3112,26 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
obj = intel_fb_obj(fb);
stride_div = intel_fb_stride_alignment(dev, fb->modifier[0],
fb->pixel_format);
- surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj);
+ surf_addr = intel_plane_obj_offset(to_intel_plane(plane), obj, 0);
- /*
- * FIXME: intel_plane_state->src, dst aren't set when transitional
- * update_plane helpers are called from legacy paths.
- * Once full atomic crtc is available, below check can be avoided.
- */
- if (drm_rect_width(&plane_state->src)) {
- scaler_id = plane_state->scaler_id;
- src_x = plane_state->src.x1 >> 16;
- src_y = plane_state->src.y1 >> 16;
- src_w = drm_rect_width(&plane_state->src) >> 16;
- src_h = drm_rect_height(&plane_state->src) >> 16;
- dst_x = plane_state->dst.x1;
- dst_y = plane_state->dst.y1;
- dst_w = drm_rect_width(&plane_state->dst);
- dst_h = drm_rect_height(&plane_state->dst);
-
- WARN_ON(x != src_x || y != src_y);
- } else {
- src_w = intel_crtc->config->pipe_src_w;
- src_h = intel_crtc->config->pipe_src_h;
- }
+ WARN_ON(drm_rect_width(&plane_state->src) == 0);
+
+ scaler_id = plane_state->scaler_id;
+ src_x = plane_state->src.x1 >> 16;
+ src_y = plane_state->src.y1 >> 16;
+ src_w = drm_rect_width(&plane_state->src) >> 16;
+ src_h = drm_rect_height(&plane_state->src) >> 16;
+ dst_x = plane_state->dst.x1;
+ dst_y = plane_state->dst.y1;
+ dst_w = drm_rect_width(&plane_state->dst);
+ dst_h = drm_rect_height(&plane_state->dst);
+
+ WARN_ON(x != src_x || y != src_y);
if (intel_rotation_90_or_270(rotation)) {
/* stride = Surface height in tiles */
tile_height = intel_tile_height(dev, fb->pixel_format,
- fb->modifier[0]);
+ fb->modifier[0], 0);
stride = DIV_ROUND_UP(fb->height, tile_height);
x_offset = stride * tile_height - y - src_h;
y_offset = x;
@@ -3132,6 +3144,9 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
}
plane_offset = y_offset << 16 | x_offset;
+ intel_crtc->adjusted_x = x_offset;
+ intel_crtc->adjusted_y = y_offset;
+
I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
I915_WRITE(PLANE_OFFSET(pipe, 0), plane_offset);
I915_WRITE(PLANE_SIZE(pipe, 0), plane_size);
@@ -3188,24 +3203,20 @@ static void intel_complete_page_flips(struct drm_device *dev)
static void intel_update_primary_planes(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
for_each_crtc(dev, crtc) {
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_plane *plane = to_intel_plane(crtc->primary);
+ struct intel_plane_state *plane_state;
- drm_modeset_lock(&crtc->mutex, NULL);
- /*
- * FIXME: Once we have proper support for primary planes (and
- * disabling them without disabling the entire crtc) allow again
- * a NULL crtc->primary->fb.
- */
- if (intel_crtc->active && crtc->primary->fb)
- dev_priv->display.update_primary_plane(crtc,
- crtc->primary->fb,
- crtc->x,
- crtc->y);
- drm_modeset_unlock(&crtc->mutex);
+ drm_modeset_lock_crtc(crtc, &plane->base);
+
+ plane_state = to_intel_plane_state(plane->base.state);
+
+ if (plane_state->base.fb)
+ plane->commit_plane(&plane->base, plane_state);
+
+ drm_modeset_unlock_crtc(crtc);
}
}
@@ -3249,6 +3260,9 @@ void intel_finish_reset(struct drm_device *dev)
* so update the base address of all primary
* planes to the the last fb to make sure we're
* showing the correct fb after a reset.
+ *
+ * FIXME: Atomic will make this obsolete since we won't schedule
+ * CS-based flips (which might get lost in gpu resets) any more.
*/
intel_update_primary_planes(dev);
return;
@@ -3319,14 +3333,23 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
return pending;
}
-static void intel_update_pipe_size(struct intel_crtc *crtc)
+static void intel_update_pipe_config(struct intel_crtc *crtc,
+ struct intel_crtc_state *old_crtc_state)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- const struct drm_display_mode *adjusted_mode;
+ struct intel_crtc_state *pipe_config =
+ to_intel_crtc_state(crtc->base.state);
- if (!i915.fastboot)
- return;
+ /* drm_atomic_helper_update_legacy_modeset_state might not be called. */
+ crtc->base.mode = crtc->base.state->mode;
+
+ DRM_DEBUG_KMS("Updating pipe size %ix%i -> %ix%i\n",
+ old_crtc_state->pipe_src_w, old_crtc_state->pipe_src_h,
+ pipe_config->pipe_src_w, pipe_config->pipe_src_h);
+
+ if (HAS_DDI(dev))
+ intel_set_pipe_csc(&crtc->base);
/*
* Update pipe size and adjust fitter if needed: the reason for this is
@@ -3335,27 +3358,24 @@ static void intel_update_pipe_size(struct intel_crtc *crtc)
* fastboot case, we'll flip, but if we don't update the pipesrc and
* pfit state, we'll end up with a big fb scanned out into the wrong
* sized surface.
- *
- * To fix this properly, we need to hoist the checks up into
- * compute_mode_changes (or above), check the actual pfit state and
- * whether the platform allows pfit disable with pipe active, and only
- * then update the pipesrc and pfit state, even on the flip path.
*/
- adjusted_mode = &crtc->config->base.adjusted_mode;
-
I915_WRITE(PIPESRC(crtc->pipe),
- ((adjusted_mode->crtc_hdisplay - 1) << 16) |
- (adjusted_mode->crtc_vdisplay - 1));
- if (!crtc->config->pch_pfit.enabled &&
- (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
- intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
- I915_WRITE(PF_CTL(crtc->pipe), 0);
- I915_WRITE(PF_WIN_POS(crtc->pipe), 0);
- I915_WRITE(PF_WIN_SZ(crtc->pipe), 0);
+ ((pipe_config->pipe_src_w - 1) << 16) |
+ (pipe_config->pipe_src_h - 1));
+
+ /* on skylake this is done by detaching scalers */
+ if (INTEL_INFO(dev)->gen >= 9) {
+ skl_detach_scalers(crtc);
+
+ if (pipe_config->pch_pfit.enabled)
+ skylake_pfit_enable(crtc);
+ } else if (HAS_PCH_SPLIT(dev)) {
+ if (pipe_config->pch_pfit.enabled)
+ ironlake_pfit_enable(crtc);
+ else if (old_crtc_state->pch_pfit.enabled)
+ ironlake_pfit_disable(crtc, true);
}
- crtc->config->pipe_src_w = adjusted_mode->crtc_hdisplay;
- crtc->config->pipe_src_h = adjusted_mode->crtc_vdisplay;
}
static void intel_fdi_normal_train(struct drm_crtc *crtc)
@@ -4401,8 +4421,7 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
int skl_update_scaler_crtc(struct intel_crtc_state *state)
{
struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
- struct drm_display_mode *adjusted_mode =
- &state->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &state->base.adjusted_mode;
DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n",
intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX);
@@ -4410,7 +4429,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state)
return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX,
&state->scaler_state.scaler_id, DRM_ROTATE_0,
state->pipe_src_w, state->pipe_src_h,
- adjusted_mode->hdisplay, adjusted_mode->vdisplay);
+ adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_vdisplay);
}
/**
@@ -4603,7 +4622,6 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum pipe pipe = intel_crtc->pipe;
- int palreg = PALETTE(pipe);
int i;
bool reenable_ips = false;
@@ -4618,10 +4636,6 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
assert_pll_enabled(dev_priv, pipe);
}
- /* use legacy palette for Ironlake */
- if (!HAS_GMCH_DISPLAY(dev))
- palreg = LGC_PALETTE(pipe);
-
/* Workaround : Do not read or write the pipe palette/gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
*/
@@ -4633,7 +4647,14 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
}
for (i = 0; i < 256; i++) {
- I915_WRITE(palreg + 4 * i,
+ u32 palreg;
+
+ if (HAS_GMCH_DISPLAY(dev))
+ palreg = PALETTE(pipe, i);
+ else
+ palreg = LGC_PALETTE(pipe, i);
+
+ I915_WRITE(palreg,
(intel_crtc->lut_r[i] << 16) |
(intel_crtc->lut_g[i] << 8) |
intel_crtc->lut_b[i]);
@@ -4931,6 +4952,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
int pipe = intel_crtc->pipe, hsw_workaround_pipe;
struct intel_crtc_state *pipe_config =
to_intel_crtc_state(crtc->state);
+ bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
if (WARN_ON(intel_crtc->active))
return;
@@ -4960,9 +4982,12 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc->active = true;
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true);
- for_each_encoder_on_crtc(dev, crtc, encoder)
+ for_each_encoder_on_crtc(dev, crtc, encoder) {
+ if (encoder->pre_pll_enable)
+ encoder->pre_pll_enable(encoder);
if (encoder->pre_enable)
encoder->pre_enable(encoder);
+ }
if (intel_crtc->config->has_pch_encoder) {
intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
@@ -4970,14 +4995,13 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
dev_priv->display.fdi_link_train(crtc);
}
- intel_ddi_enable_pipe_clock(intel_crtc);
+ if (!is_dsi)
+ intel_ddi_enable_pipe_clock(intel_crtc);
- if (INTEL_INFO(dev)->gen == 9)
+ if (INTEL_INFO(dev)->gen >= 9)
skylake_pfit_enable(intel_crtc);
- else if (INTEL_INFO(dev)->gen < 9)
- ironlake_pfit_enable(intel_crtc);
else
- MISSING_CASE(INTEL_INFO(dev)->gen);
+ ironlake_pfit_enable(intel_crtc);
/*
* On ILK+ LUT must be loaded before the pipe is running but with
@@ -4986,7 +5010,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_crtc_load_lut(crtc);
intel_ddi_set_pipe_settings(crtc);
- intel_ddi_enable_transcoder_func(crtc);
+ if (!is_dsi)
+ intel_ddi_enable_transcoder_func(crtc);
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
@@ -4994,7 +5019,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
if (intel_crtc->config->has_pch_encoder)
lpt_pch_enable(crtc);
- if (intel_crtc->config->dp_encoder_is_mst)
+ if (intel_crtc->config->dp_encoder_is_mst && !is_dsi)
intel_ddi_set_vc_payload_alloc(crtc, true);
assert_vblank_disabled(crtc);
@@ -5014,7 +5039,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
}
}
-static void ironlake_pfit_disable(struct intel_crtc *crtc)
+static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5022,7 +5047,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)
/* To avoid upsetting the power well on haswell only disable the pfit if
* it's in use. The hw state code will make sure we get this right. */
- if (crtc->config->pch_pfit.enabled) {
+ if (force || crtc->config->pch_pfit.enabled) {
I915_WRITE(PF_CTL(pipe), 0);
I915_WRITE(PF_WIN_POS(pipe), 0);
I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -5049,7 +5074,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
intel_disable_pipe(intel_crtc);
- ironlake_pfit_disable(intel_crtc);
+ ironlake_pfit_disable(intel_crtc, false);
if (intel_crtc->config->has_pch_encoder)
ironlake_fdi_disable(crtc);
@@ -5078,9 +5103,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
ironlake_fdi_pll_disable(intel_crtc);
}
-
- intel_crtc->active = false;
- intel_update_watermarks(crtc);
}
static void haswell_crtc_disable(struct drm_crtc *crtc)
@@ -5090,6 +5112,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
+ bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
for_each_encoder_on_crtc(dev, crtc, encoder) {
intel_opregion_notify_encoder(encoder, false);
@@ -5107,16 +5130,16 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
if (intel_crtc->config->dp_encoder_is_mst)
intel_ddi_set_vc_payload_alloc(crtc, false);
- intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
+ if (!is_dsi)
+ intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
- if (INTEL_INFO(dev)->gen == 9)
+ if (INTEL_INFO(dev)->gen >= 9)
skylake_scaler_disable(intel_crtc);
- else if (INTEL_INFO(dev)->gen < 9)
- ironlake_pfit_disable(intel_crtc);
else
- MISSING_CASE(INTEL_INFO(dev)->gen);
+ ironlake_pfit_disable(intel_crtc, false);
- intel_ddi_disable_pipe_clock(intel_crtc);
+ if (!is_dsi)
+ intel_ddi_disable_pipe_clock(intel_crtc);
if (intel_crtc->config->has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
@@ -5126,9 +5149,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->post_disable)
encoder->post_disable(encoder);
-
- intel_crtc->active = false;
- intel_update_watermarks(crtc);
}
static void i9xx_pfit_enable(struct intel_crtc *crtc)
@@ -5286,6 +5306,21 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state)
modeset_put_power_domains(dev_priv, put_domains[i]);
}
+static int intel_compute_max_dotclk(struct drm_i915_private *dev_priv)
+{
+ int max_cdclk_freq = dev_priv->max_cdclk_freq;
+
+ if (INTEL_INFO(dev_priv)->gen >= 9 ||
+ IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+ return max_cdclk_freq;
+ else if (IS_CHERRYVIEW(dev_priv))
+ return max_cdclk_freq*95/100;
+ else if (INTEL_INFO(dev_priv)->gen < 4)
+ return 2*max_cdclk_freq*90/100;
+ else
+ return max_cdclk_freq*90/100;
+}
+
static void intel_update_max_cdclk(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5325,8 +5360,13 @@ static void intel_update_max_cdclk(struct drm_device *dev)
dev_priv->max_cdclk_freq = dev_priv->cdclk_freq;
}
+ dev_priv->max_dotclk_freq = intel_compute_max_dotclk(dev_priv);
+
DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n",
dev_priv->max_cdclk_freq);
+
+ DRM_DEBUG_DRIVER("Max dotclock rate: %d kHz\n",
+ dev_priv->max_dotclk_freq);
}
static void intel_update_cdclk(struct drm_device *dev)
@@ -5702,10 +5742,16 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv)
if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE)
DRM_ERROR("DBuf power disable timeout\n");
- /* disable DPLL0 */
- I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE);
- if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
- DRM_ERROR("Couldn't disable DPLL0\n");
+ /*
+ * DMC assumes ownership of LCPLL and will get confused if we touch it.
+ */
+ if (dev_priv->csr.dmc_payload) {
+ /* disable DPLL0 */
+ I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) &
+ ~LCPLL_PLL_ENABLE);
+ if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1))
+ DRM_ERROR("Couldn't disable DPLL0\n");
+ }
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
}
@@ -5742,20 +5788,6 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv)
DRM_ERROR("DBuf power enable timeout\n");
}
-/* returns HPLL frequency in kHz */
-static int valleyview_get_vco(struct drm_i915_private *dev_priv)
-{
- int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
-
- /* Obtain SKU information */
- mutex_lock(&dev_priv->sb_lock);
- hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) &
- CCK_FUSE_HPLL_FREQ_MASK;
- mutex_unlock(&dev_priv->sb_lock);
-
- return vco_freq[hpll_freq] * 1000;
-}
-
/* Adjust CDclk dividers to allow high res or save power if possible */
static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
{
@@ -5793,12 +5825,12 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
/* adjust cdclk divider */
val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
- val &= ~DISPLAY_FREQUENCY_VALUES;
+ val &= ~CCK_FREQUENCY_VALUES;
val |= divider;
vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val);
if (wait_for((vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL) &
- DISPLAY_FREQUENCY_STATUS) == (divider << DISPLAY_FREQUENCY_STATUS_SHIFT),
+ CCK_FREQUENCY_STATUS) == (divider << CCK_FREQUENCY_STATUS_SHIFT),
50))
DRM_ERROR("timed out waiting for CDclk change\n");
}
@@ -5976,7 +6008,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv)
else
default_credits = PFI_CREDIT(8);
- if (DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 1000) >= dev_priv->rps.cz_freq) {
+ if (dev_priv->cdclk_freq >= dev_priv->czclk_freq) {
/* CHV suggested value is 31 or 63 */
if (IS_CHERRYVIEW(dev_priv))
credits = PFI_CREDIT_63;
@@ -6044,13 +6076,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI);
- if (!is_dsi) {
- if (IS_CHERRYVIEW(dev))
- chv_prepare_pll(intel_crtc, intel_crtc->config);
- else
- vlv_prepare_pll(intel_crtc, intel_crtc->config);
- }
-
if (intel_crtc->config->has_dp_encoder)
intel_dp_set_m_n(intel_crtc, M1_N1);
@@ -6074,10 +6099,13 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
encoder->pre_pll_enable(encoder);
if (!is_dsi) {
- if (IS_CHERRYVIEW(dev))
+ if (IS_CHERRYVIEW(dev)) {
+ chv_prepare_pll(intel_crtc, intel_crtc->config);
chv_enable_pll(intel_crtc, intel_crtc->config);
- else
+ } else {
+ vlv_prepare_pll(intel_crtc, intel_crtc->config);
vlv_enable_pll(intel_crtc, intel_crtc->config);
+ }
}
for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -6205,11 +6233,12 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
i9xx_disable_pll(intel_crtc);
}
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ if (encoder->post_pll_disable)
+ encoder->post_pll_disable(encoder);
+
if (!IS_GEN2(dev))
intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false);
-
- intel_crtc->active = false;
- intel_update_watermarks(crtc);
}
static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
@@ -6229,6 +6258,8 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
intel_crtc_disable_planes(crtc, crtc->state->plane_mask);
dev_priv->display.crtc_disable(crtc);
+ intel_crtc->active = false;
+ intel_update_watermarks(crtc);
intel_disable_shared_dpll(intel_crtc);
domains = intel_crtc->enabled_power_domains;
@@ -6465,7 +6496,7 @@ static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc,
struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = intel_crtc->base.dev;
- struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
int lane, link_bw, fdi_dotclock, ret;
bool needs_recompute = false;
@@ -6544,7 +6575,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
/* FIXME should check pixel clock limits on all platforms */
if (INTEL_INFO(dev)->gen < 4) {
@@ -6581,7 +6612,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc,
* WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
*/
if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) &&
- adjusted_mode->hsync_start == adjusted_mode->hdisplay)
+ adjusted_mode->crtc_hsync_start == adjusted_mode->crtc_hdisplay)
return -EINVAL;
if (HAS_IPS(dev))
@@ -6708,24 +6739,8 @@ static int haswell_get_display_clock_speed(struct drm_device *dev)
static int valleyview_get_display_clock_speed(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 val;
- int divider;
-
- if (dev_priv->hpll_freq == 0)
- dev_priv->hpll_freq = valleyview_get_vco(dev_priv);
-
- mutex_lock(&dev_priv->sb_lock);
- val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
- mutex_unlock(&dev_priv->sb_lock);
-
- divider = val & DISPLAY_FREQUENCY_VALUES;
-
- WARN((val & DISPLAY_FREQUENCY_STATUS) !=
- (divider << DISPLAY_FREQUENCY_STATUS_SHIFT),
- "cdclk change in progress\n");
-
- return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1);
+ return vlv_get_cck_clock_hpll(to_i915(dev), "cdclk",
+ CCK_DISPLAY_CLOCK_CONTROL);
}
static int ilk_get_display_clock_speed(struct drm_device *dev)
@@ -7386,8 +7401,7 @@ static void chv_prepare_pll(struct intel_crtc *crtc,
1 << DPIO_CHV_N_DIV_SHIFT);
/* M2 fraction division */
- if (bestm2_frac)
- vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac);
+ vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac);
/* M2 fraction division enable */
dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port));
@@ -7613,8 +7627,7 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = intel_crtc->pipe;
enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
uint32_t crtc_vtotal, crtc_vblank_end;
int vsyncshift = 0;
@@ -8128,6 +8141,14 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
else
i9xx_crtc_clock_get(crtc, pipe_config);
+ /*
+ * Normally the dotclock is filled in by the encoder .get_config()
+ * but in case the pipe is enabled w/o any ports we need a sane
+ * default.
+ */
+ pipe_config->base.adjusted_mode.crtc_clock =
+ pipe_config->port_clock / pipe_config->pixel_multiplier;
+
return true;
}
@@ -8389,8 +8410,7 @@ static void lpt_enable_clkout_dp(struct drm_device *dev, bool with_spread,
if (WARN(with_fdi && !with_spread, "FDI requires downspread\n"))
with_spread = true;
- if (WARN(dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE &&
- with_fdi, "LP PCH doesn't have FDI\n"))
+ if (WARN(HAS_PCH_LPT_LP(dev) && with_fdi, "LP PCH doesn't have FDI\n"))
with_fdi = false;
mutex_lock(&dev_priv->sb_lock);
@@ -8413,8 +8433,7 @@ static void lpt_enable_clkout_dp(struct drm_device *dev, bool with_spread,
}
}
- reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
- SBI_GEN0 : SBI_DBUFF0;
+ reg = HAS_PCH_LPT_LP(dev) ? SBI_GEN0 : SBI_DBUFF0;
tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
@@ -8430,8 +8449,7 @@ static void lpt_disable_clkout_dp(struct drm_device *dev)
mutex_lock(&dev_priv->sb_lock);
- reg = (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) ?
- SBI_GEN0 : SBI_DBUFF0;
+ reg = HAS_PCH_LPT_LP(dev) ? SBI_GEN0 : SBI_DBUFF0;
tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
@@ -9443,7 +9461,7 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv)
DRM_DEBUG_KMS("Enabling package C8+\n");
- if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
+ if (HAS_PCH_LPT_LP(dev)) {
val = I915_READ(SOUTH_DSPCLK_GATE_D);
val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
@@ -9463,7 +9481,7 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
hsw_restore_lcpll(dev_priv);
lpt_init_pch_refclk(dev);
- if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
+ if (HAS_PCH_LPT_LP(dev)) {
val = I915_READ(SOUTH_DSPCLK_GATE_D);
val |= PCH_LP_PARTITION_LEVEL_DISABLE;
I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
@@ -9813,12 +9831,10 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
}
if (intel_display_power_is_enabled(dev_priv, pfit_domain)) {
- if (INTEL_INFO(dev)->gen == 9)
+ if (INTEL_INFO(dev)->gen >= 9)
skylake_get_pfit_config(crtc, pipe_config);
- else if (INTEL_INFO(dev)->gen < 9)
- ironlake_get_pfit_config(crtc, pipe_config);
else
- MISSING_CASE(INTEL_INFO(dev)->gen);
+ ironlake_get_pfit_config(crtc, pipe_config);
}
if (IS_HASWELL(dev))
@@ -9875,13 +9891,13 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
/* On these chipsets we can only modify the base/size/stride
* whilst the cursor is disabled.
*/
- I915_WRITE(_CURACNTR, 0);
- POSTING_READ(_CURACNTR);
+ I915_WRITE(CURCNTR(PIPE_A), 0);
+ POSTING_READ(CURCNTR(PIPE_A));
intel_crtc->cursor_cntl = 0;
}
if (intel_crtc->cursor_base != base) {
- I915_WRITE(_CURABASE, base);
+ I915_WRITE(CURBASE(PIPE_A), base);
intel_crtc->cursor_base = base;
}
@@ -9891,8 +9907,8 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
}
if (intel_crtc->cursor_cntl != cntl) {
- I915_WRITE(_CURACNTR, cntl);
- POSTING_READ(_CURACNTR);
+ I915_WRITE(CURCNTR(PIPE_A), cntl);
+ POSTING_READ(CURCNTR(PIPE_A));
intel_crtc->cursor_cntl = cntl;
}
}
@@ -9924,7 +9940,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
}
cntl |= pipe << 28; /* Connect to correct pipe */
- if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+ if (HAS_DDI(dev))
cntl |= CURSOR_PIPE_CSC_ENABLE;
}
@@ -9952,8 +9968,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- int x = crtc->cursor_x;
- int y = crtc->cursor_y;
+ struct drm_plane_state *cursor_state = crtc->cursor->state;
+ int x = cursor_state->crtc_x;
+ int y = cursor_state->crtc_y;
u32 base = 0, pos = 0;
if (on)
@@ -9966,7 +9983,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
base = 0;
if (x < 0) {
- if (x + intel_crtc->base.cursor->state->crtc_w <= 0)
+ if (x + cursor_state->crtc_w <= 0)
base = 0;
pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
@@ -9975,7 +9992,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
pos |= x << CURSOR_X_SHIFT;
if (y < 0) {
- if (y + intel_crtc->base.cursor->state->crtc_h <= 0)
+ if (y + cursor_state->crtc_h <= 0)
base = 0;
pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
@@ -9991,8 +10008,8 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
/* ILK+ do this automagically */
if (HAS_GMCH_DISPLAY(dev) &&
crtc->cursor->state->rotation == BIT(DRM_ROTATE_180)) {
- base += (intel_crtc->base.cursor->state->crtc_h *
- intel_crtc->base.cursor->state->crtc_w - 1) * 4;
+ base += (cursor_state->crtc_h *
+ cursor_state->crtc_w - 1) * 4;
}
if (IS_845G(dev) || IS_I865G(dev))
@@ -10793,7 +10810,7 @@ static bool page_flip_finished(struct intel_crtc *crtc)
*/
return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
crtc->unpin_work->gtt_offset &&
- g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_GM45(crtc->pipe)),
+ g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_G4X(crtc->pipe)),
crtc->unpin_work->flip_count);
}
@@ -10819,11 +10836,11 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
spin_unlock_irqrestore(&dev->event_lock, flags);
}
-static inline void intel_mark_page_flip_active(struct intel_crtc *intel_crtc)
+static inline void intel_mark_page_flip_active(struct intel_unpin_work *work)
{
/* Ensure that the work item is consistent when activating it ... */
smp_wmb();
- atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING);
+ atomic_set(&work->pending, INTEL_FLIP_PENDING);
/* and that it is marked active as soon as the irq could fire. */
smp_wmb();
}
@@ -10859,7 +10876,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
intel_ring_emit(ring, 0); /* aux display base address, unused */
- intel_mark_page_flip_active(intel_crtc);
+ intel_mark_page_flip_active(intel_crtc->unpin_work);
return 0;
}
@@ -10891,7 +10908,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
intel_ring_emit(ring, MI_NOOP);
- intel_mark_page_flip_active(intel_crtc);
+ intel_mark_page_flip_active(intel_crtc->unpin_work);
return 0;
}
@@ -10930,7 +10947,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
intel_ring_emit(ring, pf | pipesrc);
- intel_mark_page_flip_active(intel_crtc);
+ intel_mark_page_flip_active(intel_crtc->unpin_work);
return 0;
}
@@ -10966,7 +10983,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
intel_ring_emit(ring, pf | pipesrc);
- intel_mark_page_flip_active(intel_crtc);
+ intel_mark_page_flip_active(intel_crtc->unpin_work);
return 0;
}
@@ -11043,10 +11060,10 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
DERRMR_PIPEB_PRI_FLIP_DONE |
DERRMR_PIPEC_PRI_FLIP_DONE));
if (IS_GEN8(dev))
- intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8(1) |
+ intel_ring_emit(ring, MI_STORE_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT);
else
- intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) |
+ intel_ring_emit(ring, MI_STORE_REGISTER_MEM |
MI_SRM_LRM_GLOBAL_GTT);
intel_ring_emit(ring, DERRMR);
intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
@@ -11061,7 +11078,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
intel_ring_emit(ring, (MI_NOOP));
- intel_mark_page_flip_active(intel_crtc);
+ intel_mark_page_flip_active(intel_crtc->unpin_work);
return 0;
}
@@ -11092,7 +11109,8 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
return ring != i915_gem_request_get_ring(obj->last_write_req);
}
-static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
+static void skl_do_mmio_flip(struct intel_crtc *intel_crtc,
+ struct intel_unpin_work *work)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11133,11 +11151,12 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
I915_WRITE(PLANE_CTL(pipe, 0), ctl);
I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
- I915_WRITE(PLANE_SURF(pipe, 0), intel_crtc->unpin_work->gtt_offset);
+ I915_WRITE(PLANE_SURF(pipe, 0), work->gtt_offset);
POSTING_READ(PLANE_SURF(pipe, 0));
}
-static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc)
+static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc,
+ struct intel_unpin_work *work)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -11157,32 +11176,36 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc)
I915_WRITE(reg, dspcntr);
- I915_WRITE(DSPSURF(intel_crtc->plane),
- intel_crtc->unpin_work->gtt_offset);
+ I915_WRITE(DSPSURF(intel_crtc->plane), work->gtt_offset);
POSTING_READ(DSPSURF(intel_crtc->plane));
-
}
/*
* XXX: This is the temporary way to update the plane registers until we get
* around to using the usual plane update functions for MMIO flips
*/
-static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
+static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip)
{
- struct drm_device *dev = intel_crtc->base.dev;
- u32 start_vbl_count;
+ struct intel_crtc *crtc = mmio_flip->crtc;
+ struct intel_unpin_work *work;
- intel_mark_page_flip_active(intel_crtc);
+ spin_lock_irq(&crtc->base.dev->event_lock);
+ work = crtc->unpin_work;
+ spin_unlock_irq(&crtc->base.dev->event_lock);
+ if (work == NULL)
+ return;
- intel_pipe_update_start(intel_crtc, &start_vbl_count);
+ intel_mark_page_flip_active(work);
- if (INTEL_INFO(dev)->gen >= 9)
- skl_do_mmio_flip(intel_crtc);
+ intel_pipe_update_start(crtc);
+
+ if (INTEL_INFO(mmio_flip->i915)->gen >= 9)
+ skl_do_mmio_flip(crtc, work);
else
/* use_mmio_flip() retricts MMIO flips to ilk+ */
- ilk_do_mmio_flip(intel_crtc);
+ ilk_do_mmio_flip(crtc, work);
- intel_pipe_update_end(intel_crtc, start_vbl_count);
+ intel_pipe_update_end(crtc);
}
static void intel_mmio_flip_work_func(struct work_struct *work)
@@ -11190,15 +11213,15 @@ static void intel_mmio_flip_work_func(struct work_struct *work)
struct intel_mmio_flip *mmio_flip =
container_of(work, struct intel_mmio_flip, work);
- if (mmio_flip->req)
+ if (mmio_flip->req) {
WARN_ON(__i915_wait_request(mmio_flip->req,
mmio_flip->crtc->reset_counter,
false, NULL,
&mmio_flip->i915->rps.mmioflips));
+ i915_gem_request_unreference__unlocked(mmio_flip->req);
+ }
- intel_do_mmio_flip(mmio_flip->crtc);
-
- i915_gem_request_unreference__unlocked(mmio_flip->req);
+ intel_do_mmio_flip(mmio_flip);
kfree(mmio_flip);
}
@@ -11246,6 +11269,9 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
if (atomic_read(&work->pending) >= INTEL_FLIP_COMPLETE)
return true;
+ if (atomic_read(&work->pending) < INTEL_FLIP_PENDING)
+ return false;
+
if (!work->enable_stall_check)
return false;
@@ -11396,7 +11422,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
- work->flip_count = I915_READ(PIPE_FLIPCOUNT_GM45(pipe)) + 1;
+ work->flip_count = I915_READ(PIPE_FLIPCOUNT_G4X(pipe)) + 1;
if (IS_VALLEYVIEW(dev)) {
ring = &dev_priv->ring[BCS];
@@ -11426,8 +11452,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
if (ret)
goto cleanup_pending;
- work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary), obj)
- + intel_crtc->dspaddr_offset;
+ work->gtt_offset = intel_plane_obj_offset(to_intel_plane(primary),
+ obj, 0);
+ work->gtt_offset += intel_crtc->dspaddr_offset;
if (mmio_flip) {
ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring,
@@ -11636,7 +11663,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
intel_crtc->atomic.update_wm_pre = true;
}
- if (visible)
+ if (visible || was_visible)
intel_crtc->atomic.fb_bits |=
to_intel_plane(plane)->frontbuffer_bit;
@@ -11909,14 +11936,16 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->fdi_m_n.gmch_m, pipe_config->fdi_m_n.gmch_n,
pipe_config->fdi_m_n.link_m, pipe_config->fdi_m_n.link_n,
pipe_config->fdi_m_n.tu);
- DRM_DEBUG_KMS("dp: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
+ DRM_DEBUG_KMS("dp: %i, lanes: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
pipe_config->has_dp_encoder,
+ pipe_config->lane_count,
pipe_config->dp_m_n.gmch_m, pipe_config->dp_m_n.gmch_n,
pipe_config->dp_m_n.link_m, pipe_config->dp_m_n.link_n,
pipe_config->dp_m_n.tu);
- DRM_DEBUG_KMS("dp: %i, gmch_m2: %u, gmch_n2: %u, link_m2: %u, link_n2: %u, tu2: %u\n",
+ DRM_DEBUG_KMS("dp: %i, lanes: %i, gmch_m2: %u, gmch_n2: %u, link_m2: %u, link_n2: %u, tu2: %u\n",
pipe_config->has_dp_encoder,
+ pipe_config->lane_count,
pipe_config->dp_m2_n2.gmch_m,
pipe_config->dp_m2_n2.gmch_n,
pipe_config->dp_m2_n2.link_m,
@@ -12128,10 +12157,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
- /* Compute a starting value for pipe_config->pipe_bpp taking the source
- * plane pixel format and any sink constraints into account. Returns the
- * source plane bpp so that dithering can be selected on mismatches
- * after encoders and crtc also have had their say. */
base_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
pipe_config);
if (base_bpp < 0)
@@ -12200,7 +12225,7 @@ encoder_retry:
/* Dithering seems to not pass-through bits correctly when it should, so
* only enable it on 6bpc panels. */
pipe_config->dither = pipe_config->pipe_bpp == 6*3;
- DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
+ DRM_DEBUG_KMS("hw max bpp: %i, pipe bpp: %i, dithering: %i\n",
base_bpp, pipe_config->pipe_bpp, pipe_config->dither);
fail:
@@ -12250,7 +12275,6 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2)
base.head) \
if (mask & (1 <<(intel_crtc)->pipe))
-
static bool
intel_compare_m_n(unsigned int m, unsigned int n,
unsigned int m2, unsigned int n2,
@@ -12423,6 +12447,7 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_M_N(fdi_m_n);
PIPE_CONF_CHECK_I(has_dp_encoder);
+ PIPE_CONF_CHECK_I(lane_count);
if (INTEL_INFO(dev)->gen < 8) {
PIPE_CONF_CHECK_M_N(dp_m_n);
@@ -12470,22 +12495,24 @@ intel_pipe_config_compare(struct drm_device *dev,
DRM_MODE_FLAG_NVSYNC);
}
- PIPE_CONF_CHECK_I(pipe_src_w);
- PIPE_CONF_CHECK_I(pipe_src_h);
-
- PIPE_CONF_CHECK_I(gmch_pfit.control);
+ PIPE_CONF_CHECK_X(gmch_pfit.control);
/* pfit ratios are autocomputed by the hw on gen4+ */
if (INTEL_INFO(dev)->gen < 4)
PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
- PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
+ PIPE_CONF_CHECK_X(gmch_pfit.lvds_border_bits);
- PIPE_CONF_CHECK_I(pch_pfit.enabled);
- if (current_config->pch_pfit.enabled) {
- PIPE_CONF_CHECK_I(pch_pfit.pos);
- PIPE_CONF_CHECK_I(pch_pfit.size);
- }
+ if (!adjust) {
+ PIPE_CONF_CHECK_I(pipe_src_w);
+ PIPE_CONF_CHECK_I(pipe_src_h);
+
+ PIPE_CONF_CHECK_I(pch_pfit.enabled);
+ if (current_config->pch_pfit.enabled) {
+ PIPE_CONF_CHECK_X(pch_pfit.pos);
+ PIPE_CONF_CHECK_X(pch_pfit.size);
+ }
- PIPE_CONF_CHECK_I(scaler_state.scaler_id);
+ PIPE_CONF_CHECK_I(scaler_state.scaler_id);
+ }
/* BDW+ don't expose a synchronous way to read the state */
if (IS_HASWELL(dev))
@@ -12558,8 +12585,8 @@ static void check_wm_state(struct drm_device *dev)
}
/* cursor */
- hw_entry = &hw_ddb.cursor[pipe];
- sw_entry = &sw_ddb->cursor[pipe];
+ hw_entry = &hw_ddb.plane[pipe][PLANE_CURSOR];
+ sw_entry = &sw_ddb->plane[pipe][PLANE_CURSOR];
if (skl_ddb_entry_equal(hw_entry, sw_entry))
continue;
@@ -12647,7 +12674,8 @@ check_crtc_state(struct drm_device *dev, struct drm_atomic_state *old_state)
struct intel_crtc_state *pipe_config, *sw_config;
bool active;
- if (!needs_modeset(crtc->state))
+ if (!needs_modeset(crtc->state) &&
+ !to_intel_crtc_state(crtc->state)->update_pipe)
continue;
__drm_atomic_helper_crtc_destroy_state(crtc, old_crtc_state);
@@ -12801,11 +12829,11 @@ static void update_scanline_offset(struct intel_crtc *crtc)
* one to the value.
*/
if (IS_GEN2(dev)) {
- const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
int vtotal;
- vtotal = mode->crtc_vtotal;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ vtotal = adjusted_mode->crtc_vtotal;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
vtotal /= 2;
crtc->scanline_offset = vtotal - 1;
@@ -12943,7 +12971,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state)
return ret;
}
-
static int intel_modeset_checks(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
@@ -13029,11 +13056,11 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
return ret;
- if (i915.fastboot &&
- intel_pipe_config_compare(state->dev,
+ if (intel_pipe_config_compare(state->dev,
to_intel_crtc_state(crtc->state),
pipe_config, true)) {
crtc_state->mode_changed = false;
+ to_intel_crtc_state(crtc_state)->update_pipe = true;
}
if (needs_modeset(crtc_state)) {
@@ -13131,16 +13158,30 @@ static int intel_atomic_commit(struct drm_device *dev,
for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
bool modeset = needs_modeset(crtc->state);
+ bool update_pipe = !modeset &&
+ to_intel_crtc_state(crtc->state)->update_pipe;
+ unsigned long put_domains = 0;
if (modeset && crtc->state->active) {
update_scanline_offset(to_intel_crtc(crtc));
dev_priv->display.crtc_enable(crtc);
}
+ if (update_pipe) {
+ put_domains = modeset_get_crtc_power_domains(crtc);
+
+ /* make sure intel_modeset_check_state runs */
+ any_ms = true;
+ }
+
if (!modeset)
intel_pre_plane_update(intel_crtc);
drm_atomic_helper_commit_planes_on_crtc(crtc_state);
+
+ if (put_domains)
+ modeset_put_power_domains(dev_priv, put_domains);
+
intel_post_plane_update(intel_crtc);
}
@@ -13296,8 +13337,6 @@ static void intel_shared_dpll_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- intel_update_cdclk(dev);
-
if (HAS_DDI(dev))
intel_ddi_pll_init(dev);
else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
@@ -13322,10 +13361,10 @@ static void intel_shared_dpll_init(struct drm_device *dev)
*/
int
intel_prepare_plane_fb(struct drm_plane *plane,
- struct drm_framebuffer *fb,
const struct drm_plane_state *new_state)
{
struct drm_device *dev = plane->dev;
+ struct drm_framebuffer *fb = new_state->fb;
struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
@@ -13363,19 +13402,18 @@ intel_prepare_plane_fb(struct drm_plane *plane,
*/
void
intel_cleanup_plane_fb(struct drm_plane *plane,
- struct drm_framebuffer *fb,
const struct drm_plane_state *old_state)
{
struct drm_device *dev = plane->dev;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct drm_i915_gem_object *obj = intel_fb_obj(old_state->fb);
- if (WARN_ON(!obj))
+ if (!obj)
return;
if (plane->type != DRM_PLANE_TYPE_CURSOR ||
!INTEL_INFO(dev)->cursor_needs_physical) {
mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(fb, old_state);
+ intel_unpin_fb_obj(old_state->fb, old_state);
mutex_unlock(&dev->struct_mutex);
}
}
@@ -13457,11 +13495,9 @@ intel_commit_primary_plane(struct drm_plane *plane,
if (!crtc->state->active)
return;
- if (state->visible)
- /* FIXME: kill this fastboot hack */
- intel_update_pipe_size(intel_crtc);
-
- dev_priv->display.update_primary_plane(crtc, fb, crtc->x, crtc->y);
+ dev_priv->display.update_primary_plane(crtc, fb,
+ state->src.x1 >> 16,
+ state->src.y1 >> 16);
}
static void
@@ -13479,15 +13515,23 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc_state *old_intel_state =
+ to_intel_crtc_state(old_crtc_state);
+ bool modeset = needs_modeset(crtc->state);
if (intel_crtc->atomic.update_wm_pre)
intel_update_watermarks(crtc);
/* Perform vblank evasion around commit operation */
if (crtc->state->active)
- intel_pipe_update_start(intel_crtc, &intel_crtc->start_vbl_count);
+ intel_pipe_update_start(intel_crtc);
- if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9)
+ if (modeset)
+ return;
+
+ if (to_intel_crtc_state(crtc->state)->update_pipe)
+ intel_update_pipe_config(intel_crtc, old_intel_state);
+ else if (INTEL_INFO(dev)->gen >= 9)
skl_detach_scalers(intel_crtc);
}
@@ -13497,7 +13541,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
if (crtc->state->active)
- intel_pipe_update_end(intel_crtc, intel_crtc->start_vbl_count);
+ intel_pipe_update_end(intel_crtc);
}
/**
@@ -13666,10 +13710,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
crtc = crtc ? crtc : plane->crtc;
intel_crtc = to_intel_crtc(crtc);
- plane->fb = state->base.fb;
- crtc->cursor_x = state->base.crtc_x;
- crtc->cursor_y = state->base.crtc_y;
-
if (intel_crtc->cursor_bo == obj)
goto update;
@@ -13955,7 +13995,7 @@ static void intel_setup_outputs(struct drm_device *dev)
* On SKL pre-D0 the strap isn't connected, so we assume
* it's there.
*/
- found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED;
+ found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED;
/* WaIgnoreDDIAStrap: skl */
if (found || IS_SKYLAKE(dev))
intel_ddi_init(dev, PORT_A);
@@ -14016,29 +14056,26 @@ static void intel_setup_outputs(struct drm_device *dev)
* eDP ports. Consult the VBT as well as DP_DETECTED to
* detect eDP ports.
*/
- if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED &&
+ if (I915_READ(VLV_HDMIB) & SDVO_DETECTED &&
!intel_dp_is_edp(dev, PORT_B))
- intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB,
- PORT_B);
- if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED ||
+ intel_hdmi_init(dev, VLV_HDMIB, PORT_B);
+ if (I915_READ(VLV_DP_B) & DP_DETECTED ||
intel_dp_is_edp(dev, PORT_B))
- intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
+ intel_dp_init(dev, VLV_DP_B, PORT_B);
- if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED &&
+ if (I915_READ(VLV_HDMIC) & SDVO_DETECTED &&
!intel_dp_is_edp(dev, PORT_C))
- intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,
- PORT_C);
- if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED ||
+ intel_hdmi_init(dev, VLV_HDMIC, PORT_C);
+ if (I915_READ(VLV_DP_C) & DP_DETECTED ||
intel_dp_is_edp(dev, PORT_C))
- intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C);
+ intel_dp_init(dev, VLV_DP_C, PORT_C);
if (IS_CHERRYVIEW(dev)) {
- if (I915_READ(VLV_DISPLAY_BASE + CHV_HDMID) & SDVO_DETECTED)
- intel_hdmi_init(dev, VLV_DISPLAY_BASE + CHV_HDMID,
- PORT_D);
/* eDP not supported on port D, so don't check VBT */
- if (I915_READ(VLV_DISPLAY_BASE + DP_D) & DP_DETECTED)
- intel_dp_init(dev, VLV_DISPLAY_BASE + DP_D, PORT_D);
+ if (I915_READ(CHV_HDMID) & SDVO_DETECTED)
+ intel_hdmi_init(dev, CHV_HDMID, PORT_D);
+ if (I915_READ(CHV_DP_D) & DP_DETECTED)
+ intel_dp_init(dev, CHV_DP_D, PORT_D);
}
intel_dsi_init(dev);
@@ -14534,8 +14571,6 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.queue_flip = intel_default_queue_flip;
}
- intel_panel_init_backlight_funcs(dev);
-
mutex_init(&dev_priv->pps_mutex);
}
@@ -14678,6 +14713,9 @@ static struct intel_quirk intel_quirks[] = {
/* Dell Chromebook 11 */
{ 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
+
+ /* Dell Chromebook 11 (2015 version) */
+ { 0x0a16, 0x1028, 0x0a35, quirk_backlight_present },
};
static void intel_init_quirks(struct drm_device *dev)
@@ -14813,7 +14851,8 @@ void intel_modeset_init(struct drm_device *dev)
}
}
- intel_init_dpio(dev);
+ intel_update_czclk(dev_priv);
+ intel_update_cdclk(dev);
intel_shared_dpll_init(dev);
@@ -14881,13 +14920,12 @@ intel_check_plane_mapping(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 reg, val;
+ u32 val;
if (INTEL_INFO(dev)->num_pipes == 1)
return true;
- reg = DSPCNTR(!crtc->plane);
- val = I915_READ(reg);
+ val = I915_READ(DSPCNTR(!crtc->plane));
if ((val & DISPLAY_PLANE_ENABLE) &&
(!!(val & DISPPLANE_SEL_PIPE_MASK) == crtc->pipe))
@@ -14896,13 +14934,22 @@ intel_check_plane_mapping(struct intel_crtc *crtc)
return true;
}
+static bool intel_crtc_has_encoders(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct intel_encoder *encoder;
+
+ for_each_encoder_on_crtc(dev, &crtc->base, encoder)
+ return true;
+
+ return false;
+}
+
static void intel_sanitize_crtc(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_encoder *encoder;
u32 reg;
- bool enable;
/* Clear any frame start delays used for debugging left by the BIOS */
reg = PIPECONF(crtc->config->cpu_transcoder);
@@ -14913,8 +14960,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
if (crtc->active) {
struct intel_plane *plane;
- drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
- update_scanline_offset(crtc);
drm_crtc_vblank_on(&crtc->base);
/* Disable everything but the primary plane */
@@ -14956,16 +15001,11 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
/* Adjust the state of the output pipe according to whether we
* have active connectors/encoders. */
- enable = false;
- for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
- enable = true;
- break;
- }
-
- if (!enable)
+ if (!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,
@@ -15219,6 +15259,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
* recalculation.
*/
crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED;
+
+ drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode);
+ update_scanline_offset(crtc);
}
}
}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 0a2e33fbf20d..09bdd94ca3ba 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -130,6 +130,11 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp);
static void vlv_steal_power_sequencer(struct drm_device *dev,
enum pipe pipe);
+static unsigned int intel_dp_unused_lane_mask(int lane_count)
+{
+ return ~((1 << lane_count) - 1) & 0xf;
+}
+
static int
intel_dp_max_link_bw(struct intel_dp *intel_dp)
{
@@ -253,40 +258,6 @@ static void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
dst[i] = src >> ((3-i) * 8);
}
-/* hrawclock is 1/4 the FSB frequency */
-static int
-intel_hrawclk(struct drm_device *dev)
-{
- 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))
- return 200;
-
- clkcfg = I915_READ(CLKCFG);
- switch (clkcfg & CLKCFG_FSB_MASK) {
- case CLKCFG_FSB_400:
- return 100;
- case CLKCFG_FSB_533:
- return 133;
- case CLKCFG_FSB_667:
- return 166;
- case CLKCFG_FSB_800:
- return 200;
- case CLKCFG_FSB_1067:
- return 266;
- case CLKCFG_FSB_1333:
- return 333;
- /* these two are just a guess; one of them might be right */
- case CLKCFG_FSB_1600:
- case CLKCFG_FSB_1600_ALT:
- return 400;
- default:
- return 133;
- }
-}
-
static void
intel_dp_init_panel_power_sequencer(struct drm_device *dev,
struct intel_dp *intel_dp);
@@ -333,7 +304,9 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = intel_dp->pps_pipe;
- bool pll_enabled;
+ bool pll_enabled, release_cl_override = false;
+ enum dpio_phy phy = DPIO_PHY(pipe);
+ enum dpio_channel ch = vlv_pipe_to_channel(pipe);
uint32_t DP;
if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
@@ -363,9 +336,13 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
* The DPLL for the pipe must be enabled for this to work.
* So enable temporarily it if it's not already enabled.
*/
- if (!pll_enabled)
+ if (!pll_enabled) {
+ release_cl_override = IS_CHERRYVIEW(dev) &&
+ !chv_phy_powergate_ch(dev_priv, phy, ch, true);
+
vlv_force_pll_on(dev, pipe, IS_CHERRYVIEW(dev) ?
&chv_dpll[0].dpll : &vlv_dpll[0].dpll);
+ }
/*
* Similar magic as in intel_dp_enable_port().
@@ -382,8 +359,12 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(intel_dp->output_reg);
- if (!pll_enabled)
+ if (!pll_enabled) {
vlv_force_pll_off(dev, pipe);
+
+ if (release_cl_override)
+ chv_phy_powergate_ch(dev_priv, phy, ch, false);
+ }
}
static enum pipe
@@ -593,8 +574,6 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
edp_notifier);
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 pp_div;
- u32 pp_ctrl_reg, pp_div_reg;
if (!is_edp(intel_dp) || code != SYS_RESTART)
return 0;
@@ -603,6 +582,8 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code,
if (IS_VALLEYVIEW(dev)) {
enum pipe pipe = vlv_power_sequencer_pipe(intel_dp);
+ u32 pp_ctrl_reg, pp_div_reg;
+ u32 pp_div;
pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe);
pp_div_reg = VLV_PIPE_PP_DIVISOR(pipe);
@@ -974,6 +955,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
+ case DP_AUX_I2C_WRITE_STATUS_UPDATE:
txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE;
rxsize = 2; /* 0 or 1 data bytes */
@@ -1383,6 +1365,19 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
return rate_to_index(rate, intel_dp->sink_rates);
}
+static void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
+ uint8_t *link_bw, uint8_t *rate_select)
+{
+ if (intel_dp->num_sink_rates) {
+ *link_bw = 0;
+ *rate_select =
+ intel_dp_rate_select(intel_dp, port_clock);
+ } else {
+ *link_bw = drm_dp_link_rate_to_bw_code(port_clock);
+ *rate_select = 0;
+ }
+}
+
bool
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
@@ -1404,6 +1399,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
int link_avail, link_clock;
int common_rates[DP_MAX_SUPPORTED_RATES] = {};
int common_len;
+ uint8_t link_bw, rate_select;
common_len = intel_dp_common_rates(intel_dp, common_rates);
@@ -1499,32 +1495,23 @@ found:
* CEA-861-E - 5.1 Default Encoding Parameters
* VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry
*/
- if (bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1)
- intel_dp->color_range = DP_COLOR_RANGE_16_235;
- else
- intel_dp->color_range = 0;
- }
-
- if (intel_dp->color_range)
- pipe_config->limited_color_range = true;
-
- intel_dp->lane_count = lane_count;
-
- if (intel_dp->num_sink_rates) {
- intel_dp->link_bw = 0;
- intel_dp->rate_select =
- intel_dp_rate_select(intel_dp, common_rates[clock]);
+ pipe_config->limited_color_range =
+ bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1;
} else {
- intel_dp->link_bw =
- drm_dp_link_rate_to_bw_code(common_rates[clock]);
- intel_dp->rate_select = 0;
+ pipe_config->limited_color_range =
+ intel_dp->limited_color_range;
}
+ pipe_config->lane_count = lane_count;
+
pipe_config->pipe_bpp = bpp;
pipe_config->port_clock = common_rates[clock];
- DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
- intel_dp->link_bw, intel_dp->lane_count,
+ intel_dp_compute_rate(intel_dp, pipe_config->port_clock,
+ &link_bw, &rate_select);
+
+ DRM_DEBUG_KMS("DP link bw %02x rate select %02x lane count %d clock %d bpp %d\n",
+ link_bw, rate_select, pipe_config->lane_count,
pipe_config->port_clock, bpp);
DRM_DEBUG_KMS("DP link bw required %i available %i\n",
mode_rate, link_avail);
@@ -1586,6 +1573,13 @@ static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
udelay(500);
}
+void intel_dp_set_link_params(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *pipe_config)
+{
+ intel_dp->link_rate = pipe_config->port_clock;
+ intel_dp->lane_count = pipe_config->lane_count;
+}
+
static void intel_dp_prepare(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
@@ -1593,7 +1587,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+
+ intel_dp_set_link_params(intel_dp, crtc->config);
/*
* There are four kinds of DP registers:
@@ -1619,7 +1615,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
/* Handle DP bits in common between all three register formats */
intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
- intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count);
+ intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count);
if (crtc->config->has_audio)
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
@@ -1649,8 +1645,9 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
trans_dp &= ~TRANS_DP_ENH_FRAMING;
I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
} else {
- if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
- intel_dp->DP |= intel_dp->color_range;
+ if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
+ crtc->config->limited_color_range)
+ intel_dp->DP |= DP_COLOR_RANGE_16_235;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
intel_dp->DP |= DP_SYNC_HS_HIGH;
@@ -2290,13 +2287,14 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
pipe_config->has_audio = tmp & DP_AUDIO_OUTPUT_ENABLE && port != PORT_A;
if (HAS_PCH_CPT(dev) && port != PORT_A) {
- tmp = I915_READ(TRANS_DP_CTL(crtc->pipe));
- if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH)
+ u32 trans_dp = I915_READ(TRANS_DP_CTL(crtc->pipe));
+
+ if (trans_dp & TRANS_DP_HSYNC_ACTIVE_HIGH)
flags |= DRM_MODE_FLAG_PHSYNC;
else
flags |= DRM_MODE_FLAG_NHSYNC;
- if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH)
+ if (trans_dp & TRANS_DP_VSYNC_ACTIVE_HIGH)
flags |= DRM_MODE_FLAG_PVSYNC;
else
flags |= DRM_MODE_FLAG_NVSYNC;
@@ -2320,6 +2318,9 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
pipe_config->has_dp_encoder = true;
+ pipe_config->lane_count =
+ ((tmp & DP_PORT_WIDTH_MASK) >> DP_PORT_WIDTH_SHIFT) + 1;
+
intel_dp_get_m_n(crtc, pipe_config);
if (port == PORT_A) {
@@ -2399,38 +2400,62 @@ static void vlv_post_disable_dp(struct intel_encoder *encoder)
intel_dp_link_down(intel_dp);
}
-static void chv_post_disable_dp(struct intel_encoder *encoder)
+static void chv_data_lane_soft_reset(struct intel_encoder *encoder,
+ bool reset)
{
- struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
- struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc =
- to_intel_crtc(encoder->base.crtc);
- enum dpio_channel ch = vlv_dport_to_channel(dport);
- enum pipe pipe = intel_crtc->pipe;
- u32 val;
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base));
+ struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+ enum pipe pipe = crtc->pipe;
+ uint32_t val;
- intel_dp_link_down(intel_dp);
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
+ if (reset)
+ val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+ else
+ val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
- mutex_lock(&dev_priv->sb_lock);
+ if (crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
+ if (reset)
+ val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+ else
+ val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+ }
- /* Propagate soft reset to data lane reset */
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
val |= CHV_PCS_REQ_SOFTRESET_EN;
+ if (reset)
+ val &= ~DPIO_PCS_CLK_SOFT_RESET;
+ else
+ val |= DPIO_PCS_CLK_SOFT_RESET;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
+ if (crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
+ val |= CHV_PCS_REQ_SOFTRESET_EN;
+ if (reset)
+ val &= ~DPIO_PCS_CLK_SOFT_RESET;
+ else
+ val |= DPIO_PCS_CLK_SOFT_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
+ }
+}
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
- val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
+static void chv_post_disable_dp(struct intel_encoder *encoder)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_dp_link_down(intel_dp);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
- val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+ mutex_lock(&dev_priv->sb_lock);
+
+ /* Assert data lane reset */
+ chv_data_lane_soft_reset(encoder, true);
mutex_unlock(&dev_priv->sb_lock);
}
@@ -2550,7 +2575,6 @@ static void intel_enable_dp(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
uint32_t dp_reg = I915_READ(intel_dp->output_reg);
- unsigned int lane_mask = 0x0;
if (WARN_ON(dp_reg & DP_PORT_EN))
return;
@@ -2568,13 +2592,18 @@ static void intel_enable_dp(struct intel_encoder *encoder)
pps_unlock(intel_dp);
- if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev)) {
+ unsigned int lane_mask = 0x0;
+
+ if (IS_CHERRYVIEW(dev))
+ lane_mask = intel_dp_unused_lane_mask(crtc->config->lane_count);
+
vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
lane_mask);
+ }
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
if (crtc->config->has_audio) {
@@ -2797,31 +2826,19 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
- val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
-
- /* Deassert soft data lane reset*/
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
- val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
- val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+ if (intel_crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
+ val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
+ }
/* Program Tx lane latency optimal setting*/
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < intel_crtc->config->lane_count; i++) {
/* Set the upar bit */
- data = (i == 1) ? 0x0 : 0x1;
+ if (intel_crtc->config->lane_count == 1)
+ data = 0x0;
+ else
+ data = (i == 1) ? 0x0 : 0x1;
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i),
data << DPIO_UPAR_SHIFT);
}
@@ -2842,9 +2859,11 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
val |= DPIO_TX2_STAGGER_MASK(0x1f);
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
- val |= DPIO_TX2_STAGGER_MASK(0x1f);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
+ if (intel_crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch));
+ val |= DPIO_TX2_STAGGER_MASK(0x1f);
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
+ }
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch),
DPIO_LANESTAGGER_STRAP(stagger) |
@@ -2853,16 +2872,27 @@ static void chv_pre_enable_dp(struct intel_encoder *encoder)
DPIO_TX1_STAGGER_MULT(6) |
DPIO_TX2_STAGGER_MULT(0));
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch),
- DPIO_LANESTAGGER_STRAP(stagger) |
- DPIO_LANESTAGGER_STRAP_OVRD |
- DPIO_TX1_STAGGER_MASK(0x1f) |
- DPIO_TX1_STAGGER_MULT(7) |
- DPIO_TX2_STAGGER_MULT(5));
+ if (intel_crtc->config->lane_count > 2) {
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch),
+ DPIO_LANESTAGGER_STRAP(stagger) |
+ DPIO_LANESTAGGER_STRAP_OVRD |
+ DPIO_TX1_STAGGER_MASK(0x1f) |
+ DPIO_TX1_STAGGER_MULT(7) |
+ DPIO_TX2_STAGGER_MULT(5));
+ }
+
+ /* Deassert data lane reset */
+ chv_data_lane_soft_reset(encoder, false);
mutex_unlock(&dev_priv->sb_lock);
intel_enable_dp(encoder);
+
+ /* Second common lane will stay alive on its own now */
+ if (dport->release_cl2_override) {
+ chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false);
+ dport->release_cl2_override = false;
+ }
}
static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
@@ -2874,12 +2904,27 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
to_intel_crtc(encoder->base.crtc);
enum dpio_channel ch = vlv_dport_to_channel(dport);
enum pipe pipe = intel_crtc->pipe;
+ unsigned int lane_mask =
+ intel_dp_unused_lane_mask(intel_crtc->config->lane_count);
u32 val;
intel_dp_prepare(encoder);
+ /*
+ * Must trick the second common lane into life.
+ * Otherwise we can't even access the PLL.
+ */
+ if (ch == DPIO_CH0 && pipe == PIPE_B)
+ dport->release_cl2_override =
+ !chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true);
+
+ chv_phy_powergate_lanes(encoder, true, lane_mask);
+
mutex_lock(&dev_priv->sb_lock);
+ /* Assert data lane reset */
+ chv_data_lane_soft_reset(encoder, true);
+
/* program left/right clock distribution */
if (pipe != PIPE_B) {
val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
@@ -2908,13 +2953,15 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
val |= CHV_PCS_USEDCLKCHANNEL;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch));
- val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
- if (pipe != PIPE_B)
- val &= ~CHV_PCS_USEDCLKCHANNEL;
- else
- val |= CHV_PCS_USEDCLKCHANNEL;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val);
+ if (intel_crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch));
+ val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE;
+ if (pipe != PIPE_B)
+ val &= ~CHV_PCS_USEDCLKCHANNEL;
+ else
+ val |= CHV_PCS_USEDCLKCHANNEL;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val);
+ }
/*
* This a a bit weird since generally CL
@@ -2931,6 +2978,39 @@ static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->sb_lock);
}
+static void chv_dp_post_pll_disable(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
+ u32 val;
+
+ mutex_lock(&dev_priv->sb_lock);
+
+ /* disable left/right clock distribution */
+ if (pipe != PIPE_B) {
+ val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
+ val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
+ vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
+ } else {
+ val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
+ val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
+ vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
+ }
+
+ mutex_unlock(&dev_priv->sb_lock);
+
+ /*
+ * Leave the power down bit cleared for at least one
+ * lane so that chv_powergate_phy_ch() will power
+ * on something when the channel is otherwise unused.
+ * When the port is off and the override is removed
+ * the lanes power down anyway, so otherwise it doesn't
+ * really matter what the state of power down bits is
+ * after this.
+ */
+ chv_phy_powergate_lanes(encoder, false, 0x0);
+}
+
/*
* Native read with retry for link status and receiver capability reads for
* cases where the sink may still be asleep.
@@ -3167,6 +3247,12 @@ static uint32_t vlv_signal_levels(struct intel_dp *intel_dp)
return 0;
}
+static bool chv_need_uniq_trans_scale(uint8_t train_set)
+{
+ return (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) == DP_TRAIN_PRE_EMPH_LEVEL_0 &&
+ (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) == DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+}
+
static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
@@ -3258,24 +3344,28 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
- val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
- val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
- val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
+ if (intel_crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
+ val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
+ val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK);
+ val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
+ }
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch));
val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
- val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
- val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val);
+ if (intel_crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch));
+ val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK);
+ val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val);
+ }
/* Program swing deemph */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < intel_crtc->config->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i));
val &= ~DPIO_SWING_DEEMPH9P5_MASK;
val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT;
@@ -3283,43 +3373,36 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
}
/* Program swing margin */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < intel_crtc->config->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
+
val &= ~DPIO_SWING_MARGIN000_MASK;
val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT;
+
+ /*
+ * Supposedly this value shouldn't matter when unique transition
+ * scale is disabled, but in fact it does matter. Let's just
+ * always program the same value and hope it's OK.
+ */
+ val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT);
+ val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT;
+
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
}
- /* Disable unique transition scale */
- for (i = 0; i < 4; i++) {
+ /*
+ * The document said it needs to set bit 27 for ch0 and bit 26
+ * for ch1. Might be a typo in the doc.
+ * For now, for this unique transition scale selection, set bit
+ * 27 for ch0 and ch1.
+ */
+ for (i = 0; i < intel_crtc->config->lane_count; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
- val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
- vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
- }
-
- if (((train_set & DP_TRAIN_PRE_EMPHASIS_MASK)
- == DP_TRAIN_PRE_EMPH_LEVEL_0) &&
- ((train_set & DP_TRAIN_VOLTAGE_SWING_MASK)
- == DP_TRAIN_VOLTAGE_SWING_LEVEL_3)) {
-
- /*
- * The document said it needs to set bit 27 for ch0 and bit 26
- * for ch1. Might be a typo in the doc.
- * For now, for this unique transition scale selection, set bit
- * 27 for ch0 and ch1.
- */
- for (i = 0; i < 4; i++) {
- val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
+ if (chv_need_uniq_trans_scale(train_set))
val |= DPIO_TX_UNIQ_TRANS_SCALE_EN;
- vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
- }
-
- for (i = 0; i < 4; i++) {
- val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
- val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT);
- val |= (0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT);
- vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
- }
+ else
+ val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
+ vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
}
/* Start swing calculation */
@@ -3327,14 +3410,11 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val);
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
- val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
-
- /* LRC Bypass */
- val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30);
- val |= DPIO_LRC_BYPASS;
- vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val);
+ if (intel_crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch));
+ val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
+ }
mutex_unlock(&dev_priv->sb_lock);
@@ -3520,8 +3600,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
uint8_t dp_train_pat)
{
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);
uint8_t buf[sizeof(intel_dp->train_set) + 1];
int ret, len;
@@ -3562,8 +3642,8 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
const uint8_t link_status[DP_LINK_STATUS_SIZE])
{
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);
int ret;
intel_get_adjust_train(intel_dp, link_status);
@@ -3610,8 +3690,8 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
}
/* Enable corresponding port and start training pattern 1 */
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
+static void
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
{
struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
struct drm_device *dev = encoder->dev;
@@ -3620,19 +3700,23 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
int voltage_tries, loop_tries;
uint32_t DP = intel_dp->DP;
uint8_t link_config[2];
+ uint8_t link_bw, rate_select;
if (HAS_DDI(dev))
intel_ddi_prepare_link_retrain(encoder);
+ intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
+ &link_bw, &rate_select);
+
/* Write the link configuration data */
- link_config[0] = intel_dp->link_bw;
+ link_config[0] = link_bw;
link_config[1] = intel_dp->lane_count;
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
if (intel_dp->num_sink_rates)
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
- &intel_dp->rate_select, 1);
+ &rate_select, 1);
link_config[0] = 0;
link_config[1] = DP_SET_ANSI_8B10B;
@@ -3720,17 +3804,30 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
intel_dp->DP = DP;
}
-void
-intel_dp_complete_link_train(struct intel_dp *intel_dp)
+static void
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
bool channel_eq = false;
int tries, cr_tries;
uint32_t DP = intel_dp->DP;
uint32_t training_pattern = DP_TRAINING_PATTERN_2;
- /* Training Pattern 3 for HBR2 ot 1.2 devices that support it*/
- if (intel_dp->link_bw == DP_LINK_BW_5_4 || intel_dp->use_tps3)
+ /*
+ * Training Pattern 3 for HBR2 or 1.2 devices that support it.
+ *
+ * Intel platforms that support HBR2 also support TPS3. TPS3 support is
+ * also mandatory for downstream devices that support HBR2.
+ *
+ * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
+ * supported but still not enabled.
+ */
+ if (intel_dp_source_supports_hbr2(dev) &&
+ drm_dp_tps3_supported(intel_dp->dpcd))
training_pattern = DP_TRAINING_PATTERN_3;
+ else if (intel_dp->link_rate == 540000)
+ DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
/* channel equalization */
if (!intel_dp_set_link_train(intel_dp, &DP,
@@ -3758,9 +3855,10 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
}
/* Make sure clock is still ok */
- if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+ if (!drm_dp_clock_recovery_ok(link_status,
+ intel_dp->lane_count)) {
intel_dp->train_set_valid = false;
- intel_dp_start_link_train(intel_dp);
+ intel_dp_link_training_clock_recovery(intel_dp);
intel_dp_set_link_train(intel_dp, &DP,
training_pattern |
DP_LINK_SCRAMBLING_DISABLE);
@@ -3768,7 +3866,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
continue;
}
- if (drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
+ if (drm_dp_channel_eq_ok(link_status,
+ intel_dp->lane_count)) {
channel_eq = true;
break;
}
@@ -3776,7 +3875,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
/* Try 5 times, then try clock recovery if that fails */
if (tries > 5) {
intel_dp->train_set_valid = false;
- intel_dp_start_link_train(intel_dp);
+ intel_dp_link_training_clock_recovery(intel_dp);
intel_dp_set_link_train(intel_dp, &DP,
training_pattern |
DP_LINK_SCRAMBLING_DISABLE);
@@ -3809,6 +3908,13 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
DP_TRAINING_PATTERN_DISABLE);
}
+void
+intel_dp_start_link_train(struct intel_dp *intel_dp)
+{
+ intel_dp_link_training_clock_recovery(intel_dp);
+ intel_dp_link_training_channel_equalization(intel_dp);
+}
+
static void
intel_dp_link_down(struct intel_dp *intel_dp)
{
@@ -3909,19 +4015,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
}
}
- /* Training Pattern 3 support, Intel platforms that support HBR2 alone
- * have support for TP3 hence that check is used along with dpcd check
- * to ensure TP3 can be enabled.
- * SKL < B0: due it's WaDisableHBR2 is the only exception where TP3 is
- * supported but still not enabled.
- */
- if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
- intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED &&
- intel_dp_source_supports_hbr2(dev)) {
- intel_dp->use_tps3 = true;
- DRM_DEBUG_KMS("Displayport TPS3 supported\n");
- } else
- intel_dp->use_tps3 = false;
+ DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n",
+ yesno(intel_dp_source_supports_hbr2(dev)),
+ yesno(drm_dp_tps3_supported(intel_dp->dpcd)));
/* Intermediate frequency support */
if (is_edp(intel_dp) &&
@@ -4007,22 +4103,30 @@ intel_dp_probe_mst(struct intel_dp *intel_dp)
return intel_dp->is_mst;
}
-static void intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
+static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
u8 buf;
+ int ret = 0;
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) {
DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
- return;
+ ret = -EIO;
+ goto out;
}
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
- buf & ~DP_TEST_SINK_START) < 0)
+ buf & ~DP_TEST_SINK_START) < 0) {
DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n");
+ ret = -EIO;
+ goto out;
+ }
+ intel_dp->sink_crc.started = false;
+ out:
hsw_enable_ips(intel_crtc);
+ return ret;
}
static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
@@ -4030,6 +4134,13 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
u8 buf;
+ int ret;
+
+ if (intel_dp->sink_crc.started) {
+ ret = intel_dp_sink_crc_stop(intel_dp);
+ if (ret)
+ return ret;
+ }
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0)
return -EIO;
@@ -4037,6 +4148,8 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
if (!(buf & DP_TEST_CRC_SUPPORTED))
return -ENOTTY;
+ intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
+
if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0)
return -EIO;
@@ -4048,6 +4161,7 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp)
return -EIO;
}
+ intel_dp->sink_crc.started = true;
return 0;
}
@@ -4057,38 +4171,55 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
struct drm_device *dev = dig_port->base.base.dev;
struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc);
u8 buf;
- int test_crc_count;
+ int count, ret;
int attempts = 6;
- int ret;
+ bool old_equal_new;
ret = intel_dp_sink_crc_start(intel_dp);
if (ret)
return ret;
- if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) {
- ret = -EIO;
- goto stop;
- }
-
- test_crc_count = buf & DP_TEST_COUNT_MASK;
-
do {
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
if (drm_dp_dpcd_readb(&intel_dp->aux,
DP_TEST_SINK_MISC, &buf) < 0) {
ret = -EIO;
goto stop;
}
- intel_wait_for_vblank(dev, intel_crtc->pipe);
- } while (--attempts && (buf & DP_TEST_COUNT_MASK) == test_crc_count);
+ count = buf & DP_TEST_COUNT_MASK;
+
+ /*
+ * Count might be reset during the loop. In this case
+ * last known count needs to be reset as well.
+ */
+ if (count == 0)
+ intel_dp->sink_crc.last_count = 0;
+
+ if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) {
+ ret = -EIO;
+ goto stop;
+ }
+
+ old_equal_new = (count == intel_dp->sink_crc.last_count &&
+ !memcmp(intel_dp->sink_crc.last_crc, crc,
+ 6 * sizeof(u8)));
+
+ } while (--attempts && (count == 0 || old_equal_new));
+
+ intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK;
+ memcpy(intel_dp->sink_crc.last_crc, crc, 6 * sizeof(u8));
if (attempts == 0) {
- DRM_DEBUG_KMS("Panel is unable to calculate CRC after 6 vblanks\n");
- ret = -ETIMEDOUT;
- goto stop;
+ if (old_equal_new) {
+ DRM_DEBUG_KMS("Unreliable Sink CRC counter: Current returned CRC is identical to the previous one\n");
+ } else {
+ DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n");
+ ret = -ETIMEDOUT;
+ goto stop;
+ }
}
- if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
- ret = -EIO;
stop:
intel_dp_sink_crc_stop(intel_dp);
return ret;
@@ -4248,10 +4379,10 @@ go_again:
if (bret == true) {
/* check link status - esi[10] = 0x200c */
- if (intel_dp->active_mst_links && !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
+ if (intel_dp->active_mst_links &&
+ !drm_dp_channel_eq_ok(&esi[10], intel_dp->lane_count)) {
DRM_DEBUG_KMS("channel EQ not ok, retraining\n");
intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
}
@@ -4342,7 +4473,6 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
intel_encoder->base.name);
intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
}
}
@@ -4410,58 +4540,164 @@ edp_detect(struct intel_dp *intel_dp)
return status;
}
-static enum drm_connector_status
-ironlake_dp_detect(struct intel_dp *intel_dp)
+static bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
+ struct intel_digital_port *port)
{
- struct drm_device *dev = intel_dp_to_dev(intel_dp);
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ u32 bit;
- if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
- return connector_status_disconnected;
+ switch (port->port) {
+ case PORT_A:
+ return true;
+ case PORT_B:
+ bit = SDE_PORTB_HOTPLUG;
+ break;
+ case PORT_C:
+ bit = SDE_PORTC_HOTPLUG;
+ break;
+ case PORT_D:
+ bit = SDE_PORTD_HOTPLUG;
+ break;
+ default:
+ MISSING_CASE(port->port);
+ return false;
+ }
- return intel_dp_detect_dpcd(intel_dp);
+ return I915_READ(SDEISR) & bit;
+}
+
+static bool cpt_digital_port_connected(struct drm_i915_private *dev_priv,
+ struct intel_digital_port *port)
+{
+ u32 bit;
+
+ switch (port->port) {
+ case PORT_A:
+ return true;
+ case PORT_B:
+ bit = SDE_PORTB_HOTPLUG_CPT;
+ break;
+ case PORT_C:
+ bit = SDE_PORTC_HOTPLUG_CPT;
+ break;
+ case PORT_D:
+ bit = SDE_PORTD_HOTPLUG_CPT;
+ break;
+ case PORT_E:
+ bit = SDE_PORTE_HOTPLUG_SPT;
+ break;
+ default:
+ MISSING_CASE(port->port);
+ return false;
+ }
+
+ return I915_READ(SDEISR) & bit;
+}
+
+static bool g4x_digital_port_connected(struct drm_i915_private *dev_priv,
+ struct intel_digital_port *port)
+{
+ u32 bit;
+
+ switch (port->port) {
+ case PORT_B:
+ bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
+ break;
+ case PORT_C:
+ bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
+ break;
+ case PORT_D:
+ bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
+ break;
+ default:
+ MISSING_CASE(port->port);
+ return false;
+ }
+
+ return I915_READ(PORT_HOTPLUG_STAT) & bit;
}
-static int g4x_digital_port_connected(struct drm_device *dev,
+static bool vlv_digital_port_connected(struct drm_i915_private *dev_priv,
+ struct intel_digital_port *port)
+{
+ u32 bit;
+
+ switch (port->port) {
+ case PORT_B:
+ bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+ break;
+ case PORT_C:
+ bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+ break;
+ case PORT_D:
+ bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+ break;
+ default:
+ MISSING_CASE(port->port);
+ return false;
+ }
+
+ return I915_READ(PORT_HOTPLUG_STAT) & bit;
+}
+
+static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
struct intel_digital_port *intel_dig_port)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t bit;
+ struct intel_encoder *intel_encoder = &intel_dig_port->base;
+ enum port port;
+ u32 bit;
- if (IS_VALLEYVIEW(dev)) {
- switch (intel_dig_port->port) {
- case PORT_B:
- bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
- break;
- case PORT_C:
- bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
- break;
- case PORT_D:
- bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
- break;
- default:
- return -EINVAL;
- }
- } else {
- switch (intel_dig_port->port) {
- case PORT_B:
- bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
- break;
- case PORT_C:
- bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
- break;
- case PORT_D:
- bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
- break;
- default:
- return -EINVAL;
- }
+ intel_hpd_pin_to_port(intel_encoder->hpd_pin, &port);
+ switch (port) {
+ case PORT_A:
+ bit = BXT_DE_PORT_HP_DDIA;
+ break;
+ case PORT_B:
+ bit = BXT_DE_PORT_HP_DDIB;
+ break;
+ case PORT_C:
+ bit = BXT_DE_PORT_HP_DDIC;
+ break;
+ default:
+ MISSING_CASE(port);
+ return false;
}
- if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0)
- return 0;
- return 1;
+ return I915_READ(GEN8_DE_PORT_ISR) & bit;
+}
+
+/*
+ * intel_digital_port_connected - is the specified port connected?
+ * @dev_priv: i915 private structure
+ * @port: the port to test
+ *
+ * Return %true if @port is connected, %false otherwise.
+ */
+bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
+ struct intel_digital_port *port)
+{
+ if (HAS_PCH_IBX(dev_priv))
+ return ibx_digital_port_connected(dev_priv, port);
+ if (HAS_PCH_SPLIT(dev_priv))
+ return cpt_digital_port_connected(dev_priv, port);
+ else if (IS_BROXTON(dev_priv))
+ return bxt_digital_port_connected(dev_priv, port);
+ else if (IS_VALLEYVIEW(dev_priv))
+ return vlv_digital_port_connected(dev_priv, port);
+ else
+ return g4x_digital_port_connected(dev_priv, port);
+}
+
+static enum drm_connector_status
+ironlake_dp_detect(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+
+ if (!intel_digital_port_connected(dev_priv, intel_dig_port))
+ return connector_status_disconnected;
+
+ return intel_dp_detect_dpcd(intel_dp);
}
static enum drm_connector_status
@@ -4469,7 +4705,6 @@ g4x_dp_detect(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
- int ret;
/* Can't disconnect eDP, but you can close the lid... */
if (is_edp(intel_dp)) {
@@ -4481,10 +4716,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
return status;
}
- ret = g4x_digital_port_connected(dev, intel_dig_port);
- if (ret == -EINVAL)
- return connector_status_unknown;
- else if (ret == 0)
+ if (!intel_digital_port_connected(dev->dev_private, intel_dig_port))
return connector_status_disconnected;
return intel_dp_detect_dpcd(intel_dp);
@@ -4728,7 +4960,7 @@ intel_dp_set_property(struct drm_connector *connector,
if (property == dev_priv->broadcast_rgb_property) {
bool old_auto = intel_dp->color_range_auto;
- uint32_t old_range = intel_dp->color_range;
+ bool old_range = intel_dp->limited_color_range;
switch (val) {
case INTEL_BROADCAST_RGB_AUTO:
@@ -4736,18 +4968,18 @@ intel_dp_set_property(struct drm_connector *connector,
break;
case INTEL_BROADCAST_RGB_FULL:
intel_dp->color_range_auto = false;
- intel_dp->color_range = 0;
+ intel_dp->limited_color_range = false;
break;
case INTEL_BROADCAST_RGB_LIMITED:
intel_dp->color_range_auto = false;
- intel_dp->color_range = DP_COLOR_RANGE_16_235;
+ intel_dp->limited_color_range = true;
break;
default:
return -EINVAL;
}
if (old_auto == intel_dp->color_range_auto &&
- old_range == intel_dp->color_range)
+ old_range == intel_dp->limited_color_range)
return 0;
goto done;
@@ -4947,13 +5179,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
/* indicate that we need to restart link training */
intel_dp->train_set_valid = false;
- if (HAS_PCH_SPLIT(dev)) {
- if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
- goto mst_fail;
- } else {
- if (g4x_digital_port_connected(dev, intel_dig_port) != 1)
- goto mst_fail;
- }
+ if (!intel_digital_port_connected(dev_priv, intel_dig_port))
+ goto mst_fail;
if (!intel_dp_get_dpcd(intel_dp)) {
goto mst_fail;
@@ -5028,6 +5255,13 @@ bool intel_dp_is_edp(struct drm_device *dev, enum port port)
[PORT_E] = DVO_PORT_DPE,
};
+ /*
+ * eDP not supported on g4x. so bail out early just
+ * for a bit extra safety in case the VBT is bonkers.
+ */
+ if (INTEL_INFO(dev)->gen < 5)
+ return false;
+
if (port == PORT_A)
return true;
@@ -5302,7 +5536,6 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
struct intel_dp *intel_dp = dev_priv->drrs.dp;
struct intel_crtc_state *config = NULL;
struct intel_crtc *intel_crtc = NULL;
- u32 reg, val;
enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
if (refresh_rate <= 0) {
@@ -5364,9 +5597,10 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
DRM_ERROR("Unsupported refreshrate type\n");
}
} else if (INTEL_INFO(dev)->gen > 6) {
- reg = PIPECONF(intel_crtc->config->cpu_transcoder);
- val = I915_READ(reg);
+ u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder);
+ u32 val;
+ val = I915_READ(reg);
if (index > DRRS_HIGH_RR) {
if (IS_VALLEYVIEW(dev))
val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
@@ -5765,7 +5999,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
}
intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
- intel_connector->panel.backlight_power = intel_edp_backlight_power;
+ intel_connector->panel.backlight.power = intel_edp_backlight_power;
intel_panel_setup_backlight(connector, pipe);
return true;
@@ -5853,6 +6087,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
break;
case PORT_B:
intel_encoder->hpd_pin = HPD_PORT_B;
+ if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0))
+ intel_encoder->hpd_pin = HPD_PORT_A;
break;
case PORT_C:
intel_encoder->hpd_pin = HPD_PORT_C;
@@ -5932,10 +6168,8 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
return;
intel_connector = intel_connector_alloc();
- if (!intel_connector) {
- kfree(intel_dig_port);
- return;
- }
+ if (!intel_connector)
+ goto err_connector_alloc;
intel_encoder = &intel_dig_port->base;
encoder = &intel_encoder->base;
@@ -5953,6 +6187,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_encoder->pre_enable = chv_pre_enable_dp;
intel_encoder->enable = vlv_enable_dp;
intel_encoder->post_disable = chv_post_disable_dp;
+ intel_encoder->post_pll_disable = chv_dp_post_pll_disable;
} else if (IS_VALLEYVIEW(dev)) {
intel_encoder->pre_pll_enable = vlv_dp_pre_pll_enable;
intel_encoder->pre_enable = vlv_pre_enable_dp;
@@ -5982,11 +6217,18 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_dig_port->hpd_pulse = intel_dp_hpd_pulse;
dev_priv->hotplug.irq_port[port] = intel_dig_port;
- if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
- drm_encoder_cleanup(encoder);
- kfree(intel_dig_port);
- kfree(intel_connector);
- }
+ if (!intel_dp_init_connector(intel_dig_port, intel_connector))
+ goto err_init_connector;
+
+ return;
+
+err_init_connector:
+ drm_encoder_cleanup(encoder);
+ kfree(intel_connector);
+err_connector_alloc:
+ kfree(intel_dig_port);
+
+ return;
}
void intel_dp_mst_suspend(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 6ade06888432..0639275fc471 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -39,8 +39,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct intel_dp *intel_dp = &intel_dig_port->dp;
struct drm_atomic_state *state;
int bpp, i;
- int lane_count, slots, rate;
- struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ int lane_count, slots;
+ const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct drm_connector *drm_connector;
struct intel_connector *connector, *found = NULL;
struct drm_connector_state *connector_state;
@@ -56,20 +56,11 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
*/
lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
- rate = intel_dp_max_link_rate(intel_dp);
- if (intel_dp->num_sink_rates) {
- intel_dp->link_bw = 0;
- intel_dp->rate_select = intel_dp_rate_select(intel_dp, rate);
- } else {
- intel_dp->link_bw = drm_dp_link_rate_to_bw_code(rate);
- intel_dp->rate_select = 0;
- }
-
- intel_dp->lane_count = lane_count;
+ pipe_config->lane_count = lane_count;
pipe_config->pipe_bpp = 24;
- pipe_config->port_clock = rate;
+ pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
state = pipe_config->base.state;
@@ -87,7 +78,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
return false;
}
- mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->clock, bpp);
+ mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
pipe_config->pbn = mst_pbn;
slots = drm_dp_find_vcpi_slots(&intel_dp->mst_mgr, mst_pbn);
@@ -184,6 +175,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
if (intel_dp->active_mst_links == 0) {
enum port port = intel_ddi_get_encoder_port(encoder);
+ intel_dp_set_link_params(intel_dp, intel_crtc->config);
+
/* FIXME: add support for SKL */
if (INTEL_INFO(dev)->gen < 9)
I915_WRITE(PORT_CLK_SEL(port),
@@ -195,7 +188,6 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
}
@@ -286,6 +278,10 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
break;
}
pipe_config->base.adjusted_mode.flags |= flags;
+
+ pipe_config->lane_count =
+ ((temp & DDI_PORT_WIDTH_MASK) >> DDI_PORT_WIDTH_SHIFT) + 1;
+
intel_dp_get_m_n(crtc, pipe_config);
intel_ddi_clock_get(&intel_dig_port->base, pipe_config);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 2b9e6f9775c5..0598932ce623 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -142,6 +142,7 @@ struct intel_encoder {
void (*mode_set)(struct intel_encoder *intel_encoder);
void (*disable)(struct intel_encoder *);
void (*post_disable)(struct intel_encoder *);
+ void (*post_pll_disable)(struct intel_encoder *);
/* Read out the current hw state of this connector, returning true if
* the encoder is active. If the encoder is enabled it also set the pipe
* it is connected to in the pipe parameter. */
@@ -178,12 +179,22 @@ struct intel_panel {
bool active_low_pwm;
/* PWM chip */
+ bool util_pin_active_low; /* bxt+ */
+ u8 controller; /* bxt+ only */
struct pwm_device *pwm;
struct backlight_device *device;
- } backlight;
- void (*backlight_power)(struct intel_connector *, bool enable);
+ /* Connector and platform specific backlight functions */
+ int (*setup)(struct intel_connector *connector, enum pipe pipe);
+ uint32_t (*get)(struct intel_connector *connector);
+ void (*set)(struct intel_connector *connector, uint32_t level);
+ void (*disable)(struct intel_connector *connector);
+ void (*enable)(struct intel_connector *connector);
+ uint32_t (*hz_to_pwm)(struct intel_connector *connector,
+ uint32_t hz);
+ void (*power)(struct intel_connector *, bool enable);
+ } backlight;
};
struct intel_connector {
@@ -337,6 +348,8 @@ struct intel_crtc_state {
#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
unsigned long quirks;
+ bool update_pipe;
+
/* Pipe source size (ie. panel fitter input size)
* All planes will be positioned inside this space,
* and get clipped at the edges. */
@@ -423,6 +436,8 @@ struct intel_crtc_state {
/* Used by SDVO (and if we ever fix it, HDMI). */
unsigned pixel_multiplier;
+ uint8_t lane_count;
+
/* Panel fitter controls for gen2-gen4 + VLV */
struct {
u32 control;
@@ -532,6 +547,8 @@ struct intel_crtc {
* gen4+ this only adjusts up to a tile, offsets within a tile are
* handled in the hw itself (with the TILEOFF register). */
unsigned long dspaddr_offset;
+ int adjusted_x;
+ int adjusted_y;
struct drm_i915_gem_object *cursor_bo;
uint32_t cursor_addr;
@@ -560,7 +577,13 @@ struct intel_crtc {
int scanline_offset;
- unsigned start_vbl_count;
+ struct {
+ unsigned start_vbl_count;
+ ktime_t start_vbl_time;
+ int min_vbl, max_vbl;
+ int scanline_start;
+ } debug;
+
struct intel_crtc_atomic_commit atomic;
/* scalers available on this crtc */
@@ -657,19 +680,20 @@ struct cxsr_latency {
struct intel_hdmi {
u32 hdmi_reg;
int ddc_bus;
- uint32_t color_range;
+ bool limited_color_range;
bool color_range_auto;
bool has_hdmi_sink;
bool has_audio;
enum hdmi_force_audio force_audio;
bool rgb_quant_range_selectable;
enum hdmi_picture_aspect aspect_ratio;
+ struct intel_connector *attached_connector;
void (*write_infoframe)(struct drm_encoder *encoder,
enum hdmi_infoframe_type type,
const void *frame, ssize_t len);
void (*set_infoframes)(struct drm_encoder *encoder,
bool enable,
- struct drm_display_mode *adjusted_mode);
+ const struct drm_display_mode *adjusted_mode);
bool (*infoframe_enabled)(struct drm_encoder *encoder);
};
@@ -696,23 +720,29 @@ enum link_m_n_set {
M2_N2
};
+struct sink_crc {
+ bool started;
+ u8 last_crc[6];
+ int last_count;
+};
+
struct intel_dp {
uint32_t output_reg;
uint32_t aux_ch_ctl_reg;
uint32_t DP;
+ int link_rate;
+ uint8_t lane_count;
bool has_audio;
enum hdmi_force_audio force_audio;
- uint32_t color_range;
+ bool limited_color_range;
bool color_range_auto;
- uint8_t link_bw;
- uint8_t rate_select;
- uint8_t lane_count;
uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
/* sink rates as reported by DP_SUPPORTED_LINK_RATES */
uint8_t num_sink_rates;
int sink_rates[DP_MAX_SUPPORTED_RATES];
+ struct sink_crc sink_crc;
struct drm_dp_aux aux;
uint8_t train_set[4];
int panel_power_up_delay;
@@ -735,7 +765,6 @@ struct intel_dp {
enum pipe pps_pipe;
struct edp_power_seq pps_delays;
- bool use_tps3;
bool can_mst; /* this port supports mst */
bool is_mst;
int active_mst_links;
@@ -770,6 +799,7 @@ struct intel_digital_port {
struct intel_dp dp;
struct intel_hdmi hdmi;
enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
+ bool release_cl2_override;
};
struct intel_dp_mst_encoder {
@@ -779,7 +809,7 @@ struct intel_dp_mst_encoder {
void *port; /* store this opaque as its illegal to dereference it */
};
-static inline int
+static inline enum dpio_channel
vlv_dport_to_channel(struct intel_digital_port *dport)
{
switch (dport->port) {
@@ -793,7 +823,21 @@ vlv_dport_to_channel(struct intel_digital_port *dport)
}
}
-static inline int
+static inline enum dpio_phy
+vlv_dport_to_phy(struct intel_digital_port *dport)
+{
+ switch (dport->port) {
+ case PORT_B:
+ case PORT_C:
+ return DPIO_PHY0;
+ case PORT_D:
+ return DPIO_PHY1;
+ default:
+ BUG();
+ }
+}
+
+static inline enum dpio_channel
vlv_pipe_to_channel(enum pipe pipe)
{
switch (pipe) {
@@ -834,8 +878,8 @@ struct intel_unpin_work {
u32 flip_count;
u32 gtt_offset;
struct drm_i915_gem_request *flip_queued_req;
- int flip_queued_vblank;
- int flip_ready_vblank;
+ u32 flip_queued_vblank;
+ u32 flip_ready_vblank;
bool enable_stall_check;
};
@@ -987,6 +1031,7 @@ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
extern const struct drm_plane_funcs intel_plane_funcs;
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);
@@ -995,8 +1040,6 @@ void intel_encoder_destroy(struct drm_encoder *encoder);
int intel_connector_init(struct intel_connector *);
struct intel_connector *intel_connector_alloc(void);
bool intel_connector_get_hw_state(struct intel_connector *connector);
-bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
- struct intel_digital_port *port);
void intel_connector_attach_encoder(struct intel_connector *connector,
struct intel_encoder *encoder);
struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
@@ -1038,10 +1081,8 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe);
void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
void intel_check_page_flip(struct drm_device *dev, int pipe);
int intel_prepare_plane_fb(struct drm_plane *plane,
- struct drm_framebuffer *fb,
const struct drm_plane_state *new_state);
void intel_cleanup_plane_fb(struct drm_plane *plane,
- struct drm_framebuffer *fb,
const struct drm_plane_state *old_state);
int intel_plane_atomic_get_property(struct drm_plane *plane,
const struct drm_plane_state *state,
@@ -1056,7 +1097,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
unsigned int
intel_tile_height(struct drm_device *dev, uint32_t pixel_format,
- uint64_t fb_format_modifier);
+ uint64_t fb_format_modifier, unsigned int plane);
static inline bool
intel_rotation_90_or_270(unsigned int rotation)
@@ -1137,7 +1178,9 @@ int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
- struct drm_i915_gem_object *obj);
+ struct drm_i915_gem_object *obj,
+ unsigned int plane);
+
u32 skl_plane_ctl_format(uint32_t pixel_format);
u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
u32 skl_plane_ctl_rotation(unsigned int rotation);
@@ -1155,8 +1198,9 @@ void assert_csr_loaded(struct drm_i915_private *dev_priv);
void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
+void intel_dp_set_link_params(struct intel_dp *intel_dp,
+ const struct intel_crtc_state *pipe_config);
void intel_dp_start_link_train(struct intel_dp *intel_dp);
-void intel_dp_complete_link_train(struct intel_dp *intel_dp);
void intel_dp_stop_link_train(struct intel_dp *intel_dp);
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
void intel_dp_encoder_destroy(struct drm_encoder *encoder);
@@ -1185,6 +1229,8 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp);
void intel_edp_drrs_invalidate(struct drm_device *dev,
unsigned frontbuffer_bits);
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);
/* intel_dp_mst.c */
@@ -1263,6 +1309,7 @@ int intel_connector_update_modes(struct drm_connector *connector,
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
void intel_attach_force_audio_property(struct drm_connector *connector);
void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
+void intel_attach_aspect_ratio_property(struct drm_connector *connector);
/* intel_overlay.c */
@@ -1295,7 +1342,6 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
void intel_panel_enable_backlight(struct intel_connector *connector);
void intel_panel_disable_backlight(struct intel_connector *connector);
void intel_panel_destroy_backlight(struct drm_connector *connector);
-void intel_panel_init_backlight_funcs(struct drm_device *dev);
enum drm_connector_status intel_panel_detect(struct drm_device *dev);
extern struct drm_display_mode *intel_find_panel_downclock(
struct drm_device *dev,
@@ -1339,6 +1385,12 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
void intel_display_set_init_power(struct drm_i915_private *dev, bool enable);
+void chv_phy_powergate_lanes(struct intel_encoder *encoder,
+ bool override, unsigned int mask);
+bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy,
+ enum dpio_channel ch, bool override);
+
+
/* intel_pm.c */
void intel_init_clock_gating(struct drm_device *dev);
void intel_suspend_hw(struct drm_device *dev);
@@ -1384,9 +1436,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob);
int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-void intel_pipe_update_start(struct intel_crtc *crtc,
- uint32_t *start_vbl_count);
-void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
+void intel_pipe_update_start(struct intel_crtc *crtc);
+void intel_pipe_update_end(struct intel_crtc *crtc);
/* intel_tv.c */
void intel_tv_init(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 32a6c7184ca4..170ae6f4866e 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -282,58 +282,46 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
return true;
}
-static void intel_dsi_port_enable(struct intel_encoder *encoder)
+static void bxt_dsi_device_ready(struct intel_encoder *encoder)
{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
- u32 temp;
+ u32 val;
- if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
- temp = I915_READ(VLV_CHICKEN_3);
- temp &= ~PIXEL_OVERLAP_CNT_MASK |
- intel_dsi->pixel_overlap <<
- PIXEL_OVERLAP_CNT_SHIFT;
- I915_WRITE(VLV_CHICKEN_3, temp);
- }
+ DRM_DEBUG_KMS("\n");
+ /* Exit Low power state in 4 steps*/
for_each_dsi_port(port, intel_dsi->ports) {
- temp = I915_READ(MIPI_PORT_CTRL(port));
- temp &= ~LANE_CONFIGURATION_MASK;
- temp &= ~DUAL_LINK_MODE_MASK;
- if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) {
- temp |= (intel_dsi->dual_link - 1)
- << DUAL_LINK_MODE_SHIFT;
- temp |= intel_crtc->pipe ?
- LANE_CONFIGURATION_DUAL_LINK_B :
- LANE_CONFIGURATION_DUAL_LINK_A;
- }
- /* assert ip_tg_enable signal */
- I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE);
- POSTING_READ(MIPI_PORT_CTRL(port));
- }
-}
+ /* 1. Enable MIPI PHY transparent latch */
+ val = I915_READ(BXT_MIPI_PORT_CTRL(port));
+ I915_WRITE(BXT_MIPI_PORT_CTRL(port), val | LP_OUTPUT_HOLD);
+ usleep_range(2000, 2500);
-static void intel_dsi_port_disable(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
- enum port port;
- u32 temp;
+ /* 2. Enter ULPS */
+ val = I915_READ(MIPI_DEVICE_READY(port));
+ val &= ~ULPS_STATE_MASK;
+ val |= (ULPS_STATE_ENTER | DEVICE_READY);
+ I915_WRITE(MIPI_DEVICE_READY(port), val);
+ usleep_range(2, 3);
+
+ /* 3. Exit ULPS */
+ val = I915_READ(MIPI_DEVICE_READY(port));
+ val &= ~ULPS_STATE_MASK;
+ val |= (ULPS_STATE_EXIT | DEVICE_READY);
+ I915_WRITE(MIPI_DEVICE_READY(port), val);
+ usleep_range(1000, 1500);
- for_each_dsi_port(port, intel_dsi->ports) {
- /* de-assert ip_tg_enable signal */
- temp = I915_READ(MIPI_PORT_CTRL(port));
- I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE);
- POSTING_READ(MIPI_PORT_CTRL(port));
+ /* Clear ULPS and set device ready */
+ val = I915_READ(MIPI_DEVICE_READY(port));
+ val &= ~ULPS_STATE_MASK;
+ val |= DEVICE_READY;
+ I915_WRITE(MIPI_DEVICE_READY(port), val);
}
}
-static void intel_dsi_device_ready(struct intel_encoder *encoder)
+static void vlv_dsi_device_ready(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
@@ -372,6 +360,75 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
}
}
+static void intel_dsi_device_ready(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+
+ if (IS_VALLEYVIEW(dev))
+ vlv_dsi_device_ready(encoder);
+ else if (IS_BROXTON(dev))
+ bxt_dsi_device_ready(encoder);
+}
+
+static void intel_dsi_port_enable(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
+ u32 temp;
+ u32 port_ctrl;
+
+ if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+ temp = I915_READ(VLV_CHICKEN_3);
+ temp &= ~PIXEL_OVERLAP_CNT_MASK |
+ intel_dsi->pixel_overlap <<
+ PIXEL_OVERLAP_CNT_SHIFT;
+ I915_WRITE(VLV_CHICKEN_3, temp);
+ }
+
+ for_each_dsi_port(port, intel_dsi->ports) {
+ port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
+ MIPI_PORT_CTRL(port);
+
+ temp = I915_READ(port_ctrl);
+
+ temp &= ~LANE_CONFIGURATION_MASK;
+ temp &= ~DUAL_LINK_MODE_MASK;
+
+ if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) {
+ temp |= (intel_dsi->dual_link - 1)
+ << DUAL_LINK_MODE_SHIFT;
+ temp |= intel_crtc->pipe ?
+ LANE_CONFIGURATION_DUAL_LINK_B :
+ LANE_CONFIGURATION_DUAL_LINK_A;
+ }
+ /* assert ip_tg_enable signal */
+ I915_WRITE(port_ctrl, temp | DPI_ENABLE);
+ POSTING_READ(port_ctrl);
+ }
+}
+
+static void intel_dsi_port_disable(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
+ u32 temp;
+ u32 port_ctrl;
+
+ for_each_dsi_port(port, intel_dsi->ports) {
+ /* de-assert ip_tg_enable signal */
+ port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
+ MIPI_PORT_CTRL(port);
+ temp = I915_READ(port_ctrl);
+ I915_WRITE(port_ctrl, temp & ~DPI_ENABLE);
+ POSTING_READ(port_ctrl);
+ }
+}
+
static void intel_dsi_enable(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
@@ -419,19 +476,24 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
msleep(intel_dsi->panel_on_delay);
- /* Disable DPOunit clock gating, can stall pipe
- * and we need DPLL REFA always enabled */
- tmp = I915_READ(DPLL(pipe));
- tmp |= DPLL_REF_CLK_ENABLE_VLV;
- I915_WRITE(DPLL(pipe), tmp);
-
- /* update the hw state for DPLL */
- intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
- DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
-
- tmp = I915_READ(DSPCLK_GATE_D);
- tmp |= DPOUNIT_CLOCK_GATE_DISABLE;
- I915_WRITE(DSPCLK_GATE_D, tmp);
+ if (IS_VALLEYVIEW(dev)) {
+ /*
+ * Disable DPOunit clock gating, can stall pipe
+ * and we need DPLL REFA always enabled
+ */
+ tmp = I915_READ(DPLL(pipe));
+ tmp |= DPLL_REF_CLK_ENABLE_VLV;
+ I915_WRITE(DPLL(pipe), tmp);
+
+ /* update the hw state for DPLL */
+ intel_crtc->config->dpll_hw_state.dpll =
+ DPLL_INTEGRATED_REF_CLK_VLV |
+ DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
+
+ tmp = I915_READ(DSPCLK_GATE_D);
+ tmp |= DPOUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(DSPCLK_GATE_D, tmp);
+ }
/* put device in ready state */
intel_dsi_device_ready(encoder);
@@ -495,12 +557,7 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
/* Panel commands can be sent when clock is in LP11 */
I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
- temp = I915_READ(MIPI_CTRL(port));
- temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
- I915_WRITE(MIPI_CTRL(port), temp |
- intel_dsi->escape_clk_div <<
- ESCAPE_CLOCK_DIVIDER_SHIFT);
-
+ intel_dsi_reset_clocks(encoder, port);
I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
@@ -519,10 +576,12 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
{
+ struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
enum port port;
u32 val;
+ u32 port_ctrl = 0;
DRM_DEBUG_KMS("\n");
for_each_dsi_port(port, intel_dsi->ports) {
@@ -539,25 +598,29 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
ULPS_STATE_ENTER);
usleep_range(2000, 2500);
+ if (IS_BROXTON(dev))
+ port_ctrl = BXT_MIPI_PORT_CTRL(port);
+ else if (IS_VALLEYVIEW(dev))
+ /* Common bit for both MIPI Port A & MIPI Port C */
+ port_ctrl = MIPI_PORT_CTRL(PORT_A);
+
/* Wait till Clock lanes are in LP-00 state for MIPI Port A
* only. MIPI Port C has no similar bit for checking
*/
- if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT)
- == 0x00000), 30))
+ if (wait_for(((I915_READ(port_ctrl) & AFE_LATCHOUT)
+ == 0x00000), 30))
DRM_ERROR("DSI LP not going Low\n");
- /* Disable MIPI PHY transparent latch
- * Common bit for both MIPI Port A & MIPI Port C
- */
- val = I915_READ(MIPI_PORT_CTRL(PORT_A));
- I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD);
+ /* Disable MIPI PHY transparent latch */
+ val = I915_READ(port_ctrl);
+ I915_WRITE(port_ctrl, val & ~LP_OUTPUT_HOLD);
usleep_range(1000, 1500);
I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
usleep_range(2000, 2500);
}
- vlv_disable_dsi_pll(encoder);
+ intel_disable_dsi_pll(encoder);
}
static void intel_dsi_post_disable(struct intel_encoder *encoder)
@@ -593,7 +656,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
struct drm_device *dev = encoder->base.dev;
enum intel_display_power_domain power_domain;
- u32 dpi_enabled, func;
+ u32 dpi_enabled, func, ctrl_reg;
enum port port;
DRM_DEBUG_KMS("\n");
@@ -605,8 +668,9 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
/* XXX: this only works for one DSI output */
for_each_dsi_port(port, intel_dsi->ports) {
func = I915_READ(MIPI_DSI_FUNC_PRG(port));
- dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) &
- DPI_ENABLE;
+ ctrl_reg = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) :
+ MIPI_PORT_CTRL(port);
+ dpi_enabled = I915_READ(ctrl_reg) & DPI_ENABLE;
/* Due to some hardware limitations on BYT, MIPI Port C DPI
* Enable bit does not get set. To check whether DSI Port C
@@ -631,7 +695,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
static void intel_dsi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
- u32 pclk;
+ u32 pclk = 0;
DRM_DEBUG_KMS("\n");
/*
@@ -640,7 +704,11 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
*/
pipe_config->dpll_hw_state.dpll_md = 0;
- pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp);
+ if (IS_BROXTON(encoder->base.dev))
+ pclk = bxt_get_dsi_pclk(encoder, pipe_config->pipe_bpp);
+ else if (IS_VALLEYVIEW(encoder->base.dev))
+ pclk = vlv_get_dsi_pclk(encoder, pipe_config->pipe_bpp);
+
if (!pclk)
return;
@@ -654,6 +722,7 @@ intel_dsi_mode_valid(struct drm_connector *connector,
{
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+ int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
DRM_DEBUG_KMS("\n");
@@ -667,6 +736,8 @@ intel_dsi_mode_valid(struct drm_connector *connector,
return MODE_PANEL;
if (mode->vdisplay > fixed_mode->vdisplay)
return MODE_PANEL;
+ if (fixed_mode->clock > max_dotclk)
+ return MODE_CLOCK_HIGH;
}
return MODE_OK;
@@ -695,7 +766,7 @@ static u16 txbyteclkhs(u16 pixels, int bpp, int lane_count,
}
static void set_dsi_timings(struct drm_encoder *encoder,
- const struct drm_display_mode *mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -707,10 +778,10 @@ static void set_dsi_timings(struct drm_encoder *encoder,
u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
- hactive = mode->hdisplay;
- hfp = mode->hsync_start - mode->hdisplay;
- hsync = mode->hsync_end - mode->hsync_start;
- hbp = mode->htotal - mode->hsync_end;
+ hactive = adjusted_mode->crtc_hdisplay;
+ hfp = adjusted_mode->crtc_hsync_start - adjusted_mode->crtc_hdisplay;
+ hsync = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+ hbp = adjusted_mode->crtc_htotal - adjusted_mode->crtc_hsync_end;
if (intel_dsi->dual_link) {
hactive /= 2;
@@ -721,9 +792,9 @@ static void set_dsi_timings(struct drm_encoder *encoder,
hbp /= 2;
}
- vfp = mode->vsync_start - mode->vdisplay;
- vsync = mode->vsync_end - mode->vsync_start;
- vbp = mode->vtotal - mode->vsync_end;
+ vfp = adjusted_mode->crtc_vsync_start - adjusted_mode->crtc_vdisplay;
+ vsync = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
+ vbp = adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vsync_end;
/* horizontal values are in terms of high speed byte clock */
hactive = txbyteclkhs(hactive, bpp, lane_count,
@@ -734,6 +805,21 @@ static void set_dsi_timings(struct drm_encoder *encoder,
hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
for_each_dsi_port(port, intel_dsi->ports) {
+ if (IS_BROXTON(dev)) {
+ /*
+ * Program hdisplay and vdisplay on MIPI transcoder.
+ * This is different from calculated hactive and
+ * vactive, as they are calculated per channel basis,
+ * whereas these values should be based on resolution.
+ */
+ I915_WRITE(BXT_MIPI_TRANS_HACTIVE(port),
+ adjusted_mode->crtc_hdisplay);
+ I915_WRITE(BXT_MIPI_TRANS_VACTIVE(port),
+ adjusted_mode->crtc_vdisplay);
+ I915_WRITE(BXT_MIPI_TRANS_VTOTAL(port),
+ adjusted_mode->crtc_vtotal);
+ }
+
I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
I915_WRITE(MIPI_HFP_COUNT(port), hfp);
@@ -756,8 +842,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
enum port port;
unsigned int bpp = intel_crtc->config->pipe_bpp;
u32 val, tmp;
@@ -765,7 +850,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
- mode_hdisplay = adjusted_mode->hdisplay;
+ mode_hdisplay = adjusted_mode->crtc_hdisplay;
if (intel_dsi->dual_link) {
mode_hdisplay /= 2;
@@ -774,16 +859,39 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
}
for_each_dsi_port(port, intel_dsi->ports) {
- /* escape clock divider, 20MHz, shared for A and C.
- * device ready must be off when doing this! txclkesc? */
- tmp = I915_READ(MIPI_CTRL(PORT_A));
- tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
- I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1);
-
- /* read request priority is per pipe */
- tmp = I915_READ(MIPI_CTRL(port));
- tmp &= ~READ_REQUEST_PRIORITY_MASK;
- I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH);
+ if (IS_VALLEYVIEW(dev)) {
+ /*
+ * escape clock divider, 20MHz, shared for A and C.
+ * device ready must be off when doing this! txclkesc?
+ */
+ tmp = I915_READ(MIPI_CTRL(PORT_A));
+ tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+ I915_WRITE(MIPI_CTRL(PORT_A), tmp |
+ ESCAPE_CLOCK_DIVIDER_1);
+
+ /* read request priority is per pipe */
+ tmp = I915_READ(MIPI_CTRL(port));
+ tmp &= ~READ_REQUEST_PRIORITY_MASK;
+ I915_WRITE(MIPI_CTRL(port), tmp |
+ READ_REQUEST_PRIORITY_HIGH);
+ } else if (IS_BROXTON(dev)) {
+ /*
+ * FIXME:
+ * BXT can connect any PIPE to any MIPI port.
+ * Select the pipe based on the MIPI port read from
+ * VBT for now. Pick PIPE A for MIPI port A and C
+ * for port C.
+ */
+ tmp = I915_READ(MIPI_CTRL(port));
+ tmp &= ~BXT_PIPE_SELECT_MASK;
+
+ if (port == PORT_A)
+ tmp |= BXT_PIPE_SELECT_A;
+ else if (port == PORT_C)
+ tmp |= BXT_PIPE_SELECT_C;
+
+ I915_WRITE(MIPI_CTRL(port), tmp);
+ }
/* XXX: why here, why like this? handling in irq handler?! */
I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
@@ -792,7 +900,7 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
I915_WRITE(MIPI_DPI_RESOLUTION(port),
- adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
+ adjusted_mode->crtc_vdisplay << VERTICAL_ADDRESS_SHIFT |
mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
}
@@ -838,15 +946,15 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
if (is_vid_mode(intel_dsi) &&
intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
- txbyteclkhs(adjusted_mode->htotal, bpp,
- intel_dsi->lane_count,
- intel_dsi->burst_mode_ratio) + 1);
+ txbyteclkhs(adjusted_mode->crtc_htotal, bpp,
+ intel_dsi->lane_count,
+ intel_dsi->burst_mode_ratio) + 1);
} else {
I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
- txbyteclkhs(adjusted_mode->vtotal *
- adjusted_mode->htotal,
- bpp, intel_dsi->lane_count,
- intel_dsi->burst_mode_ratio) + 1);
+ txbyteclkhs(adjusted_mode->crtc_vtotal *
+ adjusted_mode->crtc_htotal,
+ bpp, intel_dsi->lane_count,
+ intel_dsi->burst_mode_ratio) + 1);
}
I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
@@ -860,6 +968,17 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
I915_WRITE(MIPI_INIT_COUNT(port),
txclkesc(intel_dsi->escape_clk_div, 100));
+ if (IS_BROXTON(dev) && (!intel_dsi->dual_link)) {
+ /*
+ * BXT spec says write MIPI_INIT_COUNT for
+ * both the ports, even if only one is
+ * getting used. So write the other port
+ * if not in dual link mode.
+ */
+ I915_WRITE(MIPI_INIT_COUNT(port ==
+ PORT_A ? PORT_C : PORT_A),
+ intel_dsi->init_count);
+ }
/* recovery disables */
I915_WRITE(MIPI_EOT_DISABLE(port), tmp);
@@ -911,8 +1030,8 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
DRM_DEBUG_KMS("\n");
intel_dsi_prepare(encoder);
+ intel_enable_dsi_pll(encoder);
- vlv_enable_dsi_pll(encoder);
}
static enum drm_connector_status
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index 42a68593e32a..e6cb25239941 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -124,9 +124,12 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
return container_of(encoder, struct intel_dsi, base.base);
}
-extern void vlv_enable_dsi_pll(struct intel_encoder *encoder);
-extern void vlv_disable_dsi_pll(struct intel_encoder *encoder);
+extern void intel_enable_dsi_pll(struct intel_encoder *encoder);
+extern void intel_disable_dsi_pll(struct intel_encoder *encoder);
extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp);
+extern u32 bxt_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp);
+extern void intel_dsi_reset_clocks(struct intel_encoder *encoder,
+ enum port port);
struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id);
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index c6a8975b128f..cb3cf3986212 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -246,7 +246,7 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp.dsi_pll_ctrl);
}
-void vlv_enable_dsi_pll(struct intel_encoder *encoder)
+static void vlv_enable_dsi_pll(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
u32 tmp;
@@ -276,7 +276,7 @@ void vlv_enable_dsi_pll(struct intel_encoder *encoder)
DRM_DEBUG_KMS("DSI PLL locked\n");
}
-void vlv_disable_dsi_pll(struct intel_encoder *encoder)
+static void vlv_disable_dsi_pll(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
u32 tmp;
@@ -293,6 +293,26 @@ void vlv_disable_dsi_pll(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->sb_lock);
}
+static void bxt_disable_dsi_pll(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ u32 val;
+
+ DRM_DEBUG_KMS("\n");
+
+ val = I915_READ(BXT_DSI_PLL_ENABLE);
+ val &= ~BXT_DSI_PLL_DO_ENABLE;
+ I915_WRITE(BXT_DSI_PLL_ENABLE, val);
+
+ /*
+ * PLL lock should deassert within 200us.
+ * Wait up to 1ms before timing out.
+ */
+ if (wait_for((I915_READ(BXT_DSI_PLL_ENABLE)
+ & BXT_DSI_PLL_LOCKED) == 0, 1))
+ DRM_ERROR("Timeout waiting for PLL lock deassertion\n");
+}
+
static void assert_bpp_mismatch(int pixel_format, int pipe_bpp)
{
int bpp = dsi_pixel_format_bpp(pixel_format);
@@ -363,3 +383,222 @@ u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp)
return pclk;
}
+
+u32 bxt_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp)
+{
+ u32 pclk;
+ u32 dsi_clk;
+ u32 dsi_ratio;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+
+ /* Divide by zero */
+ if (!pipe_bpp) {
+ DRM_ERROR("Invalid BPP(0)\n");
+ return 0;
+ }
+
+ dsi_ratio = I915_READ(BXT_DSI_PLL_CTL) &
+ BXT_DSI_PLL_RATIO_MASK;
+
+ /* Invalid DSI ratio ? */
+ if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN ||
+ dsi_ratio > BXT_DSI_PLL_RATIO_MAX) {
+ DRM_ERROR("Invalid DSI pll ratio(%u) programmed\n", dsi_ratio);
+ return 0;
+ }
+
+ dsi_clk = (dsi_ratio * BXT_REF_CLOCK_KHZ) / 2;
+
+ /* pixel_format and pipe_bpp should agree */
+ assert_bpp_mismatch(intel_dsi->pixel_format, pipe_bpp);
+
+ pclk = DIV_ROUND_CLOSEST(dsi_clk * intel_dsi->lane_count, pipe_bpp);
+
+ DRM_DEBUG_DRIVER("Calculated pclk=%u\n", pclk);
+ return pclk;
+}
+
+static void vlv_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
+{
+ u32 temp;
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+ temp = I915_READ(MIPI_CTRL(port));
+ temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+ I915_WRITE(MIPI_CTRL(port), temp |
+ intel_dsi->escape_clk_div <<
+ ESCAPE_CLOCK_DIVIDER_SHIFT);
+}
+
+/* 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;
+
+ /* 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));
+
+ /* 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 escape clock must be as close to 20MHz possible, but should
+ * not exceed it. Hence select divide by 2
+ */
+ tmp |= BXT_MIPI_TX_ESCLK_8XDIV_BY2(port);
+
+ tmp |= BXT_MIPI_RX_ESCLK_8X_BY3(port);
+
+ I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
+}
+
+static bool bxt_configure_dsi_pll(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ u8 dsi_ratio;
+ u32 dsi_clk;
+ u32 val;
+
+ dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format,
+ intel_dsi->lane_count);
+
+ /*
+ * From clock diagram, to get PLL ratio divider, divide double of DSI
+ * link rate (i.e., 2*8x=16x frequency value) by ref clock. Make sure to
+ * round 'up' the result
+ */
+ dsi_ratio = DIV_ROUND_UP(dsi_clk * 2, BXT_REF_CLOCK_KHZ);
+ if (dsi_ratio < BXT_DSI_PLL_RATIO_MIN ||
+ dsi_ratio > BXT_DSI_PLL_RATIO_MAX) {
+ DRM_ERROR("Cant get a suitable ratio from DSI PLL ratios\n");
+ return false;
+ }
+
+ /*
+ * Program DSI ratio and Select MIPIC and MIPIA PLL output as 8x
+ * Spec says both have to be programmed, even if one is not getting
+ * used. Configure MIPI_CLOCK_CTL dividers in modeset
+ */
+ val = I915_READ(BXT_DSI_PLL_CTL);
+ val &= ~BXT_DSI_PLL_PVD_RATIO_MASK;
+ val &= ~BXT_DSI_FREQ_SEL_MASK;
+ val &= ~BXT_DSI_PLL_RATIO_MASK;
+ val |= (dsi_ratio | BXT_DSIA_16X_BY2 | BXT_DSIC_16X_BY2);
+
+ /* As per recommendation from hardware team,
+ * Prog PVD ratio =1 if dsi ratio <= 50
+ */
+ if (dsi_ratio <= 50) {
+ val &= ~BXT_DSI_PLL_PVD_RATIO_MASK;
+ val |= BXT_DSI_PLL_PVD_RATIO_1;
+ }
+
+ I915_WRITE(BXT_DSI_PLL_CTL, val);
+ POSTING_READ(BXT_DSI_PLL_CTL);
+
+ return true;
+}
+
+static void bxt_enable_dsi_pll(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
+ u32 val;
+
+ DRM_DEBUG_KMS("\n");
+
+ val = I915_READ(BXT_DSI_PLL_ENABLE);
+
+ if (val & BXT_DSI_PLL_DO_ENABLE) {
+ WARN(1, "DSI PLL already enabled. Disabling it.\n");
+ val &= ~BXT_DSI_PLL_DO_ENABLE;
+ I915_WRITE(BXT_DSI_PLL_ENABLE, val);
+ }
+
+ /* Configure PLL vales */
+ if (!bxt_configure_dsi_pll(encoder)) {
+ DRM_ERROR("Configure DSI PLL failed, abort PLL enable\n");
+ return;
+ }
+
+ /* Program TX, RX, Dphy clocks */
+ for_each_dsi_port(port, intel_dsi->ports)
+ bxt_dsi_program_clocks(encoder->base.dev, port);
+
+ /* Enable DSI PLL */
+ val = I915_READ(BXT_DSI_PLL_ENABLE);
+ val |= BXT_DSI_PLL_DO_ENABLE;
+ I915_WRITE(BXT_DSI_PLL_ENABLE, val);
+
+ /* Timeout and fail if PLL not locked */
+ if (wait_for(I915_READ(BXT_DSI_PLL_ENABLE) & BXT_DSI_PLL_LOCKED, 1)) {
+ DRM_ERROR("Timed out waiting for DSI PLL to lock\n");
+ return;
+ }
+
+ DRM_DEBUG_KMS("DSI PLL locked\n");
+}
+
+void intel_enable_dsi_pll(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+
+ if (IS_VALLEYVIEW(dev))
+ vlv_enable_dsi_pll(encoder);
+ else if (IS_BROXTON(dev))
+ bxt_enable_dsi_pll(encoder);
+}
+
+void intel_disable_dsi_pll(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+
+ if (IS_VALLEYVIEW(dev))
+ vlv_disable_dsi_pll(encoder);
+ else if (IS_BROXTON(dev))
+ bxt_disable_dsi_pll(encoder);
+}
+
+static void bxt_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
+{
+ u32 tmp;
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* 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));
+ I915_WRITE(BXT_MIPI_CLOCK_CTL, tmp);
+ I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
+}
+
+void intel_dsi_reset_clocks(struct intel_encoder *encoder, enum port port)
+{
+ struct drm_device *dev = encoder->base.dev;
+
+ if (IS_BROXTON(dev))
+ bxt_dsi_reset_clocks(encoder, port);
+ else if (IS_VALLEYVIEW(dev))
+ vlv_dsi_reset_clocks(encoder, port);
+}
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index dc532bb61d22..8492053e0ff0 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -97,7 +97,8 @@ struct intel_dvo {
struct intel_dvo_device dev;
- struct drm_display_mode *panel_fixed_mode;
+ struct intel_connector *attached_connector;
+
bool panel_wants_dither;
};
@@ -201,19 +202,28 @@ intel_dvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+ const struct drm_display_mode *fixed_mode =
+ to_intel_connector(connector)->panel.fixed_mode;
+ int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+ int target_clock = mode->clock;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
/* XXX: Validate clock range */
- if (intel_dvo->panel_fixed_mode) {
- if (mode->hdisplay > intel_dvo->panel_fixed_mode->hdisplay)
+ if (fixed_mode) {
+ if (mode->hdisplay > fixed_mode->hdisplay)
return MODE_PANEL;
- if (mode->vdisplay > intel_dvo->panel_fixed_mode->vdisplay)
+ if (mode->vdisplay > fixed_mode->vdisplay)
return MODE_PANEL;
+
+ target_clock = fixed_mode->clock;
}
+ if (target_clock > max_dotclk)
+ return MODE_CLOCK_HIGH;
+
return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
}
@@ -221,6 +231,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config)
{
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
+ const struct drm_display_mode *fixed_mode =
+ intel_dvo->attached_connector->panel.fixed_mode;
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
/* If we have timings from the BIOS for the panel, put them in
@@ -228,21 +240,8 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
* with the panel scaling set up to source from the H/VDisplay
* of the original mode.
*/
- if (intel_dvo->panel_fixed_mode != NULL) {
-#define C(x) adjusted_mode->x = intel_dvo->panel_fixed_mode->x
- C(hdisplay);
- C(hsync_start);
- C(hsync_end);
- C(htotal);
- C(vdisplay);
- C(vsync_start);
- C(vsync_end);
- C(vtotal);
- C(clock);
-#undef C
-
- drm_mode_set_crtcinfo(adjusted_mode, 0);
- }
+ if (fixed_mode)
+ intel_fixed_panel_mode(fixed_mode, adjusted_mode);
return true;
}
@@ -252,7 +251,7 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
int pipe = crtc->pipe;
u32 dvo_val;
@@ -286,11 +285,11 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder)
dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
/*I915_WRITE(DVOB_SRCDIM,
- (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
- (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
+ (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+ (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
I915_WRITE(dvo_srcdim_reg,
- (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
- (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
+ (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+ (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
/*I915_WRITE(DVOB, dvo_val);*/
I915_WRITE(dvo_reg, dvo_val);
}
@@ -311,8 +310,9 @@ intel_dvo_detect(struct drm_connector *connector, bool force)
static int intel_dvo_get_modes(struct drm_connector *connector)
{
- struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
+ const struct drm_display_mode *fixed_mode =
+ to_intel_connector(connector)->panel.fixed_mode;
/* We should probably have an i2c driver get_modes function for those
* devices which will have a fixed set of modes determined by the chip
@@ -324,9 +324,9 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
if (!list_empty(&connector->probed_modes))
return 1;
- if (intel_dvo->panel_fixed_mode != NULL) {
+ if (fixed_mode) {
struct drm_display_mode *mode;
- mode = drm_mode_duplicate(connector->dev, intel_dvo->panel_fixed_mode);
+ mode = drm_mode_duplicate(connector->dev, fixed_mode);
if (mode) {
drm_mode_probed_add(connector, mode);
return 1;
@@ -339,6 +339,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
static void intel_dvo_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
+ intel_panel_fini(&to_intel_connector(connector)->panel);
kfree(connector);
}
@@ -365,8 +366,6 @@ static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
if (intel_dvo->dev.dev_ops->destroy)
intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
- kfree(intel_dvo->panel_fixed_mode);
-
intel_encoder_destroy(encoder);
}
@@ -431,6 +430,8 @@ void intel_dvo_init(struct drm_device *dev)
return;
}
+ intel_dvo->attached_connector = intel_connector;
+
intel_encoder = &intel_dvo->base;
drm_encoder_init(dev, &intel_encoder->base,
&intel_dvo_enc_funcs, encoder_type);
@@ -535,8 +536,9 @@ void intel_dvo_init(struct drm_device *dev)
* headers, likely), so for now, just get the current
* mode being output through DVO.
*/
- intel_dvo->panel_fixed_mode =
- intel_dvo_get_current_mode(connector);
+ intel_panel_init(&intel_connector->panel,
+ intel_dvo_get_current_mode(connector),
+ NULL);
intel_dvo->panel_wants_dither = true;
}
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index 1f97fb548c2a..cf47352b7b8e 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -41,6 +41,24 @@
#include "intel_drv.h"
#include "i915_drv.h"
+static inline bool fbc_supported(struct drm_i915_private *dev_priv)
+{
+ return dev_priv->fbc.enable_fbc != NULL;
+}
+
+/*
+ * In some platforms where the CRTC's x:0/y:0 coordinates doesn't match the
+ * frontbuffer's x:0/y:0 coordinates we lie to the hardware about the plane's
+ * origin so the x and y offsets can actually fit the registers. As a
+ * consequence, the fence doesn't really start exactly at the display plane
+ * address we program because it starts at the real start of the buffer, so we
+ * have to take this into consideration here.
+ */
+static unsigned int get_crtc_fence_y_offset(struct intel_crtc *crtc)
+{
+ return crtc->base.y - crtc->adjusted_y;
+}
+
static void i8xx_fbc_disable(struct drm_i915_private *dev_priv)
{
u32 fbc_ctl;
@@ -88,7 +106,7 @@ static void i8xx_fbc_enable(struct intel_crtc *crtc)
/* Clear old tags */
for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
- I915_WRITE(FBC_TAG + (i * 4), 0);
+ I915_WRITE(FBC_TAG(i), 0);
if (IS_GEN4(dev_priv)) {
u32 fbc_ctl2;
@@ -97,7 +115,7 @@ static void i8xx_fbc_enable(struct intel_crtc *crtc)
fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
fbc_ctl2 |= FBC_CTL_PLANE(crtc->plane);
I915_WRITE(FBC_CONTROL2, fbc_ctl2);
- I915_WRITE(FBC_FENCE_OFF, crtc->base.y);
+ I915_WRITE(FBC_FENCE_OFF, get_crtc_fence_y_offset(crtc));
}
/* enable it... */
@@ -135,7 +153,7 @@ static void g4x_fbc_enable(struct intel_crtc *crtc)
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
- I915_WRITE(DPFC_FENCE_YOFF, crtc->base.y);
+ I915_WRITE(DPFC_FENCE_YOFF, get_crtc_fence_y_offset(crtc));
/* enable it... */
I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
@@ -177,6 +195,7 @@ static void ilk_fbc_enable(struct intel_crtc *crtc)
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
u32 dpfc_ctl;
int threshold = dev_priv->fbc.threshold;
+ unsigned int y_offset;
dev_priv->fbc.enabled = true;
@@ -200,7 +219,8 @@ static void ilk_fbc_enable(struct intel_crtc *crtc)
if (IS_GEN5(dev_priv))
dpfc_ctl |= obj->fence_reg;
- I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->base.y);
+ y_offset = get_crtc_fence_y_offset(crtc);
+ I915_WRITE(ILK_DPFC_FENCE_YOFF, y_offset);
I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
/* enable it... */
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
@@ -208,7 +228,7 @@ static void ilk_fbc_enable(struct intel_crtc *crtc)
if (IS_GEN6(dev_priv)) {
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
- I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->base.y);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, y_offset);
}
intel_fbc_nuke(dev_priv);
@@ -272,23 +292,23 @@ static void gen7_fbc_enable(struct intel_crtc *crtc)
if (dev_priv->fbc.false_color)
dpfc_ctl |= FBC_CTL_FALSE_COLOR;
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
if (IS_IVYBRIDGE(dev_priv)) {
/* WaFbcAsynchFlipDisableFbcQueue:ivb */
I915_WRITE(ILK_DISPLAY_CHICKEN1,
I915_READ(ILK_DISPLAY_CHICKEN1) |
ILK_FBCQ_DIS);
- } else {
+ } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
I915_WRITE(CHICKEN_PIPESL_1(crtc->pipe),
I915_READ(CHICKEN_PIPESL_1(crtc->pipe)) |
HSW_FBCQ_DIS);
}
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
I915_WRITE(SNB_DPFC_CTL_SA,
SNB_CPU_FENCE_ENABLE | obj->fence_reg);
- I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->base.y);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, get_crtc_fence_y_offset(crtc));
intel_fbc_nuke(dev_priv);
@@ -308,6 +328,18 @@ bool intel_fbc_enabled(struct drm_i915_private *dev_priv)
return dev_priv->fbc.enabled;
}
+static void intel_fbc_enable(struct intel_crtc *crtc,
+ const struct drm_framebuffer *fb)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ dev_priv->fbc.enable_fbc(crtc);
+
+ dev_priv->fbc.crtc = crtc;
+ dev_priv->fbc.fb_id = fb->base.id;
+ dev_priv->fbc.y = crtc->base.y;
+}
+
static void intel_fbc_work_fn(struct work_struct *__work)
{
struct intel_fbc_work *work =
@@ -321,13 +353,8 @@ static void intel_fbc_work_fn(struct work_struct *__work)
/* Double check that we haven't switched fb without cancelling
* the prior work.
*/
- if (crtc_fb == work->fb) {
- dev_priv->fbc.enable_fbc(work->crtc);
-
- dev_priv->fbc.crtc = work->crtc;
- dev_priv->fbc.fb_id = crtc_fb->base.id;
- dev_priv->fbc.y = work->crtc->base.y;
- }
+ if (crtc_fb == work->fb)
+ intel_fbc_enable(work->crtc, work->fb);
dev_priv->fbc.fbc_work = NULL;
}
@@ -361,7 +388,7 @@ static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv)
dev_priv->fbc.fbc_work = NULL;
}
-static void intel_fbc_enable(struct intel_crtc *crtc)
+static void intel_fbc_schedule_enable(struct intel_crtc *crtc)
{
struct intel_fbc_work *work;
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
@@ -373,7 +400,7 @@ static void intel_fbc_enable(struct intel_crtc *crtc)
work = kzalloc(sizeof(*work), GFP_KERNEL);
if (work == NULL) {
DRM_ERROR("Failed to allocate FBC work structure\n");
- dev_priv->fbc.enable_fbc(crtc);
+ intel_fbc_enable(crtc, crtc->base.primary->fb);
return;
}
@@ -417,7 +444,7 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
*/
void intel_fbc_disable(struct drm_i915_private *dev_priv)
{
- if (!dev_priv->fbc.enable_fbc)
+ if (!fbc_supported(dev_priv))
return;
mutex_lock(&dev_priv->fbc.lock);
@@ -435,7 +462,7 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- if (!dev_priv->fbc.enable_fbc)
+ if (!fbc_supported(dev_priv))
return;
mutex_lock(&dev_priv->fbc.lock);
@@ -473,6 +500,12 @@ const char *intel_no_fbc_reason_str(enum no_fbc_reason reason)
return "rotation unsupported";
case FBC_IN_DBG_MASTER:
return "Kernel debugger is active";
+ case FBC_BAD_STRIDE:
+ return "framebuffer stride not supported";
+ case FBC_PIXEL_RATE:
+ return "pixel rate is too big";
+ case FBC_PIXEL_FORMAT:
+ return "pixel format is invalid";
default:
MISSING_CASE(reason);
return "unknown reason";
@@ -542,6 +575,16 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv,
{
int compression_threshold = 1;
int ret;
+ u64 end;
+
+ /* The FBC hardware for BDW/SKL doesn't have access to the stolen
+ * reserved range size, so it always assumes the maximum (8mb) is used.
+ * If we enable FBC using a CFB on that memory range we'll get FIFO
+ * underruns, even if that range is not reserved by the BIOS. */
+ if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv))
+ end = dev_priv->gtt.stolen_size - 8 * 1024 * 1024;
+ else
+ end = dev_priv->gtt.stolen_usable_size;
/* HACK: This code depends on what we will do in *_enable_fbc. If that
* code changes, this code needs to change as well.
@@ -551,7 +594,8 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv,
*/
/* Try to over-allocate to reduce reallocations and fragmentation. */
- ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096);
+ ret = i915_gem_stolen_insert_node_in_range(dev_priv, node, size <<= 1,
+ 4096, 0, end);
if (ret == 0)
return compression_threshold;
@@ -561,7 +605,8 @@ again:
(fb_cpp == 2 && compression_threshold == 2))
return 0;
- ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096);
+ ret = i915_gem_stolen_insert_node_in_range(dev_priv, node, size >>= 1,
+ 4096, 0, end);
if (ret && INTEL_INFO(dev_priv)->gen <= 4) {
return 0;
} else if (ret) {
@@ -613,8 +658,9 @@ static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, int size,
dev_priv->fbc.uncompressed_size = size;
- DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n",
- size);
+ DRM_DEBUG_KMS("reserved %llu bytes of contiguous stolen space for FBC, threshold: %d\n",
+ dev_priv->fbc.compressed_fb.size,
+ dev_priv->fbc.threshold);
return 0;
@@ -644,7 +690,7 @@ static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
{
- if (!dev_priv->fbc.enable_fbc)
+ if (!fbc_supported(dev_priv))
return;
mutex_lock(&dev_priv->fbc.lock);
@@ -652,16 +698,134 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
mutex_unlock(&dev_priv->fbc.lock);
}
-static int intel_fbc_setup_cfb(struct drm_i915_private *dev_priv, int size,
- int fb_cpp)
+/*
+ * For SKL+, the plane source size used by the hardware is based on the value we
+ * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value
+ * we wrote to PIPESRC.
+ */
+static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc,
+ int *width, int *height)
{
+ struct intel_plane_state *plane_state =
+ to_intel_plane_state(crtc->base.primary->state);
+ int w, h;
+
+ if (intel_rotation_90_or_270(plane_state->base.rotation)) {
+ w = drm_rect_height(&plane_state->src) >> 16;
+ h = drm_rect_width(&plane_state->src) >> 16;
+ } else {
+ w = drm_rect_width(&plane_state->src) >> 16;
+ h = drm_rect_height(&plane_state->src) >> 16;
+ }
+
+ if (width)
+ *width = w;
+ if (height)
+ *height = h;
+}
+
+static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct drm_framebuffer *fb = crtc->base.primary->fb;
+ int lines;
+
+ intel_fbc_get_plane_source_size(crtc, NULL, &lines);
+ if (INTEL_INFO(dev_priv)->gen >= 7)
+ lines = min(lines, 2048);
+
+ return lines * fb->pitches[0];
+}
+
+static int intel_fbc_setup_cfb(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct drm_framebuffer *fb = crtc->base.primary->fb;
+ int size, cpp;
+
+ size = intel_fbc_calculate_cfb_size(crtc);
+ cpp = drm_format_plane_cpp(fb->pixel_format, 0);
+
if (size <= dev_priv->fbc.uncompressed_size)
return 0;
/* Release any current block */
__intel_fbc_cleanup_cfb(dev_priv);
- return intel_fbc_alloc_cfb(dev_priv, size, fb_cpp);
+ return intel_fbc_alloc_cfb(dev_priv, size, cpp);
+}
+
+static bool stride_is_valid(struct drm_i915_private *dev_priv,
+ unsigned int stride)
+{
+ /* These should have been caught earlier. */
+ WARN_ON(stride < 512);
+ WARN_ON((stride & (64 - 1)) != 0);
+
+ /* Below are the additional FBC restrictions. */
+
+ if (IS_GEN2(dev_priv) || IS_GEN3(dev_priv))
+ return stride == 4096 || stride == 8192;
+
+ if (IS_GEN4(dev_priv) && !IS_G4X(dev_priv) && stride < 2048)
+ return false;
+
+ if (stride > 16384)
+ return false;
+
+ return true;
+}
+
+static bool pixel_format_is_valid(struct drm_framebuffer *fb)
+{
+ struct drm_device *dev = fb->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ return true;
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_RGB565:
+ /* 16bpp not supported on gen2 */
+ if (IS_GEN2(dev))
+ return false;
+ /* WaFbcOnly1to1Ratio:ctg */
+ if (IS_G4X(dev_priv))
+ return false;
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * For some reason, the hardware tracking starts looking at whatever we
+ * programmed as the display plane base address register. It does not look at
+ * the X and Y offset registers. That's why we look at the crtc->adjusted{x,y}
+ * variables instead of just looking at the pipe/plane size.
+ */
+static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ unsigned int effective_w, effective_h, max_w, max_h;
+
+ if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) {
+ max_w = 4096;
+ max_h = 4096;
+ } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
+ max_w = 4096;
+ max_h = 2048;
+ } else {
+ max_w = 2048;
+ max_h = 1536;
+ }
+
+ intel_fbc_get_plane_source_size(crtc, &effective_w, &effective_h);
+ effective_w += crtc->adjusted_x;
+ effective_h += crtc->adjusted_y;
+
+ return effective_w <= max_w && effective_h <= max_h;
}
/**
@@ -690,7 +854,6 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
const struct drm_display_mode *adjusted_mode;
- unsigned int max_width, max_height;
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));
@@ -739,21 +902,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
goto out_disable;
}
- if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) {
- max_width = 4096;
- max_height = 4096;
- } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) {
- max_width = 4096;
- max_height = 2048;
- } else {
- max_width = 2048;
- max_height = 1536;
- }
- if (intel_crtc->config->pipe_src_w > max_width ||
- intel_crtc->config->pipe_src_h > max_height) {
+ if (!intel_fbc_hw_tracking_covers_screen(intel_crtc)) {
set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE);
goto out_disable;
}
+
if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) &&
intel_crtc->plane != PLANE_A) {
set_no_fbc_reason(dev_priv, FBC_BAD_PLANE);
@@ -774,14 +927,31 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
goto out_disable;
}
+ if (!stride_is_valid(dev_priv, fb->pitches[0])) {
+ set_no_fbc_reason(dev_priv, FBC_BAD_STRIDE);
+ goto out_disable;
+ }
+
+ if (!pixel_format_is_valid(fb)) {
+ set_no_fbc_reason(dev_priv, FBC_PIXEL_FORMAT);
+ goto out_disable;
+ }
+
/* If the kernel debugger is active, always disable compression */
if (in_dbg_master()) {
set_no_fbc_reason(dev_priv, FBC_IN_DBG_MASTER);
goto out_disable;
}
- if (intel_fbc_setup_cfb(dev_priv, obj->base.size,
- drm_format_plane_cpp(fb->pixel_format, 0))) {
+ /* WaFbcExceedCdClockThreshold:hsw,bdw */
+ if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) &&
+ ilk_pipe_pixel_rate(intel_crtc->config) >=
+ dev_priv->cdclk_freq * 95 / 100) {
+ set_no_fbc_reason(dev_priv, FBC_PIXEL_RATE);
+ goto out_disable;
+ }
+
+ if (intel_fbc_setup_cfb(intel_crtc)) {
set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL);
goto out_disable;
}
@@ -824,7 +994,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
__intel_fbc_disable(dev_priv);
}
- intel_fbc_enable(intel_crtc);
+ intel_fbc_schedule_enable(intel_crtc);
dev_priv->fbc.no_fbc_reason = FBC_OK;
return;
@@ -845,7 +1015,7 @@ out_disable:
*/
void intel_fbc_update(struct drm_i915_private *dev_priv)
{
- if (!dev_priv->fbc.enable_fbc)
+ if (!fbc_supported(dev_priv))
return;
mutex_lock(&dev_priv->fbc.lock);
@@ -859,7 +1029,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
{
unsigned int fbc_bits;
- if (!dev_priv->fbc.enable_fbc)
+ if (!fbc_supported(dev_priv))
return;
if (origin == ORIGIN_GTT)
@@ -886,7 +1056,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
void intel_fbc_flush(struct drm_i915_private *dev_priv,
unsigned int frontbuffer_bits, enum fb_op_origin origin)
{
- if (!dev_priv->fbc.enable_fbc)
+ if (!fbc_supported(dev_priv))
return;
if (origin == ORIGIN_GTT)
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 8c6a6fa46005..4fd5fdfef6bd 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -121,8 +121,9 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
container_of(helper, struct intel_fbdev, helper);
struct drm_framebuffer *fb;
struct drm_device *dev = helper->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_mode_fb_cmd2 mode_cmd = {};
- struct drm_i915_gem_object *obj;
+ struct drm_i915_gem_object *obj = NULL;
int size, ret;
/* we don't do packed 24bpp */
@@ -139,7 +140,12 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
size = mode_cmd.pitches[0] * mode_cmd.height;
size = PAGE_ALIGN(size);
- obj = i915_gem_object_create_stolen(dev, size);
+
+ /* If the FB is too big, just don't use it since fbdev is not very
+ * important and we should probably use that space with FBC or other
+ * features. */
+ if (size * 2 < dev_priv->gtt.stolen_usable_size)
+ obj = i915_gem_object_create_stolen(dev, size);
if (obj == NULL)
obj = i915_gem_alloc_object(dev, size);
if (!obj) {
@@ -263,7 +269,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
- DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08lx, bo %p\n",
+ DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08llx, bo %p\n",
fb->width, fb->height,
i915_gem_obj_ggtt_offset(obj), obj);
@@ -541,16 +547,13 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
struct intel_crtc *intel_crtc;
unsigned int max_size = 0;
- if (!i915.fastboot)
- return false;
-
/* Find the largest fb */
for_each_crtc(dev, crtc) {
struct drm_i915_gem_object *obj =
intel_fb_obj(crtc->primary->state->fb);
intel_crtc = to_intel_crtc(crtc);
- if (!intel_crtc->active || !obj) {
+ if (!crtc->state->active || !obj) {
DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
pipe_name(intel_crtc->pipe));
continue;
@@ -575,7 +578,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
intel_crtc = to_intel_crtc(crtc);
- if (!intel_crtc->active) {
+ if (!crtc->state->active) {
DRM_DEBUG_KMS("pipe %c not active, skipping\n",
pipe_name(intel_crtc->pipe));
continue;
@@ -638,7 +641,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
for_each_crtc(dev, crtc) {
intel_crtc = to_intel_crtc(crtc);
- if (!intel_crtc->active)
+ if (!crtc->state->active)
continue;
WARN(!crtc->primary->fb,
@@ -689,6 +692,8 @@ int intel_fbdev_init(struct drm_device *dev)
return ret;
}
+ ifbdev->helper.atomic = true;
+
dev_priv->fbdev = ifbdev;
INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
new file mode 100644
index 000000000000..081d5f648d26
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright © 2014 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_GUC_H_
+#define _INTEL_GUC_H_
+
+#include "intel_guc_fwif.h"
+#include "i915_guc_reg.h"
+
+struct i915_guc_client {
+ struct drm_i915_gem_object *client_obj;
+ struct intel_context *owner;
+ struct intel_guc *guc;
+ uint32_t priority;
+ uint32_t ctx_index;
+
+ uint32_t proc_desc_offset;
+ uint32_t doorbell_offset;
+ uint32_t cookie;
+ uint16_t doorbell_id;
+ uint16_t padding; /* Maintain alignment */
+
+ uint32_t wq_offset;
+ uint32_t wq_size;
+
+ spinlock_t wq_lock; /* Protects all data below */
+ uint32_t wq_tail;
+
+ /* GuC submission statistics & status */
+ uint64_t submissions[I915_NUM_RINGS];
+ uint32_t q_fail;
+ uint32_t b_fail;
+ int retcode;
+};
+
+enum intel_guc_fw_status {
+ GUC_FIRMWARE_FAIL = -1,
+ GUC_FIRMWARE_NONE = 0,
+ GUC_FIRMWARE_PENDING,
+ GUC_FIRMWARE_SUCCESS
+};
+
+/*
+ * This structure encapsulates all the data needed during the process
+ * of fetching, caching, and loading the firmware image into the GuC.
+ */
+struct intel_guc_fw {
+ struct drm_device * guc_dev;
+ const char * guc_fw_path;
+ size_t guc_fw_size;
+ struct drm_i915_gem_object * guc_fw_obj;
+ enum intel_guc_fw_status guc_fw_fetch_status;
+ enum intel_guc_fw_status guc_fw_load_status;
+
+ uint16_t guc_fw_major_wanted;
+ uint16_t guc_fw_minor_wanted;
+ uint16_t guc_fw_major_found;
+ uint16_t guc_fw_minor_found;
+};
+
+struct intel_guc {
+ struct intel_guc_fw guc_fw;
+
+ uint32_t log_flags;
+ struct drm_i915_gem_object *log_obj;
+
+ struct drm_i915_gem_object *ctx_pool_obj;
+ struct ida ctx_ids;
+
+ struct i915_guc_client *execbuf_client;
+
+ spinlock_t host2guc_lock; /* Protects all data below */
+
+ DECLARE_BITMAP(doorbell_bitmap, GUC_MAX_DOORBELLS);
+ uint32_t db_cacheline; /* Cyclic counter mod pagesize */
+
+ /* Action status & statistics */
+ uint64_t action_count; /* Total commands issued */
+ uint32_t action_cmd; /* Last command word */
+ uint32_t action_status; /* Last return status */
+ uint32_t action_fail; /* Total number of failures */
+ int32_t action_err; /* Last error code */
+
+ uint64_t submissions[I915_NUM_RINGS];
+ uint32_t last_seqno[I915_NUM_RINGS];
+};
+
+/* intel_guc_loader.c */
+extern void intel_guc_ucode_init(struct drm_device *dev);
+extern int intel_guc_ucode_load(struct drm_device *dev);
+extern void intel_guc_ucode_fini(struct drm_device *dev);
+extern const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status);
+extern int intel_guc_suspend(struct drm_device *dev);
+extern int intel_guc_resume(struct drm_device *dev);
+
+/* i915_guc_submission.c */
+int i915_guc_submission_init(struct drm_device *dev);
+int i915_guc_submission_enable(struct drm_device *dev);
+int i915_guc_submit(struct i915_guc_client *client,
+ struct drm_i915_gem_request *rq);
+void i915_guc_submission_disable(struct drm_device *dev);
+void i915_guc_submission_fini(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 18d7f20936c8..593d2f585978 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -32,17 +32,16 @@
* EDITING THIS FILE IS THEREFORE NOT RECOMMENDED - YOUR CHANGES MAY BE LOST.
*/
-#define GFXCORE_FAMILY_GEN8 11
#define GFXCORE_FAMILY_GEN9 12
-#define GFXCORE_FAMILY_FORCE_ULONG 0x7fffffff
+#define GFXCORE_FAMILY_UNKNOWN 0x7fffffff
-#define GUC_CTX_PRIORITY_CRITICAL 0
+#define GUC_CTX_PRIORITY_KMD_HIGH 0
#define GUC_CTX_PRIORITY_HIGH 1
-#define GUC_CTX_PRIORITY_NORMAL 2
-#define GUC_CTX_PRIORITY_LOW 3
+#define GUC_CTX_PRIORITY_KMD_NORMAL 2
+#define GUC_CTX_PRIORITY_NORMAL 3
#define GUC_MAX_GPU_CONTEXTS 1024
-#define GUC_INVALID_CTX_ID (GUC_MAX_GPU_CONTEXTS + 1)
+#define GUC_INVALID_CTX_ID GUC_MAX_GPU_CONTEXTS
/* Work queue item header definitions */
#define WQ_STATUS_ACTIVE 1
@@ -76,6 +75,7 @@
#define GUC_CTX_DESC_ATTR_RESET (1 << 4)
#define GUC_CTX_DESC_ATTR_WQLOCKED (1 << 5)
#define GUC_CTX_DESC_ATTR_PCH (1 << 6)
+#define GUC_CTX_DESC_ATTR_TERMINATED (1 << 7)
/* The guc control data is 10 DWORDs */
#define GUC_CTL_CTXINFO 0
@@ -108,6 +108,7 @@
#define GUC_CTL_DISABLE_SCHEDULER (1 << 4)
#define GUC_CTL_PREEMPTION_LOG (1 << 5)
#define GUC_CTL_ENABLE_SLPC (1 << 7)
+#define GUC_CTL_RESET_ON_PREMPT_FAILURE (1 << 8)
#define GUC_CTL_DEBUG 8
#define GUC_LOG_VERBOSITY_SHIFT 0
#define GUC_LOG_VERBOSITY_LOW (0 << GUC_LOG_VERBOSITY_SHIFT)
@@ -117,8 +118,9 @@
/* Verbosity range-check limits, without the shift */
#define GUC_LOG_VERBOSITY_MIN 0
#define GUC_LOG_VERBOSITY_MAX 3
+#define GUC_CTL_RSRVD 9
-#define GUC_CTL_MAX_DWORDS (GUC_CTL_DEBUG + 1)
+#define GUC_CTL_MAX_DWORDS (GUC_CTL_RSRVD + 1)
struct guc_doorbell_info {
u32 db_status;
@@ -208,18 +210,31 @@ struct guc_context_desc {
u32 engine_presence;
- u32 reserved0[1];
+ u8 engine_suspended;
+
+ u8 reserved0[3];
u64 reserved1[1];
u64 desc_private;
} __packed;
+#define GUC_FORCEWAKE_RENDER (1 << 0)
+#define GUC_FORCEWAKE_MEDIA (1 << 1)
+
+#define GUC_POWER_UNSPECIFIED 0
+#define GUC_POWER_D0 1
+#define GUC_POWER_D1 2
+#define GUC_POWER_D2 3
+#define GUC_POWER_D3 4
+
/* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */
enum host2guc_action {
HOST2GUC_ACTION_DEFAULT = 0x0,
HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6,
HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
+ HOST2GUC_ACTION_ENTER_S_STATE = 0x501,
+ HOST2GUC_ACTION_EXIT_S_STATE = 0x502,
HOST2GUC_ACTION_SLPC_REQUEST = 0x3003,
HOST2GUC_ACTION_LIMIT
};
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
new file mode 100644
index 000000000000..3541f76c65a7
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Vinit Azad <vinit.azad@intel.com>
+ * Ben Widawsky <ben@bwidawsk.net>
+ * Dave Gordon <david.s.gordon@intel.com>
+ * Alex Dai <yu.dai@intel.com>
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+/**
+ * DOC: GuC
+ *
+ * intel_guc:
+ * Top level structure of guc. It handles firmware loading and manages client
+ * pool and doorbells. intel_guc owns a i915_guc_client to replace the legacy
+ * ExecList submission.
+ *
+ * Firmware versioning:
+ * The firmware build process will generate a version header file with major and
+ * minor version defined. The versions are built into CSS header of firmware.
+ * i915 kernel driver set the minimal firmware version required per platform.
+ * The firmware installation package will install (symbolic link) proper version
+ * of firmware.
+ *
+ * GuC address space:
+ * GuC does not allow any gfx GGTT address that falls into range [0, WOPCM_TOP),
+ * which is reserved for Boot ROM, SRAM and WOPCM. Currently this top address is
+ * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects
+ * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM.
+ *
+ * Firmware log:
+ * Firmware log is enabled by setting i915.guc_log_level to non-negative level.
+ * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from
+ * i915_guc_load_status will print out firmware loading status and scratch
+ * registers value.
+ *
+ */
+
+#define I915_SKL_GUC_UCODE "i915/skl_guc_ver4.bin"
+MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
+
+/* User-friendly representation of an enum */
+const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status)
+{
+ switch (status) {
+ case GUC_FIRMWARE_FAIL:
+ return "FAIL";
+ case GUC_FIRMWARE_NONE:
+ return "NONE";
+ case GUC_FIRMWARE_PENDING:
+ return "PENDING";
+ case GUC_FIRMWARE_SUCCESS:
+ return "SUCCESS";
+ default:
+ return "UNKNOWN!";
+ }
+};
+
+static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
+{
+ struct intel_engine_cs *ring;
+ int i, irqs;
+
+ /* tell all command streamers NOT to forward interrupts and vblank to GuC */
+ irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
+ irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
+ for_each_ring(ring, dev_priv, i)
+ I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+ /* route all GT interrupts to the host */
+ I915_WRITE(GUC_BCS_RCS_IER, 0);
+ I915_WRITE(GUC_VCS2_VCS1_IER, 0);
+ I915_WRITE(GUC_WD_VECS_IER, 0);
+}
+
+static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
+{
+ struct intel_engine_cs *ring;
+ int i, irqs;
+
+ /* tell all command streamers to forward interrupts and vblank to GuC */
+ irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_ALWAYS);
+ irqs |= _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
+ for_each_ring(ring, dev_priv, i)
+ I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+ /* route USER_INTERRUPT to Host, all others are sent to GuC. */
+ irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+ GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+ /* These three registers have the same bit definitions */
+ I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
+ I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
+ I915_WRITE(GUC_WD_VECS_IER, ~irqs);
+}
+
+static u32 get_gttype(struct drm_i915_private *dev_priv)
+{
+ /* XXX: GT type based on PCI device ID? field seems unused by fw */
+ return 0;
+}
+
+static u32 get_core_family(struct drm_i915_private *dev_priv)
+{
+ switch (INTEL_INFO(dev_priv)->gen) {
+ case 9:
+ return GFXCORE_FAMILY_GEN9;
+
+ default:
+ DRM_ERROR("GUC: unsupported core family\n");
+ return GFXCORE_FAMILY_UNKNOWN;
+ }
+}
+
+static void set_guc_init_params(struct drm_i915_private *dev_priv)
+{
+ struct intel_guc *guc = &dev_priv->guc;
+ u32 params[GUC_CTL_MAX_DWORDS];
+ int i;
+
+ memset(&params, 0, sizeof(params));
+
+ params[GUC_CTL_DEVICE_INFO] |=
+ (get_gttype(dev_priv) << GUC_CTL_GTTYPE_SHIFT) |
+ (get_core_family(dev_priv) << GUC_CTL_COREFAMILY_SHIFT);
+
+ /*
+ * GuC ARAT increment is 10 ns. GuC default scheduler quantum is one
+ * second. This ARAR is calculated by:
+ * Scheduler-Quantum-in-ns / ARAT-increment-in-ns = 1000000000 / 10
+ */
+ params[GUC_CTL_ARAT_HIGH] = 0;
+ params[GUC_CTL_ARAT_LOW] = 100000000;
+
+ params[GUC_CTL_WA] |= GUC_CTL_WA_UK_BY_DRIVER;
+
+ params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER |
+ GUC_CTL_VCS2_ENABLED;
+
+ if (i915.guc_log_level >= 0) {
+ params[GUC_CTL_LOG_PARAMS] = guc->log_flags;
+ params[GUC_CTL_DEBUG] =
+ i915.guc_log_level << GUC_LOG_VERBOSITY_SHIFT;
+ }
+
+ /* If GuC submission is enabled, set up additional parameters here */
+ if (i915.enable_guc_submission) {
+ u32 pgs = i915_gem_obj_ggtt_offset(dev_priv->guc.ctx_pool_obj);
+ u32 ctx_in_16 = GUC_MAX_GPU_CONTEXTS / 16;
+
+ pgs >>= PAGE_SHIFT;
+ params[GUC_CTL_CTXINFO] = (pgs << GUC_CTL_BASE_ADDR_SHIFT) |
+ (ctx_in_16 << GUC_CTL_CTXNUM_IN16_SHIFT);
+
+ params[GUC_CTL_FEATURE] |= GUC_CTL_KERNEL_SUBMISSIONS;
+
+ /* Unmask this bit to enable the GuC's internal scheduler */
+ params[GUC_CTL_FEATURE] &= ~GUC_CTL_DISABLE_SCHEDULER;
+ }
+
+ I915_WRITE(SOFT_SCRATCH(0), 0);
+
+ for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
+ I915_WRITE(SOFT_SCRATCH(1 + i), params[i]);
+}
+
+/*
+ * Read the GuC status register (GUC_STATUS) and store it in the
+ * specified location; then return a boolean indicating whether
+ * the value matches either of two values representing completion
+ * of the GuC boot process.
+ *
+ * This is used for polling the GuC status in a wait_for_atomic()
+ * loop below.
+ */
+static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
+ u32 *status)
+{
+ u32 val = I915_READ(GUC_STATUS);
+ u32 uk_val = val & GS_UKERNEL_MASK;
+ *status = val;
+ return (uk_val == GS_UKERNEL_READY ||
+ ((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE));
+}
+
+/*
+ * Transfer the firmware image to RAM for execution by the microcontroller.
+ *
+ * GuC Firmware layout:
+ * +-------------------------------+ ----
+ * | CSS header | 128B
+ * | contains major/minor version |
+ * +-------------------------------+ ----
+ * | uCode |
+ * +-------------------------------+ ----
+ * | RSA signature | 256B
+ * +-------------------------------+ ----
+ *
+ * Architecturally, the DMA engine is bidirectional, and can potentially even
+ * transfer between GTT locations. This functionality is left out of the API
+ * for now as there is no need for it.
+ *
+ * Note that GuC needs the CSS header plus uKernel code to be copied by the
+ * DMA engine in one operation, whereas the RSA signature is loaded via MMIO.
+ */
+
+#define UOS_CSS_HEADER_OFFSET 0
+#define UOS_VER_MINOR_OFFSET 0x44
+#define UOS_VER_MAJOR_OFFSET 0x46
+#define UOS_CSS_HEADER_SIZE 0x80
+#define UOS_RSA_SIG_SIZE 0x100
+
+static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
+{
+ struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
+ unsigned long offset;
+ struct sg_table *sg = fw_obj->pages;
+ u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)];
+ int i, ret = 0;
+
+ /* uCode size, also is where RSA signature starts */
+ offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
+ I915_WRITE(DMA_COPY_SIZE, ucode_size);
+
+ /* Copy RSA signature from the fw image to HW for verification */
+ sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
+ for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
+ I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
+
+ /* Set the source address for the new blob */
+ offset = i915_gem_obj_ggtt_offset(fw_obj);
+ I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
+ I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
+
+ /*
+ * Set the DMA destination. Current uCode expects the code to be
+ * loaded at 8k; locations below this are used for the stack.
+ */
+ I915_WRITE(DMA_ADDR_1_LOW, 0x2000);
+ I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
+
+ /* Finally start the DMA */
+ I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(UOS_MOVE | START_DMA));
+
+ /*
+ * Spin-wait for the DMA to complete & the GuC to start up.
+ * NB: Docs recommend not using the interrupt for completion.
+ * Measurements indicate this should take no more than 20ms, so a
+ * timeout here indicates that the GuC has failed and is unusable.
+ * (Higher levels of the driver will attempt to fall back to
+ * execlist mode if this happens.)
+ */
+ ret = wait_for_atomic(guc_ucode_response(dev_priv, &status), 100);
+
+ DRM_DEBUG_DRIVER("DMA status 0x%x, GuC status 0x%x\n",
+ I915_READ(DMA_CTRL), status);
+
+ if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) {
+ DRM_ERROR("GuC firmware signature verification failed\n");
+ ret = -ENOEXEC;
+ }
+
+ DRM_DEBUG_DRIVER("returning %d\n", ret);
+
+ return ret;
+}
+
+/*
+ * Load the GuC firmware blob into the MinuteIA.
+ */
+static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
+{
+ struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ struct drm_device *dev = dev_priv->dev;
+ int ret;
+
+ ret = i915_gem_object_set_to_gtt_domain(guc_fw->guc_fw_obj, false);
+ if (ret) {
+ DRM_DEBUG_DRIVER("set-domain failed %d\n", ret);
+ return ret;
+ }
+
+ ret = i915_gem_obj_ggtt_pin(guc_fw->guc_fw_obj, 0, 0);
+ if (ret) {
+ DRM_DEBUG_DRIVER("pin failed %d\n", ret);
+ return ret;
+ }
+
+ /* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
+ I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+ /* init WOPCM */
+ I915_WRITE(GUC_WOPCM_SIZE, GUC_WOPCM_SIZE_VALUE);
+ I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE);
+
+ /* Enable MIA caching. GuC clock gating is disabled. */
+ I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
+
+ /* WaDisableMinuteIaClockGating:skl,bxt */
+ if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
+ (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) {
+ I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) &
+ ~GUC_ENABLE_MIA_CLOCK_GATING));
+ }
+
+ /* WaC6DisallowByGfxPause*/
+ I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
+
+ if (IS_BROXTON(dev))
+ I915_WRITE(GEN9LP_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
+ else
+ I915_WRITE(GEN9_GT_PM_CONFIG, GT_DOORBELL_ENABLE);
+
+ if (IS_GEN9(dev)) {
+ /* DOP Clock Gating Enable for GuC clocks */
+ I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
+ I915_READ(GEN7_MISCCPCTL)));
+
+ /* allows for 5us before GT can go to RC6 */
+ I915_WRITE(GUC_ARAT_C6DIS, 0x1FF);
+ }
+
+ set_guc_init_params(dev_priv);
+
+ ret = guc_ucode_xfer_dma(dev_priv);
+
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+ /*
+ * We keep the object pages for reuse during resume. But we can unpin it
+ * now that DMA has completed, so it doesn't continue to take up space.
+ */
+ i915_gem_object_ggtt_unpin(guc_fw->guc_fw_obj);
+
+ return ret;
+}
+
+/**
+ * intel_guc_ucode_load() - load GuC uCode into the device
+ * @dev: drm device
+ *
+ * Called from gem_init_hw() during driver loading and also after a GPU reset.
+ *
+ * The firmware image should have already been fetched into memory by the
+ * earlier call to intel_guc_ucode_init(), so here we need only check that
+ * is succeeded, and then transfer the image to the h/w.
+ *
+ * Return: non-zero code on error
+ */
+int intel_guc_ucode_load(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ int err = 0;
+
+ DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
+ intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
+ intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+
+ direct_interrupts_to_host(dev_priv);
+
+ if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_NONE)
+ return 0;
+
+ if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_SUCCESS &&
+ guc_fw->guc_fw_load_status == GUC_FIRMWARE_FAIL)
+ return -ENOEXEC;
+
+ guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
+
+ DRM_DEBUG_DRIVER("GuC fw fetch status %s\n",
+ intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
+
+ switch (guc_fw->guc_fw_fetch_status) {
+ case GUC_FIRMWARE_FAIL:
+ /* something went wrong :( */
+ err = -EIO;
+ goto fail;
+
+ case GUC_FIRMWARE_NONE:
+ case GUC_FIRMWARE_PENDING:
+ default:
+ /* "can't happen" */
+ WARN_ONCE(1, "GuC fw %s invalid guc_fw_fetch_status %s [%d]\n",
+ guc_fw->guc_fw_path,
+ intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
+ guc_fw->guc_fw_fetch_status);
+ err = -ENXIO;
+ goto fail;
+
+ case GUC_FIRMWARE_SUCCESS:
+ break;
+ }
+
+ err = i915_guc_submission_init(dev);
+ if (err)
+ goto fail;
+
+ err = guc_ucode_xfer(dev_priv);
+ if (err)
+ goto fail;
+
+ guc_fw->guc_fw_load_status = GUC_FIRMWARE_SUCCESS;
+
+ DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
+ intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
+ intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+
+ if (i915.enable_guc_submission) {
+ /* The execbuf_client will be recreated. Release it first. */
+ i915_guc_submission_disable(dev);
+
+ err = i915_guc_submission_enable(dev);
+ if (err)
+ goto fail;
+ direct_interrupts_to_guc(dev_priv);
+ }
+
+ return 0;
+
+fail:
+ if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_PENDING)
+ guc_fw->guc_fw_load_status = GUC_FIRMWARE_FAIL;
+
+ direct_interrupts_to_host(dev_priv);
+ i915_guc_submission_disable(dev);
+
+ return err;
+}
+
+static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
+{
+ struct drm_i915_gem_object *obj;
+ const struct firmware *fw;
+ const u8 *css_header;
+ const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
+ const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
+ - 0x8000; /* 32k reserved (8K stack + 24k context) */
+ int err;
+
+ DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
+ intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
+
+ err = request_firmware(&fw, guc_fw->guc_fw_path, &dev->pdev->dev);
+ if (err)
+ goto fail;
+ if (!fw)
+ goto fail;
+
+ DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n",
+ guc_fw->guc_fw_path, fw);
+ DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n",
+ fw->size, minsize, maxsize);
+
+ /* Check the size of the blob befoe examining buffer contents */
+ if (fw->size < minsize || fw->size > maxsize)
+ goto fail;
+
+ /*
+ * The GuC firmware image has the version number embedded at a well-known
+ * offset within the firmware blob; note that major / minor version are
+ * TWO bytes each (i.e. u16), although all pointers and offsets are defined
+ * in terms of bytes (u8).
+ */
+ css_header = fw->data + UOS_CSS_HEADER_OFFSET;
+ guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET);
+ guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET);
+
+ if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
+ guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
+ DRM_ERROR("GuC firmware version %d.%d, required %d.%d\n",
+ guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
+ guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
+ err = -ENOEXEC;
+ goto fail;
+ }
+
+ DRM_DEBUG_DRIVER("firmware version %d.%d OK (minimum %d.%d)\n",
+ guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
+ guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
+
+ mutex_lock(&dev->struct_mutex);
+ obj = i915_gem_object_create_from_data(dev, fw->data, fw->size);
+ mutex_unlock(&dev->struct_mutex);
+ if (IS_ERR_OR_NULL(obj)) {
+ err = obj ? PTR_ERR(obj) : -ENOMEM;
+ goto fail;
+ }
+
+ guc_fw->guc_fw_obj = obj;
+ guc_fw->guc_fw_size = fw->size;
+
+ DRM_DEBUG_DRIVER("GuC fw fetch status SUCCESS, obj %p\n",
+ guc_fw->guc_fw_obj);
+
+ release_firmware(fw);
+ guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_SUCCESS;
+ return;
+
+fail:
+ DRM_DEBUG_DRIVER("GuC fw fetch status FAIL; err %d, fw %p, obj %p\n",
+ err, fw, guc_fw->guc_fw_obj);
+ DRM_ERROR("Failed to fetch GuC firmware from %s (error %d)\n",
+ guc_fw->guc_fw_path, err);
+
+ obj = guc_fw->guc_fw_obj;
+ if (obj)
+ drm_gem_object_unreference(&obj->base);
+ guc_fw->guc_fw_obj = NULL;
+
+ release_firmware(fw); /* OK even if fw is NULL */
+ guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_FAIL;
+}
+
+/**
+ * intel_guc_ucode_init() - define parameters and fetch firmware
+ * @dev: drm device
+ *
+ * Called early during driver load, but after GEM is initialised.
+ *
+ * The firmware will be transferred to the GuC's memory later,
+ * when intel_guc_ucode_load() is called.
+ */
+void intel_guc_ucode_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+ const char *fw_path;
+
+ if (!HAS_GUC_SCHED(dev))
+ i915.enable_guc_submission = false;
+
+ if (!HAS_GUC_UCODE(dev)) {
+ fw_path = NULL;
+ } else if (IS_SKYLAKE(dev)) {
+ fw_path = I915_SKL_GUC_UCODE;
+ guc_fw->guc_fw_major_wanted = 4;
+ guc_fw->guc_fw_minor_wanted = 3;
+ } else {
+ i915.enable_guc_submission = false;
+ fw_path = ""; /* unknown device */
+ }
+
+ guc_fw->guc_dev = dev;
+ guc_fw->guc_fw_path = fw_path;
+ guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
+ guc_fw->guc_fw_load_status = GUC_FIRMWARE_NONE;
+
+ if (fw_path == NULL)
+ return;
+
+ if (*fw_path == '\0') {
+ DRM_ERROR("No GuC firmware known for this platform\n");
+ guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_FAIL;
+ return;
+ }
+
+ guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_PENDING;
+ DRM_DEBUG_DRIVER("GuC firmware pending, path %s\n", fw_path);
+ guc_fw_fetch(dev, guc_fw);
+ /* status must now be FAIL or SUCCESS */
+}
+
+/**
+ * intel_guc_ucode_fini() - clean up all allocated resources
+ * @dev: drm device
+ */
+void intel_guc_ucode_fini(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
+
+ direct_interrupts_to_host(dev_priv);
+ i915_guc_submission_fini(dev);
+
+ mutex_lock(&dev->struct_mutex);
+ if (guc_fw->guc_fw_obj)
+ drm_gem_object_unreference(&guc_fw->guc_fw_obj->base);
+ guc_fw->guc_fw_obj = NULL;
+ mutex_unlock(&dev->struct_mutex);
+
+ guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
+}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index dcd336bcdfe7..9eafa191cee2 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -113,17 +113,18 @@ static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type)
}
}
-static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type,
- enum transcoder cpu_transcoder,
- struct drm_i915_private *dev_priv)
+static u32 hsw_dip_data_reg(struct drm_i915_private *dev_priv,
+ enum transcoder cpu_transcoder,
+ enum hdmi_infoframe_type type,
+ int i)
{
switch (type) {
case HDMI_INFOFRAME_TYPE_AVI:
- return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder);
+ return HSW_TVIDEO_DIP_AVI_DATA(cpu_transcoder, i);
case HDMI_INFOFRAME_TYPE_SPD:
- return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder);
+ return HSW_TVIDEO_DIP_SPD_DATA(cpu_transcoder, i);
case HDMI_INFOFRAME_TYPE_VENDOR:
- return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder);
+ return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i);
default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", type);
return 0;
@@ -365,14 +366,13 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
u32 data_reg;
int i;
u32 val = I915_READ(ctl_reg);
- data_reg = hsw_infoframe_data_reg(type,
- intel_crtc->config->cpu_transcoder,
- dev_priv);
+ data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0);
if (data_reg == 0)
return;
@@ -381,12 +381,14 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
mmiowb();
for (i = 0; i < len; i += 4) {
- I915_WRITE(data_reg + i, *data);
+ I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
+ type, i >> 2), *data);
data++;
}
/* Write every possible data byte to force correct ECC calculation. */
for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
- I915_WRITE(data_reg + i, 0);
+ I915_WRITE(hsw_dip_data_reg(dev_priv, cpu_transcoder,
+ type, i >> 2), 0);
mmiowb();
val |= hsw_infoframe_enable(type);
@@ -447,16 +449,13 @@ static void intel_write_infoframe(struct drm_encoder *encoder,
}
static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
union hdmi_infoframe frame;
int ret;
- /* Set user selected PAR to incoming mode's member */
- adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio;
-
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
adjusted_mode);
if (ret < 0) {
@@ -494,7 +493,7 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
static void
intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
union hdmi_infoframe frame;
int ret;
@@ -509,7 +508,7 @@ intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
static void g4x_set_infoframes(struct drm_encoder *encoder,
bool enable,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
@@ -661,7 +660,7 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder)
static void ibx_set_infoframes(struct drm_encoder *encoder,
bool enable,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -713,7 +712,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
static void cpt_set_infoframes(struct drm_encoder *encoder,
bool enable,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -755,7 +754,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
static void vlv_set_infoframes(struct drm_encoder *encoder,
bool enable,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
@@ -807,7 +806,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
static void hsw_set_infoframes(struct drm_encoder *encoder,
bool enable,
- struct drm_display_mode *adjusted_mode)
+ const struct drm_display_mode *adjusted_mode)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -844,12 +843,12 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
u32 hdmi_val;
hdmi_val = SDVO_ENCODING_HDMI;
- if (!HAS_PCH_SPLIT(dev))
- hdmi_val |= intel_hdmi->color_range;
+ if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
+ hdmi_val |= HDMI_COLOR_RANGE_16_235;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1260,11 +1259,12 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
if (intel_hdmi->color_range_auto) {
/* See CEA-861-E - 5.1 Default Encoding Parameters */
- if (pipe_config->has_hdmi_sink &&
- drm_match_cea_mode(adjusted_mode) > 1)
- intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235;
- else
- intel_hdmi->color_range = 0;
+ pipe_config->limited_color_range =
+ pipe_config->has_hdmi_sink &&
+ drm_match_cea_mode(adjusted_mode) > 1;
+ } else {
+ pipe_config->limited_color_range =
+ intel_hdmi->limited_color_range;
}
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
@@ -1273,9 +1273,6 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
clock_12bpc *= 2;
}
- if (intel_hdmi->color_range)
- pipe_config->limited_color_range = true;
-
if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev))
pipe_config->has_pch_encoder = true;
@@ -1314,6 +1311,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
return false;
}
+ /* Set user selected PAR to incoming mode's member */
+ adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio;
+
return true;
}
@@ -1331,22 +1331,23 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
}
static bool
-intel_hdmi_set_edid(struct drm_connector *connector)
+intel_hdmi_set_edid(struct drm_connector *connector, bool force)
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct intel_encoder *intel_encoder =
&hdmi_to_dig_port(intel_hdmi)->base;
enum intel_display_power_domain power_domain;
- struct edid *edid;
+ struct edid *edid = NULL;
bool connected = false;
power_domain = intel_display_port_power_domain(intel_encoder);
intel_display_power_get(dev_priv, power_domain);
- edid = drm_get_edid(connector,
- intel_gmbus_get_adapter(dev_priv,
- intel_hdmi->ddc_bus));
+ if (force)
+ edid = drm_get_edid(connector,
+ intel_gmbus_get_adapter(dev_priv,
+ intel_hdmi->ddc_bus));
intel_display_power_put(dev_priv, power_domain);
@@ -1374,13 +1375,26 @@ static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector, bool force)
{
enum drm_connector_status status;
+ struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+ struct drm_i915_private *dev_priv = to_i915(connector->dev);
+ bool live_status = false;
+ unsigned int retry = 3;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
+ while (!live_status && --retry) {
+ live_status = intel_digital_port_connected(dev_priv,
+ hdmi_to_dig_port(intel_hdmi));
+ mdelay(10);
+ }
+
+ if (!live_status)
+ DRM_DEBUG_KMS("Live status not up!");
+
intel_hdmi_unset_edid(connector);
- if (intel_hdmi_set_edid(connector)) {
+ if (intel_hdmi_set_edid(connector, live_status)) {
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
@@ -1404,7 +1418,7 @@ intel_hdmi_force(struct drm_connector *connector)
if (connector->status != connector_status_connected)
return;
- intel_hdmi_set_edid(connector);
+ intel_hdmi_set_edid(connector, true);
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
}
@@ -1470,7 +1484,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
if (property == dev_priv->broadcast_rgb_property) {
bool old_auto = intel_hdmi->color_range_auto;
- uint32_t old_range = intel_hdmi->color_range;
+ bool old_range = intel_hdmi->limited_color_range;
switch (val) {
case INTEL_BROADCAST_RGB_AUTO:
@@ -1478,18 +1492,18 @@ intel_hdmi_set_property(struct drm_connector *connector,
break;
case INTEL_BROADCAST_RGB_FULL:
intel_hdmi->color_range_auto = false;
- intel_hdmi->color_range = 0;
+ intel_hdmi->limited_color_range = false;
break;
case INTEL_BROADCAST_RGB_LIMITED:
intel_hdmi->color_range_auto = false;
- intel_hdmi->color_range = HDMI_COLOR_RANGE_16_235;
+ intel_hdmi->limited_color_range = true;
break;
default:
return -EINVAL;
}
if (old_auto == intel_hdmi->color_range_auto &&
- old_range == intel_hdmi->color_range)
+ old_range == intel_hdmi->limited_color_range)
return 0;
goto done;
@@ -1525,8 +1539,7 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
intel_hdmi_prepare(encoder);
@@ -1543,8 +1556,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc =
to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
enum dpio_channel port = vlv_dport_to_channel(dport);
int pipe = intel_crtc->pipe;
u32 val;
@@ -1617,6 +1629,50 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->sb_lock);
}
+static void chv_data_lane_soft_reset(struct intel_encoder *encoder,
+ bool reset)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base));
+ struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+ enum pipe pipe = crtc->pipe;
+ uint32_t val;
+
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
+ if (reset)
+ val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+ else
+ val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
+
+ if (crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
+ if (reset)
+ val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
+ else
+ val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+ }
+
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
+ val |= CHV_PCS_REQ_SOFTRESET_EN;
+ if (reset)
+ val &= ~DPIO_PCS_CLK_SOFT_RESET;
+ else
+ val |= DPIO_PCS_CLK_SOFT_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
+
+ if (crtc->config->lane_count > 2) {
+ val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
+ val |= CHV_PCS_REQ_SOFTRESET_EN;
+ if (reset)
+ val &= ~DPIO_PCS_CLK_SOFT_RESET;
+ else
+ val |= DPIO_PCS_CLK_SOFT_RESET;
+ vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
+ }
+}
+
static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
{
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
@@ -1630,8 +1686,21 @@ static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
intel_hdmi_prepare(encoder);
+ /*
+ * Must trick the second common lane into life.
+ * Otherwise we can't even access the PLL.
+ */
+ if (ch == DPIO_CH0 && pipe == PIPE_B)
+ dport->release_cl2_override =
+ !chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, true);
+
+ chv_phy_powergate_lanes(encoder, true, 0x0);
+
mutex_lock(&dev_priv->sb_lock);
+ /* Assert data lane reset */
+ chv_data_lane_soft_reset(encoder, true);
+
/* program left/right clock distribution */
if (pipe != PIPE_B) {
val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
@@ -1683,6 +1752,39 @@ static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->sb_lock);
}
+static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe;
+ u32 val;
+
+ mutex_lock(&dev_priv->sb_lock);
+
+ /* disable left/right clock distribution */
+ if (pipe != PIPE_B) {
+ val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0);
+ val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK);
+ vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val);
+ } else {
+ val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1);
+ val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK);
+ vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val);
+ }
+
+ mutex_unlock(&dev_priv->sb_lock);
+
+ /*
+ * Leave the power down bit cleared for at least one
+ * lane so that chv_powergate_phy_ch() will power
+ * on something when the channel is otherwise unused.
+ * When the port is off and the override is removed
+ * the lanes power down anyway, so otherwise it doesn't
+ * really matter what the state of power down bits is
+ * after this.
+ */
+ chv_phy_powergate_lanes(encoder, false, 0x0);
+}
+
static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
{
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
@@ -1701,33 +1803,13 @@ static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
static void chv_hdmi_post_disable(struct intel_encoder *encoder)
{
- struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc =
- to_intel_crtc(encoder->base.crtc);
- enum dpio_channel ch = vlv_dport_to_channel(dport);
- enum pipe pipe = intel_crtc->pipe;
- u32 val;
mutex_lock(&dev_priv->sb_lock);
- /* Propagate soft reset to data lane reset */
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
- val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
- val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
+ /* Assert data lane reset */
+ chv_data_lane_soft_reset(encoder, true);
mutex_unlock(&dev_priv->sb_lock);
}
@@ -1740,8 +1822,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc =
to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
enum dpio_channel ch = vlv_dport_to_channel(dport);
int pipe = intel_crtc->pipe;
int data, i, stagger;
@@ -1758,23 +1839,6 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
val &= ~DPIO_LANEDESKEW_STRAP_OVRD;
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val);
- /* Deassert soft data lane reset*/
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch));
- val |= CHV_PCS_REQ_SOFTRESET_EN;
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch));
- val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val);
-
- val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch));
- val |= (DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
- vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val);
-
/* Program Tx latency optimal setting */
for (i = 0; i < 4; i++) {
/* Set the upar bit */
@@ -1817,6 +1881,9 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
DPIO_TX1_STAGGER_MULT(7) |
DPIO_TX2_STAGGER_MULT(5));
+ /* Deassert data lane reset */
+ chv_data_lane_soft_reset(encoder, false);
+
/* Clear calc init */
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3);
@@ -1851,31 +1918,33 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
for (i = 0; i < 4; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i));
+
val &= ~DPIO_SWING_MARGIN000_MASK;
val |= 102 << DPIO_SWING_MARGIN000_SHIFT;
+
+ /*
+ * Supposedly this value shouldn't matter when unique transition
+ * scale is disabled, but in fact it does matter. Let's just
+ * always program the same value and hope it's OK.
+ */
+ val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT);
+ val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT;
+
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val);
}
- /* Disable unique transition scale */
+ /*
+ * The document said it needs to set bit 27 for ch0 and bit 26
+ * for ch1. Might be a typo in the doc.
+ * For now, for this unique transition scale selection, set bit
+ * 27 for ch0 and ch1.
+ */
for (i = 0; i < 4; i++) {
val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i));
val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN;
vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val);
}
- /* Additional steps for 1200mV-0dB */
-#if 0
- val = vlv_dpio_read(dev_priv, pipe, VLV_TX_DW3(ch));
- if (ch)
- val |= DPIO_TX_UNIQ_TRANS_SCALE_CH1;
- else
- val |= DPIO_TX_UNIQ_TRANS_SCALE_CH0;
- vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(ch), val);
-
- vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(ch),
- vlv_dpio_read(dev_priv, pipe, VLV_TX_DW2(ch)) |
- (0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT));
-#endif
/* Start swing calculation */
val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch));
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
@@ -1885,11 +1954,6 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3;
vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val);
- /* LRC Bypass */
- val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30);
- val |= DPIO_LRC_BYPASS;
- vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, val);
-
mutex_unlock(&dev_priv->sb_lock);
intel_hdmi->set_infoframes(&encoder->base,
@@ -1899,6 +1963,12 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
g4x_enable_hdmi(encoder);
vlv_wait_port_ready(dev_priv, dport, 0x0);
+
+ /* Second common lane will stay alive on its own now */
+ if (dport->release_cl2_override) {
+ chv_phy_powergate_ch(dev_priv, DPIO_PHY0, DPIO_CH1, false);
+ dport->release_cl2_override = false;
+ }
}
static void intel_hdmi_destroy(struct drm_connector *connector)
@@ -1931,15 +2001,6 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
};
static void
-intel_attach_aspect_ratio_property(struct drm_connector *connector)
-{
- if (!drm_mode_create_aspect_ratio_property(connector->dev))
- drm_object_attach_property(&connector->base,
- connector->dev->mode_config.aspect_ratio_property,
- DRM_MODE_PICTURE_ASPECT_NONE);
-}
-
-static void
intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *connector)
{
intel_attach_force_audio_property(connector);
@@ -1974,7 +2035,14 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
intel_hdmi->ddc_bus = GMBUS_PIN_1_BXT;
else
intel_hdmi->ddc_bus = GMBUS_PIN_DPB;
- intel_encoder->hpd_pin = HPD_PORT_B;
+ /*
+ * On BXT A0/A1, sw needs to activate DDIA HPD logic and
+ * interrupts to check the external panel connection.
+ */
+ if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0))
+ intel_encoder->hpd_pin = HPD_PORT_A;
+ else
+ intel_encoder->hpd_pin = HPD_PORT_B;
break;
case PORT_C:
if (IS_BROXTON(dev_priv))
@@ -2051,6 +2119,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
intel_connector_attach_encoder(intel_connector, intel_encoder);
drm_connector_register(connector);
+ intel_hdmi->attached_connector = intel_connector;
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
* 0xd. Failure to do so will result in spurious interrupts being
@@ -2097,6 +2166,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
intel_encoder->pre_enable = chv_hdmi_pre_enable;
intel_encoder->enable = vlv_enable_hdmi;
intel_encoder->post_disable = chv_hdmi_post_disable;
+ intel_encoder->post_pll_disable = chv_hdmi_post_pll_disable;
} else if (IS_VALLEYVIEW(dev)) {
intel_encoder->pre_pll_enable = vlv_hdmi_pre_pll_enable;
intel_encoder->pre_enable = vlv_hdmi_pre_enable;
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index a64f26c670af..1369fc41d039 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -114,8 +114,8 @@ intel_i2c_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0);
- I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0);
+ I915_WRITE(GMBUS0, 0);
+ I915_WRITE(GMBUS4, 0);
}
static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
@@ -261,7 +261,6 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
u32 gmbus4_irq_en)
{
int i;
- int reg_offset = dev_priv->gpio_mmio_base;
u32 gmbus2 = 0;
DEFINE_WAIT(wait);
@@ -271,13 +270,13 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
/* Important: The hw handles only the first bit, so set only one! Since
* we also need to check for NAKs besides the hw ready/idle signal, we
* need to wake up periodically and check that ourselves. */
- I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en);
+ I915_WRITE(GMBUS4, gmbus4_irq_en);
for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
TASK_UNINTERRUPTIBLE);
- gmbus2 = I915_READ_NOTRACE(GMBUS2 + reg_offset);
+ gmbus2 = I915_READ_NOTRACE(GMBUS2);
if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
break;
@@ -285,7 +284,7 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
}
finish_wait(&dev_priv->gmbus_wait_queue, &wait);
- I915_WRITE(GMBUS4 + reg_offset, 0);
+ I915_WRITE(GMBUS4, 0);
if (gmbus2 & GMBUS_SATOER)
return -ENXIO;
@@ -298,20 +297,19 @@ static int
gmbus_wait_idle(struct drm_i915_private *dev_priv)
{
int ret;
- int reg_offset = dev_priv->gpio_mmio_base;
-#define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0)
+#define C ((I915_READ_NOTRACE(GMBUS2) & GMBUS_ACTIVE) == 0)
if (!HAS_GMBUS_IRQ(dev_priv->dev))
return wait_for(C, 10);
/* Important: The hw handles only the first bit, so set only one! */
- I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN);
+ I915_WRITE(GMBUS4, GMBUS_IDLE_EN);
ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
msecs_to_jiffies_timeout(10));
- I915_WRITE(GMBUS4 + reg_offset, 0);
+ I915_WRITE(GMBUS4, 0);
if (ret)
return 0;
@@ -325,9 +323,7 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
unsigned short addr, u8 *buf, unsigned int len,
u32 gmbus1_index)
{
- int reg_offset = dev_priv->gpio_mmio_base;
-
- I915_WRITE(GMBUS1 + reg_offset,
+ I915_WRITE(GMBUS1,
gmbus1_index |
GMBUS_CYCLE_WAIT |
(len << GMBUS_BYTE_COUNT_SHIFT) |
@@ -342,7 +338,7 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
if (ret)
return ret;
- val = I915_READ(GMBUS3 + reg_offset);
+ val = I915_READ(GMBUS3);
do {
*buf++ = val & 0xff;
val >>= 8;
@@ -380,7 +376,6 @@ static int
gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
unsigned short addr, u8 *buf, unsigned int len)
{
- int reg_offset = dev_priv->gpio_mmio_base;
unsigned int chunk_size = len;
u32 val, loop;
@@ -390,8 +385,8 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
len -= 1;
}
- I915_WRITE(GMBUS3 + reg_offset, val);
- I915_WRITE(GMBUS1 + reg_offset,
+ I915_WRITE(GMBUS3, val);
+ I915_WRITE(GMBUS1,
GMBUS_CYCLE_WAIT |
(chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
@@ -404,7 +399,7 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
val |= *buf++ << (8 * loop);
} while (--len && ++loop < 4);
- I915_WRITE(GMBUS3 + reg_offset, val);
+ I915_WRITE(GMBUS3, val);
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
GMBUS_HW_RDY_EN);
@@ -452,7 +447,6 @@ gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)
static int
gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
{
- int reg_offset = dev_priv->gpio_mmio_base;
u32 gmbus1_index = 0;
u32 gmbus5 = 0;
int ret;
@@ -466,13 +460,13 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
/* GMBUS5 holds 16-bit index */
if (gmbus5)
- I915_WRITE(GMBUS5 + reg_offset, gmbus5);
+ I915_WRITE(GMBUS5, gmbus5);
ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
/* Clear GMBUS5 after each index transfer */
if (gmbus5)
- I915_WRITE(GMBUS5 + reg_offset, 0);
+ I915_WRITE(GMBUS5, 0);
return ret;
}
@@ -486,7 +480,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
- int i = 0, inc, try = 0, reg_offset;
+ int i = 0, inc, try = 0;
int ret = 0;
intel_aux_display_runtime_get(dev_priv);
@@ -497,10 +491,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
goto out;
}
- reg_offset = dev_priv->gpio_mmio_base;
-
retry:
- I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
+ I915_WRITE(GMBUS0, bus->reg0);
for (; i < num; i += inc) {
inc = 1;
@@ -530,7 +522,7 @@ retry:
* a STOP on the very first cycle. To simplify the code we
* unconditionally generate the STOP condition with an additional gmbus
* cycle. */
- I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+ I915_WRITE(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
/* Mark the GMBUS interface as disabled after waiting for idle.
* We will re-enable it at the start of the next xfer,
@@ -541,7 +533,7 @@ retry:
adapter->name);
ret = -ETIMEDOUT;
}
- I915_WRITE(GMBUS0 + reg_offset, 0);
+ I915_WRITE(GMBUS0, 0);
ret = ret ?: i;
goto out;
@@ -570,9 +562,9 @@ clear_err:
* of resetting the GMBUS controller and so clearing the
* BUS_ERROR raised by the slave's NAK.
*/
- I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
- I915_WRITE(GMBUS1 + reg_offset, 0);
- I915_WRITE(GMBUS0 + reg_offset, 0);
+ I915_WRITE(GMBUS1, GMBUS_SW_CLR_INT);
+ I915_WRITE(GMBUS1, 0);
+ I915_WRITE(GMBUS0, 0);
DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
adapter->name, msgs[i].addr,
@@ -595,7 +587,7 @@ clear_err:
timeout:
DRM_INFO("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
bus->adapter.name, bus->reg0 & 0xff);
- I915_WRITE(GMBUS0 + reg_offset, 0);
+ I915_WRITE(GMBUS0, 0);
/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
bus->force_bit = 1;
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 29dd4488dc49..88e12bdf79e2 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -196,13 +196,21 @@
reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \
}
+#define ASSIGN_CTX_PML4(ppgtt, reg_state) { \
+ reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \
+ reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \
+}
+
enum {
ADVANCED_CONTEXT = 0,
- LEGACY_CONTEXT,
+ LEGACY_32B_CONTEXT,
ADVANCED_AD_CONTEXT,
LEGACY_64B_CONTEXT
};
-#define GEN8_CTX_MODE_SHIFT 3
+#define GEN8_CTX_ADDRESSING_MODE_SHIFT 3
+#define GEN8_CTX_ADDRESSING_MODE(dev) (USES_FULL_48BIT_PPGTT(dev) ?\
+ LEGACY_64B_CONTEXT :\
+ LEGACY_32B_CONTEXT)
enum {
FAULT_AND_HANG = 0,
FAULT_AND_HALT, /* Debug only */
@@ -213,6 +221,9 @@ enum {
#define CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17
static int intel_lr_context_pin(struct drm_i915_gem_request *rq);
+static void lrc_setup_hardware_status_page(struct intel_engine_cs *ring,
+ struct drm_i915_gem_object *default_ctx_obj);
+
/**
* intel_sanitize_enable_execlists() - sanitize i915.enable_execlists
@@ -228,6 +239,12 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
{
WARN_ON(i915.enable_ppgtt == -1);
+ /* On platforms with execlist available, vGPU will only
+ * support execlist mode, no ring buffer mode.
+ */
+ if (HAS_LOGICAL_RING_CONTEXTS(dev) && intel_vgpu_active(dev))
+ return 1;
+
if (INTEL_INFO(dev)->gen >= 9)
return 1;
@@ -255,25 +272,35 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
*/
u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
{
- u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+ u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj) +
+ LRC_PPHWSP_PN * PAGE_SIZE;
/* LRCA is required to be 4K aligned so the more significant 20 bits
* are globally unique */
return lrca >> 12;
}
-static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_request *rq)
+static bool disable_lite_restore_wa(struct intel_engine_cs *ring)
{
- struct intel_engine_cs *ring = rq->ring;
struct drm_device *dev = ring->dev;
- struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state;
+
+ return ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
+ (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) &&
+ (ring->id == VCS || ring->id == VCS2);
+}
+
+uint64_t intel_lr_context_descriptor(struct intel_context *ctx,
+ struct intel_engine_cs *ring)
+{
+ struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;
uint64_t desc;
- uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+ uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj) +
+ LRC_PPHWSP_PN * PAGE_SIZE;
WARN_ON(lrca & 0xFFFFFFFF00000FFFULL);
desc = GEN8_CTX_VALID;
- desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT;
+ desc |= GEN8_CTX_ADDRESSING_MODE(dev) << GEN8_CTX_ADDRESSING_MODE_SHIFT;
if (IS_GEN8(ctx_obj->base.dev))
desc |= GEN8_CTX_L3LLC_COHERENT;
desc |= GEN8_CTX_PRIVILEGE;
@@ -285,10 +312,8 @@ static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_request *rq)
/* desc |= GEN8_CTX_FORCE_RESTORE; */
/* WaEnableForceRestoreInCtxtDescForVCS:skl */
- if (IS_GEN9(dev) &&
- INTEL_REVID(dev) <= SKL_REVID_B0 &&
- (ring->id == BCS || ring->id == VCS ||
- ring->id == VECS || ring->id == VCS2))
+ /* WaEnableForceRestoreInCtxtDescForVCS:bxt */
+ if (disable_lite_restore_wa(ring))
desc |= GEN8_CTX_FORCE_RESTORE;
return desc;
@@ -304,13 +329,13 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
uint64_t desc[2];
if (rq1) {
- desc[1] = execlists_ctx_descriptor(rq1);
+ desc[1] = intel_lr_context_descriptor(rq1->ctx, rq1->ring);
rq1->elsp_submitted++;
} else {
desc[1] = 0;
}
- desc[0] = execlists_ctx_descriptor(rq0);
+ desc[0] = intel_lr_context_descriptor(rq0->ctx, rq0->ring);
rq0->elsp_submitted++;
/* You must always write both descriptors in the order below. */
@@ -324,7 +349,7 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
I915_WRITE_FW(RING_ELSP(ring), lower_32_bits(desc[0]));
/* ELSP is a wo register, use another nearby reg for posting */
- POSTING_READ_FW(RING_EXECLIST_STATUS(ring));
+ POSTING_READ_FW(RING_EXECLIST_STATUS_LO(ring));
intel_uncore_forcewake_put__locked(dev_priv, FORCEWAKE_ALL);
spin_unlock(&dev_priv->uncore.lock);
}
@@ -342,16 +367,18 @@ static int execlists_update_context(struct drm_i915_gem_request *rq)
WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
WARN_ON(!i915_gem_obj_is_pinned(rb_obj));
- page = i915_gem_object_get_page(ctx_obj, 1);
+ page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
reg_state[CTX_RING_TAIL+1] = rq->tail;
reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj);
- /* True PPGTT with dynamic page allocation: update PDP registers and
- * point the unallocated PDPs to the scratch page
- */
- if (ppgtt) {
+ 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);
@@ -477,7 +504,7 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
u32 status_pointer;
u8 read_pointer;
u8 write_pointer;
- u32 status;
+ u32 status = 0;
u32 status_id;
u32 submit_contexts = 0;
@@ -492,10 +519,8 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
while (read_pointer < write_pointer) {
read_pointer++;
- status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
- (read_pointer % GEN8_CSB_ENTRIES) * 8);
- status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
- (read_pointer % GEN8_CSB_ENTRIES) * 8 + 4);
+ status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES));
+ status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES));
if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
continue;
@@ -515,8 +540,14 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring)
}
}
- if (submit_contexts != 0)
+ if (disable_lite_restore_wa(ring)) {
+ /* 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);
+ }
spin_unlock(&ring->execlist_lock);
@@ -540,8 +571,6 @@ static int execlists_context_queue(struct drm_i915_gem_request *request)
i915_gem_request_reference(request);
- request->tail = request->ringbuf->tail;
-
spin_lock_irq(&ring->execlist_lock);
list_for_each_entry(cursor, &ring->execlist_queue, execlist_link)
@@ -694,13 +723,19 @@ static void
intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
{
struct intel_engine_cs *ring = request->ring;
+ struct drm_i915_private *dev_priv = request->i915;
intel_logical_ring_advance(request->ringbuf);
+ request->tail = request->ringbuf->tail;
+
if (intel_ring_stopped(ring))
return;
- execlists_context_queue(request);
+ if (dev_priv->guc.execbuf_client)
+ i915_guc_submit(dev_priv->guc.execbuf_client, request);
+ else
+ execlists_context_queue(request);
}
static void __wrap_ring_buffer(struct intel_ringbuffer *ringbuf)
@@ -767,8 +802,7 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes)
/**
* intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands
*
- * @request: The request to start some new work for
- * @ctx: Logical ring context whose ringbuffer is being prepared.
+ * @req: The request to start some new work for
* @num_dwords: number of DWORDs that we plan to write to the ringbuffer.
*
* The ringbuffer might not be ready to accept the commands right away (maybe it needs to
@@ -870,21 +904,6 @@ int intel_execlists_submission(struct i915_execbuffer_params *params,
return -EINVAL;
}
- if (args->num_cliprects != 0) {
- DRM_DEBUG("clip rectangles are only valid on pre-gen5\n");
- return -EINVAL;
- } else {
- if (args->DR4 == 0xffffffff) {
- DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
- args->DR4 = 0;
- }
-
- if (args->DR1 || args->DR4 || args->cliprects_ptr) {
- DRM_DEBUG("0 cliprects but dirt in cliprects fields\n");
- return -EINVAL;
- }
- }
-
if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
DRM_DEBUG("sol reset is gen7 only\n");
return -EINVAL;
@@ -988,34 +1007,54 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req)
return 0;
}
+static int intel_lr_context_do_pin(struct intel_engine_cs *ring,
+ struct drm_i915_gem_object *ctx_obj,
+ struct intel_ringbuffer *ringbuf)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret = 0;
+
+ WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
+ ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN,
+ PIN_OFFSET_BIAS | GUC_WOPCM_TOP);
+ if (ret)
+ return ret;
+
+ ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
+ if (ret)
+ goto unpin_ctx_obj;
+
+ ctx_obj->dirty = true;
+
+ /* Invalidate GuC TLB. */
+ if (i915.enable_guc_submission)
+ I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
+
+ return ret;
+
+unpin_ctx_obj:
+ i915_gem_object_ggtt_unpin(ctx_obj);
+
+ return ret;
+}
+
static int intel_lr_context_pin(struct drm_i915_gem_request *rq)
{
+ int ret = 0;
struct intel_engine_cs *ring = rq->ring;
struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state;
struct intel_ringbuffer *ringbuf = rq->ringbuf;
- int ret = 0;
- WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
if (rq->ctx->engine[ring->id].pin_count++ == 0) {
- ret = i915_gem_obj_ggtt_pin(ctx_obj,
- GEN8_LR_CONTEXT_ALIGN, 0);
+ ret = intel_lr_context_do_pin(ring, ctx_obj, ringbuf);
if (ret)
goto reset_pin_count;
-
- ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
- if (ret)
- goto unpin_ctx_obj;
-
- ctx_obj->dirty = true;
}
-
return ret;
-unpin_ctx_obj:
- i915_gem_object_ggtt_unpin(ctx_obj);
reset_pin_count:
rq->ctx->engine[ring->id].pin_count = 0;
-
return ret;
}
@@ -1113,7 +1152,7 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring,
if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0)
l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS;
- wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8(1) |
+ wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT));
wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
@@ -1131,7 +1170,7 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring,
wa_ctx_emit(batch, index, 0);
wa_ctx_emit(batch, index, 0);
- wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8(1) |
+ wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT));
wa_ctx_emit(batch, index, GEN8_L3SQCREG4);
wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256);
@@ -1200,9 +1239,10 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring,
/* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */
if (IS_BROADWELL(ring->dev)) {
- index = gen8_emit_flush_coherentl3_wa(ring, batch, index);
- if (index < 0)
- return index;
+ int rc = gen8_emit_flush_coherentl3_wa(ring, batch, index);
+ if (rc < 0)
+ return rc;
+ index = rc;
}
/* WaClearSlmSpaceAtContextSwitch:bdw,chv */
@@ -1426,6 +1466,9 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
struct drm_i915_private *dev_priv = dev->dev_private;
u8 next_context_status_buffer_hw;
+ lrc_setup_hardware_status_page(ring,
+ ring->default_context->engine[ring->id].state);
+
I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
@@ -1542,12 +1585,16 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req,
* Ideally, we should set Force PD Restore in ctx descriptor,
* but we can't. Force Restore would be a second option, but
* it is unsafe in case of lite-restore (because the ctx is
- * not idle). */
+ * not idle). PML4 is allocated during ppgtt init so this is
+ * not needed in 48-bit.*/
if (req->ctx->ppgtt &&
(intel_ring_flag(req->ring) & req->ctx->ppgtt->pd_dirty_rings)) {
- ret = intel_logical_ring_emit_pdps(req);
- if (ret)
- return ret;
+ if (!USES_FULL_48BIT_PPGTT(req->i915) &&
+ !intel_vgpu_active(req->i915->dev)) {
+ ret = intel_logical_ring_emit_pdps(req);
+ if (ret)
+ return ret;
+ }
req->ctx->ppgtt->pd_dirty_rings &= ~intel_ring_flag(req->ring);
}
@@ -1714,6 +1761,34 @@ static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
}
+static u32 bxt_a_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
+{
+
+ /*
+ * On BXT A steppings there is a HW coherency issue whereby the
+ * MI_STORE_DATA_IMM storing the completed request's seqno
+ * occasionally doesn't invalidate the CPU cache. Work around this by
+ * clflushing the corresponding cacheline whenever the caller wants
+ * the coherency to be guaranteed. Note that this cacheline is known
+ * to be clean at this point, since we only write it in
+ * bxt_a_set_seqno(), where we also do a clflush after the write. So
+ * this clflush in practice becomes an invalidate operation.
+ */
+
+ if (!lazy_coherency)
+ intel_flush_status_page(ring, I915_GEM_HWS_INDEX);
+
+ return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static void bxt_a_set_seqno(struct intel_engine_cs *ring, u32 seqno)
+{
+ intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
+
+ /* See bxt_a_get_seqno() explaining the reason for the clflush. */
+ intel_flush_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
static int gen8_emit_request(struct drm_i915_gem_request *request)
{
struct intel_ringbuffer *ringbuf = request->ringbuf;
@@ -1856,7 +1931,21 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
if (ret)
return ret;
- ret = intel_lr_context_deferred_create(ring->default_context, ring);
+ ret = intel_lr_context_deferred_alloc(ring->default_context, ring);
+ if (ret)
+ return ret;
+
+ /* As this is the default context, always pin it */
+ ret = intel_lr_context_do_pin(
+ ring,
+ ring->default_context->engine[ring->id].state,
+ ring->default_context->engine[ring->id].ringbuf);
+ if (ret) {
+ DRM_ERROR(
+ "Failed to pin and map ringbuffer %s: %d\n",
+ ring->name, ret);
+ return ret;
+ }
return ret;
}
@@ -1883,8 +1972,13 @@ static int logical_render_ring_init(struct drm_device *dev)
ring->init_hw = gen8_init_render_ring;
ring->init_context = gen8_init_rcs_context;
ring->cleanup = intel_fini_pipe_control;
- ring->get_seqno = gen8_get_seqno;
- ring->set_seqno = gen8_set_seqno;
+ if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ ring->get_seqno = bxt_a_get_seqno;
+ ring->set_seqno = bxt_a_set_seqno;
+ } else {
+ ring->get_seqno = gen8_get_seqno;
+ ring->set_seqno = gen8_set_seqno;
+ }
ring->emit_request = gen8_emit_request;
ring->emit_flush = gen8_emit_flush_render;
ring->irq_get = gen8_logical_ring_get_irq;
@@ -1930,8 +2024,13 @@ static int logical_bsd_ring_init(struct drm_device *dev)
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
ring->init_hw = gen8_init_common_ring;
- ring->get_seqno = gen8_get_seqno;
- ring->set_seqno = gen8_set_seqno;
+ if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ ring->get_seqno = bxt_a_get_seqno;
+ ring->set_seqno = bxt_a_set_seqno;
+ } else {
+ ring->get_seqno = gen8_get_seqno;
+ ring->set_seqno = gen8_set_seqno;
+ }
ring->emit_request = gen8_emit_request;
ring->emit_flush = gen8_emit_flush;
ring->irq_get = gen8_logical_ring_get_irq;
@@ -1980,8 +2079,13 @@ static int logical_blt_ring_init(struct drm_device *dev)
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
ring->init_hw = gen8_init_common_ring;
- ring->get_seqno = gen8_get_seqno;
- ring->set_seqno = gen8_set_seqno;
+ if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ ring->get_seqno = bxt_a_get_seqno;
+ ring->set_seqno = bxt_a_set_seqno;
+ } else {
+ ring->get_seqno = gen8_get_seqno;
+ ring->set_seqno = gen8_set_seqno;
+ }
ring->emit_request = gen8_emit_request;
ring->emit_flush = gen8_emit_flush;
ring->irq_get = gen8_logical_ring_get_irq;
@@ -2005,8 +2109,13 @@ static int logical_vebox_ring_init(struct drm_device *dev)
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
ring->init_hw = gen8_init_common_ring;
- ring->get_seqno = gen8_get_seqno;
- ring->set_seqno = gen8_set_seqno;
+ if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) {
+ ring->get_seqno = bxt_a_get_seqno;
+ ring->set_seqno = bxt_a_set_seqno;
+ } else {
+ ring->get_seqno = gen8_get_seqno;
+ ring->set_seqno = gen8_set_seqno;
+ }
ring->emit_request = gen8_emit_request;
ring->emit_flush = gen8_emit_flush;
ring->irq_get = gen8_logical_ring_get_irq;
@@ -2059,14 +2168,8 @@ int intel_logical_rings_init(struct drm_device *dev)
goto cleanup_vebox_ring;
}
- ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
- if (ret)
- goto cleanup_bsd2_ring;
-
return 0;
-cleanup_bsd2_ring:
- intel_logical_ring_cleanup(&dev_priv->ring[VCS2]);
cleanup_vebox_ring:
intel_logical_ring_cleanup(&dev_priv->ring[VECS]);
cleanup_blt_ring:
@@ -2152,7 +2255,7 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
/* The second page of the context object contains some fields which must
* be set up prior to the first execution. */
- page = i915_gem_object_get_page(ctx_obj, 1);
+ page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
/* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM
@@ -2229,13 +2332,24 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o
reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
- /* 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);
+ if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) {
+ /* 64b PPGTT (48bit canonical)
+ * PDP0_DESCRIPTOR contains the base address to PML4 and
+ * other PDP Descriptors are ignored.
+ */
+ ASSIGN_CTX_PML4(ppgtt, reg_state);
+ } else {
+ /* 32b PPGTT
+ * PDP*_DESCRIPTOR contains the base address of space supported.
+ * 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);
+ }
+
if (ring->id == RCS) {
reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE;
@@ -2276,8 +2390,7 @@ void intel_lr_context_free(struct intel_context *ctx)
i915_gem_object_ggtt_unpin(ctx_obj);
}
WARN_ON(ctx->engine[ring->id].pin_count);
- intel_destroy_ringbuffer_obj(ringbuf);
- kfree(ringbuf);
+ intel_ringbuffer_free(ringbuf);
drm_gem_object_unreference(&ctx_obj->base);
}
}
@@ -2311,12 +2424,13 @@ static void lrc_setup_hardware_status_page(struct intel_engine_cs *ring,
struct drm_i915_gem_object *default_ctx_obj)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct page *page;
- /* The status page is offset 0 from the default context object
- * in LRC mode. */
- ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(default_ctx_obj);
- ring->status_page.page_addr =
- kmap(sg_page(default_ctx_obj->pages->sgl));
+ /* The HWSP is part of the default context object in LRC mode. */
+ ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(default_ctx_obj)
+ + LRC_PPHWSP_PN * PAGE_SIZE;
+ page = i915_gem_object_get_page(default_ctx_obj, LRC_PPHWSP_PN);
+ ring->status_page.page_addr = kmap(page);
ring->status_page.obj = default_ctx_obj;
I915_WRITE(RING_HWS_PGA(ring->mmio_base),
@@ -2325,7 +2439,7 @@ static void lrc_setup_hardware_status_page(struct intel_engine_cs *ring,
}
/**
- * intel_lr_context_deferred_create() - create the LRC specific bits of a context
+ * intel_lr_context_deferred_alloc() - create the LRC specific bits of a context
* @ctx: LR context to create.
* @ring: engine to be used with the context.
*
@@ -2337,10 +2451,10 @@ static void lrc_setup_hardware_status_page(struct intel_engine_cs *ring,
*
* Return: non-zero on error.
*/
-int intel_lr_context_deferred_create(struct intel_context *ctx,
+
+int intel_lr_context_deferred_alloc(struct intel_context *ctx,
struct intel_engine_cs *ring)
{
- const bool is_global_default_ctx = (ctx == ring->default_context);
struct drm_device *dev = ring->dev;
struct drm_i915_gem_object *ctx_obj;
uint32_t context_size;
@@ -2352,107 +2466,58 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
context_size = round_up(get_lr_context_size(ring), 4096);
+ /* One extra page as the sharing data between driver and GuC */
+ context_size += PAGE_SIZE * LRC_PPHWSP_PN;
+
ctx_obj = i915_gem_alloc_object(dev, context_size);
if (!ctx_obj) {
DRM_DEBUG_DRIVER("Alloc LRC backing obj failed.\n");
return -ENOMEM;
}
- if (is_global_default_ctx) {
- ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);
- if (ret) {
- DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n",
- ret);
- drm_gem_object_unreference(&ctx_obj->base);
- return ret;
- }
- }
-
- ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
- if (!ringbuf) {
- DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
- ring->name);
- ret = -ENOMEM;
- goto error_unpin_ctx;
- }
-
- ringbuf->ring = ring;
-
- ringbuf->size = 32 * PAGE_SIZE;
- ringbuf->effective_size = ringbuf->size;
- ringbuf->head = 0;
- ringbuf->tail = 0;
- ringbuf->last_retired_head = -1;
- intel_ring_update_space(ringbuf);
-
- if (ringbuf->obj == NULL) {
- ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
- if (ret) {
- DRM_DEBUG_DRIVER(
- "Failed to allocate ringbuffer obj %s: %d\n",
- ring->name, ret);
- goto error_free_rbuf;
- }
-
- if (is_global_default_ctx) {
- ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
- if (ret) {
- DRM_ERROR(
- "Failed to pin and map ringbuffer %s: %d\n",
- ring->name, ret);
- goto error_destroy_rbuf;
- }
- }
-
+ ringbuf = intel_engine_create_ringbuffer(ring, 4 * PAGE_SIZE);
+ if (IS_ERR(ringbuf)) {
+ ret = PTR_ERR(ringbuf);
+ goto error_deref_obj;
}
ret = populate_lr_context(ctx, ctx_obj, ring, ringbuf);
if (ret) {
DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret);
- goto error;
+ goto error_ringbuf;
}
ctx->engine[ring->id].ringbuf = ringbuf;
ctx->engine[ring->id].state = ctx_obj;
- if (ctx == ring->default_context)
- lrc_setup_hardware_status_page(ring, ctx_obj);
- else if (ring->id == RCS && !ctx->rcs_initialized) {
- if (ring->init_context) {
- struct drm_i915_gem_request *req;
+ if (ctx != ring->default_context && ring->init_context) {
+ struct drm_i915_gem_request *req;
- ret = i915_gem_request_alloc(ring, ctx, &req);
- if (ret)
- return ret;
-
- ret = ring->init_context(req);
- if (ret) {
- DRM_ERROR("ring init context: %d\n", ret);
- i915_gem_request_cancel(req);
- ctx->engine[ring->id].ringbuf = NULL;
- ctx->engine[ring->id].state = NULL;
- goto error;
- }
-
- i915_add_request_no_flush(req);
+ ret = i915_gem_request_alloc(ring,
+ ctx, &req);
+ if (ret) {
+ DRM_ERROR("ring create req: %d\n",
+ ret);
+ goto error_ringbuf;
}
- ctx->rcs_initialized = true;
+ ret = ring->init_context(req);
+ if (ret) {
+ DRM_ERROR("ring init context: %d\n",
+ ret);
+ i915_gem_request_cancel(req);
+ goto error_ringbuf;
+ }
+ i915_add_request_no_flush(req);
}
-
return 0;
-error:
- if (is_global_default_ctx)
- intel_unpin_ringbuffer_obj(ringbuf);
-error_destroy_rbuf:
- intel_destroy_ringbuffer_obj(ringbuf);
-error_free_rbuf:
- kfree(ringbuf);
-error_unpin_ctx:
- if (is_global_default_ctx)
- i915_gem_object_ggtt_unpin(ctx_obj);
+error_ringbuf:
+ intel_ringbuffer_free(ringbuf);
+error_deref_obj:
drm_gem_object_unreference(&ctx_obj->base);
+ ctx->engine[ring->id].ringbuf = NULL;
+ ctx->engine[ring->id].state = NULL;
return ret;
}
@@ -2478,7 +2543,7 @@ void intel_lr_context_reset(struct drm_device *dev,
WARN(1, "Failed get_pages for context obj\n");
continue;
}
- page = i915_gem_object_get_page(ctx_obj, 1);
+ page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
reg_state = kmap_atomic(page);
reg_state[CTX_RING_HEAD+1] = 0;
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 3c63bb32ad81..4e60d54ba66d 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -30,12 +30,14 @@
/* Execlists regs */
#define RING_ELSP(ring) ((ring)->mmio_base+0x230)
-#define RING_EXECLIST_STATUS(ring) ((ring)->mmio_base+0x234)
+#define RING_EXECLIST_STATUS_LO(ring) ((ring)->mmio_base+0x234)
+#define RING_EXECLIST_STATUS_HI(ring) ((ring)->mmio_base+0x234 + 4)
#define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244)
#define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3)
#define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0)
#define CTX_CTRL_RS_CTX_ENABLE (1 << 1)
-#define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370)
+#define RING_CONTEXT_STATUS_BUF_LO(ring, i) ((ring)->mmio_base+0x370 + (i) * 8)
+#define RING_CONTEXT_STATUS_BUF_HI(ring, i) ((ring)->mmio_base+0x370 + (i) * 8 + 4)
#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0)
/* Logical Rings */
@@ -70,12 +72,20 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
}
/* Logical Ring Contexts */
+
+/* One extra page is added before LRC for GuC as shared data */
+#define LRC_GUCSHR_PN (0)
+#define LRC_PPHWSP_PN (LRC_GUCSHR_PN + 1)
+#define LRC_STATE_PN (LRC_PPHWSP_PN + 1)
+
void intel_lr_context_free(struct intel_context *ctx);
-int intel_lr_context_deferred_create(struct intel_context *ctx,
- struct intel_engine_cs *ring);
+int intel_lr_context_deferred_alloc(struct intel_context *ctx,
+ struct intel_engine_cs *ring);
void intel_lr_context_unpin(struct drm_i915_gem_request *req);
void intel_lr_context_reset(struct drm_device *dev,
struct intel_context *ctx);
+uint64_t intel_lr_context_descriptor(struct intel_context *ctx,
+ struct intel_engine_cs *ring);
/* Execlists */
int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 881b5d13592e..7f39b8ad88ae 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -98,15 +98,11 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 lvds_reg, tmp, flags = 0;
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
+ u32 tmp, flags = 0;
int dotclock;
- if (HAS_PCH_SPLIT(dev))
- lvds_reg = PCH_LVDS;
- else
- lvds_reg = LVDS;
-
- tmp = I915_READ(lvds_reg);
+ tmp = I915_READ(lvds_encoder->reg);
if (tmp & LVDS_HSYNC_POLARITY)
flags |= DRM_MODE_FLAG_NHSYNC;
else
@@ -139,8 +135,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
int pipe = crtc->pipe;
u32 temp;
@@ -289,11 +284,14 @@ intel_lvds_mode_valid(struct drm_connector *connector,
{
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
+ int max_pixclk = to_i915(connector->dev)->max_dotclk_freq;
if (mode->hdisplay > fixed_mode->hdisplay)
return MODE_PANEL;
if (mode->vdisplay > fixed_mode->vdisplay)
return MODE_PANEL;
+ if (fixed_mode->clock > max_pixclk)
+ return MODE_CLOCK_HIGH;
return MODE_OK;
}
@@ -941,6 +939,7 @@ void intel_lvds_init(struct drm_device *dev)
struct drm_display_mode *downclock_mode = NULL;
struct edid *edid;
struct drm_crtc *crtc;
+ u32 lvds_reg;
u32 lvds;
int pipe;
u8 pin;
@@ -952,7 +951,7 @@ void intel_lvds_init(struct drm_device *dev)
if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(PCH_PP_CONTROL,
I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
- } else {
+ } else if (INTEL_INFO(dev_priv)->gen < 5) {
I915_WRITE(PP_CONTROL,
I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
}
@@ -963,8 +962,15 @@ void intel_lvds_init(struct drm_device *dev)
if (dmi_check_system(intel_no_lvds))
return;
+ if (HAS_PCH_SPLIT(dev))
+ lvds_reg = PCH_LVDS;
+ else
+ lvds_reg = LVDS;
+
+ lvds = I915_READ(lvds_reg);
+
if (HAS_PCH_SPLIT(dev)) {
- if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
+ if ((lvds & LVDS_DETECTED) == 0)
return;
if (dev_priv->vbt.edp_support) {
DRM_DEBUG_KMS("disable LVDS for eDP support\n");
@@ -974,14 +980,25 @@ void intel_lvds_init(struct drm_device *dev)
pin = GMBUS_PIN_PANEL;
if (!lvds_is_present_in_vbt(dev, &pin)) {
- u32 reg = HAS_PCH_SPLIT(dev) ? PCH_LVDS : LVDS;
- if ((I915_READ(reg) & LVDS_PORT_EN) == 0) {
+ if ((lvds & LVDS_PORT_EN) == 0) {
DRM_DEBUG_KMS("LVDS is not present in VBT\n");
return;
}
DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled anyway\n");
}
+ /* Set the Panel Power On/Off timings if uninitialized. */
+ if (INTEL_INFO(dev_priv)->gen < 5 &&
+ I915_READ(PP_ON_DELAYS) == 0 && I915_READ(PP_OFF_DELAYS) == 0) {
+ /* Set T2 to 40ms and T5 to 200ms */
+ I915_WRITE(PP_ON_DELAYS, 0x019007d0);
+
+ /* Set T3 to 35ms and Tx to 200ms */
+ I915_WRITE(PP_OFF_DELAYS, 0x015e07d0);
+
+ DRM_DEBUG_KMS("Panel power timings uninitialized, setting defaults\n");
+ }
+
lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL);
if (!lvds_encoder)
return;
@@ -1040,11 +1057,7 @@ void intel_lvds_init(struct drm_device *dev)
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- if (HAS_PCH_SPLIT(dev)) {
- lvds_encoder->reg = PCH_LVDS;
- } else {
- lvds_encoder->reg = LVDS;
- }
+ lvds_encoder->reg = lvds_reg;
/* create the scaling mode property */
drm_mode_create_scaling_mode_property(dev);
@@ -1125,7 +1138,6 @@ void intel_lvds_init(struct drm_device *dev)
if (HAS_PCH_SPLIT(dev))
goto failed;
- lvds = I915_READ(LVDS);
pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
crtc = intel_get_crtc_for_pipe(dev, pipe);
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 0e860f39933d..38a4c8ce7e63 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -126,3 +126,12 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector)
drm_object_attach_property(&connector->base, prop, 0);
}
+
+void
+intel_attach_aspect_ratio_property(struct drm_connector *connector)
+{
+ if (!drm_mode_create_aspect_ratio_property(connector->dev))
+ drm_object_attach_property(&connector->base,
+ connector->dev->mode_config.aspect_ratio_property,
+ DRM_MODE_PICTURE_ASPECT_NONE);
+}
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index cb1c65739425..6dc13c02c28e 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -239,7 +239,7 @@ struct opregion_asle {
static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_swsci __iomem *swsci = dev_priv->opregion.swsci;
+ struct opregion_swsci *swsci = dev_priv->opregion.swsci;
u32 main_function, sub_function, scic;
u16 pci_swsci;
u32 dslp;
@@ -264,7 +264,7 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
}
/* Driver sleep timeout in ms. */
- dslp = ioread32(&swsci->dslp);
+ dslp = swsci->dslp;
if (!dslp) {
/* The spec says 2ms should be the default, but it's too small
* for some machines. */
@@ -277,7 +277,7 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
}
/* The spec tells us to do this, but we are the only user... */
- scic = ioread32(&swsci->scic);
+ scic = swsci->scic;
if (scic & SWSCI_SCIC_INDICATOR) {
DRM_DEBUG_DRIVER("SWSCI request already in progress\n");
return -EBUSY;
@@ -285,8 +285,8 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
scic = function | SWSCI_SCIC_INDICATOR;
- iowrite32(parm, &swsci->parm);
- iowrite32(scic, &swsci->scic);
+ swsci->parm = parm;
+ swsci->scic = scic;
/* Ensure SCI event is selected and event trigger is cleared. */
pci_read_config_word(dev->pdev, PCI_SWSCI, &pci_swsci);
@@ -301,7 +301,7 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
pci_write_config_word(dev->pdev, PCI_SWSCI, pci_swsci);
/* Poll for the result. */
-#define C (((scic = ioread32(&swsci->scic)) & SWSCI_SCIC_INDICATOR) == 0)
+#define C (((scic = swsci->scic) & SWSCI_SCIC_INDICATOR) == 0)
if (wait_for(C, dslp)) {
DRM_DEBUG_DRIVER("SWSCI request timed out\n");
return -ETIMEDOUT;
@@ -317,7 +317,7 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
}
if (parm_out)
- *parm_out = ioread32(&swsci->parm);
+ *parm_out = swsci->parm;
return 0;
@@ -341,8 +341,12 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
if (!HAS_DDI(dev))
return 0;
- port = intel_ddi_get_encoder_port(intel_encoder);
- if (port == PORT_E) {
+ if (intel_encoder->type == INTEL_OUTPUT_DSI)
+ port = 0;
+ else
+ port = intel_ddi_get_encoder_port(intel_encoder);
+
+ if (port == PORT_E) {
port = 0;
} else {
parm |= 1 << port;
@@ -363,6 +367,7 @@ int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder,
type = DISPLAY_TYPE_EXTERNAL_FLAT_PANEL;
break;
case INTEL_OUTPUT_EDP:
+ case INTEL_OUTPUT_DSI:
type = DISPLAY_TYPE_INTERNAL_FLAT_PANEL;
break;
default:
@@ -407,7 +412,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_connector *intel_connector;
- struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
@@ -432,7 +437,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head)
intel_panel_set_backlight_acpi(intel_connector, bclp, 255);
- iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
+ asle->cblv = DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID;
drm_modeset_unlock(&dev->mode_config.connection_mutex);
@@ -519,14 +524,14 @@ static void asle_work(struct work_struct *work)
struct drm_i915_private *dev_priv =
container_of(opregion, struct drm_i915_private, opregion);
struct drm_device *dev = dev_priv->dev;
- struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
u32 aslc_stat = 0;
u32 aslc_req;
if (!asle)
return;
- aslc_req = ioread32(&asle->aslc);
+ aslc_req = asle->aslc;
if (!(aslc_req & ASLC_REQ_MSK)) {
DRM_DEBUG_DRIVER("No request on ASLC interrupt 0x%08x\n",
@@ -535,34 +540,34 @@ static void asle_work(struct work_struct *work)
}
if (aslc_req & ASLC_SET_ALS_ILLUM)
- aslc_stat |= asle_set_als_illum(dev, ioread32(&asle->alsi));
+ aslc_stat |= asle_set_als_illum(dev, asle->alsi);
if (aslc_req & ASLC_SET_BACKLIGHT)
- aslc_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
+ aslc_stat |= asle_set_backlight(dev, asle->bclp);
if (aslc_req & ASLC_SET_PFIT)
- aslc_stat |= asle_set_pfit(dev, ioread32(&asle->pfit));
+ aslc_stat |= asle_set_pfit(dev, asle->pfit);
if (aslc_req & ASLC_SET_PWM_FREQ)
- aslc_stat |= asle_set_pwm_freq(dev, ioread32(&asle->pfmb));
+ aslc_stat |= asle_set_pwm_freq(dev, asle->pfmb);
if (aslc_req & ASLC_SUPPORTED_ROTATION_ANGLES)
aslc_stat |= asle_set_supported_rotation_angles(dev,
- ioread32(&asle->srot));
+ asle->srot);
if (aslc_req & ASLC_BUTTON_ARRAY)
- aslc_stat |= asle_set_button_array(dev, ioread32(&asle->iuer));
+ aslc_stat |= asle_set_button_array(dev, asle->iuer);
if (aslc_req & ASLC_CONVERTIBLE_INDICATOR)
- aslc_stat |= asle_set_convertible(dev, ioread32(&asle->iuer));
+ aslc_stat |= asle_set_convertible(dev, asle->iuer);
if (aslc_req & ASLC_DOCKING_INDICATOR)
- aslc_stat |= asle_set_docking(dev, ioread32(&asle->iuer));
+ aslc_stat |= asle_set_docking(dev, asle->iuer);
if (aslc_req & ASLC_ISCT_STATE_CHANGE)
aslc_stat |= asle_isct_state(dev);
- iowrite32(aslc_stat, &asle->aslc);
+ asle->aslc = aslc_stat;
}
void intel_opregion_asle_intr(struct drm_device *dev)
@@ -587,8 +592,8 @@ static int intel_opregion_video_event(struct notifier_block *nb,
Linux, these are handled by the dock, button and video drivers.
*/
- struct opregion_acpi __iomem *acpi;
struct acpi_bus_event *event = data;
+ struct opregion_acpi *acpi;
int ret = NOTIFY_OK;
if (strcmp(event->device_class, ACPI_VIDEO_CLASS) != 0)
@@ -599,11 +604,10 @@ static int intel_opregion_video_event(struct notifier_block *nb,
acpi = system_opregion->acpi;
- if (event->type == 0x80 &&
- (ioread32(&acpi->cevt) & 1) == 0)
+ if (event->type == 0x80 && ((acpi->cevt & 1) == 0))
ret = NOTIFY_BAD;
- iowrite32(0, &acpi->csts);
+ acpi->csts = 0;
return ret;
}
@@ -623,14 +627,14 @@ static u32 get_did(struct intel_opregion *opregion, int i)
u32 did;
if (i < ARRAY_SIZE(opregion->acpi->didl)) {
- did = ioread32(&opregion->acpi->didl[i]);
+ did = opregion->acpi->didl[i];
} else {
i -= ARRAY_SIZE(opregion->acpi->didl);
if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2)))
return 0;
- did = ioread32(&opregion->acpi->did2[i]);
+ did = opregion->acpi->did2[i];
}
return did;
@@ -639,14 +643,14 @@ static u32 get_did(struct intel_opregion *opregion, int i)
static void set_did(struct intel_opregion *opregion, int i, u32 val)
{
if (i < ARRAY_SIZE(opregion->acpi->didl)) {
- iowrite32(val, &opregion->acpi->didl[i]);
+ opregion->acpi->didl[i] = val;
} else {
i -= ARRAY_SIZE(opregion->acpi->didl);
if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2)))
return;
- iowrite32(val, &opregion->acpi->did2[i]);
+ opregion->acpi->did2[i] = val;
}
}
@@ -768,7 +772,7 @@ static void intel_setup_cadls(struct drm_device *dev)
* there are less than eight devices. */
do {
disp_id = get_did(opregion, i);
- iowrite32(disp_id, &opregion->acpi->cadl[i]);
+ opregion->acpi->cadl[i] = disp_id;
} while (++i < 8 && disp_id != 0);
}
@@ -787,16 +791,16 @@ void intel_opregion_init(struct drm_device *dev)
/* Notify BIOS we are ready to handle ACPI video ext notifs.
* Right now, all the events are handled by the ACPI video module.
* We don't actually need to do anything with them. */
- iowrite32(0, &opregion->acpi->csts);
- iowrite32(1, &opregion->acpi->drdy);
+ opregion->acpi->csts = 0;
+ opregion->acpi->drdy = 1;
system_opregion = opregion;
register_acpi_notifier(&intel_opregion_notifier);
}
if (opregion->asle) {
- iowrite32(ASLE_TCHE_BLC_EN, &opregion->asle->tche);
- iowrite32(ASLE_ARDY_READY, &opregion->asle->ardy);
+ opregion->asle->tche = ASLE_TCHE_BLC_EN;
+ opregion->asle->ardy = ASLE_ARDY_READY;
}
}
@@ -809,19 +813,19 @@ void intel_opregion_fini(struct drm_device *dev)
return;
if (opregion->asle)
- iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy);
+ opregion->asle->ardy = ASLE_ARDY_NOT_READY;
cancel_work_sync(&dev_priv->opregion.asle_work);
if (opregion->acpi) {
- iowrite32(0, &opregion->acpi->drdy);
+ opregion->acpi->drdy = 0;
system_opregion = NULL;
unregister_acpi_notifier(&intel_opregion_notifier);
}
/* just clear all opregion memory pointers now */
- iounmap(opregion->header);
+ memunmap(opregion->header);
opregion->header = NULL;
opregion->acpi = NULL;
opregion->swsci = NULL;
@@ -894,10 +898,10 @@ int intel_opregion_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
- void __iomem *base;
u32 asls, mboxes;
char buf[sizeof(OPREGION_SIGNATURE)];
int err = 0;
+ void *base;
BUILD_BUG_ON(sizeof(struct opregion_header) != 0x100);
BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100);
@@ -915,11 +919,11 @@ int intel_opregion_setup(struct drm_device *dev)
INIT_WORK(&opregion->asle_work, asle_work);
#endif
- base = acpi_os_ioremap(asls, OPREGION_SIZE);
+ base = memremap(asls, OPREGION_SIZE, MEMREMAP_WB);
if (!base)
return -ENOMEM;
- memcpy_fromio(buf, base, sizeof(buf));
+ memcpy(buf, base, sizeof(buf));
if (memcmp(buf, OPREGION_SIGNATURE, 16)) {
DRM_DEBUG_DRIVER("opregion signature mismatch\n");
@@ -931,7 +935,7 @@ int intel_opregion_setup(struct drm_device *dev)
opregion->lid_state = base + ACPI_CLID;
- mboxes = ioread32(&opregion->header->mboxes);
+ mboxes = opregion->header->mboxes;
if (mboxes & MBOX_ACPI) {
DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
opregion->acpi = base + OPREGION_ACPI_OFFSET;
@@ -946,12 +950,12 @@ int intel_opregion_setup(struct drm_device *dev)
DRM_DEBUG_DRIVER("ASLE supported\n");
opregion->asle = base + OPREGION_ASLE_OFFSET;
- iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy);
+ opregion->asle->ardy = ASLE_ARDY_NOT_READY;
}
return 0;
err_out:
- iounmap(base);
+ memunmap(base);
return err;
}
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index e2ab3f6ed022..a24df35e11e7 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -105,59 +105,55 @@ intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
struct intel_crtc_state *pipe_config,
int fitting_mode)
{
- struct drm_display_mode *adjusted_mode;
- int x, y, width, height;
-
- adjusted_mode = &pipe_config->base.adjusted_mode;
-
- x = y = width = height = 0;
+ const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ int x = 0, y = 0, width = 0, height = 0;
/* Native modes don't need fitting */
- if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
- adjusted_mode->vdisplay == pipe_config->pipe_src_h)
+ if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
+ adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h)
goto done;
switch (fitting_mode) {
case DRM_MODE_SCALE_CENTER:
width = pipe_config->pipe_src_w;
height = pipe_config->pipe_src_h;
- x = (adjusted_mode->hdisplay - width + 1)/2;
- y = (adjusted_mode->vdisplay - height + 1)/2;
+ x = (adjusted_mode->crtc_hdisplay - width + 1)/2;
+ y = (adjusted_mode->crtc_vdisplay - height + 1)/2;
break;
case DRM_MODE_SCALE_ASPECT:
/* Scale but preserve the aspect ratio */
{
- u32 scaled_width = adjusted_mode->hdisplay
+ u32 scaled_width = adjusted_mode->crtc_hdisplay
* pipe_config->pipe_src_h;
u32 scaled_height = pipe_config->pipe_src_w
- * adjusted_mode->vdisplay;
+ * adjusted_mode->crtc_vdisplay;
if (scaled_width > scaled_height) { /* pillar */
width = scaled_height / pipe_config->pipe_src_h;
if (width & 1)
width++;
- x = (adjusted_mode->hdisplay - width + 1) / 2;
+ x = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
y = 0;
- height = adjusted_mode->vdisplay;
+ height = adjusted_mode->crtc_vdisplay;
} else if (scaled_width < scaled_height) { /* letter */
height = scaled_width / pipe_config->pipe_src_w;
if (height & 1)
height++;
- y = (adjusted_mode->vdisplay - height + 1) / 2;
+ y = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
x = 0;
- width = adjusted_mode->hdisplay;
+ width = adjusted_mode->crtc_hdisplay;
} else {
x = y = 0;
- width = adjusted_mode->hdisplay;
- height = adjusted_mode->vdisplay;
+ width = adjusted_mode->crtc_hdisplay;
+ height = adjusted_mode->crtc_vdisplay;
}
}
break;
case DRM_MODE_SCALE_FULLSCREEN:
x = y = 0;
- width = adjusted_mode->hdisplay;
- height = adjusted_mode->vdisplay;
+ width = adjusted_mode->crtc_hdisplay;
+ height = adjusted_mode->crtc_vdisplay;
break;
default:
@@ -172,46 +168,46 @@ done:
}
static void
-centre_horizontally(struct drm_display_mode *mode,
+centre_horizontally(struct drm_display_mode *adjusted_mode,
int width)
{
u32 border, sync_pos, blank_width, sync_width;
/* keep the hsync and hblank widths constant */
- sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
- blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
+ sync_width = adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+ blank_width = adjusted_mode->crtc_hblank_end - adjusted_mode->crtc_hblank_start;
sync_pos = (blank_width - sync_width + 1) / 2;
- border = (mode->hdisplay - width + 1) / 2;
+ border = (adjusted_mode->crtc_hdisplay - width + 1) / 2;
border += border & 1; /* make the border even */
- mode->crtc_hdisplay = width;
- mode->crtc_hblank_start = width + border;
- mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
+ adjusted_mode->crtc_hdisplay = width;
+ adjusted_mode->crtc_hblank_start = width + border;
+ adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_hblank_start + blank_width;
- mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
- mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
+ adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hblank_start + sync_pos;
+ adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + sync_width;
}
static void
-centre_vertically(struct drm_display_mode *mode,
+centre_vertically(struct drm_display_mode *adjusted_mode,
int height)
{
u32 border, sync_pos, blank_width, sync_width;
/* keep the vsync and vblank widths constant */
- sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
- blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
+ sync_width = adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
+ blank_width = adjusted_mode->crtc_vblank_end - adjusted_mode->crtc_vblank_start;
sync_pos = (blank_width - sync_width + 1) / 2;
- border = (mode->vdisplay - height + 1) / 2;
+ border = (adjusted_mode->crtc_vdisplay - height + 1) / 2;
- mode->crtc_vdisplay = height;
- mode->crtc_vblank_start = height + border;
- mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
+ adjusted_mode->crtc_vdisplay = height;
+ adjusted_mode->crtc_vblank_start = height + border;
+ adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vblank_start + blank_width;
- mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
- mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
+ adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vblank_start + sync_pos;
+ adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + sync_width;
}
static inline u32 panel_fitter_scaling(u32 source, u32 target)
@@ -230,11 +226,11 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target)
static void i965_scale_aspect(struct intel_crtc_state *pipe_config,
u32 *pfit_control)
{
- struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
- u32 scaled_width = adjusted_mode->hdisplay *
+ const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ u32 scaled_width = adjusted_mode->crtc_hdisplay *
pipe_config->pipe_src_h;
u32 scaled_height = pipe_config->pipe_src_w *
- adjusted_mode->vdisplay;
+ adjusted_mode->crtc_vdisplay;
/* 965+ is easy, it does everything in hw */
if (scaled_width > scaled_height)
@@ -243,7 +239,7 @@ static void i965_scale_aspect(struct intel_crtc_state *pipe_config,
else if (scaled_width < scaled_height)
*pfit_control |= PFIT_ENABLE |
PFIT_SCALING_LETTER;
- else if (adjusted_mode->hdisplay != pipe_config->pipe_src_w)
+ else if (adjusted_mode->crtc_hdisplay != pipe_config->pipe_src_w)
*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
}
@@ -252,10 +248,10 @@ static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
u32 *border)
{
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
- u32 scaled_width = adjusted_mode->hdisplay *
+ u32 scaled_width = adjusted_mode->crtc_hdisplay *
pipe_config->pipe_src_h;
u32 scaled_height = pipe_config->pipe_src_w *
- adjusted_mode->vdisplay;
+ adjusted_mode->crtc_vdisplay;
u32 bits;
/*
@@ -269,9 +265,9 @@ static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
pipe_config->pipe_src_h);
*border = LVDS_BORDER_ENABLE;
- if (pipe_config->pipe_src_h != adjusted_mode->vdisplay) {
+ if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay) {
bits = panel_fitter_scaling(pipe_config->pipe_src_h,
- adjusted_mode->vdisplay);
+ adjusted_mode->crtc_vdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
bits << PFIT_VERT_SCALE_SHIFT);
@@ -285,9 +281,9 @@ static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
pipe_config->pipe_src_w);
*border = LVDS_BORDER_ENABLE;
- if (pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
+ if (pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) {
bits = panel_fitter_scaling(pipe_config->pipe_src_w,
- adjusted_mode->hdisplay);
+ adjusted_mode->crtc_hdisplay);
*pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
bits << PFIT_VERT_SCALE_SHIFT);
@@ -310,13 +306,11 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
{
struct drm_device *dev = intel_crtc->base.dev;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
- struct drm_display_mode *adjusted_mode;
-
- adjusted_mode = &pipe_config->base.adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
/* Native modes don't need fitting */
- if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
- adjusted_mode->vdisplay == pipe_config->pipe_src_h)
+ if (adjusted_mode->crtc_hdisplay == pipe_config->pipe_src_w &&
+ adjusted_mode->crtc_vdisplay == pipe_config->pipe_src_h)
goto out;
switch (fitting_mode) {
@@ -342,8 +336,8 @@ void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
* Full scaling, even if it changes the aspect ratio.
* Fortunately this is all done for us in hw.
*/
- if (pipe_config->pipe_src_h != adjusted_mode->vdisplay ||
- pipe_config->pipe_src_w != adjusted_mode->hdisplay) {
+ if (pipe_config->pipe_src_h != adjusted_mode->crtc_vdisplay ||
+ pipe_config->pipe_src_w != adjusted_mode->crtc_hdisplay) {
pfit_control |= PFIT_ENABLE;
if (INTEL_INFO(dev)->gen >= 4)
pfit_control |= PFIT_SCALING_AUTO;
@@ -387,7 +381,7 @@ intel_panel_detect(struct drm_device *dev)
/* Assume that the BIOS does not lie through the OpRegion... */
if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) {
- return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
+ return *dev_priv->opregion.lid_state & 0x1 ?
connector_status_connected :
connector_status_disconnected;
}
@@ -484,7 +478,7 @@ static u32 intel_panel_compute_brightness(struct intel_connector *connector,
return val;
}
-static u32 bdw_get_backlight(struct intel_connector *connector)
+static u32 lpt_get_backlight(struct intel_connector *connector)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -542,9 +536,10 @@ static u32 vlv_get_backlight(struct intel_connector *connector)
static u32 bxt_get_backlight(struct intel_connector *connector)
{
struct drm_device *dev = connector->base.dev;
+ struct intel_panel *panel = &connector->panel;
struct drm_i915_private *dev_priv = dev->dev_private;
- return I915_READ(BXT_BLC_PWM_DUTY1);
+ return I915_READ(BXT_BLC_PWM_DUTY(panel->backlight.controller));
}
static u32 pwm_get_backlight(struct intel_connector *connector)
@@ -566,7 +561,7 @@ static u32 intel_panel_get_backlight(struct intel_connector *connector)
mutex_lock(&dev_priv->backlight_lock);
if (panel->backlight.enabled) {
- val = dev_priv->display.get_backlight(connector);
+ val = panel->backlight.get(connector);
val = intel_panel_compute_brightness(connector, val);
}
@@ -576,7 +571,7 @@ static u32 intel_panel_get_backlight(struct intel_connector *connector)
return val;
}
-static void bdw_set_backlight(struct intel_connector *connector, u32 level)
+static void lpt_set_backlight(struct intel_connector *connector, u32 level)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -640,8 +635,9 @@ static void bxt_set_backlight(struct intel_connector *connector, u32 level)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_panel *panel = &connector->panel;
- I915_WRITE(BXT_BLC_PWM_DUTY1, level);
+ I915_WRITE(BXT_BLC_PWM_DUTY(panel->backlight.controller), level);
}
static void pwm_set_backlight(struct intel_connector *connector, u32 level)
@@ -655,13 +651,12 @@ static void pwm_set_backlight(struct intel_connector *connector, u32 level)
static void
intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
{
- struct drm_device *dev = connector->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_panel *panel = &connector->panel;
DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
level = intel_panel_compute_brightness(connector, level);
- dev_priv->display.set_backlight(connector, level);
+ panel->backlight.set(connector, level);
}
/* set backlight brightness to level in range [0..max], scaling wrt hw min */
@@ -729,6 +724,32 @@ void intel_panel_set_backlight_acpi(struct intel_connector *connector,
mutex_unlock(&dev_priv->backlight_lock);
}
+static void lpt_disable_backlight(struct intel_connector *connector)
+{
+ struct drm_device *dev = connector->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 tmp;
+
+ intel_panel_actually_set_backlight(connector, 0);
+
+ /*
+ * Although we don't support or enable CPU PWM with LPT/SPT based
+ * systems, it may have been enabled prior to loading the
+ * driver. Disable to avoid warnings on LCPLL disable.
+ *
+ * This needs rework if we need to add support for CPU PWM on PCH split
+ * platforms.
+ */
+ tmp = I915_READ(BLC_PWM_CPU_CTL2);
+ if (tmp & BLM_PWM_ENABLE) {
+ DRM_DEBUG_KMS("cpu backlight was enabled, disabling\n");
+ I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+ }
+
+ tmp = I915_READ(BLC_PWM_PCH_CTL1);
+ I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+}
+
static void pch_disable_backlight(struct intel_connector *connector)
{
struct drm_device *dev = connector->base.dev;
@@ -781,12 +802,20 @@ static void bxt_disable_backlight(struct intel_connector *connector)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 tmp;
+ struct intel_panel *panel = &connector->panel;
+ u32 tmp, val;
intel_panel_actually_set_backlight(connector, 0);
- tmp = I915_READ(BXT_BLC_PWM_CTL1);
- I915_WRITE(BXT_BLC_PWM_CTL1, tmp & ~BXT_BLC_PWM_ENABLE);
+ tmp = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+ I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+ tmp & ~BXT_BLC_PWM_ENABLE);
+
+ if (panel->backlight.controller == 1) {
+ val = I915_READ(UTIL_PIN_CTL);
+ val &= ~UTIL_PIN_ENABLE;
+ I915_WRITE(UTIL_PIN_CTL, val);
+ }
}
static void pwm_disable_backlight(struct intel_connector *connector)
@@ -809,7 +838,7 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
return;
/*
- * Do not disable backlight on the vgaswitcheroo path. When switching
+ * Do not disable backlight on the vga_switcheroo path. When switching
* away from i915, the other client may depend on i915 to handle the
* backlight. This will leave the backlight on unnecessarily when
* another client is not activated.
@@ -824,12 +853,12 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
if (panel->backlight.device)
panel->backlight.device->props.power = FB_BLANK_POWERDOWN;
panel->backlight.enabled = false;
- dev_priv->display.disable_backlight(connector);
+ panel->backlight.disable(connector);
mutex_unlock(&dev_priv->backlight_lock);
}
-static void bdw_enable_backlight(struct intel_connector *connector)
+static void lpt_enable_backlight(struct intel_connector *connector)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1018,16 +1047,38 @@ static void bxt_enable_backlight(struct intel_connector *connector)
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_panel *panel = &connector->panel;
- u32 pwm_ctl;
+ enum pipe pipe = intel_get_pipe_from_connector(connector);
+ u32 pwm_ctl, val;
+
+ /* To use 2nd set of backlight registers, utility pin has to be
+ * enabled with PWM mode.
+ * The field should only be changed when the utility pin is disabled
+ */
+ if (panel->backlight.controller == 1) {
+ val = I915_READ(UTIL_PIN_CTL);
+ if (val & UTIL_PIN_ENABLE) {
+ DRM_DEBUG_KMS("util pin already enabled\n");
+ val &= ~UTIL_PIN_ENABLE;
+ I915_WRITE(UTIL_PIN_CTL, val);
+ }
- pwm_ctl = I915_READ(BXT_BLC_PWM_CTL1);
+ val = 0;
+ if (panel->backlight.util_pin_active_low)
+ val |= UTIL_PIN_POLARITY;
+ I915_WRITE(UTIL_PIN_CTL, val | UTIL_PIN_PIPE(pipe) |
+ UTIL_PIN_MODE_PWM | UTIL_PIN_ENABLE);
+ }
+
+ pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
if (pwm_ctl & BXT_BLC_PWM_ENABLE) {
DRM_DEBUG_KMS("backlight already enabled\n");
pwm_ctl &= ~BXT_BLC_PWM_ENABLE;
- I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl);
+ I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+ pwm_ctl);
}
- I915_WRITE(BXT_BLC_PWM_FREQ1, panel->backlight.max);
+ I915_WRITE(BXT_BLC_PWM_FREQ(panel->backlight.controller),
+ panel->backlight.max);
intel_panel_actually_set_backlight(connector, panel->backlight.level);
@@ -1035,9 +1086,10 @@ static void bxt_enable_backlight(struct intel_connector *connector)
if (panel->backlight.active_low_pwm)
pwm_ctl |= BXT_BLC_PWM_POLARITY;
- I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl);
- POSTING_READ(BXT_BLC_PWM_CTL1);
- I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl | BXT_BLC_PWM_ENABLE);
+ I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller), pwm_ctl);
+ POSTING_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+ I915_WRITE(BXT_BLC_PWM_CTL(panel->backlight.controller),
+ pwm_ctl | BXT_BLC_PWM_ENABLE);
}
static void pwm_enable_backlight(struct intel_connector *connector)
@@ -1073,7 +1125,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
panel->backlight.device->props.max_brightness);
}
- dev_priv->display.enable_backlight(connector);
+ panel->backlight.enable(connector);
panel->backlight.enabled = true;
if (panel->backlight.device)
panel->backlight.device->props.power = FB_BLANK_UNBLANK;
@@ -1101,10 +1153,10 @@ static int intel_backlight_device_update_status(struct backlight_device *bd)
* callback needs to take this into account.
*/
if (panel->backlight.enabled) {
- if (panel->backlight_power) {
+ if (panel->backlight.power) {
bool enable = bd->props.power == FB_BLANK_UNBLANK &&
bd->props.brightness != 0;
- panel->backlight_power(connector, enable);
+ panel->backlight.power(connector, enable);
}
} else {
bd->props.power = FB_BLANK_POWERDOWN;
@@ -1212,10 +1264,150 @@ static void intel_backlight_device_unregister(struct intel_connector *connector)
#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
/*
- * Note: The setup hooks can't assume pipe is set!
+ * SPT: This value represents the period of the PWM stream in clock periods
+ * multiplied by 16 (default increment) or 128 (alternate increment selected in
+ * SCHICKEN_1 bit 0). PWM clock is 24 MHz.
+ */
+static u32 spt_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;
+ u32 mul, clock;
+
+ if (I915_READ(SOUTH_CHICKEN1) & SPT_PWM_GRANULARITY)
+ mul = 128;
+ else
+ mul = 16;
+
+ clock = MHz(24);
+
+ return clock / (pwm_freq_hz * mul);
+}
+
+/*
+ * LPT: This value represents the period of the PWM stream in clock periods
+ * multiplied by 128 (default increment) or 16 (alternate increment, selected in
+ * LPT SOUTH_CHICKEN2 register bit 5).
+ */
+static u32 lpt_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;
+ u32 mul, clock;
+
+ if (I915_READ(SOUTH_CHICKEN2) & LPT_PWM_GRANULARITY)
+ mul = 16;
+ else
+ mul = 128;
+
+ if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE)
+ clock = MHz(135); /* LPT:H */
+ else
+ clock = MHz(24); /* LPT:LP */
+
+ return clock / (pwm_freq_hz * mul);
+}
+
+/*
+ * ILK/SNB/IVB: This value represents the period of the PWM stream in PCH
+ * display raw clocks multiplied by 128.
+ */
+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));
+
+ return clock / (pwm_freq_hz * 128);
+}
+
+/*
+ * Gen2: This field determines the number of time base events (display core
+ * clock frequency/32) in total for a complete cycle of modulated backlight
+ * control.
*
- * XXX: Query mode clock or hardware clock and program PWM modulation frequency
- * appropriately when it's 0. Use VBT and/or sane defaults.
+ * Gen3: A time base event equals the display core clock ([DevPNV] HRAW clock)
+ * divided by 32.
+ */
+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;
+ int clock;
+
+ if (IS_PINEVIEW(dev))
+ clock = intel_hrawclk(dev);
+ else
+ clock = 1000 * dev_priv->display.get_display_clock_speed(dev);
+
+ return clock / (pwm_freq_hz * 32);
+}
+
+/*
+ * Gen4: This value represents the period of the PWM stream in display core
+ * clocks multiplied by 128.
+ */
+static u32 i965_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 = 1000 * dev_priv->display.get_display_clock_speed(dev);
+
+ return clock / (pwm_freq_hz * 128);
+}
+
+/*
+ * VLV: This value represents the period of the PWM stream in display core
+ * clocks ([DevCTG] 200MHz HRAW clocks) multiplied by 128 or 25MHz S0IX clocks
+ * multiplied by 16. CHV uses a 19.2MHz S0IX clock.
+ */
+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;
+
+ if ((I915_READ(CBR1_VLV) & CBR_PWM_CLOCK_MUX_SELECT) == 0) {
+ if (IS_CHERRYVIEW(dev))
+ return KHz(19200) / (pwm_freq_hz * 16);
+ else
+ return MHz(25) / (pwm_freq_hz * 16);
+ } else {
+ clock = intel_hrawclk(dev);
+ return MHz(clock) / (pwm_freq_hz * 128);
+ }
+}
+
+static u32 get_backlight_max_vbt(struct intel_connector *connector)
+{
+ struct drm_device *dev = connector->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_panel *panel = &connector->panel;
+ u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz;
+ u32 pwm;
+
+ if (!pwm_freq_hz) {
+ DRM_DEBUG_KMS("backlight frequency not specified in VBT\n");
+ return 0;
+ }
+
+ if (!panel->backlight.hz_to_pwm) {
+ DRM_DEBUG_KMS("backlight frequency setting from VBT currently not supported on this platform\n");
+ return 0;
+ }
+
+ pwm = panel->backlight.hz_to_pwm(connector, pwm_freq_hz);
+ if (!pwm) {
+ DRM_DEBUG_KMS("backlight frequency conversion failed\n");
+ return 0;
+ }
+
+ DRM_DEBUG_KMS("backlight frequency %u Hz from VBT\n", pwm_freq_hz);
+
+ return pwm;
+}
+
+/*
+ * Note: The setup hooks can't assume pipe is set!
*/
static u32 get_backlight_min_vbt(struct intel_connector *connector)
{
@@ -1243,7 +1435,7 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector)
return scale(min, 0, 255, 0, panel->backlight.max);
}
-static int bdw_setup_backlight(struct intel_connector *connector, enum pipe unused)
+static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unused)
{
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1255,12 +1447,16 @@ static int bdw_setup_backlight(struct intel_connector *connector, enum pipe unus
pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
panel->backlight.max = pch_ctl2 >> 16;
+
+ if (!panel->backlight.max)
+ panel->backlight.max = get_backlight_max_vbt(connector);
+
if (!panel->backlight.max)
return -ENODEV;
panel->backlight.min = get_backlight_min_vbt(connector);
- val = bdw_get_backlight(connector);
+ val = lpt_get_backlight(connector);
panel->backlight.level = intel_panel_compute_brightness(connector, val);
panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
@@ -1281,6 +1477,10 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
panel->backlight.max = pch_ctl2 >> 16;
+
+ if (!panel->backlight.max)
+ panel->backlight.max = get_backlight_max_vbt(connector);
+
if (!panel->backlight.max)
return -ENODEV;
@@ -1312,12 +1512,18 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu
panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
panel->backlight.max = ctl >> 17;
- if (panel->backlight.combination_mode)
- panel->backlight.max *= 0xff;
+
+ if (!panel->backlight.max) {
+ panel->backlight.max = get_backlight_max_vbt(connector);
+ panel->backlight.max >>= 1;
+ }
if (!panel->backlight.max)
return -ENODEV;
+ if (panel->backlight.combination_mode)
+ panel->backlight.max *= 0xff;
+
panel->backlight.min = get_backlight_min_vbt(connector);
val = i9xx_get_backlight(connector);
@@ -1341,12 +1547,16 @@ static int i965_setup_backlight(struct intel_connector *connector, enum pipe unu
ctl = I915_READ(BLC_PWM_CTL);
panel->backlight.max = ctl >> 16;
- if (panel->backlight.combination_mode)
- panel->backlight.max *= 0xff;
+
+ if (!panel->backlight.max)
+ panel->backlight.max = get_backlight_max_vbt(connector);
if (!panel->backlight.max)
return -ENODEV;
+ if (panel->backlight.combination_mode)
+ panel->backlight.max *= 0xff;
+
panel->backlight.min = get_backlight_min_vbt(connector);
val = i9xx_get_backlight(connector);
@@ -1363,21 +1573,8 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
struct drm_device *dev = connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_panel *panel = &connector->panel;
- enum pipe p;
u32 ctl, ctl2, val;
- for_each_pipe(dev_priv, p) {
- u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(p));
-
- /* Skip if the modulation freq is already set */
- if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
- continue;
-
- cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
- I915_WRITE(VLV_BLC_PWM_CTL(p), (0xf42 << 16) |
- cur_val);
- }
-
if (WARN_ON(pipe != PIPE_A && pipe != PIPE_B))
return -ENODEV;
@@ -1386,6 +1583,10 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
ctl = I915_READ(VLV_BLC_PWM_CTL(pipe));
panel->backlight.max = ctl >> 16;
+
+ if (!panel->backlight.max)
+ panel->backlight.max = get_backlight_max_vbt(connector);
+
if (!panel->backlight.max)
return -ENODEV;
@@ -1408,10 +1609,32 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
struct intel_panel *panel = &connector->panel;
u32 pwm_ctl, val;
- pwm_ctl = I915_READ(BXT_BLC_PWM_CTL1);
+ /*
+ * For BXT hard coding the Backlight controller to 0.
+ * TODO : Read the controller value from VBT and generalize
+ */
+ panel->backlight.controller = 0;
+
+ pwm_ctl = I915_READ(BXT_BLC_PWM_CTL(panel->backlight.controller));
+
+ /* Keeping the check if controller 1 is to be programmed.
+ * This will come into affect once the VBT parsing
+ * is fixed for controller selection, and controller 1 is used
+ * for a prticular display configuration.
+ */
+ if (panel->backlight.controller == 1) {
+ val = I915_READ(UTIL_PIN_CTL);
+ panel->backlight.util_pin_active_low =
+ val & UTIL_PIN_POLARITY;
+ }
+
panel->backlight.active_low_pwm = pwm_ctl & BXT_BLC_PWM_POLARITY;
+ panel->backlight.max =
+ I915_READ(BXT_BLC_PWM_FREQ(panel->backlight.controller));
+
+ if (!panel->backlight.max)
+ panel->backlight.max = get_backlight_max_vbt(connector);
- panel->backlight.max = I915_READ(BXT_BLC_PWM_FREQ1);
if (!panel->backlight.max)
return -ENODEV;
@@ -1475,9 +1698,13 @@ int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe)
}
}
+ /* ensure intel_panel has been initialized first */
+ if (WARN_ON(!panel->backlight.setup))
+ return -ENODEV;
+
/* set level and max in panel struct */
mutex_lock(&dev_priv->backlight_lock);
- ret = dev_priv->display.setup_backlight(intel_connector, pipe);
+ ret = panel->backlight.setup(intel_connector, pipe);
mutex_unlock(&dev_priv->backlight_lock);
if (ret) {
@@ -1509,54 +1736,66 @@ void intel_panel_destroy_backlight(struct drm_connector *connector)
}
/* Set up chip specific backlight functions */
-void intel_panel_init_backlight_funcs(struct drm_device *dev)
+static void
+intel_panel_init_backlight_funcs(struct intel_panel *panel)
{
+ struct intel_connector *intel_connector =
+ container_of(panel, struct intel_connector, panel);
+ struct drm_device *dev = intel_connector->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
if (IS_BROXTON(dev)) {
- dev_priv->display.setup_backlight = bxt_setup_backlight;
- dev_priv->display.enable_backlight = bxt_enable_backlight;
- dev_priv->display.disable_backlight = bxt_disable_backlight;
- dev_priv->display.set_backlight = bxt_set_backlight;
- dev_priv->display.get_backlight = bxt_get_backlight;
- } else if (IS_BROADWELL(dev) || IS_SKYLAKE(dev)) {
- dev_priv->display.setup_backlight = bdw_setup_backlight;
- dev_priv->display.enable_backlight = bdw_enable_backlight;
- dev_priv->display.disable_backlight = pch_disable_backlight;
- dev_priv->display.set_backlight = bdw_set_backlight;
- dev_priv->display.get_backlight = bdw_get_backlight;
+ panel->backlight.setup = bxt_setup_backlight;
+ panel->backlight.enable = bxt_enable_backlight;
+ panel->backlight.disable = bxt_disable_backlight;
+ panel->backlight.set = bxt_set_backlight;
+ panel->backlight.get = bxt_get_backlight;
+ } else if (HAS_PCH_LPT(dev) || HAS_PCH_SPT(dev)) {
+ panel->backlight.setup = lpt_setup_backlight;
+ panel->backlight.enable = lpt_enable_backlight;
+ panel->backlight.disable = lpt_disable_backlight;
+ panel->backlight.set = lpt_set_backlight;
+ panel->backlight.get = lpt_get_backlight;
+ if (HAS_PCH_LPT(dev))
+ panel->backlight.hz_to_pwm = lpt_hz_to_pwm;
+ else
+ panel->backlight.hz_to_pwm = spt_hz_to_pwm;
} else if (HAS_PCH_SPLIT(dev)) {
- dev_priv->display.setup_backlight = pch_setup_backlight;
- dev_priv->display.enable_backlight = pch_enable_backlight;
- dev_priv->display.disable_backlight = pch_disable_backlight;
- dev_priv->display.set_backlight = pch_set_backlight;
- dev_priv->display.get_backlight = pch_get_backlight;
+ panel->backlight.setup = pch_setup_backlight;
+ panel->backlight.enable = pch_enable_backlight;
+ panel->backlight.disable = pch_disable_backlight;
+ panel->backlight.set = pch_set_backlight;
+ panel->backlight.get = pch_get_backlight;
+ panel->backlight.hz_to_pwm = pch_hz_to_pwm;
} else if (IS_VALLEYVIEW(dev)) {
if (dev_priv->vbt.has_mipi) {
- dev_priv->display.setup_backlight = pwm_setup_backlight;
- dev_priv->display.enable_backlight = pwm_enable_backlight;
- dev_priv->display.disable_backlight = pwm_disable_backlight;
- dev_priv->display.set_backlight = pwm_set_backlight;
- dev_priv->display.get_backlight = pwm_get_backlight;
+ panel->backlight.setup = pwm_setup_backlight;
+ panel->backlight.enable = pwm_enable_backlight;
+ panel->backlight.disable = pwm_disable_backlight;
+ panel->backlight.set = pwm_set_backlight;
+ panel->backlight.get = pwm_get_backlight;
} else {
- dev_priv->display.setup_backlight = vlv_setup_backlight;
- dev_priv->display.enable_backlight = vlv_enable_backlight;
- dev_priv->display.disable_backlight = vlv_disable_backlight;
- dev_priv->display.set_backlight = vlv_set_backlight;
- dev_priv->display.get_backlight = vlv_get_backlight;
+ panel->backlight.setup = vlv_setup_backlight;
+ panel->backlight.enable = vlv_enable_backlight;
+ panel->backlight.disable = vlv_disable_backlight;
+ panel->backlight.set = vlv_set_backlight;
+ panel->backlight.get = vlv_get_backlight;
+ panel->backlight.hz_to_pwm = vlv_hz_to_pwm;
}
} else if (IS_GEN4(dev)) {
- dev_priv->display.setup_backlight = i965_setup_backlight;
- dev_priv->display.enable_backlight = i965_enable_backlight;
- dev_priv->display.disable_backlight = i965_disable_backlight;
- dev_priv->display.set_backlight = i9xx_set_backlight;
- dev_priv->display.get_backlight = i9xx_get_backlight;
+ panel->backlight.setup = i965_setup_backlight;
+ panel->backlight.enable = i965_enable_backlight;
+ panel->backlight.disable = i965_disable_backlight;
+ panel->backlight.set = i9xx_set_backlight;
+ panel->backlight.get = i9xx_get_backlight;
+ panel->backlight.hz_to_pwm = i965_hz_to_pwm;
} else {
- dev_priv->display.setup_backlight = i9xx_setup_backlight;
- dev_priv->display.enable_backlight = i9xx_enable_backlight;
- dev_priv->display.disable_backlight = i9xx_disable_backlight;
- dev_priv->display.set_backlight = i9xx_set_backlight;
- dev_priv->display.get_backlight = i9xx_get_backlight;
+ panel->backlight.setup = i9xx_setup_backlight;
+ panel->backlight.enable = i9xx_enable_backlight;
+ panel->backlight.disable = i9xx_disable_backlight;
+ panel->backlight.set = i9xx_set_backlight;
+ panel->backlight.get = i9xx_get_backlight;
+ panel->backlight.hz_to_pwm = i9xx_hz_to_pwm;
}
}
@@ -1564,6 +1803,8 @@ int intel_panel_init(struct intel_panel *panel,
struct drm_display_mode *fixed_mode,
struct drm_display_mode *downclock_mode)
{
+ intel_panel_init_backlight_funcs(panel);
+
panel->fixed_mode = fixed_mode;
panel->downclock_mode = downclock_mode;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index ddbb7ed0a193..d52a15df6917 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -52,82 +52,20 @@
#define INTEL_RC6p_ENABLE (1<<1)
#define INTEL_RC6pp_ENABLE (1<<2)
-static void gen9_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- /* WaEnableLbsSlaRetryTimerDecrement:skl */
- I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
- GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
-
- /* WaDisableKillLogic:bxt,skl */
- I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
- ECOCHK_DIS_TLB);
-}
-
-static void skl_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- gen9_init_clock_gating(dev);
-
- if (INTEL_REVID(dev) <= SKL_REVID_B0) {
- /*
- * WaDisableSDEUnitClockGating:skl
- * WaSetGAPSunitClckGateDisable:skl
- */
- I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
- GEN8_GAPSUNIT_CLOCK_GATE_DISABLE |
- GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
-
- /* WaDisableVFUnitClockGating:skl */
- I915_WRITE(GEN6_UCGCTL2, I915_READ(GEN6_UCGCTL2) |
- GEN6_VFUNIT_CLOCK_GATE_DISABLE);
- }
-
- if (INTEL_REVID(dev) <= SKL_REVID_D0) {
- /* WaDisableHDCInvalidation:skl */
- I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
- BDW_DISABLE_HDC_INVALIDATION);
-
- /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
- I915_WRITE(FF_SLICE_CS_CHICKEN2,
- _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
- }
-
- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
- * involving this register should also be added to WA batch as required.
- */
- if (INTEL_REVID(dev) <= SKL_REVID_E0)
- /* WaDisableLSQCROPERFforOCL:skl */
- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
- GEN8_LQSC_RO_PERF_DIS);
-
- /* WaEnableGapsTsvCreditFix:skl */
- if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) {
- I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
- GEN9_GAPS_TSV_CREDIT_DISABLE));
- }
-}
-
static void bxt_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- gen9_init_clock_gating(dev);
+ /* WaDisableSDEUnitClockGating:bxt */
+ I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
+ GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
/*
* FIXME:
- * GEN8_SDEUNIT_CLOCK_GATE_DISABLE applies on A0 only.
* GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ applies on 3x6 GT SKUs only.
*/
- /* WaDisableSDEUnitClockGating:bxt */
I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
- GEN8_SDEUNIT_CLOCK_GATE_DISABLE |
GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
-
- /* FIXME: apply on A0 only */
- I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
}
static void i915_pineview_get_mem_freq(struct drm_device *dev)
@@ -691,12 +629,9 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
crtc = single_enabled_crtc(dev);
if (crtc) {
- const struct drm_display_mode *adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
int pixel_size = crtc->primary->state->fb->bits_per_pixel / 8;
- int clock;
-
- adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
- clock = adjusted_mode->crtc_clock;
+ int clock = adjusted_mode->crtc_clock;
/* Display SR */
wm = intel_calculate_wm(clock, &pineview_display_wm,
@@ -1200,7 +1135,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc)
case DRM_PLANE_TYPE_CURSOR:
for (level = 0; level < wm_state->num_levels; level++)
wm_state->sr[level].cursor =
- wm_state->sr[level].cursor;
+ wm_state->wm[level].cursor;
break;
case DRM_PLANE_TYPE_PRIMARY:
for (level = 0; level < wm_state->num_levels; level++)
@@ -1490,8 +1425,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
if (crtc) {
/* self-refresh has much higher latency */
static const int sr_latency_ns = 12000;
- const struct drm_display_mode *adjusted_mode =
- &to_intel_crtc(crtc)->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
int clock = adjusted_mode->crtc_clock;
int htotal = adjusted_mode->crtc_htotal;
int hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
@@ -1638,8 +1572,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
if (HAS_FW_BLC(dev) && enabled) {
/* self-refresh has much higher latency */
static const int sr_latency_ns = 6000;
- const struct drm_display_mode *adjusted_mode =
- &to_intel_crtc(enabled)->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &to_intel_crtc(enabled)->config->base.adjusted_mode;
int clock = adjusted_mode->crtc_clock;
int htotal = adjusted_mode->crtc_htotal;
int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w;
@@ -1780,16 +1713,6 @@ struct skl_pipe_wm_parameters {
uint32_t pipe_htotal;
uint32_t pixel_rate; /* in KHz */
struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
- struct intel_plane_wm_parameters cursor;
-};
-
-struct ilk_pipe_wm_parameters {
- bool active;
- uint32_t pipe_htotal;
- uint32_t pixel_rate;
- struct intel_plane_wm_parameters pri;
- struct intel_plane_wm_parameters spr;
- struct intel_plane_wm_parameters cur;
};
struct ilk_wm_maximums {
@@ -1810,26 +1733,26 @@ struct intel_wm_config {
* For both WM_PIPE and WM_LP.
* mem_value must be in 0.1us units.
*/
-static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params,
+static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
+ const struct intel_plane_state *pstate,
uint32_t mem_value,
bool is_lp)
{
+ int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
uint32_t method1, method2;
- if (!params->active || !params->pri.enabled)
+ if (!cstate->base.active || !pstate->visible)
return 0;
- method1 = ilk_wm_method1(params->pixel_rate,
- params->pri.bytes_per_pixel,
- mem_value);
+ method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), bpp, mem_value);
if (!is_lp)
return method1;
- method2 = ilk_wm_method2(params->pixel_rate,
- params->pipe_htotal,
- params->pri.horiz_pixels,
- params->pri.bytes_per_pixel,
+ method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
+ cstate->base.adjusted_mode.crtc_htotal,
+ drm_rect_width(&pstate->dst),
+ bpp,
mem_value);
return min(method1, method2);
@@ -1839,21 +1762,21 @@ static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params,
* For both WM_PIPE and WM_LP.
* mem_value must be in 0.1us units.
*/
-static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params,
+static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate,
+ const struct intel_plane_state *pstate,
uint32_t mem_value)
{
+ int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
uint32_t method1, method2;
- if (!params->active || !params->spr.enabled)
+ if (!cstate->base.active || !pstate->visible)
return 0;
- method1 = ilk_wm_method1(params->pixel_rate,
- params->spr.bytes_per_pixel,
- mem_value);
- method2 = ilk_wm_method2(params->pixel_rate,
- params->pipe_htotal,
- params->spr.horiz_pixels,
- params->spr.bytes_per_pixel,
+ method1 = ilk_wm_method1(ilk_pipe_pixel_rate(cstate), bpp, mem_value);
+ method2 = ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
+ cstate->base.adjusted_mode.crtc_htotal,
+ drm_rect_width(&pstate->dst),
+ bpp,
mem_value);
return min(method1, method2);
}
@@ -1862,29 +1785,33 @@ static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params,
* For both WM_PIPE and WM_LP.
* mem_value must be in 0.1us units.
*/
-static uint32_t ilk_compute_cur_wm(const struct ilk_pipe_wm_parameters *params,
+static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
+ const struct intel_plane_state *pstate,
uint32_t mem_value)
{
- if (!params->active || !params->cur.enabled)
+ int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+
+ if (!cstate->base.active || !pstate->visible)
return 0;
- return ilk_wm_method2(params->pixel_rate,
- params->pipe_htotal,
- params->cur.horiz_pixels,
- params->cur.bytes_per_pixel,
+ return ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
+ cstate->base.adjusted_mode.crtc_htotal,
+ drm_rect_width(&pstate->dst),
+ bpp,
mem_value);
}
/* Only for WM_LP. */
-static uint32_t ilk_compute_fbc_wm(const struct ilk_pipe_wm_parameters *params,
+static uint32_t ilk_compute_fbc_wm(const struct intel_crtc_state *cstate,
+ const struct intel_plane_state *pstate,
uint32_t pri_val)
{
- if (!params->active || !params->pri.enabled)
+ int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+
+ if (!cstate->base.active || !pstate->visible)
return 0;
- return ilk_wm_fbc(pri_val,
- params->pri.horiz_pixels,
- params->pri.bytes_per_pixel);
+ return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->dst), bpp);
}
static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
@@ -2049,10 +1976,12 @@ static bool ilk_validate_wm_level(int level,
}
static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
+ const struct intel_crtc *intel_crtc,
int level,
- const struct ilk_pipe_wm_parameters *p,
+ struct intel_crtc_state *cstate,
struct intel_wm_level *result)
{
+ struct intel_plane *intel_plane;
uint16_t pri_latency = dev_priv->wm.pri_latency[level];
uint16_t spr_latency = dev_priv->wm.spr_latency[level];
uint16_t cur_latency = dev_priv->wm.cur_latency[level];
@@ -2064,10 +1993,29 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
cur_latency *= 5;
}
- result->pri_val = ilk_compute_pri_wm(p, pri_latency, level);
- result->spr_val = ilk_compute_spr_wm(p, spr_latency);
- result->cur_val = ilk_compute_cur_wm(p, cur_latency);
- result->fbc_val = ilk_compute_fbc_wm(p, result->pri_val);
+ for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) {
+ struct intel_plane_state *pstate =
+ to_intel_plane_state(intel_plane->base.state);
+
+ switch (intel_plane->base.type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ result->pri_val = ilk_compute_pri_wm(cstate, pstate,
+ pri_latency,
+ level);
+ result->fbc_val = ilk_compute_fbc_wm(cstate, pstate,
+ result->pri_val);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ result->spr_val = ilk_compute_spr_wm(cstate, pstate,
+ spr_latency);
+ break;
+ case DRM_PLANE_TYPE_CURSOR:
+ result->cur_val = ilk_compute_cur_wm(cstate, pstate,
+ cur_latency);
+ break;
+ }
+ }
+
result->enable = true;
}
@@ -2076,7 +2024,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
u32 linetime, ips_linetime;
if (!intel_crtc->active)
@@ -2085,9 +2033,9 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
/* The WM are computed with base on how long it takes to fill a single
* row at the given clock rate, multiplied by 8.
* */
- linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8,
- mode->crtc_clock);
- ips_linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8,
+ linetime = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
+ adjusted_mode->crtc_clock);
+ ips_linetime = DIV_ROUND_CLOSEST(adjusted_mode->crtc_htotal * 1000 * 8,
dev_priv->cdclk_freq);
return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) |
@@ -2326,48 +2274,6 @@ static void skl_setup_wm_latency(struct drm_device *dev)
intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
}
-static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
- struct ilk_pipe_wm_parameters *p)
-{
- struct drm_device *dev = crtc->dev;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_plane *plane;
-
- if (!intel_crtc->active)
- return;
-
- p->active = true;
- p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
- p->pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config);
-
- if (crtc->primary->state->fb)
- p->pri.bytes_per_pixel =
- crtc->primary->state->fb->bits_per_pixel / 8;
- else
- p->pri.bytes_per_pixel = 4;
-
- p->cur.bytes_per_pixel = 4;
- /*
- * TODO: for now, assume primary and cursor planes are always enabled.
- * Setting them to false makes the screen flicker.
- */
- p->pri.enabled = true;
- p->cur.enabled = true;
-
- p->pri.horiz_pixels = intel_crtc->config->pipe_src_w;
- p->cur.horiz_pixels = intel_crtc->base.cursor->state->crtc_w;
-
- drm_for_each_legacy_plane(plane, dev) {
- struct intel_plane *intel_plane = to_intel_plane(plane);
-
- if (intel_plane->pipe == pipe) {
- p->spr = intel_plane->wm;
- break;
- }
- }
-}
-
static void ilk_compute_wm_config(struct drm_device *dev,
struct intel_wm_config *config)
{
@@ -2387,34 +2293,47 @@ static void ilk_compute_wm_config(struct drm_device *dev,
}
/* Compute new watermarks for the pipe */
-static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
- const struct ilk_pipe_wm_parameters *params,
+static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
struct intel_pipe_wm *pipe_wm)
{
+ struct drm_crtc *crtc = cstate->base.crtc;
struct drm_device *dev = crtc->dev;
const struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_plane *intel_plane;
+ struct intel_plane_state *sprstate = 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,
- .sprites_enabled = params->spr.enabled,
- .sprites_scaled = params->spr.scaled,
};
struct ilk_wm_maximums max;
- pipe_wm->pipe_enabled = params->active;
- pipe_wm->sprites_enabled = params->spr.enabled;
- pipe_wm->sprites_scaled = params->spr.scaled;
+ for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+ if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) {
+ sprstate = to_intel_plane_state(intel_plane->base.state);
+ break;
+ }
+ }
+
+ 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 = sprstate->visible;
+ pipe_wm->sprites_scaled = config.sprites_scaled;
/* ILK/SNB: LP2+ watermarks only w/o sprites */
- if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled)
+ if (INTEL_INFO(dev)->gen <= 6 && sprstate->visible)
max_level = 1;
/* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
- if (params->spr.scaled)
+ if (config.sprites_scaled)
max_level = 0;
- ilk_compute_wm_level(dev_priv, 0, params, &pipe_wm->wm[0]);
+ ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]);
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
@@ -2431,7 +2350,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
for (level = 1; level <= max_level; level++) {
struct intel_wm_level wm = {};
- ilk_compute_wm_level(dev_priv, level, params, &wm);
+ ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm);
/*
* Disable any watermark level that exceeds the
@@ -2899,7 +2818,12 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
int plane;
u32 val;
+ memset(ddb, 0, sizeof(*ddb));
+
for_each_pipe(dev_priv, pipe) {
+ if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe)))
+ continue;
+
for_each_plane(dev_priv, pipe, plane) {
val = I915_READ(PLANE_BUF_CFG(pipe, plane));
skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane],
@@ -2907,7 +2831,8 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
}
val = I915_READ(CUR_BUF_CFG(pipe));
- skl_ddb_entry_init_from_hw(&ddb->cursor[pipe], val);
+ skl_ddb_entry_init_from_hw(&ddb->plane[pipe][PLANE_CURSOR],
+ val);
}
}
@@ -2976,13 +2901,14 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
alloc_size = skl_ddb_entry_size(alloc);
if (alloc_size == 0) {
memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
- memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe]));
+ memset(&ddb->plane[pipe][PLANE_CURSOR], 0,
+ sizeof(ddb->plane[pipe][PLANE_CURSOR]));
return;
}
cursor_blocks = skl_cursor_allocation(config);
- ddb->cursor[pipe].start = alloc->end - cursor_blocks;
- ddb->cursor[pipe].end = alloc->end;
+ ddb->plane[pipe][PLANE_CURSOR].start = alloc->end - cursor_blocks;
+ ddb->plane[pipe][PLANE_CURSOR].end = alloc->end;
alloc_size -= cursor_blocks;
alloc->end -= cursor_blocks;
@@ -3121,8 +3047,8 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
sizeof(new_ddb->plane[pipe])))
return true;
- if (memcmp(&new_ddb->cursor[pipe], &cur_ddb->cursor[pipe],
- sizeof(new_ddb->cursor[pipe])))
+ if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR],
+ sizeof(new_ddb->plane[pipe][PLANE_CURSOR])))
return true;
return false;
@@ -3166,7 +3092,8 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
if (fb) {
p->plane[0].enabled = true;
p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
- drm_format_plane_cpp(fb->pixel_format, 1) : fb->bits_per_pixel / 8;
+ drm_format_plane_cpp(fb->pixel_format, 1) :
+ drm_format_plane_cpp(fb->pixel_format, 0);
p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
drm_format_plane_cpp(fb->pixel_format, 0) : 0;
p->plane[0].tiling = fb->modifier[0];
@@ -3181,17 +3108,17 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
p->plane[0].rotation = crtc->primary->state->rotation;
fb = crtc->cursor->state->fb;
- p->cursor.y_bytes_per_pixel = 0;
+ p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0;
if (fb) {
- p->cursor.enabled = true;
- p->cursor.bytes_per_pixel = fb->bits_per_pixel / 8;
- p->cursor.horiz_pixels = crtc->cursor->state->crtc_w;
- p->cursor.vert_pixels = crtc->cursor->state->crtc_h;
+ p->plane[PLANE_CURSOR].enabled = true;
+ p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8;
+ p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w;
+ p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h;
} else {
- p->cursor.enabled = false;
- p->cursor.bytes_per_pixel = 0;
- p->cursor.horiz_pixels = 64;
- p->cursor.vert_pixels = 64;
+ p->plane[PLANE_CURSOR].enabled = false;
+ p->plane[PLANE_CURSOR].bytes_per_pixel = 0;
+ p->plane[PLANE_CURSOR].horiz_pixels = 64;
+ p->plane[PLANE_CURSOR].vert_pixels = 64;
}
}
@@ -3305,11 +3232,12 @@ static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
&result->plane_res_l[i]);
}
- ddb_blocks = skl_ddb_entry_size(&ddb->cursor[pipe]);
- result->cursor_en = skl_compute_plane_wm(dev_priv, p, &p->cursor,
+ ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]);
+ result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p,
+ &p->plane[PLANE_CURSOR],
ddb_blocks, level,
- &result->cursor_res_b,
- &result->cursor_res_l);
+ &result->plane_res_b[PLANE_CURSOR],
+ &result->plane_res_l[PLANE_CURSOR]);
}
static uint32_t
@@ -3337,7 +3265,7 @@ static void skl_compute_transition_wm(struct drm_crtc *crtc,
/* Until we know more, just disable transition WMs */
for (i = 0; i < intel_num_planes(intel_crtc); i++)
trans_wm->plane_en[i] = false;
- trans_wm->cursor_en = false;
+ trans_wm->plane_en[PLANE_CURSOR] = false;
}
static void skl_compute_pipe_wm(struct drm_crtc *crtc,
@@ -3386,13 +3314,13 @@ static void skl_compute_wm_results(struct drm_device *dev,
temp = 0;
- temp |= p_wm->wm[level].cursor_res_l << PLANE_WM_LINES_SHIFT;
- temp |= p_wm->wm[level].cursor_res_b;
+ temp |= p_wm->wm[level].plane_res_l[PLANE_CURSOR] << PLANE_WM_LINES_SHIFT;
+ temp |= p_wm->wm[level].plane_res_b[PLANE_CURSOR];
- if (p_wm->wm[level].cursor_en)
+ if (p_wm->wm[level].plane_en[PLANE_CURSOR])
temp |= PLANE_WM_EN;
- r->cursor[pipe][level] = temp;
+ r->plane[pipe][PLANE_CURSOR][level] = temp;
}
@@ -3408,12 +3336,12 @@ static void skl_compute_wm_results(struct drm_device *dev,
}
temp = 0;
- temp |= p_wm->trans_wm.cursor_res_l << PLANE_WM_LINES_SHIFT;
- temp |= p_wm->trans_wm.cursor_res_b;
- if (p_wm->trans_wm.cursor_en)
+ temp |= p_wm->trans_wm.plane_res_l[PLANE_CURSOR] << PLANE_WM_LINES_SHIFT;
+ temp |= p_wm->trans_wm.plane_res_b[PLANE_CURSOR];
+ if (p_wm->trans_wm.plane_en[PLANE_CURSOR])
temp |= PLANE_WM_EN;
- r->cursor_trans[pipe] = temp;
+ r->plane_trans[pipe][PLANE_CURSOR] = temp;
r->wm_linetime[pipe] = p_wm->linetime;
}
@@ -3447,12 +3375,13 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
I915_WRITE(PLANE_WM(pipe, i, level),
new->plane[pipe][i][level]);
I915_WRITE(CUR_WM(pipe, level),
- new->cursor[pipe][level]);
+ new->plane[pipe][PLANE_CURSOR][level]);
}
for (i = 0; i < intel_num_planes(crtc); i++)
I915_WRITE(PLANE_WM_TRANS(pipe, i),
new->plane_trans[pipe][i]);
- I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]);
+ I915_WRITE(CUR_WM_TRANS(pipe),
+ new->plane_trans[pipe][PLANE_CURSOR]);
for (i = 0; i < intel_num_planes(crtc); i++) {
skl_ddb_entry_write(dev_priv,
@@ -3464,7 +3393,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
}
skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
- &new->ddb.cursor[pipe]);
+ &new->ddb.plane[pipe][PLANE_CURSOR]);
}
}
@@ -3672,6 +3601,26 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
}
}
+static void skl_clear_wm(struct skl_wm_values *watermarks, enum pipe pipe)
+{
+ watermarks->wm_linetime[pipe] = 0;
+ memset(watermarks->plane[pipe], 0,
+ sizeof(uint32_t) * 8 * I915_MAX_PLANES);
+ memset(watermarks->plane_trans[pipe],
+ 0, sizeof(uint32_t) * I915_MAX_PLANES);
+ watermarks->plane_trans[pipe][PLANE_CURSOR] = 0;
+
+ /* Clear ddb entries for pipe */
+ memset(&watermarks->ddb.pipe[pipe], 0, sizeof(struct skl_ddb_entry));
+ memset(&watermarks->ddb.plane[pipe], 0,
+ sizeof(struct skl_ddb_entry) * I915_MAX_PLANES);
+ memset(&watermarks->ddb.y_plane[pipe], 0,
+ sizeof(struct skl_ddb_entry) * I915_MAX_PLANES);
+ memset(&watermarks->ddb.plane[pipe][PLANE_CURSOR], 0,
+ sizeof(struct skl_ddb_entry));
+
+}
+
static void skl_update_wm(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -3682,7 +3631,11 @@ static void skl_update_wm(struct drm_crtc *crtc)
struct skl_pipe_wm pipe_wm = {};
struct intel_wm_config config = {};
- memset(results, 0, sizeof(*results));
+
+ /* Clear all dirty flags */
+ memset(results->dirty, 0, sizeof(bool) * I915_MAX_PIPES);
+
+ skl_clear_wm(results, intel_crtc->pipe);
skl_compute_wm_global_parameters(dev, &config);
@@ -3737,19 +3690,19 @@ skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
static void ilk_update_wm(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct ilk_wm_maximums max;
- struct ilk_pipe_wm_parameters params = {};
struct ilk_wm_values results = {};
enum intel_ddb_partitioning partitioning;
struct intel_pipe_wm pipe_wm = {};
struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
struct intel_wm_config config = {};
- ilk_compute_wm_parameters(crtc, &params);
+ WARN_ON(cstate->base.active != intel_crtc->active);
- intel_compute_pipe_wm(crtc, &params, &pipe_wm);
+ intel_compute_pipe_wm(cstate, &pipe_wm);
if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
return;
@@ -3789,12 +3742,6 @@ ilk_update_sprite_wm(struct drm_plane *plane,
struct drm_device *dev = plane->dev;
struct intel_plane *intel_plane = to_intel_plane(plane);
- intel_plane->wm.enabled = enabled;
- intel_plane->wm.scaled = scaled;
- intel_plane->wm.horiz_pixels = sprite_width;
- intel_plane->wm.vert_pixels = sprite_width;
- intel_plane->wm.bytes_per_pixel = pixel_size;
-
/*
* IVB workaround: must disable low power watermarks for at least
* one frame before enabling scaling. LP watermarks can be re-enabled
@@ -3826,10 +3773,10 @@ static void skl_pipe_wm_active_state(uint32_t val,
(val >> PLANE_WM_LINES_SHIFT) &
PLANE_WM_LINES_MASK;
} else {
- active->wm[level].cursor_en = is_enabled;
- active->wm[level].cursor_res_b =
+ active->wm[level].plane_en[PLANE_CURSOR] = is_enabled;
+ active->wm[level].plane_res_b[PLANE_CURSOR] =
val & PLANE_WM_BLOCKS_MASK;
- active->wm[level].cursor_res_l =
+ active->wm[level].plane_res_l[PLANE_CURSOR] =
(val >> PLANE_WM_LINES_SHIFT) &
PLANE_WM_LINES_MASK;
}
@@ -3842,10 +3789,10 @@ static void skl_pipe_wm_active_state(uint32_t val,
(val >> PLANE_WM_LINES_SHIFT) &
PLANE_WM_LINES_MASK;
} else {
- active->trans_wm.cursor_en = is_enabled;
- active->trans_wm.cursor_res_b =
+ active->trans_wm.plane_en[PLANE_CURSOR] = is_enabled;
+ active->trans_wm.plane_res_b[PLANE_CURSOR] =
val & PLANE_WM_BLOCKS_MASK;
- active->trans_wm.cursor_res_l =
+ active->trans_wm.plane_res_l[PLANE_CURSOR] =
(val >> PLANE_WM_LINES_SHIFT) &
PLANE_WM_LINES_MASK;
}
@@ -3871,12 +3818,12 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
for (i = 0; i < intel_num_planes(intel_crtc); i++)
hw->plane[pipe][i][level] =
I915_READ(PLANE_WM(pipe, i, level));
- hw->cursor[pipe][level] = I915_READ(CUR_WM(pipe, level));
+ hw->plane[pipe][PLANE_CURSOR][level] = I915_READ(CUR_WM(pipe, level));
}
for (i = 0; i < intel_num_planes(intel_crtc); i++)
hw->plane_trans[pipe][i] = I915_READ(PLANE_WM_TRANS(pipe, i));
- hw->cursor_trans[pipe] = I915_READ(CUR_WM_TRANS(pipe));
+ hw->plane_trans[pipe][PLANE_CURSOR] = I915_READ(CUR_WM_TRANS(pipe));
if (!intel_crtc->active)
return;
@@ -3891,7 +3838,7 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
skl_pipe_wm_active_state(temp, active, false,
false, i, level);
}
- temp = hw->cursor[pipe][level];
+ temp = hw->plane[pipe][PLANE_CURSOR][level];
skl_pipe_wm_active_state(temp, active, false, true, i, level);
}
@@ -3900,7 +3847,7 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
skl_pipe_wm_active_state(temp, active, true, false, i, 0);
}
- temp = hw->cursor_trans[pipe];
+ temp = hw->plane_trans[pipe][PLANE_CURSOR];
skl_pipe_wm_active_state(temp, active, true, true, i, 0);
}
@@ -4261,7 +4208,7 @@ static void ironlake_enable_drps(struct drm_device *dev)
fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
MEMMODE_FSTART_SHIFT;
- vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
+ vstart = (I915_READ(PXVFREQ(fstart)) & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT;
dev_priv->ips.fmax = fmax; /* IPS callback will increase this */
@@ -4292,10 +4239,10 @@ static void ironlake_enable_drps(struct drm_device *dev)
ironlake_set_drps(dev, fstart);
- dev_priv->ips.last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
- I915_READ(0x112e0);
+ dev_priv->ips.last_count1 = I915_READ(DMIEC) +
+ I915_READ(DDREC) + I915_READ(CSIEC);
dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies);
- dev_priv->ips.last_count2 = I915_READ(0x112f4);
+ dev_priv->ips.last_count2 = I915_READ(GFXEC);
dev_priv->ips.last_time2 = ktime_get_raw_ns();
spin_unlock_irq(&mchdev_lock);
@@ -4466,6 +4413,10 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
+ if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0))
+ return;
+
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
WARN_ON(val > dev_priv->rps.max_freq);
WARN_ON(val < dev_priv->rps.min_freq);
@@ -4786,6 +4737,12 @@ static void gen9_enable_rps(struct drm_device *dev)
gen6_init_rps_frequencies(dev);
+ /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
+ if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) {
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+ return;
+ }
+
/* Program defaults and thresholds for RPS*/
I915_WRITE(GEN6_RC_VIDEO_FREQ,
GEN9_FREQUENCY(dev_priv->rps.rp1_freq));
@@ -4823,13 +4780,22 @@ static void gen9_enable_rc6(struct drm_device *dev)
I915_WRITE(GEN6_RC_CONTROL, 0);
/* 2b: Program RC6 thresholds.*/
- I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16);
+
+ /* WaRsDoubleRc6WrlWithCoarsePowerGating: Doubling WRL only when CPG is enabled */
+ if (IS_SKYLAKE(dev) && !((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) &&
+ (INTEL_REVID(dev) <= SKL_REVID_E0)))
+ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16);
+ else
+ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16);
I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); /* 12500 * 1280ns */
I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); /* 25 * 1280ns */
for_each_ring(ring, dev_priv, unused)
I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
+
+ if (HAS_GUC_UCODE(dev))
+ I915_WRITE(GUC_MAX_IDLE_COUNT, 0xA);
+
I915_WRITE(GEN6_RC_SLEEP, 0);
- I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
/* 2c: Program Coarse Power Gating Policies. */
I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 25);
@@ -4840,17 +4806,30 @@ static void gen9_enable_rc6(struct drm_device *dev)
rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
"on" : "off");
- I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
- GEN6_RC_CTL_EI_MODE(1) |
- rc6_mask);
+ /* WaRsUseTimeoutMode */
+ if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) ||
+ (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) {
+ I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */
+ I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
+ GEN7_RC_CTL_TO_MODE |
+ rc6_mask);
+ } else {
+ I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
+ I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
+ GEN6_RC_CTL_EI_MODE(1) |
+ rc6_mask);
+ }
/*
* 3b: Enable Coarse Power Gating only when RC6 is enabled.
- * WaDisableRenderPowerGating:skl,bxt - Render PG need to be disabled with RC6.
+ * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
*/
- I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
- GEN9_MEDIA_PG_ENABLE : 0);
-
+ if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
+ ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
+ I915_WRITE(GEN9_PG_ENABLE, 0);
+ else
+ I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
+ (GEN9_RENDER_PG_ENABLE | GEN9_MEDIA_PG_ENABLE) : 0);
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
@@ -5148,32 +5127,27 @@ static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
u32 val, rp0;
- if (dev->pdev->revision >= 0x20) {
- val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
+ val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
- switch (INTEL_INFO(dev)->eu_total) {
- case 8:
- /* (2 * 4) config */
- rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT);
- break;
- case 12:
- /* (2 * 6) config */
- rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT);
- break;
- case 16:
- /* (2 * 8) config */
- default:
- /* Setting (2 * 8) Min RP0 for any other combination */
- rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT);
- break;
- }
- rp0 = (rp0 & FB_GFX_FREQ_FUSE_MASK);
- } else {
- /* For pre-production hardware */
- val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
- rp0 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) &
- PUNIT_GPU_STATUS_MAX_FREQ_MASK;
+ switch (INTEL_INFO(dev)->eu_total) {
+ case 8:
+ /* (2 * 4) config */
+ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT);
+ break;
+ case 12:
+ /* (2 * 6) config */
+ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT);
+ break;
+ case 16:
+ /* (2 * 8) config */
+ default:
+ /* Setting (2 * 8) Min RP0 for any other combination */
+ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT);
+ break;
}
+
+ rp0 = (rp0 & FB_GFX_FREQ_FUSE_MASK);
+
return rp0;
}
@@ -5189,18 +5163,11 @@ static int cherryview_rps_rpe_freq(struct drm_i915_private *dev_priv)
static int cherryview_rps_guar_freq(struct drm_i915_private *dev_priv)
{
- struct drm_device *dev = dev_priv->dev;
u32 val, rp1;
- if (dev->pdev->revision >= 0x20) {
- val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
- rp1 = (val & FB_GFX_FREQ_FUSE_MASK);
- } else {
- /* For pre-production hardware */
- val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
- rp1 = ((val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) &
- PUNIT_GPU_STATUS_MAX_FREQ_MASK);
- }
+ val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
+ rp1 = (val & FB_GFX_FREQ_FUSE_MASK);
+
return rp1;
}
@@ -5415,25 +5382,10 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
mutex_unlock(&dev_priv->sb_lock);
switch ((val >> 2) & 0x7) {
- case 0:
- case 1:
- dev_priv->rps.cz_freq = 200;
- dev_priv->mem_freq = 1600;
- break;
- case 2:
- dev_priv->rps.cz_freq = 267;
- dev_priv->mem_freq = 1600;
- break;
case 3:
- dev_priv->rps.cz_freq = 333;
dev_priv->mem_freq = 2000;
break;
- case 4:
- dev_priv->rps.cz_freq = 320;
- dev_priv->mem_freq = 1600;
- break;
- case 5:
- dev_priv->rps.cz_freq = 400;
+ default:
dev_priv->mem_freq = 1600;
break;
}
@@ -5565,7 +5517,7 @@ static void cherryview_enable_rps(struct drm_device *dev)
/* RPS code assumes GPLL is used */
WARN_ONCE((val & GPLLENABLE) == 0, "GPLL not enabled\n");
- DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & GPLLENABLE ? "yes" : "no");
+ DRM_DEBUG_DRIVER("GPLL enabled? %s\n", yesno(val & GPLLENABLE));
DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
dev_priv->rps.cur_freq = (val >> 8) & 0xff;
@@ -5655,7 +5607,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
/* RPS code assumes GPLL is used */
WARN_ONCE((val & GPLLENABLE) == 0, "GPLL not enabled\n");
- DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & GPLLENABLE ? "yes" : "no");
+ DRM_DEBUG_DRIVER("GPLL enabled? %s\n", yesno(val & GPLLENABLE));
DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
dev_priv->rps.cur_freq = (val >> 8) & 0xff;
@@ -5864,7 +5816,7 @@ static unsigned long __i915_gfx_val(struct drm_i915_private *dev_priv)
assert_spin_locked(&mchdev_lock);
- pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_freq * 4));
+ pxvid = I915_READ(PXVFREQ(dev_priv->rps.cur_freq));
pxvid = (pxvid >> 24) & 0x7f;
ext_v = pvid_to_extvid(dev_priv, pxvid);
@@ -6107,13 +6059,13 @@ static void intel_init_emon(struct drm_device *dev)
I915_WRITE(CSIEW2, 0x04000004);
for (i = 0; i < 5; i++)
- I915_WRITE(PEW + (i * 4), 0);
+ I915_WRITE(PEW(i), 0);
for (i = 0; i < 3; i++)
- I915_WRITE(DEW + (i * 4), 0);
+ I915_WRITE(DEW(i), 0);
/* Program P-state weights to account for frequency power adjustment */
for (i = 0; i < 16; i++) {
- u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
+ u32 pxvidfreq = I915_READ(PXVFREQ(i));
unsigned long freq = intel_pxfreq(pxvidfreq);
unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT;
@@ -6134,7 +6086,7 @@ static void intel_init_emon(struct drm_device *dev)
for (i = 0; i < 4; i++) {
u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
(pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
- I915_WRITE(PXW + (i * 4), val);
+ I915_WRITE(PXW(i), val);
}
/* Adjust magic regs to magic values (more experimental results) */
@@ -6150,7 +6102,7 @@ static void intel_init_emon(struct drm_device *dev)
I915_WRITE(EG7, 0);
for (i = 0; i < 8; i++)
- I915_WRITE(PXWL + (i * 4), 0);
+ I915_WRITE(PXWL(i), 0);
/* Enable PMON + select events */
I915_WRITE(ECR, 0x80000019);
@@ -6604,14 +6556,14 @@ static void lpt_init_clock_gating(struct drm_device *dev)
* TODO: this bit should only be enabled when really needed, then
* disabled when not needed anymore in order to save power.
*/
- if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE)
+ if (HAS_PCH_LPT_LP(dev))
I915_WRITE(SOUTH_DSPCLK_GATE_D,
I915_READ(SOUTH_DSPCLK_GATE_D) |
PCH_LP_PARTITION_LEVEL_DISABLE);
/* WADPOClockGatingDisable:hsw */
- I915_WRITE(_TRANSA_CHICKEN1,
- I915_READ(_TRANSA_CHICKEN1) |
+ I915_WRITE(TRANS_CHICKEN1(PIPE_A),
+ I915_READ(TRANS_CHICKEN1(PIPE_A)) |
TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
}
@@ -6619,7 +6571,7 @@ static void lpt_suspend_hw(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
+ if (HAS_PCH_LPT_LP(dev)) {
uint32_t val = I915_READ(SOUTH_DSPCLK_GATE_D);
val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
@@ -7105,9 +7057,6 @@ void intel_init_pm(struct drm_device *dev)
if (IS_BROXTON(dev))
dev_priv->display.init_clock_gating =
bxt_init_clock_gating;
- else if (IS_SKYLAKE(dev))
- dev_priv->display.init_clock_gating =
- skl_init_clock_gating;
dev_priv->display.update_wm = skl_update_wm;
dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
} else if (HAS_PCH_SPLIT(dev)) {
@@ -7260,7 +7209,7 @@ static int vlv_gpu_freq_div(unsigned int czclk_freq)
static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val)
{
- int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->mem_freq, 4);
+ int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000);
div = vlv_gpu_freq_div(czclk_freq);
if (div < 0)
@@ -7271,7 +7220,7 @@ static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val)
static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val)
{
- int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->mem_freq, 4);
+ int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000);
mul = vlv_gpu_freq_div(czclk_freq);
if (mul < 0)
@@ -7282,7 +7231,7 @@ static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val)
static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val)
{
- int div, czclk_freq = dev_priv->rps.cz_freq;
+ int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000);
div = vlv_gpu_freq_div(czclk_freq) / 2;
if (div < 0)
@@ -7293,7 +7242,7 @@ static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val)
static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
{
- int mul, czclk_freq = dev_priv->rps.cz_freq;
+ int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000);
mul = vlv_gpu_freq_div(czclk_freq) / 2;
if (mul < 0)
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index a04b4dc5ed9b..213581c215b3 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -73,14 +73,14 @@ static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe)
}
static void intel_psr_write_vsc(struct intel_dp *intel_dp,
- struct edp_vsc_psr *vsc_psr)
+ const struct edp_vsc_psr *vsc_psr)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder);
- u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config->cpu_transcoder);
+ enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder);
uint32_t *data = (uint32_t *) vsc_psr;
unsigned int i;
@@ -90,12 +90,14 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp,
I915_WRITE(ctl_reg, 0);
POSTING_READ(ctl_reg);
- for (i = 0; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4) {
- if (i < sizeof(struct edp_vsc_psr))
- I915_WRITE(data_reg + i, *data++);
- else
- I915_WRITE(data_reg + i, 0);
+ for (i = 0; i < sizeof(*vsc_psr); i += 4) {
+ I915_WRITE(HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder,
+ i >> 2), *data);
+ data++;
}
+ for (; i < VIDEO_DIP_VSC_DATA_SIZE; i += 4)
+ I915_WRITE(HSW_TVIDEO_DIP_VSC_DATA(cpu_transcoder,
+ i >> 2), 0);
I915_WRITE(ctl_reg, VIDEO_DIP_ENABLE_VSC_HSW);
POSTING_READ(ctl_reg);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 61b451fbd09e..9461a238f5d5 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -719,7 +719,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_workarounds *w = &dev_priv->workarounds;
- if (WARN_ON_ONCE(w->count == 0))
+ if (w->count == 0)
return 0;
ring->gpu_caches_dirty = true;
@@ -802,42 +802,29 @@ static int wa_add(struct drm_i915_private *dev_priv,
#define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
-static int bdw_init_workarounds(struct intel_engine_cs *ring)
+static int gen8_init_workarounds(struct intel_engine_cs *ring)
{
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
- /* WaDisableAsyncFlipPerfMode:bdw */
+ /* WaDisableAsyncFlipPerfMode:bdw,chv */
WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE);
- /* WaDisablePartialInstShootdown:bdw */
- /* WaDisableThreadStallDopClockGating:bdw (pre-production) */
+ /* WaDisablePartialInstShootdown:bdw,chv */
WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
- PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE |
- STALL_DOP_GATING_DISABLE);
-
- /* WaDisableDopClockGating:bdw */
- WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
- DOP_CLOCK_GATING_DISABLE);
-
- WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
- GEN8_SAMPLER_POWER_BYPASS_DIS);
+ PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
/* Use Force Non-Coherent whenever executing a 3D context. This is a
* workaround for for a possible hang in the unlikely event a TLB
* invalidation occurs during a PSD flush.
*/
+ /* WaForceEnableNonCoherent:bdw,chv */
+ /* WaHdcDisableFetchWhenMasked:bdw,chv */
WA_SET_BIT_MASKED(HDC_CHICKEN0,
- /* WaForceEnableNonCoherent:bdw */
- HDC_FORCE_NON_COHERENT |
- /* WaForceContextSaveRestoreNonCoherent:bdw */
- HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
- /* WaHdcDisableFetchWhenMasked:bdw */
HDC_DONOT_FETCH_MEM_WHEN_MASKED |
- /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
- (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
+ HDC_FORCE_NON_COHERENT);
/* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
* "The Hierarchical Z RAW Stall Optimization allows non-overlapping
@@ -845,13 +832,12 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring)
* stalling waiting for the earlier ones to write to Hierarchical Z
* buffer."
*
- * This optimization is off by default for Broadwell; turn it on.
+ * This optimization is off by default for BDW and CHV; turn it on.
*/
WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
- /* Wa4x4STCOptimizationDisable:bdw */
- WA_SET_BIT_MASKED(CACHE_MODE_1,
- GEN8_4x4_STC_OPTIMIZATION_DISABLE);
+ /* Wa4x4STCOptimizationDisable:bdw,chv */
+ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
/*
* BSpec recommends 8x4 when MSAA is used,
@@ -868,56 +854,51 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring)
return 0;
}
-static int chv_init_workarounds(struct intel_engine_cs *ring)
+static int bdw_init_workarounds(struct intel_engine_cs *ring)
{
+ int ret;
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
+ ret = gen8_init_workarounds(ring);
+ if (ret)
+ return ret;
- /* WaDisableAsyncFlipPerfMode:chv */
- WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE);
+ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */
+ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
- /* WaDisablePartialInstShootdown:chv */
- /* WaDisableThreadStallDopClockGating:chv */
- WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
- PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE |
- STALL_DOP_GATING_DISABLE);
+ /* WaDisableDopClockGating:bdw */
+ WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
+ DOP_CLOCK_GATING_DISABLE);
+
+ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
+ GEN8_SAMPLER_POWER_BYPASS_DIS);
- /* Use Force Non-Coherent whenever executing a 3D context. This is a
- * workaround for a possible hang in the unlikely event a TLB
- * invalidation occurs during a PSD flush.
- */
- /* WaForceEnableNonCoherent:chv */
- /* WaHdcDisableFetchWhenMasked:chv */
WA_SET_BIT_MASKED(HDC_CHICKEN0,
- HDC_FORCE_NON_COHERENT |
- HDC_DONOT_FETCH_MEM_WHEN_MASKED);
+ /* WaForceContextSaveRestoreNonCoherent:bdw */
+ HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
+ /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
+ (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
- /* According to the CACHE_MODE_0 default value documentation, some
- * CHV platforms disable this optimization by default. Turn it on.
- */
- WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
+ return 0;
+}
- /* Wa4x4STCOptimizationDisable:chv */
- WA_SET_BIT_MASKED(CACHE_MODE_1,
- GEN8_4x4_STC_OPTIMIZATION_DISABLE);
+static int chv_init_workarounds(struct intel_engine_cs *ring)
+{
+ int ret;
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ ret = gen8_init_workarounds(ring);
+ if (ret)
+ return ret;
+
+ /* WaDisableThreadStallDopClockGating:chv */
+ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
/* Improve HiZ throughput on CHV. */
WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
- /*
- * BSpec recommends 8x4 when MSAA is used,
- * however in practice 16x4 seems fastest.
- *
- * Note that PS/WM thread counts depend on the WIZ hashing
- * disable bit, which we don't touch here, but it's good
- * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
- */
- WA_SET_FIELD_MASKED(GEN7_GT_MODE,
- GEN6_WIZ_HASHING_MASK,
- GEN6_WIZ_HASHING_16x4);
-
return 0;
}
@@ -927,6 +908,14 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
+ /* WaEnableLbsSlaRetryTimerDecrement:skl */
+ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
+ GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
+
+ /* WaDisableKillLogic:bxt,skl */
+ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
+ ECOCHK_DIS_TLB);
+
/* WaDisablePartialInstShootdown:skl,bxt */
WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
@@ -963,10 +952,9 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring)
}
/* Wa4x4STCOptimizationDisable:skl,bxt */
- WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
-
/* WaDisablePartialResolveInVc:skl,bxt */
- WA_SET_BIT_MASKED(CACHE_MODE_1, GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE);
+ WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE |
+ GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE));
/* WaCcsTlbPrefetchDisable:skl,bxt */
WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
@@ -985,6 +973,16 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring)
tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE;
WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp);
+ /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */
+ if (IS_SKYLAKE(dev) ||
+ (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_B0)) {
+ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
+ GEN8_SAMPLER_POWER_BYPASS_DIS);
+ }
+
+ /* WaDisableSTUnitPowerOptimization:skl,bxt */
+ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
+
return 0;
}
@@ -1030,13 +1028,39 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *ring)
return 0;
}
-
static int skl_init_workarounds(struct intel_engine_cs *ring)
{
+ int ret;
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- gen9_init_workarounds(ring);
+ ret = gen9_init_workarounds(ring);
+ if (ret)
+ return ret;
+
+ if (INTEL_REVID(dev) <= SKL_REVID_D0) {
+ /* WaDisableHDCInvalidation:skl */
+ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
+ BDW_DISABLE_HDC_INVALIDATION);
+
+ /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
+ I915_WRITE(FF_SLICE_CS_CHICKEN2,
+ _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
+ }
+
+ /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
+ * involving this register should also be added to WA batch as required.
+ */
+ if (INTEL_REVID(dev) <= SKL_REVID_E0)
+ /* WaDisableLSQCROPERFforOCL:skl */
+ I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
+ GEN8_LQSC_RO_PERF_DIS);
+
+ /* WaEnableGapsTsvCreditFix:skl */
+ if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) {
+ I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
+ GEN9_GAPS_TSV_CREDIT_DISABLE));
+ }
/* WaDisablePowerCompilerClockGating:skl */
if (INTEL_REVID(dev) == SKL_REVID_B0)
@@ -1073,10 +1097,24 @@ static int skl_init_workarounds(struct intel_engine_cs *ring)
static int bxt_init_workarounds(struct intel_engine_cs *ring)
{
+ int ret;
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- gen9_init_workarounds(ring);
+ ret = gen9_init_workarounds(ring);
+ if (ret)
+ return ret;
+
+ /* WaStoreMultiplePTEenable:bxt */
+ /* This is a requirement according to Hardware specification */
+ if (INTEL_REVID(dev) == BXT_REVID_A0)
+ I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
+
+ /* WaSetClckGatingDisableMedia:bxt */
+ if (INTEL_REVID(dev) == BXT_REVID_A0) {
+ I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
+ ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
+ }
/* WaDisableThreadStallDopClockGating:bxt */
WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
@@ -1998,14 +2036,14 @@ int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
return 0;
}
-void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
+static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
{
drm_gem_object_unreference(&ringbuf->obj->base);
ringbuf->obj = NULL;
}
-int intel_alloc_ringbuffer_obj(struct drm_device *dev,
- struct intel_ringbuffer *ringbuf)
+static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+ struct intel_ringbuffer *ringbuf)
{
struct drm_i915_gem_object *obj;
@@ -2025,6 +2063,48 @@ int intel_alloc_ringbuffer_obj(struct drm_device *dev,
return 0;
}
+struct intel_ringbuffer *
+intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
+{
+ struct intel_ringbuffer *ring;
+ int ret;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (ring == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ ring->ring = engine;
+
+ ring->size = size;
+ /* Workaround an erratum on the i830 which causes a hang if
+ * the TAIL pointer points to within the last 2 cachelines
+ * of the buffer.
+ */
+ ring->effective_size = size;
+ if (IS_I830(engine->dev) || IS_845G(engine->dev))
+ ring->effective_size -= 2 * CACHELINE_BYTES;
+
+ ring->last_retired_head = -1;
+ intel_ring_update_space(ring);
+
+ ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
+ if (ret) {
+ DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
+ engine->name, ret);
+ kfree(ring);
+ return ERR_PTR(ret);
+ }
+
+ return ring;
+}
+
+void
+intel_ringbuffer_free(struct intel_ringbuffer *ring)
+{
+ intel_destroy_ringbuffer_obj(ring);
+ kfree(ring);
+}
+
static int intel_init_ring_buffer(struct drm_device *dev,
struct intel_engine_cs *ring)
{
@@ -2033,22 +2113,20 @@ static int intel_init_ring_buffer(struct drm_device *dev,
WARN_ON(ring->buffer);
- ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
- if (!ringbuf)
- return -ENOMEM;
- ring->buffer = ringbuf;
-
ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->execlist_queue);
i915_gem_batch_pool_init(dev, &ring->batch_pool);
- ringbuf->size = 32 * PAGE_SIZE;
- ringbuf->ring = ring;
memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
init_waitqueue_head(&ring->irq_queue);
+ ringbuf = intel_engine_create_ringbuffer(ring, 32 * PAGE_SIZE);
+ if (IS_ERR(ringbuf))
+ return PTR_ERR(ringbuf);
+ ring->buffer = ringbuf;
+
if (I915_NEED_GFX_HWS(dev)) {
ret = init_status_page(ring);
if (ret)
@@ -2060,15 +2138,6 @@ static int intel_init_ring_buffer(struct drm_device *dev,
goto error;
}
- WARN_ON(ringbuf->obj);
-
- ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
- if (ret) {
- DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
- ring->name, ret);
- goto error;
- }
-
ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
if (ret) {
DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
@@ -2077,14 +2146,6 @@ static int intel_init_ring_buffer(struct drm_device *dev,
goto error;
}
- /* Workaround an erratum on the i830 which causes a hang if
- * the TAIL pointer points to within the last 2 cachelines
- * of the buffer.
- */
- ringbuf->effective_size = ringbuf->size;
- if (IS_I830(dev) || IS_845G(dev))
- ringbuf->effective_size -= 2 * CACHELINE_BYTES;
-
ret = i915_cmd_parser_init_ring(ring);
if (ret)
goto error;
@@ -2092,7 +2153,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
return 0;
error:
- kfree(ringbuf);
+ intel_ringbuffer_free(ringbuf);
ring->buffer = NULL;
return ret;
}
@@ -2100,19 +2161,18 @@ error:
void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
{
struct drm_i915_private *dev_priv;
- struct intel_ringbuffer *ringbuf;
if (!intel_ring_initialized(ring))
return;
dev_priv = to_i915(ring->dev);
- ringbuf = ring->buffer;
intel_stop_ring_buffer(ring);
WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0);
- intel_unpin_ringbuffer_obj(ringbuf);
- intel_destroy_ringbuffer_obj(ringbuf);
+ intel_unpin_ringbuffer_obj(ring->buffer);
+ intel_ringbuffer_free(ring->buffer);
+ ring->buffer = NULL;
if (ring->cleanup)
ring->cleanup(ring);
@@ -2121,9 +2181,6 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
i915_cmd_parser_fini_ring(ring);
i915_gem_batch_pool_fini(&ring->batch_pool);
-
- kfree(ringbuf);
- ring->buffer = NULL;
}
static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
@@ -2610,6 +2667,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
GEN8_RING_SEMAPHORE_INIT;
}
} else if (INTEL_INFO(dev)->gen >= 6) {
+ ring->init_context = intel_rcs_ctx_init;
ring->add_request = gen6_add_request;
ring->flush = gen7_render_ring_flush;
if (INTEL_INFO(dev)->gen == 6)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 2e85fda94963..49fa41dc0eb6 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -377,6 +377,13 @@ intel_ring_sync_index(struct intel_engine_cs *ring,
return idx;
}
+static inline void
+intel_flush_status_page(struct intel_engine_cs *ring, int reg)
+{
+ drm_clflush_virt_range(&ring->status_page.page_addr[reg],
+ sizeof(uint32_t));
+}
+
static inline u32
intel_read_status_page(struct intel_engine_cs *ring,
int reg)
@@ -413,12 +420,12 @@ intel_write_status_page(struct intel_engine_cs *ring,
#define I915_GEM_HWS_SCRATCH_INDEX 0x40
#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
-void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
+struct intel_ringbuffer *
+intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size);
int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
struct intel_ringbuffer *ringbuf);
-void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
-int intel_alloc_ringbuffer_obj(struct drm_device *dev,
- struct intel_ringbuffer *ringbuf);
+void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
+void intel_ringbuffer_free(struct intel_ringbuffer *ring);
void intel_stop_ring_buffer(struct intel_engine_cs *ring);
void intel_cleanup_ring_buffer(struct intel_engine_cs *ring);
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index 7401cf90b0db..d89c1d0aa1b7 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -464,14 +464,14 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv)
bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv,
SKL_DISP_PW_2);
- WARN(!IS_SKYLAKE(dev), "Platform doesn't support DC5.\n");
- WARN(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n");
- WARN(pg2_enabled, "PG2 not disabled to enable DC5.\n");
+ WARN_ONCE(!IS_SKYLAKE(dev), "Platform doesn't support DC5.\n");
+ WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n");
+ WARN_ONCE(pg2_enabled, "PG2 not disabled to enable DC5.\n");
- WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5),
- "DC5 already programmed to be enabled.\n");
- WARN(dev_priv->pm.suspended,
- "DC5 cannot be enabled, if platform is runtime-suspended.\n");
+ WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5),
+ "DC5 already programmed to be enabled.\n");
+ WARN_ONCE(dev_priv->pm.suspended,
+ "DC5 cannot be enabled, if platform is runtime-suspended.\n");
assert_csr_loaded(dev_priv);
}
@@ -487,8 +487,8 @@ static void assert_can_disable_dc5(struct drm_i915_private *dev_priv)
if (dev_priv->power_domains.initializing)
return;
- WARN(!pg2_enabled, "PG2 not enabled to disable DC5.\n");
- WARN(dev_priv->pm.suspended,
+ WARN_ONCE(!pg2_enabled, "PG2 not enabled to disable DC5.\n");
+ WARN_ONCE(dev_priv->pm.suspended,
"Disabling of DC5 while platform is runtime-suspended should never happen.\n");
}
@@ -527,12 +527,12 @@ static void assert_can_enable_dc6(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
- WARN(!IS_SKYLAKE(dev), "Platform doesn't support DC6.\n");
- WARN(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n");
- WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
- "Backlight is not disabled.\n");
- WARN((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
- "DC6 already programmed to be enabled.\n");
+ WARN_ONCE(!IS_SKYLAKE(dev), "Platform doesn't support DC6.\n");
+ WARN_ONCE(!HAS_RUNTIME_PM(dev), "Runtime PM not enabled.\n");
+ WARN_ONCE(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
+ "Backlight is not disabled.\n");
+ WARN_ONCE((I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
+ "DC6 already programmed to be enabled.\n");
assert_csr_loaded(dev_priv);
}
@@ -547,8 +547,8 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv)
return;
assert_csr_loaded(dev_priv);
- WARN(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
- "DC6 already programmed to be disabled.\n");
+ WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6),
+ "DC6 already programmed to be disabled.\n");
}
static void skl_enable_dc6(struct drm_i915_private *dev_priv)
@@ -657,9 +657,15 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
}
} else {
if (enable_requested) {
- I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
- POSTING_READ(HSW_PWR_WELL_DRIVER);
- DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
+ if (IS_SKYLAKE(dev) &&
+ (power_well->data == SKL_DISP_PW_1) &&
+ (intel_csr_load_status_get(dev_priv) == FW_LOADED))
+ DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n");
+ else {
+ I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
+ POSTING_READ(HSW_PWR_WELL_DRIVER);
+ DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
+ }
if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) &&
power_well->data == SKL_DISP_PW_2) {
@@ -671,7 +677,7 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
wait_for((state = intel_csr_load_status_get(dev_priv)) !=
FW_UNINITIALIZED, 1000);
if (state != FW_LOADED)
- DRM_ERROR("CSR firmware not ready (%d)\n",
+ DRM_DEBUG("CSR firmware not ready (%d)\n",
state);
else
if (SKL_ENABLE_DC6(dev))
@@ -856,6 +862,25 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
static void vlv_display_power_well_init(struct drm_i915_private *dev_priv)
{
+ enum pipe pipe;
+
+ /*
+ * Enable the CRI clock source so we can get at the
+ * display and the reference clock for VGA
+ * hotplug / manual detection. Supposedly DSI also
+ * needs the ref clock up and running.
+ *
+ * CHV DPLL B/C have some issues if VGA mode is enabled.
+ */
+ for_each_pipe(dev_priv->dev, pipe) {
+ u32 val = I915_READ(DPLL(pipe));
+
+ val |= DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
+ if (pipe != PIPE_A)
+ val |= DPLL_INTEGRATED_CRI_CLK_VLV;
+
+ I915_WRITE(DPLL(pipe), val);
+ }
spin_lock_irq(&dev_priv->irq_lock);
valleyview_enable_display_irqs(dev_priv);
@@ -907,13 +932,7 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
{
WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC);
- /*
- * Enable the CRI clock source so we can get at the
- * display and the reference clock for VGA
- * hotplug / manual detection.
- */
- I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS |
- DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
+ /* since ref/cri clock was enabled */
udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
vlv_set_power_well(dev_priv, power_well, true);
@@ -948,30 +967,149 @@ static void vlv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
vlv_set_power_well(dev_priv, power_well, false);
}
+#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
+
+static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv,
+ int power_well_id)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ struct i915_power_well *power_well;
+ int i;
+
+ for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
+ if (power_well->data == power_well_id)
+ return power_well;
+ }
+
+ return NULL;
+}
+
+#define BITS_SET(val, bits) (((val) & (bits)) == (bits))
+
+static void assert_chv_phy_status(struct drm_i915_private *dev_priv)
+{
+ struct i915_power_well *cmn_bc =
+ lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_BC);
+ struct i915_power_well *cmn_d =
+ lookup_power_well(dev_priv, PUNIT_POWER_WELL_DPIO_CMN_D);
+ u32 phy_control = dev_priv->chv_phy_control;
+ u32 phy_status = 0;
+ u32 phy_status_mask = 0xffffffff;
+ u32 tmp;
+
+ /*
+ * The BIOS can leave the PHY is some weird state
+ * where it doesn't fully power down some parts.
+ * Disable the asserts until the PHY has been fully
+ * reset (ie. the power well has been disabled at
+ * least once).
+ */
+ if (!dev_priv->chv_phy_assert[DPIO_PHY0])
+ phy_status_mask &= ~(PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH0) |
+ PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 0) |
+ PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 1) |
+ PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH1) |
+ PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 0) |
+ PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1));
+
+ if (!dev_priv->chv_phy_assert[DPIO_PHY1])
+ phy_status_mask &= ~(PHY_STATUS_CMN_LDO(DPIO_PHY1, DPIO_CH0) |
+ PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0) |
+ PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1));
+
+ if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) {
+ phy_status |= PHY_POWERGOOD(DPIO_PHY0);
+
+ /* this assumes override is only used to enable lanes */
+ if ((phy_control & PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH0)) == 0)
+ phy_control |= PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH0);
+
+ if ((phy_control & PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH1)) == 0)
+ phy_control |= PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1);
+
+ /* CL1 is on whenever anything is on in either channel */
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH0) |
+ PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1)))
+ phy_status |= PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH0);
+
+ /*
+ * The DPLLB check accounts for the pipe B + port A usage
+ * with CL2 powered up but all the lanes in the second channel
+ * powered down.
+ */
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY0, DPIO_CH1)) &&
+ (I915_READ(DPLL(PIPE_B)) & DPLL_VCO_ENABLE) == 0)
+ phy_status |= PHY_STATUS_CMN_LDO(DPIO_PHY0, DPIO_CH1);
+
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0x3, DPIO_PHY0, DPIO_CH0)))
+ phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 0);
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0xc, DPIO_PHY0, DPIO_CH0)))
+ phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH0, 1);
+
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0x3, DPIO_PHY0, DPIO_CH1)))
+ phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 0);
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0xc, DPIO_PHY0, DPIO_CH1)))
+ phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY0, DPIO_CH1, 1);
+ }
+
+ if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) {
+ phy_status |= PHY_POWERGOOD(DPIO_PHY1);
+
+ /* this assumes override is only used to enable lanes */
+ if ((phy_control & PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY1, DPIO_CH0)) == 0)
+ phy_control |= PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY1, DPIO_CH0);
+
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0xf, DPIO_PHY1, DPIO_CH0)))
+ phy_status |= PHY_STATUS_CMN_LDO(DPIO_PHY1, DPIO_CH0);
+
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0x3, DPIO_PHY1, DPIO_CH0)))
+ phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 0);
+ if (BITS_SET(phy_control,
+ PHY_CH_POWER_DOWN_OVRD(0xc, DPIO_PHY1, DPIO_CH0)))
+ phy_status |= PHY_STATUS_SPLINE_LDO(DPIO_PHY1, DPIO_CH0, 1);
+ }
+
+ phy_status &= phy_status_mask;
+
+ /*
+ * The PHY may be busy with some initial calibration and whatnot,
+ * so the power state can take a while to actually change.
+ */
+ if (wait_for((tmp = I915_READ(DISPLAY_PHY_STATUS) & phy_status_mask) == phy_status, 10))
+ WARN(phy_status != tmp,
+ "Unexpected PHY_STATUS 0x%08x, expected 0x%08x (PHY_CONTROL=0x%08x)\n",
+ tmp, phy_status, dev_priv->chv_phy_control);
+}
+
+#undef BITS_SET
+
static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
struct i915_power_well *power_well)
{
enum dpio_phy phy;
+ enum pipe pipe;
+ uint32_t tmp;
WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DPIO_CMN_BC &&
power_well->data != PUNIT_POWER_WELL_DPIO_CMN_D);
- /*
- * Enable the CRI clock source so we can get at the
- * display and the reference clock for VGA
- * hotplug / manual detection.
- */
if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+ pipe = PIPE_A;
phy = DPIO_PHY0;
- I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS |
- DPLL_REF_CLK_ENABLE_VLV);
- I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS |
- DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
} else {
+ pipe = PIPE_C;
phy = DPIO_PHY1;
- I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | DPLL_VGA_MODE_DIS |
- DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV);
}
+
+ /* since ref/cri clock was enabled */
udelay(1); /* >10ns for cmnreset, >0ns for sidereset */
vlv_set_power_well(dev_priv, power_well, true);
@@ -979,8 +1117,38 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv,
if (wait_for(I915_READ(DISPLAY_PHY_STATUS) & PHY_POWERGOOD(phy), 1))
DRM_ERROR("Display PHY %d is not power up\n", phy);
+ mutex_lock(&dev_priv->sb_lock);
+
+ /* Enable dynamic power down */
+ tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW28);
+ tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN |
+ DPIO_SUS_CLK_CONFIG_GATE_CLKREQ;
+ vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp);
+
+ if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) {
+ tmp = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW6_CH1);
+ tmp |= DPIO_DYNPWRDOWNEN_CH1;
+ vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW6_CH1, tmp);
+ } else {
+ /*
+ * Force the non-existing CL2 off. BXT does this
+ * too, so maybe it saves some power even though
+ * CL2 doesn't exist?
+ */
+ tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30);
+ tmp |= DPIO_CL2_LDOFUSE_PWRENB;
+ vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, tmp);
+ }
+
+ mutex_unlock(&dev_priv->sb_lock);
+
dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(phy);
I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
+
+ DRM_DEBUG_KMS("Enabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n",
+ phy, dev_priv->chv_phy_control);
+
+ assert_chv_phy_status(dev_priv);
}
static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
@@ -1004,6 +1172,137 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv,
I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
vlv_set_power_well(dev_priv, power_well, false);
+
+ DRM_DEBUG_KMS("Disabled DPIO PHY%d (PHY_CONTROL=0x%08x)\n",
+ phy, dev_priv->chv_phy_control);
+
+ /* PHY is fully reset now, so we can enable the PHY state asserts */
+ dev_priv->chv_phy_assert[phy] = true;
+
+ assert_chv_phy_status(dev_priv);
+}
+
+static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpio_phy phy,
+ enum dpio_channel ch, bool override, unsigned int mask)
+{
+ enum pipe pipe = phy == DPIO_PHY0 ? PIPE_A : PIPE_C;
+ u32 reg, val, expected, actual;
+
+ /*
+ * The BIOS can leave the PHY is some weird state
+ * where it doesn't fully power down some parts.
+ * Disable the asserts until the PHY has been fully
+ * reset (ie. the power well has been disabled at
+ * least once).
+ */
+ if (!dev_priv->chv_phy_assert[phy])
+ return;
+
+ if (ch == DPIO_CH0)
+ reg = _CHV_CMN_DW0_CH0;
+ else
+ reg = _CHV_CMN_DW6_CH1;
+
+ mutex_lock(&dev_priv->sb_lock);
+ val = vlv_dpio_read(dev_priv, pipe, reg);
+ mutex_unlock(&dev_priv->sb_lock);
+
+ /*
+ * This assumes !override is only used when the port is disabled.
+ * All lanes should power down even without the override when
+ * the port is disabled.
+ */
+ if (!override || mask == 0xf) {
+ expected = DPIO_ALLDL_POWERDOWN | DPIO_ANYDL_POWERDOWN;
+ /*
+ * If CH1 common lane is not active anymore
+ * (eg. for pipe B DPLL) the entire channel will
+ * shut down, which causes the common lane registers
+ * to read as 0. That means we can't actually check
+ * the lane power down status bits, but as the entire
+ * register reads as 0 it's a good indication that the
+ * channel is indeed entirely powered down.
+ */
+ if (ch == DPIO_CH1 && val == 0)
+ expected = 0;
+ } else if (mask != 0x0) {
+ expected = DPIO_ANYDL_POWERDOWN;
+ } else {
+ expected = 0;
+ }
+
+ if (ch == DPIO_CH0)
+ actual = val >> DPIO_ANYDL_POWERDOWN_SHIFT_CH0;
+ else
+ actual = val >> DPIO_ANYDL_POWERDOWN_SHIFT_CH1;
+ actual &= DPIO_ALLDL_POWERDOWN | DPIO_ANYDL_POWERDOWN;
+
+ WARN(actual != expected,
+ "Unexpected DPIO lane power down: all %d, any %d. Expected: all %d, any %d. (0x%x = 0x%08x)\n",
+ !!(actual & DPIO_ALLDL_POWERDOWN), !!(actual & DPIO_ANYDL_POWERDOWN),
+ !!(expected & DPIO_ALLDL_POWERDOWN), !!(expected & DPIO_ANYDL_POWERDOWN),
+ reg, val);
+}
+
+bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy,
+ enum dpio_channel ch, bool override)
+{
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ bool was_override;
+
+ mutex_lock(&power_domains->lock);
+
+ was_override = dev_priv->chv_phy_control & PHY_CH_POWER_DOWN_OVRD_EN(phy, ch);
+
+ if (override == was_override)
+ goto out;
+
+ if (override)
+ dev_priv->chv_phy_control |= PHY_CH_POWER_DOWN_OVRD_EN(phy, ch);
+ else
+ dev_priv->chv_phy_control &= ~PHY_CH_POWER_DOWN_OVRD_EN(phy, ch);
+
+ I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
+
+ DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d (DPIO_PHY_CONTROL=0x%08x)\n",
+ phy, ch, dev_priv->chv_phy_control);
+
+ assert_chv_phy_status(dev_priv);
+
+out:
+ mutex_unlock(&power_domains->lock);
+
+ return was_override;
+}
+
+void chv_phy_powergate_lanes(struct intel_encoder *encoder,
+ bool override, unsigned int mask)
+{
+ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+ struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ enum dpio_phy phy = vlv_dport_to_phy(enc_to_dig_port(&encoder->base));
+ enum dpio_channel ch = vlv_dport_to_channel(enc_to_dig_port(&encoder->base));
+
+ mutex_lock(&power_domains->lock);
+
+ dev_priv->chv_phy_control &= ~PHY_CH_POWER_DOWN_OVRD(0xf, phy, ch);
+ dev_priv->chv_phy_control |= PHY_CH_POWER_DOWN_OVRD(mask, phy, ch);
+
+ if (override)
+ dev_priv->chv_phy_control |= PHY_CH_POWER_DOWN_OVRD_EN(phy, ch);
+ else
+ dev_priv->chv_phy_control &= ~PHY_CH_POWER_DOWN_OVRD_EN(phy, ch);
+
+ I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
+
+ DRM_DEBUG_KMS("Power gating DPIO PHY%d CH%d lanes 0x%x (PHY_CONTROL=0x%08x)\n",
+ phy, ch, mask, dev_priv->chv_phy_control);
+
+ assert_chv_phy_status(dev_priv);
+
+ assert_chv_phy_powergate(dev_priv, phy, ch, override, mask);
+
+ mutex_unlock(&power_domains->lock);
}
static bool chv_pipe_power_well_enabled(struct drm_i915_private *dev_priv,
@@ -1167,8 +1466,6 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
intel_runtime_pm_put(dev_priv);
}
-#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
-
#define HSW_ALWAYS_ON_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PIPE_A) | \
BIT(POWER_DOMAIN_TRANSCODER_EDP) | \
@@ -1430,21 +1727,6 @@ static struct i915_power_well chv_power_wells[] = {
},
};
-static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_priv,
- int power_well_id)
-{
- struct i915_power_domains *power_domains = &dev_priv->power_domains;
- struct i915_power_well *power_well;
- int i;
-
- for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
- if (power_well->data == power_well_id)
- return power_well;
- }
-
- return NULL;
-}
-
bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
int power_well_id)
{
@@ -1529,6 +1811,21 @@ static struct i915_power_well bxt_power_wells[] = {
}
};
+static int
+sanitize_disable_power_well_option(const struct drm_i915_private *dev_priv,
+ int disable_power_well)
+{
+ if (disable_power_well >= 0)
+ return !!disable_power_well;
+
+ if (IS_SKYLAKE(dev_priv)) {
+ DRM_DEBUG_KMS("Disabling display power well support\n");
+ return 0;
+ }
+
+ return 1;
+}
+
#define set_power_wells(power_domains, __power_wells) ({ \
(power_domains)->power_wells = (__power_wells); \
(power_domains)->power_well_count = ARRAY_SIZE(__power_wells); \
@@ -1545,6 +1842,9 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
{
struct i915_power_domains *power_domains = &dev_priv->power_domains;
+ i915.disable_power_well = sanitize_disable_power_well_option(dev_priv,
+ i915.disable_power_well);
+
mutex_init(&power_domains->lock);
/*
@@ -1583,7 +1883,6 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv)
/* Make sure we're not suspended first. */
pm_runtime_get_sync(device);
- pm_runtime_disable(device);
}
/**
@@ -1630,19 +1929,80 @@ static void chv_phy_control_init(struct drm_i915_private *dev_priv)
* DISPLAY_PHY_CONTROL can get corrupted if read. As a
* workaround never ever read DISPLAY_PHY_CONTROL, and
* instead maintain a shadow copy ourselves. Use the actual
- * power well state to reconstruct the expected initial
- * value.
+ * power well state and lane status to reconstruct the
+ * expected initial value.
*/
dev_priv->chv_phy_control =
PHY_LDO_SEQ_DELAY(PHY_LDO_DELAY_600NS, DPIO_PHY0) |
PHY_LDO_SEQ_DELAY(PHY_LDO_DELAY_600NS, DPIO_PHY1) |
- PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH0) |
- PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY0, DPIO_CH1) |
- PHY_CH_POWER_MODE(PHY_CH_SU_PSR, DPIO_PHY1, DPIO_CH0);
- if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc))
+ PHY_CH_POWER_MODE(PHY_CH_DEEP_PSR, DPIO_PHY0, DPIO_CH0) |
+ PHY_CH_POWER_MODE(PHY_CH_DEEP_PSR, DPIO_PHY0, DPIO_CH1) |
+ PHY_CH_POWER_MODE(PHY_CH_DEEP_PSR, DPIO_PHY1, DPIO_CH0);
+
+ /*
+ * If all lanes are disabled we leave the override disabled
+ * with all power down bits cleared to match the state we
+ * would use after disabling the port. Otherwise enable the
+ * override and set the lane powerdown bits accding to the
+ * current lane status.
+ */
+ if (cmn_bc->ops->is_enabled(dev_priv, cmn_bc)) {
+ uint32_t status = I915_READ(DPLL(PIPE_A));
+ unsigned int mask;
+
+ mask = status & DPLL_PORTB_READY_MASK;
+ if (mask == 0xf)
+ mask = 0x0;
+ else
+ dev_priv->chv_phy_control |=
+ PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH0);
+
+ dev_priv->chv_phy_control |=
+ PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH0);
+
+ mask = (status & DPLL_PORTC_READY_MASK) >> 4;
+ if (mask == 0xf)
+ mask = 0x0;
+ else
+ dev_priv->chv_phy_control |=
+ PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY0, DPIO_CH1);
+
+ dev_priv->chv_phy_control |=
+ PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY0, DPIO_CH1);
+
dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY0);
- if (cmn_d->ops->is_enabled(dev_priv, cmn_d))
+
+ dev_priv->chv_phy_assert[DPIO_PHY0] = false;
+ } else {
+ dev_priv->chv_phy_assert[DPIO_PHY0] = true;
+ }
+
+ if (cmn_d->ops->is_enabled(dev_priv, cmn_d)) {
+ uint32_t status = I915_READ(DPIO_PHY_STATUS);
+ unsigned int mask;
+
+ mask = status & DPLL_PORTD_READY_MASK;
+
+ if (mask == 0xf)
+ mask = 0x0;
+ else
+ dev_priv->chv_phy_control |=
+ PHY_CH_POWER_DOWN_OVRD_EN(DPIO_PHY1, DPIO_CH0);
+
+ dev_priv->chv_phy_control |=
+ PHY_CH_POWER_DOWN_OVRD(mask, DPIO_PHY1, DPIO_CH0);
+
dev_priv->chv_phy_control |= PHY_COM_LANE_RESET_DEASSERT(DPIO_PHY1);
+
+ dev_priv->chv_phy_assert[DPIO_PHY1] = false;
+ } else {
+ dev_priv->chv_phy_assert[DPIO_PHY1] = true;
+ }
+
+ I915_WRITE(DISPLAY_PHY_CONTROL, dev_priv->chv_phy_control);
+
+ DRM_DEBUG_KMS("Initial PHY_CONTROL=0x%08x\n",
+ dev_priv->chv_phy_control);
}
static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv)
@@ -1688,7 +2048,9 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
power_domains->initializing = true;
if (IS_CHERRYVIEW(dev)) {
+ mutex_lock(&power_domains->lock);
chv_phy_control_init(dev_priv);
+ mutex_unlock(&power_domains->lock);
} else if (IS_VALLEYVIEW(dev)) {
mutex_lock(&power_domains->lock);
vlv_cmnlane_wa(dev_priv);
@@ -1820,8 +2182,6 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
if (!HAS_RUNTIME_PM(dev))
return;
- pm_runtime_set_active(device);
-
/*
* RPM depends on RC6 to save restore the GT HW context, so make RC6 a
* requirement.
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index c98098e884cc..c42b636c2087 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -53,7 +53,7 @@
#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK))
-static const char *tv_format_names[] = {
+static const char * const tv_format_names[] = {
"NTSC_M" , "NTSC_J" , "NTSC_443",
"PAL_B" , "PAL_D" , "PAL_G" ,
"PAL_H" , "PAL_I" , "PAL_M" ,
@@ -63,7 +63,7 @@ static const char *tv_format_names[] = {
"SECAM_60"
};
-#define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names))
+#define TV_FORMAT_NUM ARRAY_SIZE(tv_format_names)
struct intel_sdvo {
struct intel_encoder base;
@@ -107,6 +107,11 @@ struct intel_sdvo {
bool color_range_auto;
/**
+ * HDMI user specified aspect ratio
+ */
+ enum hdmi_picture_aspect aspect_ratio;
+
+ /**
* This is set if we're going to treat the device as TV-out.
*
* While we have these nice friendly flags for output types that ought
@@ -452,7 +457,7 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer);
}
-static const char *cmd_status_names[] = {
+static const char * const cmd_status_names[] = {
"Power on",
"Success",
"Not supported",
@@ -603,11 +608,11 @@ log_fail:
return false;
}
-static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
+static int intel_sdvo_get_pixel_multiplier(const struct drm_display_mode *adjusted_mode)
{
- if (mode->clock >= 100000)
+ if (adjusted_mode->crtc_clock >= 100000)
return 1;
- else if (mode->clock >= 50000)
+ else if (adjusted_mode->crtc_clock >= 50000)
return 2;
else
return 4;
@@ -1181,6 +1186,10 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
if (intel_sdvo->is_tv)
i9xx_adjust_sdvo_tv_clock(pipe_config);
+ /* Set user selected PAR to incoming mode's member */
+ if (intel_sdvo->is_hdmi)
+ adjusted_mode->picture_aspect_ratio = intel_sdvo->aspect_ratio;
+
return true;
}
@@ -1189,8 +1198,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc);
- struct drm_display_mode *adjusted_mode =
- &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
struct drm_display_mode *mode = &crtc->config->base.mode;
struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
u32 sdvox;
@@ -2044,6 +2052,23 @@ intel_sdvo_set_property(struct drm_connector *connector,
goto done;
}
+ if (property == connector->dev->mode_config.aspect_ratio_property) {
+ switch (val) {
+ case DRM_MODE_PICTURE_ASPECT_NONE:
+ intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
+ break;
+ case DRM_MODE_PICTURE_ASPECT_4_3:
+ intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
+ break;
+ case DRM_MODE_PICTURE_ASPECT_16_9:
+ intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
+ break;
+ default:
+ return -EINVAL;
+ }
+ goto done;
+ }
+
#define CHECK_PROPERTY(name, NAME) \
if (intel_sdvo_connector->name == property) { \
if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
@@ -2222,7 +2247,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
*/
static void
intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
- struct intel_sdvo *sdvo, u32 reg)
+ struct intel_sdvo *sdvo)
{
struct sdvo_device_mapping *mapping;
@@ -2239,7 +2264,7 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
static void
intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
- struct intel_sdvo *sdvo, u32 reg)
+ struct intel_sdvo *sdvo)
{
struct sdvo_device_mapping *mapping;
u8 pin;
@@ -2383,6 +2408,8 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo,
intel_attach_broadcast_rgb_property(&connector->base.base);
intel_sdvo->color_range_auto = true;
}
+ intel_attach_aspect_ratio_property(&connector->base.base);
+ intel_sdvo->aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
}
static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
@@ -2925,7 +2952,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
intel_sdvo->sdvo_reg = sdvo_reg;
intel_sdvo->is_sdvob = is_sdvob;
intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1;
- intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
+ intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo);
if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev))
goto err_i2c_bus;
@@ -2987,7 +3014,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
*/
intel_sdvo->base.cloneable = 0;
- intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
+ intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo);
/* Set the input timing to the screen. Assume always input 0. */
if (!intel_sdvo_set_target_input(intel_sdvo))
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 9d8af2f8a875..56dc132e8e20 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -53,13 +53,15 @@ format_is_yuv(uint32_t format)
}
}
-static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
+static int usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
+ int usecs)
{
/* paranoia */
- if (!mode->crtc_htotal)
+ if (!adjusted_mode->crtc_htotal)
return 1;
- return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal);
+ return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock,
+ 1000 * adjusted_mode->crtc_htotal);
}
/**
@@ -76,26 +78,25 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
* avoid random delays. The value written to @start_vbl_count should be
* supplied to intel_pipe_update_end() for error checking.
*/
-void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
+void intel_pipe_update_start(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
- const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
+ const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
enum pipe pipe = crtc->pipe;
long timeout = msecs_to_jiffies_timeout(1);
int scanline, min, max, vblank_start;
wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
DEFINE_WAIT(wait);
- vblank_start = mode->crtc_vblank_start;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ vblank_start = adjusted_mode->crtc_vblank_start;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
vblank_start = DIV_ROUND_UP(vblank_start, 2);
/* FIXME needs to be calibrated sensibly */
- min = vblank_start - usecs_to_scanlines(mode, 100);
+ min = vblank_start - usecs_to_scanlines(adjusted_mode, 100);
max = vblank_start - 1;
local_irq_disable();
- *start_vbl_count = 0;
if (min <= 0 || max <= 0)
return;
@@ -103,7 +104,9 @@ void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
if (WARN_ON(drm_crtc_vblank_get(&crtc->base)))
return;
- trace_i915_pipe_update_start(crtc, min, max);
+ crtc->debug.min_vbl = min;
+ crtc->debug.max_vbl = max;
+ trace_i915_pipe_update_start(crtc);
for (;;) {
/*
@@ -134,9 +137,12 @@ void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
drm_crtc_vblank_put(&crtc->base);
- *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
+ crtc->debug.scanline_start = scanline;
+ crtc->debug.start_vbl_time = ktime_get();
+ crtc->debug.start_vbl_count =
+ dev->driver->get_vblank_counter(dev, pipe);
- trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count);
+ trace_i915_pipe_update_vblank_evaded(crtc);
}
/**
@@ -148,19 +154,27 @@ void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
* re-enables interrupts and verifies the update was actually completed
* before a vblank using the value of @start_vbl_count.
*/
-void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
+void intel_pipe_update_end(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
enum pipe pipe = crtc->pipe;
+ int scanline_end = intel_get_crtc_scanline(crtc);
u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
+ ktime_t end_vbl_time = ktime_get();
- trace_i915_pipe_update_end(crtc, end_vbl_count);
+ trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
local_irq_enable();
- if (start_vbl_count && start_vbl_count != end_vbl_count)
- DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n",
- pipe_name(pipe), start_vbl_count, end_vbl_count);
+ if (crtc->debug.start_vbl_count &&
+ crtc->debug.start_vbl_count != end_vbl_count) {
+ DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n",
+ pipe_name(pipe), crtc->debug.start_vbl_count,
+ end_vbl_count,
+ ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time),
+ crtc->debug.min_vbl, crtc->debug.max_vbl,
+ crtc->debug.scanline_start, scanline_end);
+ }
}
static void
@@ -189,6 +203,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
int scaler_id;
plane_ctl = PLANE_CTL_ENABLE |
+ PLANE_CTL_PIPE_GAMMA_ENABLE |
PLANE_CTL_PIPE_CSC_ENABLE;
plane_ctl |= skl_plane_ctl_format(fb->pixel_format);
@@ -223,12 +238,12 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
else if (key->flags & I915_SET_COLORKEY_SOURCE)
plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
- surf_addr = intel_plane_obj_offset(intel_plane, obj);
+ surf_addr = intel_plane_obj_offset(intel_plane, obj, 0);
if (intel_rotation_90_or_270(rotation)) {
/* stride: Surface height in tiles */
tile_height = intel_tile_height(dev, fb->pixel_format,
- fb->modifier[0]);
+ fb->modifier[0], 0);
stride = DIV_ROUND_UP(fb->height, tile_height);
plane_size = (src_w << 16) | src_h;
x_offset = stride * tile_height - y - (src_h + 1);
@@ -598,7 +613,7 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
struct intel_plane *intel_plane = to_intel_plane(plane);
int pipe = intel_plane->pipe;
- I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
+ I915_WRITE(SPRCTL(pipe), 0);
/* Can't leave the scaler enabled... */
if (intel_plane->can_scale)
I915_WRITE(SPRSCALE(pipe), 0);
@@ -923,8 +938,6 @@ intel_commit_sprite_plane(struct drm_plane *plane,
crtc = crtc ? crtc : plane->crtc;
- plane->fb = fb;
-
if (!crtc->state->active)
return;
@@ -1121,7 +1134,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
intel_plane->pipe = pipe;
intel_plane->plane = plane;
- intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe);
+ intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane);
intel_plane->check_plane = intel_check_sprite_plane;
intel_plane->commit_plane = intel_commit_sprite_plane;
possible_crtcs = (1 << pipe);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 0568ae6ec9dd..6bea78944cd6 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1138,13 +1138,13 @@ static void intel_tv_pre_enable(struct intel_encoder *encoder)
j = 0;
for (i = 0; i < 60; i++)
- I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
+ I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
for (i = 0; i < 60; i++)
- I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
+ I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
for (i = 0; i < 43; i++)
- I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
+ I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
for (i = 0; i < 43; i++)
- I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
+ I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
I915_WRITE(TV_CTL, tv_ctl);
}
@@ -1291,7 +1291,7 @@ static void intel_tv_find_better_format(struct drm_connector *connector)
return;
- for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) {
+ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
tv_mode = tv_modes + i;
if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
@@ -1579,7 +1579,7 @@ intel_tv_init(struct drm_device *dev)
struct intel_encoder *intel_encoder;
struct intel_connector *intel_connector;
u32 tv_dac_on, tv_dac_off, save_tv_dac;
- char *tv_format_names[ARRAY_SIZE(tv_modes)];
+ const char *tv_format_names[ARRAY_SIZE(tv_modes)];
int i, initial_mode = 0;
if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
@@ -1677,7 +1677,7 @@ intel_tv_init(struct drm_device *dev)
/* Create TV properties then attach current values */
for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
- tv_format_names[i] = (char *)tv_modes[i].name;
+ tv_format_names[i] = tv_modes[i].name;
drm_mode_create_tv_properties(dev,
ARRAY_SIZE(tv_modes),
tv_format_names);
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 9d3c2e420d2b..43cba129a0c0 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -27,7 +27,7 @@
#include <linux/pm_runtime.h>
-#define FORCEWAKE_ACK_TIMEOUT_MS 2
+#define FORCEWAKE_ACK_TIMEOUT_MS 50
#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__))
@@ -52,8 +52,7 @@ static const char * const forcewake_domain_names[] = {
const char *
intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id)
{
- BUILD_BUG_ON((sizeof(forcewake_domain_names)/sizeof(const char *)) !=
- FW_DOMAIN_ID_COUNT);
+ BUILD_BUG_ON(ARRAY_SIZE(forcewake_domain_names) != FW_DOMAIN_ID_COUNT);
if (id >= 0 && id < FW_DOMAIN_ID_COUNT)
return forcewake_domain_names[id];
@@ -526,7 +525,7 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
}
/* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+#define NEEDS_FORCE_WAKE(reg) \
((reg) < 0x40000 && (reg) != FORCEWAKE)
#define REG_RANGE(reg, start, end) ((reg) >= (start) && (reg) < (end))
@@ -728,7 +727,7 @@ static u##x \
gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
GEN6_READ_HEADER(x); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
- if (NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+ if (NEEDS_FORCE_WAKE(reg)) \
__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
val = __raw_i915_read##x(dev_priv, reg); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
@@ -762,7 +761,7 @@ chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
GEN6_READ_FOOTER; \
}
-#define SKL_NEEDS_FORCE_WAKE(dev_priv, reg) \
+#define SKL_NEEDS_FORCE_WAKE(reg) \
((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
#define __gen9_read(x) \
@@ -770,9 +769,10 @@ static u##x \
gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
enum forcewake_domains fw_engine; \
GEN6_READ_HEADER(x); \
- if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+ hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
+ if (!SKL_NEEDS_FORCE_WAKE(reg)) \
fw_engine = 0; \
- else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
fw_engine = FORCEWAKE_RENDER; \
else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
fw_engine = FORCEWAKE_MEDIA; \
@@ -783,6 +783,7 @@ gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
if (fw_engine) \
__force_wake_get(dev_priv, fw_engine); \
val = __raw_i915_read##x(dev_priv, reg); \
+ hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
GEN6_READ_FOOTER; \
}
@@ -867,7 +868,7 @@ static void \
gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
GEN6_WRITE_HEADER; \
- if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+ if (NEEDS_FORCE_WAKE(reg)) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
__raw_i915_write##x(dev_priv, reg, val); \
@@ -882,7 +883,7 @@ static void \
hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
GEN6_WRITE_HEADER; \
- if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+ if (NEEDS_FORCE_WAKE(reg)) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
@@ -983,7 +984,8 @@ gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
bool trace) { \
enum forcewake_domains fw_engine; \
GEN6_WRITE_HEADER; \
- if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)) || \
+ hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
+ if (!SKL_NEEDS_FORCE_WAKE(reg) || \
is_gen9_shadowed(dev_priv, reg)) \
fw_engine = 0; \
else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
@@ -997,6 +999,8 @@ gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
if (fw_engine) \
__force_wake_get(dev_priv, fw_engine); \
__raw_i915_write##x(dev_priv, reg, val); \
+ hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
+ hsw_unclaimed_reg_detect(dev_priv); \
GEN6_WRITE_FOOTER; \
}
@@ -1198,8 +1202,6 @@ void intel_uncore_init(struct drm_device *dev)
switch (INTEL_INFO(dev)->gen) {
default:
- MISSING_CASE(INTEL_INFO(dev)->gen);
- return;
case 9:
ASSIGN_WRITE_MMIO_VFUNCS(gen9);
ASSIGN_READ_MMIO_VFUNCS(gen9);
@@ -1427,21 +1429,21 @@ static int ironlake_do_reset(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+ I915_WRITE(ILK_GDSR,
ILK_GRDOM_RENDER | ILK_GRDOM_RESET_ENABLE);
- ret = wait_for((I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) &
+ ret = wait_for((I915_READ(ILK_GDSR) &
ILK_GRDOM_RESET_ENABLE) == 0, 500);
if (ret)
return ret;
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+ I915_WRITE(ILK_GDSR,
ILK_GRDOM_MEDIA | ILK_GRDOM_RESET_ENABLE);
- ret = wait_for((I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) &
+ ret = wait_for((I915_READ(ILK_GDSR) &
ILK_GRDOM_RESET_ENABLE) == 0, 500);
if (ret)
return ret;
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, 0);
+ I915_WRITE(ILK_GDSR, 0);
return 0;
}
@@ -1529,13 +1531,22 @@ static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *)
int intel_gpu_reset(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = to_i915(dev);
int (*reset)(struct drm_device *);
+ int ret;
reset = intel_get_gpu_reset(dev);
if (reset == NULL)
return -ENODEV;
- return reset(dev);
+ /* If the power well sleeps during the reset, the reset
+ * request may be dropped and never completes (causing -EIO).
+ */
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+ ret = reset(dev);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+ return ret;
}
bool intel_has_gpu_reset(struct drm_device *dev)